AI-перевод
Команда yfm translate умеет переводить документацию большими языковыми моделями (LLM). Поддерживаются провайдеры yandexgpt, openai, openrouter и anthropic.
Пайплайн тот же, что и у остальных провайдеров перевода: текст извлекается из разметки, переводится и собирается обратно. Разметка Markdown, HTML-теги, код и Liquid-конструкции в модель не попадают - переводятся только текстовые сегменты.
Провайдер здесь описывает протокол API, а не конкретного вендора: любую совместимую инсталляцию (self-hosted модель, внутренний шлюз) можно подключить тем же провайдером, заменив адрес API.
Быстрый старт
-
Получите ключ API и передайте его через переменную окружения или опцию
--auth(значение или путь к файлу с токеном):export OPENAI_API_KEY="sk-..." -
Оцените объем перевода без запросов к API:
yfm translate -i . -o ./translated --provider openai --source ru --target en --dry-runВ строке
PROCESSEDбудет прогноз количества запросов и токенов. Файлы в output при этом собираются с исходным, непереведенным текстом - не принимайте их за результат перевода. -
Попробуйте перевод на одном файле или разделе:
yfm translate -i . -o ./translated --provider openai --source ru --target en \ --files ru/index.md --cache-dir .translate-cacheПроверьте качество результата и при необходимости настройте глоссарий или промпты.
-
Запустите полный прогон с кэшем и копированием ассетов:
yfm translate -i . -o ./translated --provider openai --source ru --target en \ --cache-dir .translate-cache --copy-assets -
Проверьте результат: повторный запуск той же команды должен показать
requests: 0- все сегменты берутся из кэша. Переведенную версию можно собрать обычнымyfm build.
Ошибка одного файла или превышение лимитов не останавливают прогон: упавшие файлы помечаются ERR, остальные продолжаются. Перезапуск команды доведет хвосты - уже переведенные сегменты возьмутся из кэша.
Провайдеры
|
Провайдер |
API |
Модель по умолчанию |
Переменные окружения |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Авторизация:
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. Путь запроса доклеивается к базе автоматически:
|
Провайдер |
База по умолчанию |
Путь запроса |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Для 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-провайдеров.
|
Опция |
По умолчанию |
Описание |
|
|
|
Провайдер перевода. Для AI-перевода: |
|
|
из переменной окружения |
Токен или путь к файлу с токеном. В файл конфигурации класть нельзя |
|
|
зависит от провайдера |
Идентификатор модели |
|
|
- |
Идентификатор каталога Yandex AI Studio. Только для |
|
|
URL API провайдера |
База URL для совместимых инсталляций |
|
|
- |
Дополнительный HTTP-заголовок в формате |
|
|
встроенный |
Системный промпт: строка или путь к файлу. См. Промпты |
|
|
встроенный |
Пользовательский промпт: строка или путь к файлу |
|
|
|
|
|
|
- |
Путь к YAML-файлу с обязательными переводами терминов, относительно input. См. Глоссарий |
|
|
выключено |
Оценка качества перевода второй моделью. См. Оценка качества |
|
|
модель перевода |
Модель для оценки качества |
|
|
|
Порог: сегменты с оценкой ниже попадают в отчет и в лог |
|
|
- |
Директория персистентного кэша переводов. См. Кэш |
|
|
- |
Отключить кэш для текущего запуска |
|
|
|
Температура сэмплирования. |
|
|
|
Максимум токенов в одном ответе модели |
|
|
|
Бюджет входных токенов одного запроса. Сегменты группируются в батчи до этого лимита |
|
|
|
Максимум одновременных запросов к API |
|
|
|
Число повторов при временных ошибках API |
|
|
|
Таймаут одного запроса в миллисекундах |
Конфигурация в файле
Все опции, кроме --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
|
Поле |
Описание |
|
|
Термин на языке оригинала, то есть на языке из |
|
|
Перевод, который должен попасть в результат. Повторите исходное написание, чтобы термин остался без изменений |
Глоссарий один на запуск и не привязан к языковой паре, поэтому для перевода на несколько языков нужен отдельный файл на каждый --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 оценка не выполняется.
Как читать лог
|
Строка |
Что означает |
|
|
Файл взят в работу. Если строки нет - файл не попал в scope прогона (фильтры |
|
|
Файл отфильтрован; в скобках причина: |
|
|
Батч из N сегментов отправлен в модель. В |
|
|
Файл переведен и записан в output |
|
|
Сегмент крупнее |
|
|
Ответ модели не разобрался на фрагменты, батч повторяется по одному сегменту |
|
|
Оценка сегмента ниже |
|
|
Файл не переведен, прогон продолжается. Фатальна только ошибка авторизации |
|
|
Итог по прогону: запросы, токены, объем текста и число сегментов из кэша |
|
|
Итог оценки качества |
Решение проблем
Ошибка 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 после перевода нет - такие случаи помогает находить оценка качества.