Перевод текстов через API: пайплайн для больших объёмов
Перевести один абзац просто. Перевести десять тысяч строк без двойных списаний и с предсказуемой ценой — отдельная задача.
4 мин · · Обновлено · автоматизация · перевод
Модель под задачу, а не по умолчанию
Перевод — не самая творческая задача, поэтому гнать весь объём через самую дорогую модель бессмысленно. Для прямого перевода технических и маркетинговых текстов стоит начать с дешёвых glm-5.3-flash ($0.04/$0.04 за 1M токенов) и gpt-5.6-luna ($0.10/$0.10). Для художественных текстов или текстов с игрой слов, где важно сохранить тон, попробуйте claude-sonnet-5 ($0.30/$0.30) — проверьте на своих текстах, держит ли он стиль на длинных фрагментах лучше. Не обязательно выбирать одну модель на весь пайплайн: можно прогнать первый проход дешёвой моделью, а сложные абзацы — те, что редактор пометил — пересчитать через claude-opus-5-5.
Оценка стоимости до запуска
Перед тем как гнать десять тысяч строк, полезно посчитать токены бесплатно:
curl https://api.zukko.pro/v1/messages/count_tokens \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-sonnet-5","messages":[{"role":"user","content":"текст для перевода..."}]}'Запрос ничего не стоит и не идёт к модели, так что можно прогнать через него весь корпус заранее и посчитать примерный бюджет по цене модели из GET /v1/models/info — там же лимиты.
Пакетная обработка без двойного списания
Сетевые обрывы на большом объёме — обычное дело: клиент падает по таймауту, вы не знаете, дошёл ли перевод строки до биллинга, и повторяете запрос. Чтобы не заплатить дважды за одну и ту же строку, добавляйте заголовок Idempotency-Key с уникальным значением на каждую строку (например хэш от текста + номер строки):
import hashlib, requests
def translate_line(text, key):
idem = hashlib.sha256(f"{key}:{text}".encode()).hexdigest()
resp = requests.post(
"https://api.zukko.pro/v1/chat/completions",
headers={
"Authorization": "Bearer fetch_ваш_ключ",
"Idempotency-Key": idem,
},
json={
"model": "glm-5.3-flash",
"messages": [
{"role": "system", "content": "Переведи на английский, сохрани форматирование."},
{"role": "user", "content": text},
],
},
timeout=30,
)
return resp.json()Повтор запроса с тем же Idempotency-Key и тем же телом в течение 24 часов вернёт тот же ответ без нового списания. А если тело вдруг изменится при том же ключе — это ошибка 422 idempotency_conflict, сразу видно, что где-то разъехалась логика ретраев.
Кэш для повторяющихся фрагментов
В большом корпусе часто попадаются одинаковые куски — шаблонные фразы, повторяющиеся блоки интерфейса, юридические формулировки. Для них имеет смысл включить кэш ответов заголовком X-Zukko-Cache: true (temperature: 0 тоже включает кэш, но только у моделей, которые принимают этот параметр; Claude-модели — claude-sonnet-5, claude-opus-5-5 — могут отклонить temperature, отличную от 1, с ошибкой 400, поэтому им его не передавайте): тогда одинаковый запрос от одного пользователя кэшируется на срок до 7 суток для чата, повтор возвращается мгновенно и бесплатно. Срабатывает это только при полном совпадении тела запроса — тот же фрагмент с тем же системным промптом и параметрами; похожие, но не идентичные куски в кэш не попадают. В ответе это видно по заголовку X-Zukko-Cache: hit — удобно логировать долю кэш-хитов у себя, потому что в /v1/usage такие попадания не пишутся.
Батчинг нескольких строк в один запрос
Слать по одному короткому предложению за запрос дорого по накладным расходам: каждый вызов платит временем на обвязку ответа независимо от длины текста. Практичнее объединять пачку строк — 20-50 в зависимости от длины — в один запрос с нумерованным списком и просить вернуть перевод в том же порядке с теми же номерами. Вызовов на тот же объём текста становится меньше, а Idempotency-Key в этом случае вешается на пачку целиком, а не на каждую строку по отдельности.
Лимиты и что делать при 429
Собственного rate limit у шлюза нет. 429 от Zukko означает лимит расхода конкретного ключа: key_daily_limit_reached (сбрасывается в 00:00 UTC) или key_monthly_limit_reached, если на ключе в кабинете задан дневной или месячный лимит. Прочие 429 при параллельном прогоне приходят от провайдера модели; правильная реакция на них — не долбить запросами дальше, а сделать паузу с экспоненциальной задержкой и уменьшить параллелизм воркеров. Если пайплайн запущен ночью без присмотра, лимит на ключ — это ещё и страховка от того, что баг в цикле retry сожжёт весь баланс за час.
Резервная модель при отказе основной
Если основная модель для перевода недоступна (503 provider_unavailable или 503 model_disabled), скрипт должен уметь переключиться на резервную без остановки всего пайплайна. Обычно это соседняя модель того же уровня: gpt-5.6-luna как запасной вариант для glm-5.3-flash, claude-opus-5-5 как запасной для claude-sonnet-5. Разумно держать список фолбэков в конфиге, а не в коде, чтобы менять порядок без деплоя.
FALLBACK = {
"glm-5.3-flash": "gpt-5.6-luna",
"claude-sonnet-5": "claude-opus-5-5",
}
def translate_with_fallback(text, model="glm-5.3-flash"):
try:
return translate_line(text, model)
except requests.HTTPError as e:
if e.response.status_code == 503 and model in FALLBACK:
return translate_line(text, FALLBACK[model])
raiseПроверка качества выборочным обратным переводом
На большом объёме нет смысла вычитывать каждую строку вручную. Практичнее взять случайную выборку — например каждую сотую строку — и прогнать перевод обратно на исходный язык той же моделью. Если обратный перевод сильно расходится по смыслу с оригиналом, строка уходит в очередь на ручную проверку. Это не ловит стилистические огрехи, но надёжно ловит смысловые потери и случаи, когда модель домыслила отсутствующий в оригинале кусок.
Проверка результата и отслеживание расходов
По ходу прогона полезно смотреть заголовок X-Zukko-Cost-Micros в каждом ответе (он есть у обычных, не потоковых ответов) и складывать в лог — так видно среднюю цену строки перевода и можно поймать аномалию, если какая-то модель вдруг начала генерировать втрое больше токенов, чем обычно. Полную историю по завершении (общую на весь аккаунт, все ключи вместе) можно свести через GET /v1/usage с курсорной пагинацией — сверить фактический расход с тем, что насчитал count_tokens заранее.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- AI-агент для поиска работы: резюме под вакансию и сопроводительные письмаСобираем небольшой инструмент: вы даёте текст вакансии и файл с реальным опытом, получаете адаптированное резюме, письмо и список пробелов. Без выдуманных навыков.
- Художественные тексты с нейросетью: как писать вместе, а не вместоКак работать с моделью над прозой: собрать «библию» проекта, держать стиль, редактировать по проходам и считать стоимость длинного текста.
- Нейросеть для тестировщика: тест-кейсы, чек-листы и баг-репортыКак QA-инженеру использовать модель для тест-кейсов, чек-листов и баг-репортов, проверять полноту покрытия и не получить придуманные требования.
- Перевод субтитров нейросетью: SRT без сбитых таймкодовГлавный риск при переводе SRT нейросетью — сломанная структура файла. Показываем схему, где таймкоды не попадают к модели, и скрипт на Python с проверкой.