AI-перевод

Статья обновлена 13 августа 2026 г.

Команда yfm translate умеет переводить документацию большими языковыми моделями (LLM). Поддерживаются провайдеры yandexgpt, openai, openrouter и anthropic.

Пайплайн тот же, что и у остальных провайдеров перевода: текст извлекается из разметки, переводится и собирается обратно. Разметка Markdown, HTML-теги, код и Liquid-конструкции в модель не попадают - переводятся только текстовые сегменты.

Провайдер здесь описывает протокол API, а не конкретного вендора: любую совместимую инсталляцию (self-hosted модель, внутренний шлюз) можно подключить тем же провайдером, заменив адрес API.

Быстрый старт

  1. Получите ключ API и передайте его через переменную окружения или опцию --auth (значение или путь к файлу с токеном):

    export OPENAI_API_KEY="sk-..."
    
  2. Оцените объем перевода без запросов к API:

    yfm translate -i . -o ./translated --provider openai --source ru --target en --dry-run
    

    В строке PROCESSED будет прогноз количества запросов и токенов. Файлы в output при этом собираются с исходным, непереведенным текстом - не принимайте их за результат перевода.

  3. Попробуйте перевод на одном файле или разделе:

    yfm translate -i . -o ./translated --provider openai --source ru --target en \
      --files ru/index.md --cache-dir .translate-cache
    

    Проверьте качество результата и при необходимости настройте глоссарий или промпты.

  4. Запустите полный прогон с кэшем и копированием ассетов:

    yfm translate -i . -o ./translated --provider openai --source ru --target en \
      --cache-dir .translate-cache --copy-assets
    
  5. Проверьте результат: повторный запуск той же команды должен показать requests: 0 - все сегменты берутся из кэша. Переведенную версию можно собрать обычным yfm build.

Ошибка одного файла или превышение лимитов не останавливают прогон: упавшие файлы помечаются ERR, остальные продолжаются. Перезапуск команды доведет хвосты - уже переведенные сегменты возьмутся из кэша.

Провайдеры

Провайдер

API

Модель по умолчанию

Переменные окружения

yandexgpt

Yandex AI Studio

yandexgpt-lite

YANDEX_API_KEY, YC_IAM_TOKEN

openai

OpenAI Chat Completions

gpt-4o-mini

OPENAI_API_KEY

openrouter

OpenRouter

openai/gpt-4o-mini

OPENROUTER_API_KEY

anthropic

Anthropic Messages

claude-sonnet-4-5

ANTHROPIC_API_KEY

