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

OpenAI Agents API + JSON Schema на практике: стабильный, проверяемый, исполняемый JSON (2026)

Около 16 мин

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

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

Дверь Что запирает Кто исполняет
Function parameters order_id, булевы, перечисления additionalProperties: false
Проверка хозяина arguments в required_actions Нет прохода — нет функции
Итоговая карточка Объект для пользователя Вторая Schema; не text.format
MCP inputSchema другой таблицы инструментов Субагенты могут унаследовать

Schema — дверь, не вежливость. Широкий object — ещё одна открытая дверь.

Стабильно, проверяемо, исполняемо: три процедуры, не один выключатель

На Agents API модель по-прежнему только заполняет JSON. Официальной функции нужна Schema parameters: required, additionalProperties: false и где надо pattern / enum. Это стабилизирует заполнение. Проверяемость — прогнать ту же Schema по arguments до исполнения. Исполнение — хозяин даёт побочные эффекты только после двери.

  • Стабильно: жёсткая Schema инструмента. Широкий object приглашает выдуманные ключи.
  • Проверяемо: локально проверить вызов в required_actions. function_call в истории мало.
  • Исполняемо: не гонять lookup_order, если дверь не пройдена. Писать назад success: false и причину. Не трогать склад молча.

Как зовут инструменты: Разбор OpenAI Agents API. Как четыре объекта сидят на ID: JSON-структуры Agents API. Общее деление Schema / Function Calling / Structured Output: Зачем ИИ нужен JSON Schema. Этот текст не переопределяет слова. Он только сажает их на Agents session.

Первая дверь: parameters в agent.tools

Официальная запись function — имя, описание и JSON Schema. Писать в agent.tools при создании. Вымышленный заказ — без настоящих секретов:

{
  "type": "function",
  "name": "lookup_order",
  "description": "Look up an order by ID. Confirm before any refund.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" },
      "include_lines": { "type": "boolean" }
    },
    "required": ["order_id", "include_lines"],
    "additionalProperties": false
  }
}

Рычагов мало: каждое поле в required; объекты закрывают лишние ключи; номера — через pattern, не голый string. Функции по умолчанию грузятся заранее. Отложить: defer_loading: true и tool_search в таблице. Сама дверь не меняется.

Аргументы, не прошедшие дверь, нельзя исполнять

Когда session встаёт на agent.session.requires_action, в required_actions лежит function_call. Этот пример похож на поиск и уже перелез через забор: номер ломает pattern, появился ключ refund:

{
  "type": "function_call",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "name": "lookup_order",
  "arguments": {
    "order_id": "1042",
    "include_lines": true,
    "refund": true
  }
}

Та же пара turn_id / call_id — проходящая форма выглядит так. Лишний ключ, дыра в required, поплывший pattern: ничего из этого не исполнять:

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

Вторая дверь: хозяин гоняет ту же Schema ещё раз

Официальная Schema улучшает заполнение. Побочные эффекты она не берёт. Проверить локально до запуска. Провал записать объектом для разбора:

{
  "check": "lookup_order",
  "schema": "parameters",
  "pass": ["order_id", "include_lines"],
  "fail": [
    { "path": "/order_id", "reason": "pattern" },
    { "path": "/refund", "reason": "additionalProperties" }
  ],
  "execute": false
}

При провале слать agent.session.input.tool_result с success: false и читаемым error. При успехе сериализовать output в строку. Не открывать новую session как «повтор».

{
  "type": "agent.session.input.tool_result",
  "turn_id": "turn_2",
  "call_id": "call_3c91",
  "success": false,
  "error": "order_id failed schema: expected ^[A-Z]-\\d{4}$"
}

Итоговая карточка — третья дверь, не text.format у Responses

