Маршруты и возможности моделей

«Поддерживает ли эта модель вызовы инструментов?» — звучит как вопрос о модели. Но это не так. Это вопрос о модели и об эндпоинте, на котором вы её вызываете — и одна и та же модель может ответить «да» на одном и «нет» на другом. На этой странице объясняется, почему так и каким образом Entity Enricher решает этот вопрос: измеряя, а не доверяя каталогу.

Модель, которая поддерживает функцию, но отказывает в ней

Отправьте семейству gpt-6 от OpenAI запрос с функциями-инструментами на классический эндпоинт /v1/chat/completions — и запрос будет отклонён сразу же:

400 Bad Request
Function tools with reasoning_effort are not supported.
Use /v1/responses or set reasoning_effort to 'none'.

Отправьте ту же модель, те же инструменты и тот же промпт на /v1/responses — и она ответит нормально: по обоим каналам структурированного вывода, с усилием рассуждения или без него. В самой модели ничего не изменилось. Изменился только адрес.

Следствие

Возможность — это свойство не одной модели. Это свойство пары (модель, эндпоинт). Поэтому любой каталог, который хранит одно значение true/false на модель, отвечает на вопрос, которого он на самом деле не видит.

Что такое маршрут

Маршрут — это просто эндпоинт, на который отправляется запрос. Тот же провайдер, та же модель, тот же ключ API — но другой формат передачи, другая структура запроса и другой набор правил о том, что можно совмещать. OpenAI предоставляет два таких эндпоинта, и большая часть отрасли скопировала более старый.

МаршрутФорма обменаКто его поддерживает
Chat Completions
/v1/chat/completions
2023
Без сохранения состояния: вы отправляете весь список сообщений и получаете обратно следующее сообщение. Между вызовами на сервере ничего не хранится.OpenAI и де-факто отраслевой стандарт, скопированный почти всеми остальными — xAI, DeepSeek, Alibaba, Groq, Together, Ollama и большинством OpenAI-совместимых шлюзов.
Responses API
/v1/responses
2025
Возвращает список типизированных элементов — элемент рассуждения, сообщение, вызов функции-инструмента, вызов размещённого инструмента, — хранит состояние на сервере и может переносить рассуждение из одного хода в следующий.Только OpenAI. Похожий эндпоинт, говорящий в формате Chat Completions, не обслуживает автоматически и этот.

Именно поэтому выражение «OpenAI API» сегодня неоднозначно: их два, они пересекаются и действуют по разным правилам.

Почему вообще существуют два API

Модели с рассуждением сломали модель сообщений. Внутреннее рассуждение модели — не сообщение: это не то, что она сказала вам, и не то, что вы сказали ей. В Chat Completions есть только список сообщений, поэтому рассуждению там негде разместиться — а то, что он не может представить, он теряет между ходами.

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

Чем объясняется отказ выше

Вызов функции-инструмента — это обмен в два хода: модель запрашивает инструмент, ваш код отвечает, модель продолжает. В Chat Completions рассуждение негде сохранить между этими ходами, поэтому продолжение молча возобновилось бы без него — модели пришлось бы заново проделать то размышление, за которое вы уже заплатили, и, скорее всего, она проделала бы его иначе.

Поэтому провайдер отклоняет такую комбинацию, а не ухудшает результат молча. Сообщение об ошибке — не ограничение модели; это старый API признаёт, что у него нет места для того, что производит эта модель.

Возможности указывают в разные стороны

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

Инструментам и веб-поиску нужен Responses API

Структурированный вывод через канал инструментов — это ровно та комбинация, которую Chat Completions отклоняет на модели с рассуждением, а размещённый провайдером инструмент веб-поиска принимается только там.

Бинарное аудио работает только в Chat Completions

Передача «сырых» аудиоданных на пути через Responses API невозможна, поэтому модель с поддержкой аудио доступна только через более старый эндпоинт.

Одна модель, две возможности, два разных эндпоинта. Нет единого true/false, которое было бы честным для обоих, — поэтому Entity Enricher ведёт карту возможностей для каждого маршрута, и поэтому запуск, которому нужны две возможности, живущие на двух разных маршрутах, отклоняется явно, а не теряет одну из них незаметно.

Как Entity Enricher измеряет маршрут

