В этом материале
Arguments собираются отдельно для каждого вызова. Валидность JSON и завершение tool call нужно подтвердить до исполнения, сохранив исходную последовательность.
Потоковый вызов инструмента приходит не как готовая функция, а как последовательность изменений. Название, идентификатор и строка arguments могут появляться не одновременно. Наивный обработчик пытается разобрать каждый фрагмент как самостоятельный JSON либо склеивает все аргументы в одну строку. Обе ошибки проявляются особенно заметно, когда модель возвращает несколько вызовов. Для проверки провайдера нужен маленький детерминированный протокол сборки, отделённый от исполнения инструментов.
Выберите ключ сборки
Схема API OpenRouter описывает tool_calls как часть ответа и соответствующие сообщения инструмента. При обработке потока храните отдельную запись каждого вызова в области конкретного choice. Index используется для сопоставления изменений, а ID сохраняется как идентификатор прикладного вызова. Конкретную форму delta проверяют по выбранному интерфейсу и версии.
Не предполагайте, что каждое событие повторяет название функции и ID. Если реализация передаёт их только в начале, последующие фрагменты должны дополнять ту же запись. Отсутствующий ID в первом наблюдаемом фрагменте также нельзя исправлять случайным общим значением для всех вызовов.
Разделите строки и объекты
Arguments на границе протокола могут быть строкой с JSON внутри. Полученный кусок этой строки ещё не обязан быть валидным документом. Сначала собирают данные вызова в правильном порядке, затем разбирают завершённое значение и проверяют его по схеме инструмента.
Документация vLLM о tool calling показывает зависимость поведения от модели и парсера. Поэтому один тест на обычном тексте не подтверждает пригодность выбранной конфигурации для инструментов. Нужны fixtures именно той формы вызовов, которую сервис собирается объявлять поддержанной.
Сделайте пример с двумя вызовами
Пусть тестовый поток содержит вызовы с индексами 0 и 1. Их fragments чередуются: часть первого аргумента, начало второго, продолжение первого, завершение второго. Ожидаемый результат — две независимые строки arguments и два сохранённых идентификатора. Общая конкатенация обязана провалить этот fixture.
Функции в таком тесте ничего не выполняют. Достаточно проверить имена, аргументы и связь с вызовом. Это позволяет отладить parser без внешних действий, настоящих учётных записей и пользовательских секретов. Число событий и размер накопленного буфера заранее ограничиваются.
Проверьте транспортные границы
Один сетевой read не равен одному tool delta. Стандарт SSE задаёт собственные правила выделения событий. Сначала bytes проходят декодирование и framing, только затем прикладной обработчик получает данные для сборки вызовов. Нельзя искать закрывающую фигурную скобку в произвольном сетевом буфере как признак завершения функции.
Дополните fixture разрезанием внутри строки, escaped quotation mark и многобайтового символа. Ожидаемое итоговое значение должно остаться прежним. Ошибка JSON в действительно завершённом arguments классифицируется отдельно от обычного ожидания следующего фрагмента.
Установите границу исполнения
Исполнение начинается только после подтверждённого завершения вызова и проверки аргументов. Корректное имя функции не означает разрешения на любые действия. Слой авторизации инструментов остаётся отдельным от conformance-теста API. Обрыв потока не должен превращать частично собранную строку в допустимую команду.
Основы описаны в tool calling, транспортная проверка — в streaming vLLM. Здесь итогом является воспроизводимый fixture сборки, а не обещание, что любой движок или модель поддерживает одинаковые tool calls.