Карточка заказа для пользователя — не Schema параметров инструмента. Agents session сама не накладывает text.format.json_schema из Responses. Три работы держать отдельно:

  • Параметры инструмента: запирать дверь побочных эффектов. Поиск и запись — здесь.
  • Итоговая карточка: вынуть объект из items, проверить второй Schema, потом показать.
  • Если итоговую форму надо запереть Structured Outputs: это слой Responses. Не мешать в тот же ресурс session.

Кому держать цикл: Agents API vs Responses API. Строка MCP — ещё одна таблица инструментов; её inputSchema тоже хочет additionalProperties: false. Граница: MCP Tool Schema vs Function Calling. Субагенты наследуют Schema MCP, не вашу function.

Пять шагов к исполняемому JSON

Не начинать с «пожалуйста, выведите JSON». Идти по дверям:

  1. Сначала написать Schema инструмента. Затянуть pattern, enum, required, additionalProperties: false один раз.
  2. Ту же Schema положить в валидатор хозяина. Не держать вторую, плывущую копию.
  3. На required_actions сначала проверить, потом исполнить. Дверь не пройдена → success: false.
  4. Итоговой карточке — своя Schema. Проверять после извлечения из items. Проза — не карточка.
  5. Поля книги учёта держать самим. Compact роняет детали. Суммы и согласования не живут только в чате.

Как поток становится Schema: JSON Schema и рабочие процессы агента. Этот текст требует лишь, чтобы каждая дверь на Agents session была объектом.

Разбирать стабильный вывод — разложить два JSON-следа

Сдвиг обычно — кривая дверь, не более глупая модель.

  • формат parameters рядом с arguments. Искать лишние ключи и дыры.
  • извлечь JSONPath вытащить order_id и $.parameters.required.
  • JSON Diff падающий вызов и проходящий. Поплыл pattern — сначала Schema.
  • Schema карточки и Schema инструмента смотреть отдельно. Запереть только карточку — это фасад.
  • Не вставлять заказы, session и внутренний MCP в публичный форматтер. JSONSort работает в браузере локально.

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

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

  • Писать «выведите JSON» только в instructions. Это не дверь. Дверь — parameters плюс валидатор хозяина.
  • В required перечислить лишь часть полей. Пропущенные ключи могут остаться пустыми. В следующем прыжке дыры.
  • Не писать additionalProperties или ставить true. Официальные примеры закрывают лишние ключи. Один лишний refund — и побочный эффект кренится.
  • Копировать text.format из Responses в Agents session. Два ресурса. Итоговую карточку проверять самим.
  • Гонять функцию после провала проверки. Исполняемо значит: дверь пройдена. Сначала error.
  • Отдать function субагенту. Субагенты не поддерживают function-инструменты. Жёсткая Schema остаётся у главного агента.

FAQ

Есть ли у Agents API Structured Outputs?

Параметры инструмента затягиваются JSON Schema. Объект для пользователя session сама не оборачивает в text.format из Responses. Итоговую форму запирайте сами или кладите этот прыжок на Responses.

Если официальная Schema есть, всё равно проверять?

Да. Официальная дверь улучшает заполнение. Побочные эффекты — в вашем процессе. arguments из required_actions гнать через ту же Schema; провал — success: false.

Нужны ли pattern и enum?

Да. Голый string даёт модели 1042 вместо A-1042. Суммы и статусы хотят enum или явный формат. Широкие типы — обычный путь через забор.

Нужна ли MCP-инструментам та же дисциплина?

Да. inputSchema тоже закрывает лишние ключи и перечисляет каждый required. Субагенты наследуют MCP, не function. Дверь к вашим заказам остаётся у главного агента.

Провал проверки встанет ли session?

Достаточно tool_result на той же паре turn_id / call_id. Ясный error даёт модели повторить с новыми аргументами. Не открывать новую session как повтор.

Вывод

Стабильный JSON на Agents API — не более длинный prompt. Это три двери: parameters инструмента, проверка хозяина и отдельная Schema итоговой карточки. Исполнение — после двери.

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

Дальше

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