﻿# Потоковые tool calls: сборка arguments по index и id

Как проверять потоковые tool calls: объединять arguments по index, сохранять id и не исполнять незавершённый JSON при фрагментации ответа.

Автор: Команда Retrivium
Обновлено: 2026-11-01
Канонический URL: https://retrivium.ai/ru/journal/provider-streamed-tool-argument-assembly/
Language: ru

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

## Выберите ключ сборки

[Схема API OpenRouter](https://openrouter.ai/docs/api_reference/overview) описывает tool_calls как часть ответа и соответствующие сообщения инструмента. При обработке потока храните отдельную запись каждого вызова в области конкретного choice. Index используется для сопоставления изменений, а ID сохраняется как идентификатор прикладного вызова. Конкретную форму delta проверяют по выбранному интерфейсу и версии.

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

## Разделите строки и объекты

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

[Документация vLLM о tool calling](https://docs.vllm.ai/en/stable/features/tool_calling/) показывает зависимость поведения от модели и парсера. Поэтому один тест на обычном тексте не подтверждает пригодность выбранной конфигурации для инструментов. Нужны fixtures именно той формы вызовов, которую сервис собирается объявлять поддержанной.

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

Пусть тестовый поток содержит вызовы с индексами 0 и 1. Их fragments чередуются: часть первого аргумента, начало второго, продолжение первого, завершение второго. Ожидаемый результат — две независимые строки arguments и два сохранённых идентификатора. Общая конкатенация обязана провалить этот fixture.

Функции в таком тесте ничего не выполняют. Достаточно проверить имена, аргументы и связь с вызовом. Это позволяет отладить parser без внешних действий, настоящих учётных записей и пользовательских секретов. Число событий и размер накопленного буфера заранее ограничиваются.

## Проверьте транспортные границы

Один сетевой read не равен одному tool delta. [Стандарт SSE](https://html.spec.whatwg.org/multipage/server-sent-events.html) задаёт собственные правила выделения событий. Сначала bytes проходят декодирование и framing, только затем прикладной обработчик получает данные для сборки вызовов. Нельзя искать закрывающую фигурную скобку в произвольном сетевом буфере как признак завершения функции.

Дополните fixture разрезанием внутри строки, escaped quotation mark и многобайтового символа. Ожидаемое итоговое значение должно остаться прежним. Ошибка JSON в действительно завершённом arguments классифицируется отдельно от обычного ожидания следующего фрагмента.

## Установите границу исполнения

Исполнение начинается только после подтверждённого завершения вызова и проверки аргументов. Корректное имя функции не означает разрешения на любые действия. Слой авторизации инструментов остаётся отдельным от conformance-теста API. Обрыв потока не должен превращать частично собранную строку в допустимую команду.

Основы описаны в [tool calling](/ru/journal/openrouter-tool-calling/), транспортная проверка — в [streaming vLLM](/ru/journal/vllm-openai-streaming-test/). Здесь итогом является воспроизводимый fixture сборки, а не обещание, что любой движок или модель поддерживает одинаковые tool calls.
