Перейти к содержимому
5 мин чтения

Как сопоставить параметры режима рассуждения между моделями

Параметры режима рассуждения у OpenAI, Claude и Gemini: как сопоставить effort и budget, выявить игнорирование и тестировать маршруты.

Как сопоставить параметры режима рассуждения между моделями

Режим рассуждения нельзя описать одной шкалой от "быстро" до "умно". Одни API принимают уровень усилия, другие принимают числовой бюджет, третьи сами решают, думать ли вообще, а четвертые молча приводят ваш параметр к ближайшему допустимому значению. Если спрятать все это за переключателем "Thinking: High", команда получит непредсказуемые счета, странные задержки и ложную уверенность в том, что настройка работает.

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

Один ярлык не означает один механизм

reasoning.effort, thinkingBudget, thinkingLevel, budget_tokens и effort регулируют разные вещи. Их нельзя безопасно свести к полю reasoning_level без потери смысла.

У OpenAI reasoning.effort задает интенсивность рассуждения. Это не контракт на фиксированное число reasoning tokens. В актуальных руководствах OpenAI для Responses API уровни могут включать none, low, medium, high, xhigh и max, но набор зависит от модели. Даже когда две модели принимают одинаковое слово high, они не обязаны тратить одинаковое время или число токенов.

У Anthropic нужно различать старый ручной бюджет и адаптивный режим. thinking: {"type":"enabled", "budget_tokens": N} задает бюджет внутреннего рассуждения для моделей, где этот режим еще поддерживается. В документации Claude прямо сказано, что budget_tokens должен быть меньше max_tokens, а фактический расход может быть ниже заданного бюджета. На новых моделях ручной бюджет постепенно уходит: Anthropic рекомендует thinking: {"type":"adaptive"} вместе с effort, а некоторые модели ручной режим отвергают с 400.

У Google это разделение особенно заметно. Gemini 2.5 работает с числовым thinkingBudget; на отдельных моделях 0 отключает thinking, а -1 включает динамический выбор бюджета. Gemini 3 ориентируется на thinkingLevel, и Google отдельно предупреждает, что числовой бюджет в новых поколениях не дает точного управления, даже если API его еще принимает.

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

Таблица преобразований должна хранить семантику, а не только имена полей

Рабочая таблица не должна быть списком красивых соответствий вроде high = 8192. Она обязана хранить границы применимости: семейство модели, API, разрешенные значения, точность контроля, возможность отключения и наблюдаемый сигнал в ответе.

Ниже приведен шаблон, который удобно держать рядом с кодом маршрутизации. Идентификаторы моделей меняются быстрее, чем архитектурные правила, поэтому привязывайте запись к точному model ID и версии карточки модели.

Семейство и режимНативная настройкаЧто контролируетМожно ли выключитьНасколько точен контрольЧто проверять в ответе
OpenAI reasoning через Responses APIreasoning.effortЖелаемую интенсивность внутренней работыТолько если модель принимает noneНизкая, это уровень, а не бюджетusage, задержку, качество на тестах
Claude с ручным thinkingthinking.type=enabled, budget_tokensВерхнюю цель для thinking tokensДа, через отсутствие или отключение thinking, если версия поддерживаетСредняя, модель может не выбрать весь бюджетusage.output_tokens_details.thinking_tokens
Claude с adaptive thinkingthinking.type=adaptive, effortГлубину работы, а решение о thinking оставляет моделиЗависит от версии моделиНизкая для токенов, средняя для поведенияusage, инструментальные вызовы, задержку
Gemini 2.5thinkingBudgetЧисловой ориентир на thinkingЗависит от конкретной моделиСредняя, но не равна гарантированному расходуusage metadata, задержку, тестовый балл
Gemini 3thinkingLevelДискретный уровень thinkingНа части моделей нельзяНизкая, Google сам определяет расходуровень в запросе, usage, тестовый балл
Унифицированный шлюзreasoning.effort или reasoning.max_tokensЗапрос на преобразование в нативный режимТолько если это допускают модель и провайдерЗависит от конечного маршрутавыбранную модель, effective config, usage

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

В документации OpenRouter это видно без догадок: reasoning.effort приводится к Google thinkingLevel, а reasoning.max_tokens может быть передан как thinkingBudget. Там же указано, что для Gemini 3 числовой бюджет внутри все равно может быть преобразован в уровень, а реальное потребление определяет Google. Это правильный пример честной нормализации: API не обещает точность, которой у провайдера нет.

Сначала разделите бюджет, усилие и лимит ответа

