AI-разработка

JSON-структуры OpenAI Agents API: как связаны Agent, Tool Call, Tool Result и Handoff (2026)

Около 16 мин

После публичной беты трудность не в том, «умеет ли звать инструмент». А в том, как четыре объекта сидят на одной цепи. Item типа handoff нет. Скрепки — ID: session_id, turn_id, call_id, agent_id. Этот текст только разбирает эту JSON-цепь.

Перед чтением

Объект Официальная форма Скрепка
Agent Модель, таблица инструментов, multi_agent Пишется при создании session
Tool Call function_call в required_actions turn_id + call_id
Tool Result agent.session.input.tool_result Та же пара назад
Handoff items create / send / wait / interrupt agent_id / subagent_id

function_call в истории не значит, что результат ещё ждут. Ожидание — в required_actions.

Четыре объекта сходятся на ID, не на абзаце

В Agents API Agent — конфигурация при создании session. Tool Call — function_call в required_actions, когда session остановилась. Tool Result — agent.session.input.tool_result в поток событий. «Handoff» здесь — набор координационных items, не объект handoff из SDK.

  • Та же пара turn_id / call_id: вызов и результат должны сойтись. Иначе harness не продолжит.
  • Истории мало: function_call в items значит лишь, что вызов был. Ещё ждут? Читать required_actions.
  • Handoff — не type: смотреть create_subagent_call и subagent_id. Не искать поле с именем handoff.

Как зовут инструменты: Разбор OpenAI Agents API. Как продолжается длинная задача: Долгий Agents API. Кому держать цикл: Agents API vs Responses API. Если Agent и Function Calling ещё одно слово — сначала Полный гид по AI-агенту.

Agent: объект конфигурации, не ответ

Создание пишет модель, инструкции, инструменты и multi_agent один раз. Этот объект — подлежащее всех следующих items. Официально: POST /v1/agents/sessions с OpenAI-Beta: agents=v1:

{
  "agent": {
    "model": "gpt-6-astra",
    "instructions": "Look up orders. Confirm before any refund.",
    "tools": [
      {
        "type": "function",
        "name": "lookup_order",
        "parameters": {
          "type": "object",
          "properties": {
            "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
          },
          "required": ["order_id"],
          "additionalProperties": false
        }
      }
    ],
    "multi_agent": { "enabled": true, "max_concurrent_subagents": 3 }
  },
  "environment": { "type": "openai_hosted" },
  "input": [{ "role": "user", "content": [{ "type": "input_text", "text": "Look up A-1042." }] }]
}

Конфиг Agent остаётся с session. Смена модели или силы рассуждения обновляет эту session; сохранённый шаблон действует только на новые session. Среда — отдельный ресурс: openai_hosted или ваша песочница. Удаление session не чистит sandbox.

Tool Call: верить required_actions

Когда нужен результат функции, session шлёт agent.session.requires_action. Ожидающие вызовы — в required_actions как function_call с turn_id / call_id:

{
  "type": "function_call",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "name": "lookup_order",
  "arguments": { "order_id": "A-1042" }
}

Аргументы должны пройти Schema. Широкий object — не дверь. См. Зачем ИИ нужен JSON Schema. В истории items тоже может быть function_call; официально: одна история не доказывает, что результат ещё ждут.

Tool Result: та же пара в поток событий

После выполнения отправьте agent.session.input.tool_result на endpoint событий. Скопируйте turn_id и call_id из ожидающего действия. Успех: success: true и строковый output. Ошибка: success: false и error:

{
  "type": "agent.session.input.tool_result",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "success": true,
  "output": "{\"order_id\":\"A-1042\",\"status\":\"paid\"}"
}

Объекты сначала сериализовать в строки. Если функция уже отработала до обрыва — снова сдать сохранённый результат той же парой. Не открывать новую session как «повтор». Harness продолжит turn только когда придут нужные результаты.

Handoff: координационные items, не имя поля

С multi_agent.enabled harness даёт create, message, wait и interrupt. Эти инструменты не объявляете. Координация видна как items:

