OpenAI Agents API + JSON Schema на практике: стабильный, проверяемый, исполняемый JSON (2026)
Общий текст про 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». Идти по дверям:
- Сначала написать Schema инструмента. Затянуть pattern, enum, required, additionalProperties: false один раз.
- Ту же Schema положить в валидатор хозяина. Не держать вторую, плывущую копию.
- На required_actions сначала проверить, потом исполнить. Дверь не пройдена → success: false.
- Итоговой карточке — своя Schema. Проверять после извлечения из items. Проза — не карточка.
- Поля книги учёта держать самим. 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. Если можете указать путь, данные проверяемы. Модели сменятся; двери должны устояться раньше.
Дальше
- OpenAI Agents API, полный разбор Как стыкуются Session, tool calling и Schema
- JSON-структуры Agents API Agent / Tool Call / Tool Result / Handoff
- Agents API vs Responses API Кто должен крутить цикл
- Долгий Agents API Session, compact, субагенты
- Зачем ИИ нужен JSON Schema Schema / Function Calling / Structured Output
- Локальный ящик JSONSort Формат, проверка, Diff
- Все статьи Ещё заметки про JSON и ИИ
Журнал изменений: Первая публикация