Команды регулярно путают три ограничения и потом ищут ошибку в модели.

Бюджет рассуждения относится к внутренней работе. В классическом Claude это budget_tokens. Он дает модели пространство подумать, но не говорит, какой объем финального текста она должна вернуть.

Уровень усилия задает предпочтение, а не арифметику. high у OpenAI или Claude означает, что модель может потратить больше вычислений и токенов на трудную задачу. В простом запросе разница между medium и high иногда будет почти незаметна. В задаче с инструментами она может проявиться в числе вызовов, повторных проверках и длине хода.

Общий лимит вывода ограничивает все, что модель генерирует в рамках ответа. Его названия различаются: max_output_tokens, max_tokens, max_completion_tokens. В некоторых API reasoning и финальный текст конкурируют за один потолок. Если вы дали 2 000 токенов и попросили большой thinking budget, модель не обязана сохранить достаточно места для полезного ответа.

Это не теоретическая тонкость. В документации Claude указано, что budget_tokens должен быть меньше max_tokens. Там же usage считает thinking частью выходных токенов, а output_tokens_details.thinking_tokens показывает разбиение только для наблюдаемости. Счет выставляют по итоговому output_tokens, а не по красивому сокращенному trace, который вы увидели в ответе.

Практическое правило простое: финансовый потолок задает общий лимит и лимит на запросы вашего приложения. Режим рассуждения выбирает глубину работы внутри этого потолка. Не используйте effort как предохранитель расходов.

Нормализуйте запрос в два слоя

Клиентскому коду нужен маленький и устойчивый контракт. Маршрутизатору нужен второй, более подробный контракт с правилами конкретной модели. Смешивать их в одном объекте неудобно: либо вы тащите в каждый сервис названия всех провайдеров, либо теряете важные запреты.

Первый слой можно оставить таким:

{
  "reasoning": {
    "mode": "enabled",
    "intent": "balanced",
    "max_reasoning_tokens": null,
    "allow_fallback": false
  },
  "max_output_tokens": 6000
}

Здесь intent не должен притворяться нативным параметром. Это ваша внутренняя политика: fast, balanced, deep. Поле max_reasoning_tokens имеет смысл только там, где у модели есть числовой бюджет. allow_fallback заставляет вас явно решить, приемлемо ли понижение запроса с deep до medium.

Второй слой превращает политику в точный запрос и записывает результат преобразования:

{
  "requested": {
    "intent": "deep",
    "max_reasoning_tokens": 12000
  },
  "effective": {
    "provider": "google",
    "parameter": "thinkingLevel",
    "value": "high",
    "budget_applied": false,
    "reason": "Модель принимает уровни, а не точный бюджет"
  }
}

Этот объект не обязательно отправлять пользователю. Его нужно писать в журнал трассировки и добавлять к данным эксперимента. Иначе через месяц вы увидите падение качества и не поймете, изменилась модель, провайдер, правило преобразования или сам запрос.

Для OpenAI-совместимого клиента нестандартный объект часто передают через extra_body, чтобы SDK не выбросил поле до отправки:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.airouter.kz/v1",
    api_key="${AI_ROUTER_API_KEY}"
)

response = client.chat.completions.create(
    model="provider/model-id",
    messages=[
        {"role": "user", "content": "Реши задачу и верни только JSON по схеме."}
    ],
    max_tokens=6000,
    extra_body={
        "reasoning": {
            "effort": "high",
            "exclude": True
        }
    }
)

AI Router позволяет сохранить OpenAI SDK и заменить base_url на api.airouter.kz, но совместимость транспорта не делает каждый параметр универсальным. Перед выпуском новой модели ваш адаптер должен получить ее возможности и решить, что делать с неподдерживаемыми полями.

Молчаливое игнорирование ловят парные тесты

Тестируйте больше моделей
Маршрутизируйте тестовые запросы к 500+ моделям, не переписывая прикладной код под каждого провайдера.

Проверка вида "отправили high, получили 200" бесполезна. Молчаливое игнорирование проявляется не в статусе, а в том, что режимы дают статистически неотличимый результат на задачах, где глубина должна менять ход решения.

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

Подходящий минимальный набор содержит:

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

Запускайте одну и ту же выборку как минимум в двух режимах, например low и high. Перемешивайте порядок запусков, чтобы случайная нагрузка не совпала с одним уровнем. Одинаковые запросы лучше повторять несколько раз: генерация недетерминирована, а один ответ может случайно оказаться лучше.