{
  "data": [
    {
      "type": "create_subagent_call",
      "agent_id": "agent_main",
      "task": "Compare A-1042 packing notes with the invoice."
    },
    {
      "type": "send_subagent_input_call",
      "subagent_id": "sub_7a12",
      "input": "Focus on line items only."
    },
    {
      "type": "agent_message",
      "from": "sub_7a12",
      "text": "Invoice lines match packing notes for A-1042."
    }
  ]
}
  • create_subagent_call: отправка. agent_id — кто запросил. Готово не значит, что подзадача кончилась.
  • send / wait / interrupt: сказать, ждать, остановить. agent_message может нести видимый меж агентный текст; поток — не полная стенограмма.
  • Объект handoff в SDK: живёт в вашем процессном runner. Это не тот же ресурс, что эти items.

То, что вы отдаёте следующему подлежащему, должно быть проверяемым JSON: номер заказа, намерение, основание. Как уложить в Schema: JSON Schema и рабочие процессы агента.

Цепь держится, только если скрепки совпали

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

{
  "session_id": "sess_8f21",
  "links": [
    { "object": "agent", "id": "agent_main" },
    { "object": "turn", "id": "turn_2" },
    { "object": "function_call", "call_id": "call_3c91" },
    { "object": "tool_result", "call_id": "call_3c91" },
    { "object": "subagent", "id": "sub_7a12", "via": "create_subagent_call" }
  ]
}
Объект Тип, который видите Приколото к Обычный сдвиг
Agent session.agent session_id Новая session как «повтор»
Tool Call function_call turn_id + call_id Читать только историю items
Tool Result input.tool_result Та же пара output ещё объект, не строка
Handoff create_subagent_call agent_id / subagent_id Искать поле с именем handoff
Turn turn.completed / failed turn_id; у корня subagent_id пуст Простой читать как успех

Строка MCP — ещё одна таблица инструментов. Вторую схему ID она не изобретает. Граница: MCP Tool Schema vs Function Calling.

Разбирать цепь — разложить два JSON-следа

Большинство сдвигов — плывущие скрепки, не более глупая модель.

  • формат required_actions рядом с событием записи назад. call_id должен совпасть буква в букву.
  • извлечь JSONPath вытащить turn_id, call_id, subagent_id.
  • JSON Diff вызов и результат одного заказа. Поплыло — сначала ID.
  • Items главного агента и субагента — отдельными списками. В одной странице координация прилипнет не к тому.
  • Не вставлять заказы, session и внутренний MCP в публичный форматтер. JSONSort работает в браузере локально.

Если оба следа собираются по ID, вы читаете структуру. Иначе — лозунги.

Частые ловушки

  • Считать function_call в items ещё ожидающим. Ожидание — required_actions.
  • Писать назад другую пару ID. Harness не сведёт; turn встанет.
  • Отправить output сырым объектом. Официально нужна строка или поддерживаемый массив content.
  • Искать type: handoff в payload. Agents API использует create / send / wait / interrupt.
  • Отдать function субагенту. Субагенты не поддерживают function-инструменты. Поиск заказа — у главного агента.
  • Считать SDK handoff и items session одним ресурсом. Удаление одного не чистит другое.

FAQ

У каждого Tool Call должен быть Tool Result?

Каждый ожидающий вызов нужно записать назад. Исторический function_call, который уже кончился, второго результата не требует. Критерий — required_actions, не длина списка items.

Есть ли в Agents API JSON-поле с именем handoff?

Не как первоклассный item type. Координация: create_subagent_call, send_subagent_input_call, wait_for_subagents_call, interrupt_subagent_call. Handoff в SDK — другой объект.

Чем call_id отличается от item_id?

call_id скрепляет вызов функции с её результатом. item_id именует сохранённый item. Поток вешает дельты текста на ту же часть через item_id. Две скрепки — не смешивать.

Как turn может быть completed, если инструмент упал?

Официально: completed не значит, что каждый инструмент успешен. Смотреть также success у tool_result и items этого turn.

Можно ли завести свой handoff JSON в приложении?

Можно, и нужно. Это ваш деловой объект: номер заказа, намерение, основание. Не ждите, что официальные items запомнят суммы. Пишите Schema и храните отдельно от items session.

Вывод

Agent, Tool Call, Tool Result и Handoff — не четыре абзаца. Это четыре объекта на одной JSON-цепи, скреплённые ID. Официальная запись назад — событие; официальная передача — координационный item.

Сначала запишите, сведёте ли вызов и результат одним call_id. Если да, структура держится. Модели сменятся; скрепки должны устояться раньше.

Дальше

Журнал изменений: Первая публикация