Авторизация:

  • yandexgpt - IAM-токен (t1.) или OAuth-токен (y0_) передаются как Bearer, любое другое значение - как Api-Key сервисного аккаунта. Дополнительно требуется --folder - идентификатор каталога, если --model задана коротким именем (yandexgpt-lite). Полный URI модели (gpt://<folder>/yandexgpt/latest) можно указывать без --folder.
  • openai, openrouter - Bearer-ключ.
  • anthropic - ключ в заголовке x-api-key.

Подключение совместимых инсталляций

Self-hosted модель или внутренний шлюз с совместимым API подключается тем же провайдером с опцией --api-base. Путь запроса доклеивается к базе автоматически:

Провайдер

База по умолчанию

Путь запроса

yandexgpt

https://llm.api.cloud.yandex.net

/foundationModels/v1/completion

openai

https://api.openai.com/v1

/chat/completions

openrouter

https://openrouter.ai/api/v1

/chat/completions

anthropic

https://api.anthropic.com/v1

/messages

Для openai, openrouter и anthropic включайте /v1 в базу. Базу можно задать и переменными окружения OPENAI_BASE_URL, OPENROUTER_BASE_URL, ANTHROPIC_BASE_URL.

Если шлюз требует свою схему авторизации, передайте заголовки опцией --api-header (можно повторять). Пользовательские заголовки перекрывают стандартные, поэтому так можно целиком заменить авторизацию. Опция --auth при этом формально обязательна - передайте заглушку:

yfm translate -i . -o ./translated \
  --provider openai \
  --api-base https://llm.internal.example.com/v1 \
  --model my-model \
  --auth dummy \
  --api-header "Authorization: OAuth $(cat ~/.tokens/llm)" \
  --source ru --target en --cache-dir .translate-cache

Путь запроса для каждого провайдера фиксирован: если шлюз использует нестандартный путь, переопределить его нельзя.

Справочник опций

Общие опции команды (--source, --target, --files, --include, --exclude, --dry-run и другие) описаны на странице Локализация. Опция --target может быть передана несколько раз - перевод выполнится на каждый язык. Ниже - опции AI-провайдеров.

Опция

По умолчанию

Описание

--provider

yandex

Провайдер перевода. Для AI-перевода: yandexgpt, openai, openrouter или anthropic. Значение по умолчанию yandex - это машинный перевод Yandex Translate, не LLM

--auth

из переменной окружения

Токен или путь к файлу с токеном. В файл конфигурации класть нельзя

--model

зависит от провайдера

Идентификатор модели

--folder

-

Идентификатор каталога Yandex AI Studio. Только для yandexgpt, обязателен при коротком имени модели

--api-base

URL API провайдера

База URL для совместимых инсталляций

--api-header

-

Дополнительный HTTP-заголовок в формате "Name: value". Можно повторять. Перекрывает стандартные заголовки

--system-prompt

встроенный

Системный промпт: строка или путь к файлу. См. Промпты

--user-prompt

встроенный

Пользовательский промпт: строка или путь к файлу

--prompt-mode

append

append - ваш системный промпт добавляется к встроенному, replace - полностью заменяет его

--glossary

-

Путь к YAML-файлу с обязательными переводами терминов, относительно input. См. Глоссарий

--judge

выключено

Оценка качества перевода второй моделью. См. Оценка качества

--judge-model

модель перевода

Модель для оценки качества

--judge-threshold

70

Порог: сегменты с оценкой ниже попадают в отчет и в лог

--cache-dir

-

Директория персистентного кэша переводов. См. Кэш

--no-cache

-

Отключить кэш для текущего запуска

--temperature

0

Температура сэмплирования. 0 - детерминированный перевод

--max-output-tokens

4000

Максимум токенов в одном ответе модели

--max-batch-tokens

2000

Бюджет входных токенов одного запроса. Сегменты группируются в батчи до этого лимита

--max-concurrency

5

Максимум одновременных запросов к API

--retry

3

Число повторов при временных ошибках API

--timeout

60000

Таймаут одного запроса в миллисекундах

Конфигурация в файле

Все опции, кроме --auth, можно зафиксировать в секции translate файла конфигурации .yfm. Имена - в camelCase, флаги командной строки имеют приоритет:

translate:
  provider: openai
  model: gpt-4o-mini
  cacheDir: .translate-cache
  maxConcurrency: 2
  apiHeaders:
    X-Custom-Header: value

Токен в конфигурации хранить нельзя: команда завершится ошибкой Do not store authToken in public config. Используйте переменные окружения или --auth.

Промпты

Встроенный системный промпт настроен на технический перевод: сохранять разметку, не переводить код и идентификаторы, не добавлять пояснений. Свои инструкции можно добавить к нему (--prompt-mode append, по умолчанию) или полностью заменить его (--prompt-mode replace).

Значение --system-prompt и --user-prompt - строка или путь к файлу. Поддерживаются плейсхолдеры:

  • {{source}}, {{target}} - языки перевода;
  • {{glossary}} - глоссарий в текстовом виде;
  • {{context}} - контекст документа (заголовок и путь файла);
  • {{separator}} - разделитель фрагментов;
  • {{fragments}}, {{text}} - переводимые фрагменты (только в --user-prompt).

Пример: потребовать соблюдения корпоративного тона:

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --system-prompt "Use formal tone. Address the reader as 'you'."

Глоссарий

Модель переводит каждый сегмент отдельно и не видит, как этот же термин переведен в соседнем файле или в предыдущем запуске. Из-за этого «сборка» в одном месте становится build, в другом - assembly, а название продукта неожиданно переводится. Глоссарий задает обязательные переводы терминов и убирает такой разнобой.

Типовые случаи:

  • у продукта есть устоявшаяся терминология, и перевод должен совпадать с интерфейсом и остальной документацией;
  • термин, название или идентификатор не должен переводиться вообще - тогда translatedText повторяет sourceText;
  • модель систематически ошибается в конкретном термине.

Глоссарий - YAML-файл с единственным ключом glossaryPairs. Это список пар «термин в оригинале - требуемый перевод»:

glossaryPairs:
  - sourceText: оглавление
    translatedText: table of contents
  - sourceText: сборка
    translatedText: build
  - sourceText: Diplodoc
    translatedText: Diplodoc

Поле

Описание

sourceText

Термин на языке оригинала, то есть на языке из --source

translatedText

Перевод, который должен попасть в результат. Повторите исходное написание, чтобы термин остался без изменений

Глоссарий один на запуск и не привязан к языковой паре, поэтому для перевода на несколько языков нужен отдельный файл на каждый --target.

Путь в --glossary указывается относительно --input:

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --glossary glossary.yaml

В файле конфигурации путь указывается относительно самого .yfm:

translate:
  glossary: glossary.yaml

Если файла нет, команда завершится с ошибкой.

Пары подставляются в промпт каждого запроса к модели списком вида термин → перевод (плейсхолдер {{glossary}}, см. Промпты). Отсюда следуют три особенности:

  • Это инструкция модели, а не замена по тексту после перевода. Термин из глоссария соблюдается почти всегда, но гарантии нет: результат стоит проверять поиском по переводу или оценкой качества.
  • Словоформы модель разбирает сама, отдельные строки на падежи и множественное число заводить не нужно.
  • Глоссарий целиком уходит в каждый запрос и расходует токены на каждом батче. Держите в нем только термины, которые действительно важны или которые модель путает, а не весь словарь продукта.

Изменение глоссария инвалидирует кэш переводов: после правки файла все сегменты переводятся заново.

Кэш переводов

Опция --cache-dir включает персистентный кэш: пары «сегмент - перевод» сохраняются на диск, и повторные запуски отправляют в модель только новые и измененные сегменты. Кэш сбрасывается на диск после каждого обработанного файла, поэтому прерывание прогона безопасно - перезапуск продолжит с того же места.

Как устроен кэш:

  • На каждую комбинацию «провайдер + модель + пара языков» создается отдельный файл <провайдер>.<модель>.<источник>-<цель>.json. Смена --model не затирает кэш другой модели, но и не использует его.
  • Изменение промптов или глоссария автоматически инвалидирует кэш: сохраненные переводы устаревают и выполняются заново. Обновление CLI со встроенными промптами действует так же.
  • --no-cache отключает кэш на один запуск, не удаляя сохраненные переводы.

Директорию кэша имеет смысл коммитить в репозиторий или сохранять между запусками CI - тогда при регулярных переводах оплачиваются только изменившиеся сегменты.

Оценка качества

Опция --judge включает оценку перевода второй моделью: каждая пара «оригинал - перевод» получает балл от 0 до 100. Режим строго опциональный - расход токенов вырастает примерно вдвое.

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --cache-dir .translate-cache --judge --judge-model gpt-4o --judge-threshold 80

По умолчанию оценивает та же модель, что переводила. Это удобно для поиска грубых ошибок, но такая самооценка завышена. Для честного сравнения используйте --judge-model с моделью не слабее переводящей: слабый судья не заметит ошибок сильного переводчика.

Результаты:

  • Сегменты с оценкой ниже --judge-threshold попадают в лог как WARN с баллом и причиной.

  • В output записывается отчет translate-quality.<язык>.json:

    {
      "model": "gpt-4o",
      "threshold": 80,
      "scored": 214,
      "averageScore": 93.4,
      "low": 2,
      "segments": [
        {
          "path": "ru/tools/docs/build.md",
          "source": "Сборка проекта выполняется командой...",
          "translation": "The project is built with...",
          "score": 55,
          "issue": "Omitted the second sentence"
        }
      ]
    }
    

    В segments попадают только сегменты ниже порога, отсортированные от худших к лучшим.

  • Итоговая строка в логе: judge: 214 units scored, average score 93.4/100, 2 below threshold 80. Первое число - количество оцененных сегментов, не балл.

Оценка не влияет на результат перевода и не прерывает прогон: сбой оценки отдельного батча логируется и пропускается. В --dry-run оценка не выполняется.

Как читать лог

Строка

Что означает

TRANSLATE <файл>

Файл взят в работу. Если строки нет - файл не попал в scope прогона (фильтры --files, --include, --exclude, язык)

SKIPPED [reason] <файл>

Файл отфильтрован; в скобках причина: exclude, include, language

REQUEST <файл> N units, ~X tokens

Батч из N сегментов отправлен в модель. В --dry-run таких строк нет

TRANSLATED <файл>

Файл переведен и записан в output

WARN ... Part is too big (~N tokens > M)

Сегмент крупнее --max-batch-tokens и остался на исходном языке

WARN ... Batch of N fragments failed ... retrying one-by-one

Ответ модели не разобрался на фрагменты, батч повторяется по одному сегменту

WARN <файл> Translation quality N/100: ...

Оценка сегмента ниже --judge-threshold

ERR <файл> ...

Файл не переведен, прогон продолжается. Фатальна только ошибка авторизации

PROCESSED requests: R input-tokens: I output-tokens: O bytes: B cached-units: C

Итог по прогону: запросы, токены, объем текста и число сегментов из кэша

PROCESSED judge: N units scored, average score A/100, M below threshold T

Итог оценки качества

Решение проблем

Ошибка 429 (rate limit)

CLI сам повторяет запрос до --retry раз с экспоненциальной паузой и учитывает заголовок Retry-After. Если лимиты API все равно превышаются, перезапустите прогон с меньшей параллельностью:

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --cache-dir .translate-cache --max-concurrency 2

Уже переведенные сегменты возьмутся из кэша, в модель уйдут только оставшиеся.

WARN Part is too big

Сегмент оказался крупнее --max-batch-tokens и остался на исходном языке. Увеличьте --max-batch-tokens (при необходимости вместе с --max-output-tokens) или разбейте текст в исходнике на более короткие абзацы.

Ответ модели обрезан

Ошибки вида response was truncated означают, что модели не хватило лимита ответа. Увеличьте --max-output-tokens или уменьшите --max-batch-tokens.

Файл не переводится

Если правка в файле не попадает в перевод, сначала проверьте scope прогона: опции --files и --include сужают набор файлов, и изменения вне этого набора в прогон не попадают - в логе для такого файла нет строки TRANSLATE. Это не проблема кэша.

Также помните, что кэш ведется отдельно на каждую модель: после смены --model переводы другой модели не переиспользуются.

В output исходный текст

  • После --dry-run это ожидаемо: файлы собираются без обращения к модели, с исходным текстом.
  • Отдельный сегмент может совпадать с оригиналом и в обычном прогоне: модель осознанно не переводит текст, который уже на целевом языке, имена собственные и нетекстовые фрагменты. Пустой ответ модели никогда не принимается за перевод - в этом случае сохраняется исходный текст.

Известные ограничения

  • Страницы с блоками ::: page-constructor внутри .md переводятся ненадежно (translation#273). Пока рекомендуется исключать их из прогона через --exclude.
  • Путь запроса для каждого провайдера фиксирован - шлюз с нестандартным путем API подключить не получится.
  • Модель может повредить инлайн-разметку внутри сегмента (ссылки, выделение). Структурной валидации Markdown после перевода нет - такие случаи помогает находить оценка качества.
Предыдущая
Следующая