AI-перевод

Статья обновлена 22 сентября 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 (можно повторять). Пользовательские заголовки перекрывают стандартные, поэтому так можно целиком заменить авторизацию. Если заголовок авторизации передан через --api-header, опция --auth не нужна - стандартный заголовок авторизации в этом случае не отправляется:

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

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

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

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

Опция

По умолчанию

Описание

--provider

yandex

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

--auth

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

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

--model

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

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

--fallback-model

-

Резервная модель в том же формате, что --model. См. Резервная модель

--folder

-

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

--api-base

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

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

--fallback-api-base

значение --api-base

База URL только для резервной модели. Требует --fallback-model. См. Резервная модель

--api-header

-

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

--system-prompt

встроенный

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

--user-prompt

встроенный

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

--prompt-mode

append

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

--context-file

-

Дополнительный контекст для промпта: путь к текстовому файлу или многострочный текст. Можно повторять. См. Контекст перевода

--glossary

-

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

--judge

выключено

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

--judge-model

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

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

--judge-threshold

70

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

--cache-dir

-

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

--no-cache

-

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

--temperature

0

Температура сэмплирования. 0 - детерминированный перевод. Значение none не отправляет параметр в запросе, модель использует свое значение. См. Модель не принимает temperature

--max-output-tokens

4000

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

--max-batch-tokens

2000

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

--max-concurrency

5

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

--retry

3

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

--rate-limit-retry

8

Число повторов запросов, отклоненных с кодом 429. Считается отдельно от --retry. См. Ошибка 429

--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}} - контекст документа (заголовок и путь файла);
  • {{contextFiles}} - секции из --context-file;
  • {{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'."

Контекст перевода

Опция --context-file передает модели справочные материалы произвольной структуры: описание проекта, стайлгайд, тексты интерфейса, заметки по терминологии. Опцию можно повторять - каждое значение становится отдельной секцией.

Значение - путь к текстовому файлу (md, json, txt - содержимое уходит в модель как есть) или сразу многострочный текст. Значение без переноса строки считается путем: если такого файла нет, команда завершится ошибкой Context file not found.

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --context-file ./styleguide.md --context-file ./ui-texts.json

Секции добавляются в конец системного промпта. Чтобы управлять размещением, используйте плейсхолдер {{contextFiles}} в --system-prompt или --user-prompt.

В файле конфигурации опция называется contextFiles и принимает список. Пути из командной строки считаются от текущей директории, пути из конфигурации - от расположения .yfm:

translate:
  contextFiles:
    - styleguide.md
    - |
      Product names are never translated.

Как и глоссарий, контекст уходит в каждый запрос и расходует токены на каждом батче - держите его компактным. Изменение контекста инвалидирует кэш переводов.

Глоссарий

Модель переводит каждый сегмент отдельно и не видит, как этот же термин переведен в соседнем файле или в предыдущем запуске. Из-за этого «сборка» в одном месте становится 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}}, см. Промпты). Отсюда следуют три особенности:

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

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

Резервная модель

Опция --fallback-model задает вторую модель на том же провайдере. Если запрос не удался после всех повторов (включая повторы rate limit), батч отправляется резервной модели - с теми же учетными данными, базой API и заголовками. Другой провайдер или другой ключ для резервной модели указать нельзя.

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

Переключение видно в логе: WARN ... Primary model failed (...); retrying with the fallback model, а в итоговой строке прогона растет счетчик fallback в requests. Ошибка авторизации фатальна и резервной моделью не перезапускается - учетные данные у моделей общие.

Опция --fallback-api-base переопределяет базовый URL только для резервной модели. Она нужна шлюзам, которые маршрутизируют запросы путем: если вендор зашит в путь, а имя модели едет в теле запроса, то через базу основной модели резерв другого вендора недостижим - шлюз отвечает ошибкой вида «model is not available for vendor».

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --api-base https://gateway.example.com/anthropic/v1 --model claude-sonnet-4-5 \
  --fallback-api-base https://gateway.example.com/openai/v1 --fallback-model gpt-4o \
  --cache-dir .translate-cache

Провайдер, учетные данные и заголовки у резервной модели остаются общими с основной - переопределяется только база URL, поэтому оба адреса должны говорить на протоколе выбранного провайдера. Без --fallback-model опция считается ошибкой конфигурации.

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

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

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

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

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

Наполнение кэша из готовых переводов

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

yfm translate seed -i . --source ru --target en --cache-dir .translate-cache

Переводы должны лежать в том же корне, что и исходники, в директории целевого языка (ru/page.md -> en/page.md). Для каждого исходного файла его перевод разбивается на сегменты тем же способом, что при переводе, а затем сегменты сопоставляются.

Как сопоставляются файлы

Сопоставление идет по блокам. Блок - это абзац, элемент списка, строка таблицы, заголовок, заголовок ката: одна строка скелета документа с сегментами (для YAML-файлов - одно переводимое свойство). Блоки двух файлов выравниваются по структуре и по языконезависимым якорям текста: ссылкам, инлайн-коду и числам. Внутри пары блоков сегменты сопоставляются позиционно.

Расхождение остается внутри своего блока. Если переводчик слил два предложения абзаца в одно, из сида выпадает только этот абзац, остальной файл наполняет кэш. Раздел, которого в переводе еще нет, пропускается; раздел, который переехал в другое место, находится по якорям.

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

Сегменты, оставшиеся непереведенными (текст совпадает с исходным и содержит символы исходной письменности), не наполняют кэш - их переведет модель.

Повторяющиеся предложения

Сид хранит два представления пар:

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

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

Результат