Сохраняйте не только оценку качества. Для каждой попытки запишите точный model ID, провайдера, тело запроса после нормализации, время первого байта, полную задержку, usage, finish reason, количество вызовов инструментов и итог проверок. Если модель возвращает billed thinking tokens, сохраняйте их отдельно от видимого reasoning текста.

Простейший сигнал подозрения выглядит так: low и high дают одинаковую медиану задержки, одинаковое usage и одинаковый процент прохождения на задачах, где сильный режим обычно делает дополнительные проверки. Это еще не доказательство игнорирования, но достаточная причина открыть трассировку и сверить effective config.

Сделайте тест на деградацию параметра отдельным контрактом

Проверка качества отвечает на вопрос "есть ли эффект". Контрактный тест отвечает на вопрос "какой эффект допустим". Это разные тесты, и оба нужны.

Для каждой записи таблицы преобразований задайте ожидаемое поведение. Примеры:

СитуацияОжиданиеОшибка, которую вы ловите
deep для модели с thinkingLevelВ effective config записан допустимый уровеньШлюз передал несуществующее поле или не записал преобразование
Числовой бюджет для Gemini 3В журнале указано, что точный бюджет не гарантированКоманда решила, что 12 000 означает ровно 12 000 thinking tokens
reasoning: none для модели с обязательным thinkingЯвная ошибка или заранее объявленный fallbackТихое включение режима, который приложение считало выключенным
Ручной budget_tokens для новой ClaudeОшибка совместимости или переход на adaptive policyПродакшен получает 400 после смены версии модели
high вместе с малым общим лимитомПредупреждение или отклонение конфигурацииОбрезанный финальный ответ из-за нехватки output tokens

Не прячьте эти правила в условные операторы по всему коду. Храните их в одном реестре возможностей. В зрелом варианте запись выглядит так:

model: google/gemini-family-version
reasoning:
  enabled: true
  required: false
  controls:
    - kind: effort
      accepted: [minimal, low, medium, high]
      maps_to: thinkingLevel
    - kind: budget
      accepted: false
  disable:
    supported: false
  observability:
    usage_breakdown: provider-dependent
  fallback:
    xhigh: high
    max: high

Реестр не обязан быть вручную написанной энциклопедией. Часть возможностей можно получать из API каталога моделей, но данные каталога не заменяют тест. Каталог говорит, что поле допустимо. Он не гарантирует, что конкретный маршрут, регион, версия провайдера и выбранный режим инструментов дадут ожидаемый эффект.

Не используйте один режим для чата, RAG и агентов

Сравнивайте закрытые и open-weight модели
Подключайте Llama 4, Qwen 3, Gemma 4 и другие open-weight модели на инфраструктуре AI Router.

Самая популярная, но плохая рекомендация звучит так: включите high везде, если качество важно. Она кажется безопасной, потому что снимает необходимость выбирать. На деле она маскирует ошибки в постановке задачи и заставляет дорогую модель разбирать запросы, где нужен быстрый поиск, строгая схема или нормальный reranker.

Для короткого чата по известной базе знаний сначала проверяйте retrieval, цитирование источников и ограничение ответа. Высокий reasoning effort не исправит документ, который не попал в контекст.

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

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

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

Видимый reasoning не годится для учета и аудита

Контролируйте доступ к экспериментам
Маскируйте PII и применяйте rate-limits на уровне ключа к LLM-запросам.

Разработчики любят использовать текст рассуждения как доказательство того, что модель "думала". Это ненадежно по двум причинам.

Во-первых, часть моделей вообще не возвращает внутренние reasoning tokens. Например, OpenAI o-series не обязаны раскрывать их через унифицированные интерфейсы. Во-вторых, Anthropic может показать сокращенный thinking trace, а тарифицировать полную внутреннюю работу. В документации extended thinking указано, что billed output и видимый объем thinking могут не совпадать; для наблюдаемости нужен usage.output_tokens_details.thinking_tokens, если конкретный ответ его предоставляет.

Для аудита храните факты, которые можно сопоставить между провайдерами:

  • policy ID, которая выбрала режим;
  • requested config и effective config;
  • точный model ID и маршрут провайдера;
  • входной размер, выходной размер и доступную разбивку usage;
  • задержку, результат валидатора и следы инструментов.

Не записывайте скрытые рассуждения в журналы только ради любопытства. В банке, healthcare или госсистеме такой текст легко становится еще одним массивом чувствительных данных, который надо классифицировать, хранить, выдавать по доступам и удалять по политике. Для расследования сбоя обычно полезнее воспроизводимый вход, версия промпта, конфигурация и проверяемый результат.

