Tool Calling (вызов функций)
Tool Calling (также называемый Function Calling) позволяет моделям выходить за рамки генерации текста, возвращая структурированный «запрос вызова функции» при необходимости. Ваша программа выполняет реальную логику (проверить погоду, запросить базу данных, оформить заказ), возвращает результат модели, и модель генерирует окончательный ответ на его основе. RouteAPI поддерживает Tool Calling как на /v1/chat/completions (формат OpenAI), так и на /v1/messages (формат Claude).
1. Обзор Tool Calling
Section titled “1. Обзор Tool Calling”Что такое Tool Calling
Section titled “Что такое Tool Calling”Tool Calling — это многораундовый обмен:
- Вы объявляете набор «инструментов» в запросе (каждый инструмент имеет имя, описание и схему параметров).
- Модель определяет, нужен ли инструмент; если да, она возвращает запрос вызова с параметрами вместо прямого ответа.
- Ваш код разбирает параметры, выполняет реальную логику и получает результат.
- Вы передаёте результат обратно модели, которая генерирует ответ на естественном языке для пользователя.
Сама модель не выполняет никакой код; она только решает «какой инструмент вызвать» и «какие параметры передать». Фактическое выполнение всегда происходит на вашей стороне, что означает, что границы безопасности (проверки прав доступа, фильтрация параметров) находятся под вашим контролем.
Сценарии применения
Section titled “Сценарии применения”| Сценарий | Описание |
|---|---|
| Запросы данных в реальном времени | Погода, обменные курсы, котировки акций, запасы — информация, отсутствующая в обучающих данных модели |
| Интеграция внутренних систем | Запросы к базам данных, вызовы внутренних API, чтение статуса заказов |
| Выполнение действий | Оформление заказов, отправка электронных писем, создание тикетов — операции с побочными эффектами |
| Структурированное извлечение | Принудить модель выводить данные согласно фиксированной схеме, эквивалентно методу структурированного вывода |
| Оркестровка агентов | Фреймворки агентов используют Tool Calling для управления многошаговыми задачами |
Поддерживаемые модели
Section titled “Поддерживаемые модели”Способность Tool Calling зависит от выбранной модели. Большинство основных моделей (серии OpenAI GPT, Claude, Gemini и др.) поддерживают её, но детали, такие как максимальное количество инструментов и поддержка параллельных вызовов, различаются. Конечная точка списка моделей не возвращает поле с признаком поддержки Tool Calling: сверяйтесь с документацией поставщика модели либо отправьте целевой модели один реальный запрос с tools для проверки, подробнее см. Models.
2. Формат определения инструмента (OpenAI)
Section titled “2. Формат определения инструмента (OpenAI)”В /v1/chat/completions инструменты объявляются через массив верхнего уровня tools, где каждый инструмент является вложенным объектом с type: "function".
Структура массива tools
Section titled “Структура массива tools”{ "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Запросить текущую погоду для указанного города. Использовать полное название города на китайском языке.", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "Название города, например, Пекин" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "Единица температуры, по умолчанию градусы Цельсия" } }, "required": ["city"] } } } ]}function schema
Section titled “function schema”| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
type | string | Да | Фиксированное значение "function" |
function.name | string | Да | Имя инструмента, может содержать только буквы, цифры, подчёркивания и дефисы |
function.description | string | Рекомендуется | Описание назначения инструмента, модель использует это для принятия решения о вызове |
function.parameters | object | Нет | Определение параметров, стандартная JSON Schema |
Качество description напрямую определяет, правильно ли модель выберет инструмент. Чётко описать назначение, значение каждого параметра, диапазон значений и граничные условия эффективнее, чем настройка любых параметров сэмплирования.
parameters (JSON Schema)
Section titled “parameters (JSON Schema)”parameters использует стандартную JSON Schema для описания структуры параметров:
type: Обычно"object".properties: Тип, описание, перечисляемые значения для каждого параметра.required: Список обязательных имён параметров.enum: Ограничить диапазон значений, значительно снижает вероятность того, что модель передаст неверные значения.
Инструменты без параметров всё равно должны предоставить пустую схему: "parameters": { "type": "object", "properties": {} }.
3. Формат определения инструмента (Claude)
Section titled “3. Формат определения инструмента (Claude)”В /v1/messages определения инструментов имеют плоскую структуру без внешних оболочек type и function, а поле параметров называется input_schema.
Различия массива tools
Section titled “Различия массива tools”{ "tools": [ { "name": "get_weather", "description": "Запросить текущую погоду для указанного города. Использовать полное название города на китайском языке.", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "Название города, например, Пекин" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["city"] } } ]}input_schema
Section titled “input_schema”Внутренняя структура input_schema идентична parameters OpenAI, обе являются стандартной JSON Schema. Различие только во внешней оболочке.
Сравнение двух форматов
Section titled “Сравнение двух форматов”| Элемент | OpenAI (/v1/chat/completions) | Claude (/v1/messages) |
|---|---|---|
| Внешняя оболочка | { "type": "function", "function": {...} } | Прямая плоская структура, без оболочки |
| Поле имени инструмента | function.name | name |
| Поле описания | function.description | description |
| Поле параметра | function.parameters | input_schema |
| Схема параметра | Стандартная JSON Schema | Стандартная JSON Schema (идентично) |
| Возврат модели | Массив message.tool_calls | Блок tool_use в content |
| Роль передачи результата | Независимое сообщение role: "tool" | Блок tool_result в сообщении user |
| Поле ассоциации результата | tool_call_id | tool_use_id |
Полные детали протокола Claude (включая is_error, потоковый input_json_delta и т. д.) см. в Протокол Claude Messages. Последующие примеры на этой странице по умолчанию используют формат OpenAI.
4. Опции tool_choice
Section titled “4. Опции tool_choice”tool_choice контролирует, как модель выбирает инструменты.
| Значение | Поведение |
|---|---|
"auto" | Модель сама решает, вызывать ли инструмент и какой. Значение по умолчанию при наличии tools |
"none" | Запретить вызов любого инструмента, модель выводит только текст |
"required" | Должен вызвать хотя бы один инструмент, но модель выбирает какой |
{ "type": "function", "function": { "name": "get_weather" } } | Принудительно вызвать указанный инструмент |
auto (по умолчанию)
Section titled “auto (по умолчанию)”{ "tool_choice": "auto" }Наиболее распространённый. Подходит для сценариев, где «вопросы пользователя иногда требуют инструментов, иногда прямых ответов».
{ "tool_choice": "none" }Временно отключить инструменты, сохраняя определения. Часто используется на заключительном этапе «пусть модель подведёт итог, не вызывать инструменты снова».
required
Section titled “required”{ "tool_choice": "required" }Принудить модель пойти по пути инструмента. Подходит для сценариев типа структурированного извлечения, которые «должны производить структурированные результаты».
Указать конкретный инструмент
Section titled “Указать конкретный инструмент”{ "tool_choice": { "type": "function", "function": { "name": "get_weather" } }}Эквивалент в формате Claude: { "type": "tool", "name": "get_weather" }, required соответствует { "type": "any" }, none соответствует { "type": "none" }.
5. Процесс Tool Calling
Section titled “5. Процесс Tool Calling”Полный вызов инструмента включает как минимум два раунда запросов.
Первый раунд: модель возвращает tool_calls
Section titled “Первый раунд: модель возвращает tool_calls”Отправить запрос с tools:
curl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Какая сейчас погода в Пекине?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Запросить текущую погоду для указанного города.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ] }'Когда модель определяет, что нужен инструмент, finish_reason будет tool_calls, message.content будет null, а tool_calls содержит запрос вызова:
{ "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } } ] }, "finish_reason": "tool_calls" } ]}Обратите внимание, что arguments — это JSON строка, а не объект; вам нужно самостоятельно разобрать её с помощью JSON.parse / json.loads. Модель может иногда генерировать недействительный JSON, поэтому разбор должен быть в try/catch.
Выполнить инструмент
Section titled “Выполнить инструмент”Отправить по function.name к вашей реальной логике, выполнить с разобранными параметрами:
import json
args = json.loads(tool_call["function"]["arguments"])result = get_weather(**args) # "Пекин, ясно, 23 градуса"Второй раунд: передать результат инструмента
Section titled “Второй раунд: передать результат инструмента”Добавить сообщение assistant первого раунда (с tool_calls) обратно в messages как есть, затем добавить сообщение role: "tool", несущее результат. tool_call_id должен точно совпадать с id из первого раунда:
{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Какая сейчас погода в Пекине?" }, { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } } ] }, { "role": "tool", "tool_call_id": "call_abc123", "content": "Пекин, ясно, температура 23 градуса Цельсия, влажность 45%." } ], "tools": []}Модель генерирует окончательный ответ
Section titled “Модель генерирует окончательный ответ”Запрос второго раунда возвращает результат на естественном языке, finish_reason возвращается к stop:
{ "choices": [ { "message": { "role": "assistant", "content": "В Пекине сейчас ясно, температура 23 градуса Цельсия, влажность 45%, довольно комфортно." }, "finish_reason": "stop" } ]}6. Многораундовый Tool Calling
Section titled “6. Многораундовый Tool Calling”Последовательные вызовы нескольких инструментов
Section titled “Последовательные вызовы нескольких инструментов”Модели может потребоваться несколько раундов вызовов инструментов для выполнения задачи: сначала проверить номер заказа, затем использовать номер заказа для проверки логистики. Каждый раунд следует циклу «модель возвращает tool_calls → выполнить → передать обратно результат», пока finish_reason не вернётся к stop. Производственный код должен быть написан в виде цикла с установленным максимальным лимитом раундов для предотвращения бесконечных циклов:
MAX_TURNS = 5for _ in range(MAX_TURNS): resp = call_model(messages) msg = resp["choices"][0]["message"] messages.append(msg) if not msg.get("tool_calls"): break # Модель даёт окончательный ответ for tc in msg["tool_calls"]: result = dispatch(tc) # Выполнить и вернуть строку messages.append({ "role": "tool", "tool_call_id": tc["id"], "content": result, })Параллельные вызовы инструментов
Section titled “Параллельные вызовы инструментов”В одном раунде модель может одновременно запросить несколько независимых инструментов (например, проверить погоду в Пекине и Шанхае одновременно), в результате чего tool_calls будет многоэлементным массивом. Вам нужно добавить соответствующее сообщение role: "tool" для каждого tool_call, с tool_call_id, выровненным один к одному; пропуск одного вызовет ошибку в следующем раунде.
Чтобы отключить параллелизм и заставить модель вызывать только один инструмент за раз, добавьте "parallel_tool_calls": false в формате OpenAI или добавьте "disable_parallel_tool_use": true в tool_choice для формата Claude.
7. Потоковый Tool Calling
Section titled “7. Потоковый Tool Calling”Когда установлено stream: true, параметры вызова инструмента возвращаются инкрементально по частям.
tool_calls в потоковом выводе
Section titled “tool_calls в потоковом выводе”В delta.tool_calls каждого SSE chunk содержится index (идентифицирует, какой вызов инструмента), а function.arguments — это фрагмент JSON параметров:
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"id":"call_abc123","type":"function","function":{"name":"get_weather","arguments":""}}]}}]}
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]}}]}
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"北京\"}"}}]}}]}
data: {"choices":[{"finish_reason":"tool_calls"}]}
data: [DONE]Как обрабатывать инкрементный delta
Section titled “Как обрабатывать инкрементный delta”Накапливать по группам index: id и name обычно появляются только в первом фрагменте, arguments нужно конкатенировать все фрагменты перед разбором. Не пытайтесь разбирать промежуточные состояния во время конкатенации (это неполный JSON).
buffers = {} # index -> {"id", "name", "args"}for chunk in stream: for tc in chunk["choices"][0]["delta"].get("tool_calls", []): i = tc["index"] buf = buffers.setdefault(i, {"id": "", "name": "", "args": ""}) if tc.get("id"): buf["id"] = tc["id"] fn = tc.get("function", {}) if fn.get("name"): buf["name"] = fn["name"] if fn.get("arguments"): buf["args"] += fn["arguments"]
# Разобрать после завершения потокаfor buf in buffers.values(): args = json.loads(buf["args"])Потоковые параметры инструмента в формате Claude возвращаются инкрементально через partial_json события input_json_delta, накапливаются по index, затем разбираются; детали в Протокол Claude Messages.
8. Статус поддержки моделей
Section titled “8. Статус поддержки моделей”Модели, поддерживающие Tool Calling
Section titled “Модели, поддерживающие Tool Calling”Большинство основных моделей, агрегированных RouteAPI, поддерживают Tool Calling, включая серии OpenAI GPT, Claude, Gemini и др. Сначала убедитесь через конечную точку списка моделей, что модель доступна в вашем аккаунте:
curl https://api.routeapi.ai/v1/models \ -H "Authorization: Bearer $ROUTEAPI_KEY"Эта конечная точка возвращает только доступность модели и доступные эндпоинты, но не способность Tool Calling. Наличие поддержки Tool Calling определяйте по документации поставщика либо по одному реальному запросу с tools.
Ограничения моделей
Section titled “Ограничения моделей”Разные модели различаются в следующих измерениях; проверьте в тестовой среде перед переходом в производство:
| Измерение | Описание |
|---|---|
| Максимальное количество инструментов | Верхний лимит инструментов, которые можно объявить в одном запросе, зависит от модели |
| Параллельные вызовы | Некоторые модели не поддерживают возврат нескольких tool_calls в одном раунде |
Поддержка tool_choice | Не все модели поддерживают required / указание конкретных инструментов |
| Сложность параметров | Глубоко вложенные или очень большие JSON Schema могут быть обрезаны или проигнорированы некоторыми моделями |
| Гранулярность потокового инкремента | Способ фрагментации arguments непоследователен между моделями; необходимо накапливать по index |
9. Полные примеры
Section titled “9. Полные примеры”Пример инструмента запроса погоды (от начала до конца)
Section titled “Пример инструмента запроса погоды (от начала до конца)”Следующие три фрагмента кода функционально эквивалентны: определить инструмент → первый раунд получить tool_calls → выполнить → второй раунд передать обратно результат → получить окончательный ответ.
curl (вручную завершить два раунда):
# Первый раунд: отправить запрос с инструментамиcurl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [{ "role": "user", "content": "Какая сейчас погода в Пекине?" }], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Запросить текущую погоду для указанного города.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } }] }'
# Второй раунд: передать обратно результат инструмента (tool_call_id использует значение из первого раунда)curl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Какая сейчас погода в Пекине?" }, { "role": "assistant", "content": null, "tool_calls": [{ "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } }] }, { "role": "tool", "tool_call_id": "call_abc123", "content": "Пекин, ясно, температура 23 градуса Цельсия, влажность 45%." } ] }'Python (SDK OpenAI, автоматически завершает два раунда):
import jsonimport osfrom openai import OpenAI
client = OpenAI( api_key=os.environ["ROUTEAPI_KEY"], base_url="https://api.routeapi.ai/v1",)
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Запросить текущую погоду для указанного города. Использовать полное название города на китайском языке.", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "Название города, например, Пекин"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, }, "required": ["city"], }, }, }]
def get_weather(city: str, unit: str = "celsius") -> str: # Заменить на реальный вызов сервиса погоды return f"{city}, ясно, температура 23 градуса Цельсия, влажность 45%."
messages = [{"role": "user", "content": "Какая сейчас погода в Пекине?"}]
# Первый раундresp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools)msg = resp.choices[0].message
if msg.tool_calls: # Сообщение assistant должно быть добавлено обратно как есть, иначе tool_call_id не может выровняться messages.append(msg) for tc in msg.tool_calls: args = json.loads(tc.function.arguments) result = get_weather(**args) messages.append( {"role": "tool", "tool_call_id": tc.id, "content": result} )
# Второй раунд resp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools )
print(resp.choices[0].message.content)Node.js (пакет openai, автоматически завершает два раунда):
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.ROUTEAPI_KEY, baseURL: 'https://api.routeapi.ai/v1',});
const tools = [ { type: 'function', function: { name: 'get_weather', description: 'Запросить текущую погоду для указанного города. Использовать полное название города на китайском языке.', parameters: { type: 'object', properties: { city: { type: 'string', description: 'Название города, например, Пекин' }, unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }, }, required: ['city'], }, }, },];
function getWeather(city, unit = 'celsius') { // Заменить на реальный вызов сервиса погоды return `${city}, ясно, температура 23 градуса Цельсия, влажность 45%.`;}
const messages = [{ role: 'user', content: 'Какая сейчас погода в Пекине?' }];
// Первый раундlet resp = await client.chat.completions.create({ model: 'gpt-5.5', messages, tools,});const msg = resp.choices[0].message;
if (msg.tool_calls) { messages.push(msg); // Добавить сообщение assistant обратно как есть for (const tc of msg.tool_calls) { const args = JSON.parse(tc.function.arguments); const result = getWeather(args.city, args.unit); messages.push({ role: 'tool', tool_call_id: tc.id, content: result }); }
// Второй раунд resp = await client.chat.completions.create({ model: 'gpt-5.5', messages, tools, });}
console.log(resp.choices[0].message.content);Пример инструмента запроса к базе данных
Section titled “Пример инструмента запроса к базе данных”Используйте инструменты как безопасные обёртки для внутренних систем. Ключевое: SQL не должен генерироваться моделью напрямую; вместо этого модель выбирает параметры, а ваш код создаёт параметризованные запросы, чтобы избежать инъекции.
tools = [ { "type": "function", "function": { "name": "query_order", "description": "Запросить статус заказа и сумму по номеру заказа.", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "Номер заказа, например ORD-20260917-001", } }, "required": ["order_id"], }, }, }]
def query_order(order_id: str) -> str: # Использовать параметризованный запрос, никогда не объединять вывод модели напрямую в SQL row = db.execute( "SELECT status, amount FROM orders WHERE order_id = %s", (order_id,), ).fetchone() if row is None: return json.dumps({"found": False}) return json.dumps({"found": True, "status": row[0], "amount": row[1]})Результаты инструментов рекомендуется передавать обратно в виде JSON-строк; модели могут более надёжно разбирать структурированные поля.
Пример оркестровки нескольких инструментов
Section titled “Пример оркестровки нескольких инструментов”Объявить несколько инструментов одновременно; модель выбирает по мере необходимости или даже вызывает параллельно. Здесь используются два инструмента: погода + обменный курс:
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Запросить текущую погоду для указанного города.", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }, }, { "type": "function", "function": { "name": "get_exchange_rate", "description": "Запросить обменный курс между двумя валютами.", "parameters": { "type": "object", "properties": { "from_currency": {"type": "string", "description": "Например USD"}, "to_currency": {"type": "string", "description": "Например CNY"}, }, "required": ["from_currency", "to_currency"], }, }, },]
dispatch = { "get_weather": lambda city: f"{city}, ясно, 23 градуса.", "get_exchange_rate": lambda from_currency, to_currency: f"1 {from_currency} = 7.2 {to_currency}",}
messages = [{"role": "user", "content": "Какая погода в Пекине? Также скажите мне обменный курс USD к CNY."}]
# Цикл для обработки многораундовых / параллельных вызовов инструментов, установить лимит для предотвращения бесконечных цикловfor _ in range(5): resp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools ) msg = resp.choices[0].message messages.append(msg) if not msg.tool_calls: break # Во время параллельных вызовов tool_calls — многоэлементный массив; каждый должен быть передан обратно for tc in msg.tool_calls: args = json.loads(tc.function.arguments) result = dispatch[tc.function.name](**args) messages.append( {"role": "tool", "tool_call_id": tc.id, "content": result} )
print(messages[-1]["content"])10. Обработка ошибок
Section titled “10. Обработка ошибок”Tool Calling вводит три потенциальные точки ошибки: со стороны модели, со стороны вашего кода и со стороны восходящего сервиса.
Сбой проверки параметров инструмента
Section titled “Сбой проверки параметров инструмента”Модель может вернуть недействительный JSON, или пропустить обязательные параметры, или передать значения вне диапазона enum. Обязательно:
- Обернуть
JSON.parse/json.loadsв try/catch. - После разбора проверить обязательные поля и диапазоны значений согласно схеме.
- Когда проверка не удалась, передать сообщение об ошибке обратно как результат инструмента, чтобы позволить модели самокорректироваться, вместо того чтобы напрямую выбрасывать исключение для завершения разговора:
try: args = json.loads(tc.function.arguments) city = args["city"] # Проверить обязательное полеexcept (json.JSONDecodeError, KeyError) as exc: result = f"Сбой разбора параметров: {exc}. Пожалуйста, предоставьте действительный параметр city снова."else: result = get_weather(city)
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})Тайм-аут выполнения инструмента
Section titled “Тайм-аут выполнения инструмента”Инструменты поддерживаются реальными сервисами, которые могут истечь по времени или быть недоступными. Установите лимит тайм-аута для каждого вызова инструмента; если тайм-аут, передайте результат обратно как чёткое описание ошибки, чтобы позволить модели переключиться на другую стратегию:
try: result = call_service(args, timeout=5)except TimeoutError: result = "Тайм-аут сервиса, данные не получены, пожалуйста, повторите попытку позже или используйте другой метод."Не выполняйте автоматические повторные попытки для инструментов с побочными эффектами (оформление заказов, отправка электронных писем), так как они могут выполняться повторно. Идемпотентный дизайн или проверка перед записью безопаснее.
Инструмент возвращает ошибку
Section titled “Инструмент возвращает ошибку”Ошибки бизнес-уровня (заказ не найден, нет разрешения) также должны быть переданы обратно модели, вместо молчаливого возврата пустых значений. Передайте обратно структурированную информацию об ошибке; модель может предоставить разумные объяснения пользователям:
messages.append({ "role": "tool", "tool_call_id": tc.id, "content": json.dumps({"error": "order_not_found", "order_id": order_id}),})Формат Claude соответственно устанавливает "is_error": true в блоке tool_result, см. Протокол Claude Messages.
Напоминания о совместимости
Section titled “Напоминания о совместимости”- Способность Tool Calling, максимальное количество инструментов, поддержка параллельных вызовов зависят от выбранной модели; проверьте в тестовой среде перед переходом в производство.
argumentsвсегда является JSON-строкой, а не объектом; необходимо явно разбирать.- В потоковых сценариях необходимо накапливать фрагменты
argumentsпоindex, разбирать после полной конкатенации. - Необязательные параметры, явно переданные как
0илиfalse, считаются установленными пользователем, не рассматриваются как значения по умолчанию и отбрасываются. - Записывайте request ID, ID модели, код статуса и использование токенов для каждого запроса для более лёгкого устранения неполадок. Подробности структуры ошибок в Ошибки и отладка.