Как поднять ИИ-переводчик на своём сервере
DeepL и Google Cloud Translation берут плату за каждый переведённый символ, а бесплатный лимит — по 500 000 знаков в месяц у обоих — для документооборота компании кончается за неделю. Свой переводчик на сервере убирает счётчик и не отправляет текст на чужую инфраструктуру: движок — Ollama с обычной инструктированной моделью, которую нужно лишь научить не превращать перевод в диалог с пояснениями.
Содержание
- Зачем свой переводчик, когда есть DeepL и Google Translate
- Перевод — не диалог: почему инструктированная модель мешает сама себе
- Ставим движок: модель и Modelfile под перевод
- API и structured output: чистый перевод без комментариев модели
- Длинные документы: контекст, скорость и почему нельзя раздавать все потоки
- Честно: когда Ollama — не лучший инструмент для перевода
- Какой сервер брать под переводчик в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Зачем свой переводчик, когда есть DeepL и Google Translate
Оба крупных облачных переводчика устроены одинаково: бесплатная квота — по 500 000 символов в месяц у Google Cloud Translation (Basic) и DeepL API Free — дальше плата за каждый символ. Для разового письма хватает, для документооборота или каталога на несколько языков квота исчезает за считаные дни.
Вторая проблема — не деньги, а доступ: платный тариф обычно требует привязки карты, и для аккаунта из России это барьер ещё до того, как вы увидели цену за миллион символов. Третья — конфиденциальность: текст договора или переписки с клиентом целиком уходит на чужой сервер, прежде чем вернуться переводом.
Свой переводчик на сервере снимает все три ограничения разом. Если Ollama уже стоит у вас ради другой ИИ-задачи — например, автодополнения кода — добавить перевод — это команда ollama pull, а не второй движок и порт. Для одного лишь перевода экономичнее по памяти специализированные LibreTranslate и NLLB — этот путь мы разбирали отдельно. Здесь — перевод через ту же LLM, что уже отвечает за остальные ИИ-задачи.
Перевод — не диалог: почему инструктированная модель мешает сама себе
Спросите модель напрямую — и получите не перевод, а вежливый ответ ассистента вокруг него:
$ ollama run qwen2.5:7b "Переведи на английский: Оплата возможна картой российского банка, по СБП или криптовалютой."
Конечно! Вот перевод на английский:
"Payment can be made with a Russian bank card, via SBP, or in cryptocurrency."
Если нужно перевести что-то ещё — дайте знать!
Для человека это нормальный ответ. Для пайплайна, который ждёт чистую строку в поле интерфейса или файл локализации, это брак: кавычки, вступление и последняя фраза уедут прямо в продукт. Причина не в баге, а в обучении — модель дообучена быть полезным собеседником, а «полезность» для неё — это пояснить, предложить, уточнить. Ровно то, что не нужно движку перевода.
В статье про автодополнение кода проблема была обратной: нужен -base-тег в обход диалогового обучения. Для перевода наоборот — диалог как раз нужен, чтобы работал system-промпт, но сам рефлекс «объяснить, предложить, уточнить» нужно заблокировать явно.
Первый слой защиты — system-промпт, прямо запрещающий диалог: «Ты — движок машинного перевода. Возвращаешь только перевод, без вступлений и вопросов». Обычно достаточно, но не всегда: на двусмысленном тексте модель иногда добавит «Note:» или откажется переводить дословно. Второй, надёжный слой — формат ответа, физически не допускающий ничего, кроме перевода. У Ollama он есть с версии 0.5 (наш стенд — 0.33.1): параметр format принимает JSON-схему, и модель обязана вернуть строго соответствующий ей объект.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть OllamaСтавим движок: модель и Modelfile под перевод
Базовая установка Ollama — отдельная тема, разбирали её в статье про локальный запуск LLM; при заказе сервера в каталоге apps.maatrix.io она ставится автоматически, этот шаг можно пропустить.
ollama pull qwen2.5:7b
$ ollama list
NAME ID SIZE MODIFIED
qwen2.5:7b 845dbda0ea48 4.7 GB 2 minutes ago
Модель выбрана не случайно — единственная в статье с собственными замерами скорости на CPU (раздел ниже), а её словарь на 151 936 токенов устроен так, что не-английский текст режется на подтокены эффективнее — меньше токенов на фразу, быстрее генерация. Для языков вне основных двух-трёх десятков присмотритесь к aya-expanse:8b, модели Cohere с фокусом на 23 языка; собственных замеров для неё у нас нет — прогоните на своей нагрузке отдельно.
Постоянные настройки удобнее закрепить в Modelfile, а не передавать в каждом запросе:
FROM qwen2.5:7b
SYSTEM """
Ты — движок машинного перевода, не диалоговый ассистент. Возвращаешь только перевод текста, без вступлений, пояснений и вопросов. Не переводи содержимое внутри {{ }} и HTML-тегов — оставляй как есть. Сохраняй разметку и переносы строк исходного текста.
"""
PARAMETER temperature 0.2
PARAMETER num_ctx 8192
PARAMETER num_predict 4096
ollama create translator -f Modelfile
Низкая температура (0.2) убирает творческую вариативность — перевод должен быть точным, а не «одним из вариантов»; для полной воспроизводимости добавьте PARAMETER seed 42. num_predict 4096 даёт достаточно токенов на длинный абзац, не обрезая ответ на середине — почему это критично, увидите ниже.
API и structured output: чистый перевод без комментариев модели
Без ограничения формата ответ приходит так же, как в примере выше. Добавляем format с JSON-схемой — и модель не может вернуть ничего, кроме объекта с полем перевода:
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "translator",
"prompt": "Переведи на английский: Оплата возможна картой российского банка, по СБП или криптовалютой.",
"stream": false,
"format": {
"type": "object",
"properties": {
"translation": {"type": "string"}
},
"required": ["translation"]
}
}' | jq -r '.response | fromjson | .translation'
Payment can be made with a Russian bank card, via SBP, or in cryptocurrency.
Важная деталь: поле .response у Ollama — всегда строка. Со схемой в ней лежит валидный JSON, поэтому парсите дважды: сначала ответ API, потом .response как отдельный JSON — в примере это fromjson в jq, в Python — два json.loads подряд.
Если не хочется собирать отдельную модель через Modelfile ради одного проекта, system-промпт можно передать прямо в запросе полем system, без ollama create — настройка тогда живёт в коде клиента.
У строгого формата есть обратная сторона: если num_predict не хватает на длинный ответ, генерация обрывается посреди JSON-строки, и парсер падает с честной ошибкой:
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 17 (char 16)
Лечится поднятием num_predict под реальный объём текста (абзац на 1500 знаков — в среднем 400–500 токенов на выходе, берите с запасом в два-три раза).
Отдельно проверьте текст с плейсхолдерами — то, что реально встречается в интерфейсах: Здравствуйте, {name}! У вас <b>3 новых сообщения</b>. Без запрета модель нередко переводит и содержимое тега, и имя переменной внутри {}. Правило из Modelfile запрещает трогать {{ }} и HTML-теги, но новый формат (%s, :username) придётся добавлять явно — само не обобщается.
Длинные документы: контекст, скорость и почему нельзя раздавать все потоки
У каждой модели в Ollama есть потолок контекста — смотрите его через ollama show:
$ ollama show qwen2.5:7b | grep -A1 context
context length 32768
Это предел самой модели, а не то, что Ollama выделит по умолчанию — дефолт обычно скромнее. Письмо на пару страниц в него может не поместиться, и модель молча переведёт только видимый хвост, без ошибки в логах. num_ctx 8192 из Modelfile выше — запас для документов на 5–6 тысяч знаков; для более длинных поднимайте значение или режьте текст на абзацы, держа в system-промпте список терминов, чтобы одно слово не переводилось по-разному в соседних кусках.
Перевод не похож на чат или автодополнение по нагрузке: там ответ короче вопроса, а перевод примерно равен исходнику по длине — время съедает не обработка входа (prompt eval), а генерация (eval), которая у LLM на порядок медленнее. На нашем стенде (AMD EPYC 9554, 16 vCPU = 8 физических ядер плюс их гипертреды, Ollama 0.33.1) генерация qwen2.5:7b выходит на полку около 7,4–7,6 ток/с уже на 4 потоках — дальше ядра почти не помогают, упор в память, а не в вычисления; обработка входа на 16 потоках быстрее, 68,0 ток/с. Письмо в 1800 знаков — около 500 токенов на входе и столько же на выходе, то есть порядка минуты на генерацию плюс несколько секунд на вход; для потока в сотни документов в день это счётчик, который стоит прикинуть заранее.
Не раздавайте процессу все потоки без разбора: на том же стенде 32 потока при 16 vCPU обрушивают генерацию до 0,35 ток/с — в двадцать раз медленнее, чем на 4–8. Причина — oversubscription: планировщик ОС дробит время между вдвое большим числом потоков, чем есть исполнителей. Держите число потоков на уровне физических ядер сервера; подробнее — в статье Ollama не использует все ядра CPU.
Генерация и память других моделей на тех же 16 потоках:
| Модель | Генерация, ток/с (16 потоков) | В памяти |
|---|---|---|
| qwen2.5:3b | 34,1 | 2,2 ГБ |
| mistral:7b | 12,1 | 5,0 ГБ |
| llama3.1:8b | 12,8 | 5,6 ГБ |
| qwen2.5:7b | 7,4–7,6 | 5,1 ГБ |
gemma2:9b в том же прогоне дала 8,8 ток/с — память для неё отдельно не фиксировали, в таблицу не включаем. Mistral и llama3.1 обгоняют qwen2.5:7b при сопоставимом числе параметров — цена широкого словаря, выгодного для нелатинских языков, но занимающего часть параметров модели.
Честно: когда Ollama — не лучший инструмент для перевода
Первое ограничение — невоспроизводимость: при температуре выше нуля один и тот же текст может дать разную формулировку между запусками. Для чата незаметно, для файла локализации в git — лишний шум в диффе. Фикс — PARAMETER seed и температура ближе к нулю, но по умолчанию это не включено.
Второе — цена ресурса на символ: LLM в несколько гигабайт весов ради короткой строки интерфейса избыточна, специализированные модели вроде LibreTranslate или компактных конфигураций NLLB занимают на порядок меньше памяти. Для тысяч однотипных строк экономичнее решение из статьи про переводчик на локальной модели; Ollama выигрывает там, где важны контекст, тон и инструкции вроде «не трогай плейсхолдеры».
Третье — качество на редких языковых парах: данные большинства открытых моделей смещены к английскому, китайскому и крупным европейским языкам, и для пар вроде русский — узбекский результат стоит проверять предметно. aya-expanse с фокусом на 23 языка отчасти закрывает разрыв, но тоже требует проверки на своих текстах.
Четвёртое — потолок скорости на CPU: для десятков писем в день конфигурации выше хватает, для сотен документов в час или перевода в реальном времени упрётесь в предел 7,4–7,6 ток/с на экземпляр — и честный ответ не «добавить потоков» (см. обвал до 0,35 ток/с выше), а GPU или отдельный движок под большой поток.
| LLM через Ollama | Специализированная MT | |
|---|---|---|
| Контекст и тон | Учитывает | Не учитывает |
| Плейсхолдеры и разметка | Управляемо промптом | Часто ломает |
| Память на экземпляр | Единицы ГБ | Сотни МБ |
| Скорость на символ | Ниже | Выше |
| Воспроизводимость | Нужен seed | Стабильна by design |
Ни один из столбцов не отменяет другой — это вопрос задачи, а не превосходства одного инструмента.
Какой сервер брать под переводчик в MAATRIX
Честный минимум — 4 vCPU, 8 ГБ RAM, 40 ГБ NVMe. qwen2.5:7b весит 5,1 ГБ в памяти по нашим замерам — на 8 ГБ это запас под систему и разовый всплеск, не более: больше одного-двух параллельных запросов в моменте лучше не ждать. При нехватке памяти вы получите честную ошибку ещё до первого токена — Ollama проверяет память заранее:
Error: model requires more system memory (5.1 GiB) than is available (3.4 GiB)
Комфортный вариант — 8 vCPU, 16–32 ГБ RAM, 80–100 ГБ NVMe: помещаются одновременно qwen2.5:7b и aya-expanse:8b (OLLAMA_MAX_LOADED_MODELS=2), очередь из нескольких клиентов не растягивается на минуты. qwen2.5:14b тяжелее примерно вдвое по памяти при той же квантизации — от 10–11 ГБ только под веса, если решите поднять качество этим путём.
Для сотен документов в час или перевода в реальном времени разговор о CPU заканчивается — нужна видеокарта: 7–8B в 4-битном квантовании требует порядка 5–6 ГБ VRAM, у MAATRIX это уровень RTX 4090 или A5000, подробнее — в статье про GPU-сервер в Великобритании для инференса LLM.
Локация — Великобритания: для документов и переписки с европейскими контрагентами низкий пинг до ЕС и деловая респектабельность юрисдикции значат больше, чем для внутреннего инструмента, а конфиденциальность текста — ради которой вы и заводили свой переводчик — требует юрисдикции без лишних вопросов к трансграничной передаче. Для аудитории строго внутри России ближе российская локация.
Ollama из каталога apps.maatrix.io ставится на сервер автоматически при заказе — команды из раздела про установку не понадобятся, доступы появляются в кабинете. Дальше — ollama pull qwen2.5:7b, Modelfile из статьи и первый перевод через API за несколько минут. Оплата — картой российского банка, по СБП, криптой или токеном MAAT, зарубежная карта для Лондона не нужна. Заказать конфигурацию под задачу — аренда VPS для доступа к нейросетям в Великобритании.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть OllamaОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Как убрать «Конечно! Вот перевод:» и другие комментарии модели?
Задайте system-промпт, запрещающий диалог, и передавайте format с JSON-схемой вида {"translation": "string"} в /api/generate. Со схемой модель физически не вернёт ничего, кроме поля перевода — в отличие от текстового промпта, который она иногда нарушает.
Какую модель Ollama взять для перевода на русский?
qwen2.5:7b: единственная модель в статье с собственными замерами на CPU и словарём на 151 936 токенов, который эффективнее режет нелатинские языки. Для пар вне основных двух-трёх десятков языков присмотритесь к aya-expanse (фокус на 23 языка), но прогоните её на своих текстах — готовых замеров у нас нет.
Хватит ли CPU-сервера или сразу брать GPU?
Для десятков писем в день хватает CPU: qwen2.5:7b держит около 7,4–7,6 ток/с генерации на 4–8 потоках в наших замерах. Для сотен документов в час или перевода в реальном времени нужна видеокарта — на CPU очередь будет расти быстрее, чем вы её разберёте, а лишние потоки вместо GPU только обрушивают скорость.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.