Выбирайте режим по измеренной границе, а не по названию

У режима рассуждения нет правильного значения "по умолчанию" для всей компании. Есть конкретная граница, после которой дополнительное время и расход перестают заметно улучшать ваш результат.

Начните с трех политик: fast, balanced, deep. Для каждой закрепите допустимые режимы по семействам моделей, общий лимит вывода и набор задач. Затем постройте простую таблицу: процент прохождения, медианная задержка, медианный output usage, число вызовов инструментов и цена успешно завершенного задания. Если deep прибавляет качество только на задачах миграции кода, отправляйте туда лишь этот класс запросов.

Не переносите найденное соответствие на новую модель автоматически. Переход с thinkingBudget на thinkingLevel, замена Claude с ручного thinking на adaptive или обновление OpenAI модели меняют смысл прежних уровней. Сначала обновите запись в реестре, затем прогоните контрактные и парные тесты, и только после этого меняйте маршрут продакшена.

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

Часто задаваемые вопросы

Можно ли считать reasoning effort точным лимитом токенов?

Нет. reasoning.effort обычно задает желаемую интенсивность работы модели, а не число скрытых токенов. У OpenAI и современных Claude это поведенческий сигнал, поэтому два одинаковых запроса могут потребовать разный внутренний расход. Если вам нужен финансовый потолок, ограничивайте общий вывод и измеряйте фактическое использование.

Почему API возвращает 200, хотя параметр рассуждения не сработал?

Потому что API часто принимает неизвестные или неприменимые поля ради совместимости. Шлюз может нормализовать параметр, ближайший поддерживаемый уровень или убрать поле перед вызовом провайдера. Статус 200 доказывает только то, что запрос обработан, а не то, что настройка изменила поведение модели.

Как проверить, что модель действительно использует thinking?

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

Чем thinkingBudget отличается от thinkingLevel в Gemini?

Для Gemini 2.5 thinkingBudget и thinkingLevel не равнозначны: первый задает числовой бюджет, второй относится к более новым семействам. Для Gemini 3 Google рекомендует уровни minimal, low, medium и high; числовой бюджет там может быть принят только ради обратной совместимости. Не переносите конфигурацию между поколениями без отдельного теста.

Нужно ли использовать budget_tokens для новых моделей Claude?

На новых моделях Claude ручной budget_tokens уже не является универсальным способом управления. Для ряда версий Anthropic рекомендует адаптивное мышление вместе с effort, а некоторые модели отклоняют ручной бюджет с ошибкой 400. Проверяйте документацию именно для идентификатора модели, а не для семейства Claude в целом.

Всегда ли high лучше, чем medium?

Нет. Логическая сложность, наличие инструментов, длина контекста и требуемый формат ответа влияют сильнее, чем имя уровня. Начинайте с обычного режима, затем повышайте усилие только на тех сценариях, где тесты показывают заметный прирост качества.

Как не оставить слишком мало токенов на финальный ответ?

Устанавливайте отдельно max_output_tokens или эквивалентный общий предел вывода. Бюджет рассуждений часто входит в этот лимит или конкурирует с финальным ответом за него. Если дать модели мало выходных токенов, она может потратить их на внутреннюю работу и оборвать полезный ответ.

Можно ли логировать цепочку рассуждений для аудита?

Не пытайтесь хранить внутреннюю цепочку рассуждений как обязательный журнал. У части провайдеров она не возвращается, у части приходит в сокращенном виде, а у некоторых моделей видимый текст не совпадает с тарифицируемым внутренним расходом. Для наблюдаемости храните настройки, usage, задержку, результат проверки и идентификатор модели.

Как передать нестандартный reasoning-параметр через OpenAI SDK?

Передавайте настройку через extra_body или аналогичный механизм SDK, чтобы библиотека не отбросила незнакомое поле. Сохраните фактический JSON запроса на тестовом стенде и сравните его с тем, что видит шлюз. При смене модели не наследуйте поле автоматически, если ее карточка не объявляет поддержку.

Можно ли менять провайдера без переписывания клиента?

Да, если ваш код использует OpenAI-совместимый клиент и вы не полагаетесь на специфичные для одного провайдера поля без проверки. AI Router позволяет сменить base_url на api.airouter.kz и продолжить работу с привычными SDK, кодом и промптами. Но смысл каждого параметра рассуждения все равно нужно валидировать для выбранной модели.