Результат сохраняется в файл seed.<источник>-<цель>.json в директории кэша. В отличие от основного кэша он не привязан к провайдеру и модели и переживает смену промптов, глоссария и модели. При переводе он проверяется раньше основного кэша, поэтому отражает фактическое состояние переводов, включая ручные правки. Повторный запуск seed полностью перезаписывает файл.

Подкоманда принимает те же опции области действия, что и перевод (--files, --include, --exclude, --vars), опция --cache-dir обязательна. Итог в логе:

PROCESSED ru-en seeded-files: 1090 seeded-units: 24500 skipped-units: 12 missing-targets: 34 mismatched: 3 failed: 34 partial-files: 140 unseeded-units: 900 doubtful-units: 25

Счетчик

Что означает

seeded-files, seeded-units

Файлы и сегменты, давшие пары, включая частично наполненные файлы

skipped-units

Непереведенные сегменты, оставленные модели

missing-targets

Исходные файлы без перевода

partial-files, unseeded-units

Файлы, чей перевод сопоставился частично, и их сегменты, оставшиеся без пары

mismatched

Файлы, чей перевод не сопоставился с исходником совсем

failed

Файлы, чей исходник или перевод не удалось прочитать или разобрать

doubtful-units

Сомнительные пары: сохранены для своего файла, но не попали в словарь

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

WARN ru/releases.md Existing translation diverges in 13 of 270 units; they were not seeded.
WARN ru/alien.md Existing translation does not align with the source; the file was not seeded.
WARN ru/broken.md Failed to seed the file: ...

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

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

Опция --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 оценка не выполняется.

Починка ответов модели

Модель иногда отвечает не тем, о чем ее просили: добавляет выделение вокруг фрагмента, теряет маркер инлайн-разметки или возвращает текст непереведенным. Три таких случая CLI разбирает сам, до сборки файла. Каждый попадает в блок fixes отчета о прогоне и в итоговую строку лога, а два последних дают в логе отдельные предупреждения.

Случай

Что делает CLI

Счетчики

Лишняя разметка

Модель обернула перевод в **, _ или другой разделитель, которого не было в оригинале. Лишние разделители снимаются молча - на исходных и на кэшированных переводах одинаково

markupStripped

Поврежденная разметка

Модель потеряла маркер разметки, и строка не собирается. Фрагмент перезапрашивается отдельным запросом; если повтор не починил разметку, во фрагменте остается исходный текст - непереведенный фрагмент собирается корректно, а поломанная разметка нет

markupRetried, markupDamaged

Непереведенный фрагмент

Модель вернула текст неизменным на исходном языке. Фрагмент перезапрашивается; если и повтор вернул то же самое, остается исходный текст. В кэш такой сегмент не попадает, поэтому следующий прогон попробует его снова

untranslatedRetried, untranslatedKept

Фрагменты, оставшиеся с исходным текстом, попадают в счетчик units.untranslated отчета. В режиме --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 ... N fragment(s) came back untranslated; retrying them

Модель вернула фрагменты неизменными, они перезапрашиваются. См. Починка ответов модели

WARN ... N fragment(s) came back with damaged markup; retrying them

Модель повредила разметку фрагментов, они перезапрашиваются

WARN ... N fragment(s) stayed damaged after the retry; keeping their source text

Повтор не починил разметку, во фрагментах остался исходный текст

WARN <файл> Unit returned untranslated by the model.

Сегмент вернулся непереведенным и после повтора. В кэш он не записывается

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

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

WARN ... Primary model failed ... retrying with the fallback model

Батч не переведен основной моделью и отправлен резервной

WARN ... The model refused the configured temperature; requests continue without it

Модель не принимает заданную температуру, запросы идут без параметра. См. Модель не принимает temperature

ERR <файл> ...

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

PROCESSED run <статус> in Ts; files: ...; units: ...; requests: ...

Итог по прогону: статус, длительность, файлы, сегменты и доля кэша, символы, токены, запросы (с числом запросов к резервной модели и повторов) и ошибки. Те же числа в машиночитаемом виде дает опция --report

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

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

Строка итога выглядит так:

INFO PROCESSED run success in 12.4s; files: 12 translated, 0 failed; units: 340 (154 cached, 45.3% hit rate); chars: 15200 in / 16900 out; tokens: 5200 in / 4800 out; requests: 18 (2 fallback, 3 retries); errors: 0

Если в прогоне что-то чинилось, в строку добавляются разделы про снятую и поврежденную разметку и про непереведенные фрагменты: счетчики, которые остались нулевыми, в итог не попадают.

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

Ошибка 429 (rate limit)

CLI сам повторяет такие запросы до --rate-limit-retry раз (по умолчанию 8) - это отдельный, больший бюджет, чем --retry для остальных временных ошибок. Паузы растут экспоненциально до 60 секунд, заголовок Retry-After учитывается, и пока окно rate limit длится, все запросы прогона приостанавливаются вместе. Если лимиты 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.

Модель не принимает temperature

Часть свежих моделей принимает только свое значение температуры и отвечает ошибкой на temperature: 0, который CLI шлет по умолчанию. Такой отказ распознается: запрос повторяется без параметра, дальше запросы идут без него, а в лог один раз выводится WARN ... The model refused the configured temperature; requests continue without it. Настраивать для этого ничего не нужно.

Отказаться от параметра заранее можно значением none:

yfm translate -i . -o ./translated --provider openai --source ru --target en \
  --temperature none --cache-dir .translate-cache

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

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

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

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

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

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

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

  • Путь запроса для каждого провайдера фиксирован - шлюз с нестандартным путем API подключить не получится.
  • Модель может повредить инлайн-разметку внутри сегмента (ссылки, выделение). Часть таких случаев CLI ловит и перезапрашивает сам, см. Починка ответов модели, но структурной валидации Markdown после перевода нет - остальное помогает находить оценка качества.