Проверка возможностей не отправляет синтетический запрос, написанный вручную. Она задействует реальный путь агента — тот же код, что и при запуске обогащения, — с принудительно включённой проверяемой возможностью, и решение принимает ответ провайдера. Поэтому измеряется то, что приложение действительно может сделать, а не то, что API теоретически мог бы принять.

Вся эта цепочка — каналы структурированного вывода, зрение, PDF, аудио, веб-поиск, рассуждение и управление его глубиной для каждого запроса — выполняется по одному разу на каждый маршрут, который может выбрать маршрутизатор. Почти у любого провайдера маршрут один, и проверка стоит ровно столько же, сколько и раньше; дважды измеряются только провайдеры с интерфейсом OpenAI, к которым действительно можно обратиться двумя способами.

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

Да

Запрос был принят, и модель вернула ответ ожидаемого вида.

Записывается как измеренное true для этого маршрута — и перевешивает любое заявление, собранное из внешних каталогов.

Нет

Провайдер явно отклонил эту возможность, либо клиент вообще отказался формировать запрос.

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

Неизвестно

Что-либо ещё: ограничение частоты запросов, отсутствующий уровень доступа, тайм-аут, ошибка 5xx у провайдера, нераспознанная ошибка.

Ничего не записывается, и следующая проверка сможет это прояснить.

Почему по умолчанию — «неизвестно», а не «нет»

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

Принято — не значит понято

Ответ HTTP 200 подтверждает, что запрос был принят. Он не подтверждает, что модель действительно прочитала вложение — провайдер может спокойно принять изображение и передать его модели, которая на него даже не смотрит. Поэтому каждая проверка с полезной нагрузкой несёт такую нагрузку, ответ по которой можно сверить:

ВозможностьОтправленная полезная нагрузкаЗаданный вопрос
ЗрениеОднотонное красное изображение«Какой цвет в нём преобладает?»
Входные данные PDFPDF, содержащий ровно одно слово«Какое слово есть в документе?»
АудиовходАудиофайл с поддающимся подсчёту количеством тонов«Сколько отдельных сигналов?»

Два отдельных результата — и это намеренно

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

Утверждения против измерений

Публичные каталоги моделей, такие как LiteLLM или PricePerToken, указывают возможности как простой факт о модели, без привязки к эндпоинту. Это не небрежность — для этого просто нет поля. Но это значит, что заявление может быть совершенно верным в целом и всё же неверным для того эндпоинта, который использует ваш запуск.

Утверждение, собранное автоматически

«Эта модель поддерживает вызовы инструментов.» Где-то это правда. Где именно — не сказано. Годится как отправная точка для модели, которую ещё никто не проверял.

Измерение

«На этом эндпоинте в этот момент модель приняла вызовы инструментов.» Здесь назван маршрут, поэтому его можно сравнить с тем маршрутом, который действительно будет использован при запуске.

Указание маршрута также сохраняет честность измерения со временем. Вердикт, вынесенный на эндпоинте, который модель больше не использует, — не более надёжное свидетельство, чем заявление: это свидетельство о чём-то другом. Без записанного рядом маршрута старое измерение было бы неотличимо от текущего и перевесило бы каталог для неподходящего эндпоинта. Когда маршрут записан, такое измерение просто не применяется, и заявление остаётся в силе, пока его не заменит измерение на нужном эндпоинте.

Как читать это в продукте

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

Обслуживающий маршрут (по умолчанию)

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

Указанный маршрут

Закрепите всю таблицу за одним эндпоинтом — и значки будут отвечать только за него: так вы увидите, как возможность появляется или исчезает при переключении между эндпоинтами, и сможете сравнить две модели на равных.

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

Что это значит для вас

Чаще всего ничего — и в этом весь смысл. Вы никогда не выбираете маршрут. Вы выбираете модель и описываете свой запуск, а маршрутизатор подбирает эндпоинт, способный обеспечить то, что нужно запуску: инструменты и веб-поиск идут туда, где они принимаются, а аудиовложение — туда, где передаётся аудио.

Единственный случай, который вы заметите, — это настоящий конфликт: например, запрос веб-поиска с одновременным прикреплением аудиофайла к одной и той же модели OpenAI, поскольку ни один эндпоинт не обслуживает и то и другое. Такой запуск отклоняется явно, с указанием обеих возможностей и того, что способен передать каждый маршрут, — вместо того чтобы выполниться и молча отбросить одну из них. Уберите одно из требований или выберите модель, которая поддерживает оба, — и запуск продолжится.

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