20 KiB
00. Провайдерские грабли — справочник для адаптеров
Назначение: единый список практических особенностей LLM-провайдеров, найденных полигоном при живых вызовах. Бэкенд-сессия читает это напрямую при написании/правке адаптеров internal/llm, чтобы не переоткрывать в Go то, что уже поймано в Python. Дата: 2026-07-04, проверять при смене версий моделей.
Разделение ролей: полигон (eval/, Python) — тупой замерочный зонд, характеризует сырое поведение провайдера (отказ/качество/латентность); бэкенд (backend/internal/llm, Go) — продакшн-адаптеры (retry/failover/ledger). Код не общий (разные языки) и не должен быть — но знание о граблях общее и живёт здесь.
⚠ ПРАВИЛО ДВУХ НАПРАВЛЕНИЙ (решение владельца 10.07, после Gemini-кейса): (1) клейм о поведении модели → проверяй живой пробой (уже было правилом); (2) аномалия на проводе (интермиттентные 4xx/5xx, «model no longer available», новый/неожиданный finish_reason, молча игнорируемые параметры) → СНАЧАЛА официальная дока вендора (deprecations / changelog / status page) + свежий /models-листинг, ПОТОМ диагноз. Не гадать и не абсорбировать интерпретацию аномалии в доки/промты/адаптеры без вендор-сверки с датой и URL. Прецедент: 404-флейки gemini-2.5-flash интерпретировались вслепую, а офиц. дока сразу давала ответ — вся 2.5-серия EOL 16.10.2026 (см. календарь ниже).
Эндпоинты и модели (OpenAI-совместимые, если не указано иное)
| Провайдер | base_url | Модель (на 2026-07-04) | env-ключ |
|---|---|---|---|
| DeepSeek | https://api.deepseek.com/v1 |
deepseek-v4-flash (deepseek-chat не в /models, но работает как алиас до депрекации 24.07.2026; эхает zh — см. ниже, брать v4-flash с thinking) |
DEEPSEEK_API_KEY |
| xAI Grok | https://api.x.ai/v1 |
grok-4.3 (дефолт-редактор/переводчик; для thinking-OFF слать явный reasoning_effort:"none" — см. thinking-таблицу ниже; слаг НЕ меняем на non-reasoning вариант — он = grok-4.3+none под капотом, ретайр 15.05.2026). grok-4-fast не в /v1/models, но работает как алиас (HTTP 200). |
XAI_API_KEY |
| GLM (Z.ai) | https://api.z.ai/api/paas/v4 |
glm-4.5-air (дёшево) / glm-4.6; в /models: glm-4.7, glm-5, glm-5.1, glm-5.2 |
ZAI_API_KEY |
| Gemini | https://generativelanguage.googleapis.com/v1beta/openai |
gemini-2.5-flash, gemini-2.5-pro, gemini-3.1-pro-preview |
GEMINI_API_KEY |
| Kimi (Moonshot) | https://api.moonshot.ai/v1 (intl, не .cn) |
kimi-k2.6 (доступны k2.5, k2.7-code) |
KIMI_API_KEY |
| OpenAI | https://api.openai.com/v1 |
gpt-5-mini |
OPENAI_API_KEY |
| Qwen (DashScope intl) | https://dashscope-intl.aliyuncs.com/compatible-mode/v1 |
qwen-flash |
DASHSCOPE_API_KEY |
| OpenRouter | https://openrouter.ai/api/v1 |
зависит от хостера | OPENROUTER_API_KEY |
| Локаль (ollama) | http://localhost:11434/v1 (chat) или /api/generate |
тег модели | не нужен |
Thinking / reasoning — главный источник граблей
У всех современных моделей режим «размышления» включён по умолчанию и ломает роль переводчика: рассуждения съедают бюджет вывода → перевод обрезается или пустой, латентность ×3–5. Для роли переводчика/редактора reasoning обязателен к управлению. Как — зависит от провайдера:
| Провайдер | Поведение по умолчанию | Как управлять (для перевода) |
|---|---|---|
| DeepSeek v4-flash | гибридная reasoning-модель, thinking ON по умолчанию | Управление (официальные доки, api-docs.deepseek.com/guides/thinking_mode, проверено 04.07): в body extra_body={"thinking":{"type":"enabled"|"disabled"}} (дефолт enabled). Т.е. выключить МОЖНО, параметр есть. НО для роли ПЕРЕВОДЧИКА не выключать: disabled→non-thinking режим, который на плотном CJK ЭХАЕТ исходник. Оставлять thinking ВКЛ; reasoning→reasoning_content, content чистый; max_tokens ≥8000 (иначе reasoning съест бюджет → content пуст, finish=length — это НЕ отказ). ⚠ thinking-режим НЕ поддерживает temperature/top_p/penalties (шлём — молча игнорируются). reasoning_effort: только high/max (low/medium→high, xhigh→max); none НЕ существует → 400. Для дешёвой роли ЭКСТРАКЦИИ (не перевод) thinking можно выключить — echo бьёт по переводу, не по JSON-выводу (перепроверить). |
| GLM-4.5-air / 4.6 | thinking ON, не влезал в 180с | отключить: extra_body: {"thinking": {"type": "disabled"}} |
| Gemini 2.5 Flash | thinking ON, съедал max_tokens, молча обрезал перевод |
отключить: extra_body.google.thinking_config.thinking_budget: 0 |
| Gemini 3.1 Pro | thinking обязателен | thinking_budget:0 → HTTP 400 «only works in thinking mode». НЕ отключать; дать большой max_tokens (≥8000) |
| gpt-5-mini (reasoning) | reasoning ON, выжигал бюджет → пустой ответ | reasoning_effort: "minimal"; без temperature; max_completion_tokens вместо max_tokens |
| Kimi K2.6 | думающая, очень многословная: ~11k reasoning-токенов на абзац; reasoning в reasoning_content, ответ в content; при малом бюджете reasoning съедает лимит → content пуст (finish=length, не ошибка!) |
дать max_tokens ≥16000; ответ из content. Дорогой в роли редактора — reasoning биллится как выход |
| grok-4.3 (xAI) | reasoning ON по дефолту = low (must-be-explicit: не задал → думает) |
Off-switch (Chat Completions) — ПЛОСКИЙ reasoning_effort:"none" в теле (reasoning_effort ∈ {none,low,medium,high}). ⚠ Вложенная форма extra_body.reasoning.effort:"none" — это Responses API; Chat Completions её МОЛЧА ГЛОТАЕТ (остаётся дефолт low) — из-за этого exp08-проба ложно решила «не отключается». Проверено 05.07: reasoning_effort:"none"→usage.reasoning_tokens=0, дефолт→444, low→384 (на правке ~2000 ток.). reasoning у xAI аддитивен к completion (billed = completion+reasoning). grok-4.20-0309-non-reasoning = grok-4.3 + effort:none под капотом (ретайр 15.05.2026) → слаг не нужен, слать none явно. Для роли РЕДАКТОРА (ru-вход) — ВСЕГДА явный reasoning_effort:"none"; для роли ПЕРЕВОДЧИКА на плотном CJK reasoning-off НЕПРИГОДЕН (D19.1: эхо 4/10 + дегенеративный луп; ⚠ языковой констрейнт в system при none ИНВЕРТИРУЕТ эхо 3/10→9/10 — research/15 P4) — эскалация канала B идёт reasoning-ON. (Сужено оркестратором по D19.1/D21; было «editor/translator».) Источник: docs.x.ai/developers/model-capabilities/text/reasoning. |
| Qwen3.5 / локальные | thinking ON | ollama: think: false + num_predict cap. Иначе рассуждения (в поле thinking, не response) забивают контекст |
Находка (эксп. 03): reasoning реально улучшает реалии/имена в переводе (羅生門: «Радзёмон»→«Рашо-мон»), но локально нежизнеспособен (8.6 мин/фрагмент). Открытый вопрос для бэкенда: проверить think-ON на быстром облачном черновике/редакторе как рычаг качества.
Эхо как свойство КЛАССА, не квирк вендора (обобщение D19.2 / D21.9)
«reasoning-off + плотный CJK-вход = зона эха». Это свойство класса reasoning-моделей, а НЕ квирк отдельного вендора: воспроизведено на deepseek (non-thinking режим, 00-эхо-бюллетень выше) и на обоих слагах grok при reasoning_effort:"none" (exp10/D19.1: 4/10 verbatim-эхо + 1 дегенеративный луп на zh-фрагментах насилия, reasoning_tokens=0; контроль тех же фрагментов при reasoning-ON — 0/10 эха, reasoning_tokens>0). Механика одна: без цепочки рассуждений модель на плотной CJK-прозе возвращает исходник вместо перевода — валидный HTTP 200 с неправильным содержимым (не ошибка API, не content_filter; ретраи не спасают, эхо стохастично per-fragment). Следствия:
- Для роли ПЕРЕВОДЧИКА на плотном CJK reasoning-off непригоден в принципе (не только у одного вендора) — канал B переводит reasoning-ON (grok) либо не-reasoning-моделью без эхо-мины (Mistral: проба zh→ru чисто,
cjk_share=0). ⚠ Register-оговорка (exp11/D22, дописано оркестратором): reasoning-ON снимает эхо на СОВРЕМЕННОЙ прозе (совр. zh-вебновелла 0/10, совр. ja 1/6, en 0/6), но НЕ на архаичной плотно-ханьской (金瓶梅, минский байхуа: grok-ON эхо 4/6 приreasoning_tokens349–847; ON vs OFF там неразличимы) — эскалацию на grok-ON не считать лекарством от эха на архаичных zh-текстах; Mistral на той же архаике чист 6/6. - Downstream echo-гейт (
untranslated_echo,cjk_share>0.15) обязателен НАВСЕГДА и промпт-митигациями НЕ заменяется — это последняя линия против тихого провала. - ⚠ Инверсия языкового констрейнта (research/15 P4): языковая строка в
systemу reasoning-off модели может УСИЛИВАТЬ эхо, а не гасить его — на grokreasoning_effort:noneодна формулировка констрейнта подняла эхо 3/10→9/10. Проверена одна формулировка на одном слаге; чувствительность к формулировке/модели неизвестна. → Запрет (D21.6): не вносить языковые констрейнты в промпты reasoning-off путей без per-model замера. (Латентное:translator.md:10уже несёт языковую строку, но едет только на thinking-ON DeepSeek — вне зоны инверсии; при заводке Mistral-канала B прогнать P4-реплику на боевом промпте.)
Параметры сэмплинга
| Провайдер | Грабля |
|---|---|
| Kimi K2.6 | принимает только temperature: 1; иное → HTTP 400 «only 1 is allowed for this model» |
| gpt-5-mini | temperature не принимается вовсе (см. выше) |
Локаль (ollama /v1) |
top_k/min_p/repeat_penalty не пробрасываются (ollama issue #11325) → запекать в Modelfile (паттерн qwen3-vojo). Для llama-server — расширить запрос этими полями |
| Локаль (ollama) | max_tokens/num_predict покрывает thinking + ответ вместе (в отличие от xAI, где thinking сверх лимита) |
Контент-фильтры / safety
- Gemini:
safety_settingsчерез OpenAI-совместимый слой не передаются (HTTP 400 «Unknown name safety_settings»). Дефолт фильтров у 2.5/3 — OFF (gap-2). Для явного контроля фильтров (роль судьи 18+) нужен нативный Gemini API, не OpenAI-слой. - Qwen Model Studio: внешний фильтр
data_inspection_failedна вход/выход, неотключаем (риск молчаливых вырезаний) — не тестировано (нет ключа). - Детект отказов/вырезаний — см.
eval/refusal_bench.py(паттерны soft-отказа + coverage-гейт по len_ratio/sent_cov, пороги в эксп. 02).
Транспорт / инфраструктура
- Прокси на localhost: в env стенда webshare-прокси,
NO_PROXY=<local>— WinINET-нотация, которую curl/urllib/Go не понимают → запрос к 127.0.0.1 уходит на прокси и получает 403. Лечение: явныйNO_PROXY="localhost,127.0.0.1,0.0.0.0,::1"+ в коде обходить прокси для loopback/172.x (бэкенд: local-адаптер с no-proxy транспортом — уже сделано). - DeepSeek cache-поля: в
usageдва варианта именования (бэкенд обрабатывает оба). - «Эхо» черновика (тихий отказ): deepseek-chat на плотной CJK-прозе воспроизводимо (3 из 3 ретраев на zh-фрагменте Лу Синя «祝福») возвращает оригинал вместо перевода (82% CJK в «переводе»). Не ошибка API — валидный ответ с неправильным содержимым; ретраи не помогают (детерминировано для фрагмента). Митигация в
eval/editor_bench.py: детектор доли CJK (порог 15%) → фолбэк на другого провайдера (GLM перевёл тот же текст чисто). Бэкенд/гейт: детектор CJK-артефактов в русском выходе обязателен (смыкается с anti-omission coverage-гейтом Р7 и уже запланированным «детектором CJK-артефактов» — 7 из 18 моделей грешат); эскалация на другого провайдера, а не ретрай. NB: проверено на deepseek-chat; актуальную роль-модельdeepseek-v4-flashперепроверить. - Таймауты: книжные чанки на локали занимают 63–278 с (не 45 с как в чат-vojo). Нужен per-роль лег-таймаут ~300–600 с + стриминг как keep-alive. Донорский транспорт vojo имел скрытый per-attempt потолок 60 с.
Календарь деприкаций / цен (мониторить ежеквартально)
deepseek-chat→deepseek-v4-flashк 24.07.2026.- Gemini 2.5-серия (pro/flash/flash-lite) — shutdown 16.10.2026 («earliest possible date», офиц. deprecations-страница; live-фактчек оркестратора 09.07). Замены по вендору: 3.1-pro-preview / 3.5-flash / 3.1-flash-lite. ⚠ До даты на 2.5-flash уже наблюдён интермиттентный 404 «model no longer available» при наличии слага в /models (research/15, сырьё) — вендором не документирован; судья fidelity
memory_evalсидит на 2.5-flash → мигрировать (D21.9). Отдельно:finish_reason=PROHIBITED_CONTENTна Gemini 3.x — НЕконфигурируемый фильтр-класс (safety_settings не влияют, в отличие отSAFETY); наблюдён на violence-сцене → вывод exp07 «content_filter мёртв» на Gemini 3.x не переносится. (Добавлено оркестратором по research/15 + фактчеку.) - Grok 4.1 Fast retired 15.05.2026 → слаги молча редиректят на
grok-4.3(цена ×9). Ретайрнулся дешёвый тир, НЕ сам xAI: grok-4.3 остаётся основным пермиссивным тиром канала B. - Аудит /models 04.07.2026 (воркфлоу) — с поправкой на перепроверку: и
deepseek-chat, иgrok-4-fastНЕ в списках /models (там v4-flash/v4-pro у DeepSeek; версионные слаги у xAI), НО оба работают как алиасы (перепроверено вживую: HTTP 200, переводят). Агент-аудитор написал «сняты» — это была неточность: «нет в /models» ≠ «не работает». deepseek-chat депрекируется 24.07.2026. У xAI есть мигрированные слаги-обёртки (grok-4.20-0309-non-reasoning/-reasoning/-multi-agent, ретайр 15.05.2026), но для перевода/редактуры берёмgrok-4.3+ явныйreasoning_effort:"none"(слаг не меняем; non-reasoning вариант = grok-4.3+noneпод капотом — см. thinking-таблицу). xAIusageотдаёт нестандартныеcost_in_usd_ticks/num_sources_used— игнорировать. Урок: имя модели проверять не только/models, но и пробным вызовом — алиас может работать, даже если его нет в списке; и наоборот. Реальная причина сменить deepseek на v4-flash — не «chat умер», а ЭХО на zh (лечится thinking-on), см. раздел thinking. - Claude Sonnet 5 промо $2/$10 до 31.08.2026 (не закладывать в долгий прайс).
- ПОПРАВКА (04.07, владелец): удалён только Anthropic (за дороговизну). OpenAI ОСТАЁТСЯ (ключ есть — GPT-5 nano/mini). Живой набор ключей у бэкенда и полигона: DEEPSEEK, ZAI, KIMI, OPENAI, GEMINI, XAI, MISTRAL (добавлен 09.07,
6ab92b5). Источник истины по стеку —architecture/05-decisions-log.md(D3) и Р4. Ранее эта строка ошибочно исключала OpenAI — исправлено оркестратором.
Провенанс
Кто что нашёл: эндпоинты/thinking/temp/safety — полигон (эксп. 02, 03, 04, живые вызовы); Grok-retired/cache-write Anthropic/per-attempt-60с — бэкенд (шаг 0 валидации); localhost-прокси — оба стенда независимо.