OpenAI Agents API + JSON Schema 실전: 안정적이고 검증 가능하며 실행 가능한 JSON을 어떻게 내나 (2026)
일반 Schema 글은 왜 계약이 필요한지를 이미 썼다. 이 글은 Agents API에만 둔다: 모델이 채운 JSON은 문을 통과한 뒤에만 실행한다. 도구 인자, MCP 입력, 당신 장부는 세 문이지 「JSON을 출력하라」는 문장이 아니다.
읽기 전 한눈
| 문 | 무엇을 잠그나 | 누가 실행하나 |
|---|---|---|
| Function parameters | order_id, 불리언, 열거 | additionalProperties: false |
| 호스트 검증 | required_actions의 arguments | 통과하지 않으면 함수를 돌리지 않음 |
| 최종 카드 | 사용자에게 보여줄 객체 | 별 Schema. text.format이 아님 |
| MCP | 다른 도구 표의 inputSchema | subagent가 이어받을 수 있음 |
Schema는 문이지 예의가 아니다. 넓은 object는 문을 하나 더 열어 둔 것이다.
안정, 검증, 실행은 세 절차이지 스위치 하나가 아니다
Agents API에서도 모델은 JSON만 채운다. 공식 function에는 parameters Schema가 필요하다. required, additionalProperties: false, 필요할 때 pattern / enum. 이것이 채움을 안정시킨다. 검증은 실행 전에 같은 Schema로 arguments를 돌리는 것이다. 실행은 문을 통과한 뒤 호스트가 부작용을 내는 것이다.
- 안정: 도구 인자를 엄한 Schema로 쓴다. 넓은
object는 키 발명을 부른다. - 검증:
required_actions의 호출을 로컬에서 검증한다. 이력의 function_call로는 부족하다. - 실행: 문을 못 넘으면
lookup_order를 돌리지 않는다.success: false와 이유를 되돌린다. 조용히 저장소를 건드리지 마라.
도구 호출은 OpenAI Agents API 완전 해설. 네 대상을 ID로 잇는 이야기는 Agents API JSON 데이터 구조. Schema / Function Calling / Structured Output의 일반 구분은 AI에 JSON Schema가 필요한 이유. 이 글은 그 단어를 다시 정의하지 않는다. Agents session에 얹는 법만 쓴다.
첫 문: agent.tools의 parameters
공식 function은 name, description, JSON Schema다. session 생성 때 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
}
실패면 events 엔드포인트에 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}$"
}
최종 카드는 셋째 문이지 Responses의 text.format이 아니다
사용자에게 보여줄 주문 카드는 도구 인자 Schema가 아니다. Agents session은 Responses의 text.format.json_schema를 자동으로 걸지 않는다. 세 일을 나눠 쓴다:
- 도구 인자: 부작용 입구를 잠근다. 조회와 쓰기는 여기.
- 최종 카드: items에서 객체를 뽑은 뒤 다른 Schema로 검증하고 보여 준다.
- 최종 모양을 Structured Outputs로 잠그려면: 그것은 Responses 층이다. 같은 session 자원에 섞지 마라.
루프를 맡길지는 Agents API vs Responses API. MCP 행은 다른 도구 표다. inputSchema에도 additionalProperties: false가 필요하다. 경계는 MCP Tool Schema vs Function Calling. subagent는 MCP Schema를 이어받고 function은 이어받지 않는다.
실행 가능한 JSON으로 가는 다섯 걸음
「JSON을 출력하라」에서 시작하지 마라. 문을 걷는다:
- 먼저 도구 Schema를 쓴다. pattern, enum, required, additionalProperties: false를 한 번에 조인다.
- 같은 Schema를 호스트 검증기에 넣는다. 공식 parameters와 따로 쓰지 마라.
- required_actions에서는 검증한 뒤 실행한다. 못 넘으면 success: false.
- 최종 카드는 별 Schema. items에서 뽑은 뒤 검증한다. 산문을 카드로 쓰지 마라.
- 장부 칸은 당신이 쥔다. compact는 세부를 버린다. 금액과 승인을 대화에만 두지 마라.
워크플로를 Schema로 담는 이야기는 JSON Schema와 Agent 워크플로. 이 글이 요구하는 것은 Agents session의 문이 모두 객체라는 것이다.
안정 출력을 되짚으려면 JSON 두 줄을 펼친다
흐름의 대부분은 문이 어긋난 것이다. 모델이 둔해진 것이 아니다.
- parameters와 arguments를 포맷하고 여분 키와 빠진 칸을 본다.
- JSONPath 추출로
order_id와$.parameters.required를 뽑는다. - 문을 못 넘긴 호출과 넘긴 호출을 JSON Diff. pattern이 흘렀으면 먼저 Schema를 본다.
- 카드 Schema와 도구 Schema는 따로 본다. 카드만 잠그면 입구는 열린 채로 남는다.
- 주문, session, 사내 MCP를 공개 포맷터에 붙이지 마라. JSONSort는 브라우저에서 로컬로 돈다.
두 궤적이 Schema로 다시 세워져야 JSON을 모은 것이다. 아니면 산문을 모은 것이다.
흔한 함정
- instructions에 「JSON을 출력하라」만 쓴다. 그것은 문이 아니다. 문은 parameters와 호스트 검증기다.
- required에 일부 칸만 나열한다. 빠진 키는 비어 남을 수 있고 다음 홉에 구멍이 난다.
- additionalProperties를 안 쓰거나 true로 둔다. 공식 예는 여분 키를 닫는다. refund가 하나 늘면 부작용이 기운다.
- Responses의 text.format을 Agents session에 복사한다. 자원이 둘이다. 최종 카드는 직접 검증한다.
- 검증에 떨어져도 함수를 실행한다. 실행의 전제는 문 통과다. 먼저 error를 되돌린다.
- subagent에게 function을 돌리게 한다. 하위 에이전트는 function 도구를 쓰지 못한다. 엄한 Schema는 주 Agent에 남긴다.
FAQ
Agents API에 Structured Outputs가 있나?
도구 인자는 JSON Schema로 조인다. 사용자에게 보여줄 최종 객체에 session이 Responses text.format을 자동으로 걸지 않는다. 최종 모양을 잠그려면 직접 검증하거나 그 홉을 Responses에 둔다.
공식 Schema가 있는데도 다시 검증하나?
한다. 공식 문은 채움 품질을 올린다. 부작용은 당신 프로세스에서 난다. required_actions의 arguments를 같은 Schema에 통과시키고, 실패면 success: false.
pattern과 enum이 필요한가?
필요하다. 맨 string이면 모델이 1042를 넣고 A-1042를 넣지 않는다. 금액과 상태는 enum이나 명시 형식. 넓은 타입이 가장 흔한 월담이다.
MCP 도구도 같은 규율이 필요한가?
필요하다. inputSchema도 여분 키를 닫고 required를 다 적는다. subagent는 MCP를 이어받고 function은 이어받지 않는다. 자사 주문의 문은 주 Agent에 남긴다.
검증 실패가 session을 멈추게 하나?
같은 turn_id / call_id 쌍으로 tool_result를 되돌리면 된다. error를 분명하게 쓰면 모델이 인자를 바꿔 다시 부를 수 있다. 새 session을 재시도로 쓰지 마라.
결론
Agents API의 안정 JSON은 더 긴 지시가 아니다. 세 문이다. 도구 parameters, 호스트 재검증, 최종 카드의 별 Schema. 실행은 문을 통과한 뒤다.
A-1042가 어느 규칙에서 떨어지는지를 먼저 쓴다. 경로를 가리킬 수 있으면 데이터는 검증 가능하다. 모델은 바뀐다. 문을 먼저 안정시킨다.
더 읽기
- OpenAI Agents API 완전 해설 Session, Tool Calling, Schema의 이음
- Agents API JSON 데이터 구조 Agent / Tool Call / Tool Result / Handoff
- Agents API vs Responses API 누가 루프를 도나
- 오래 도는 Agents API Session, compact, Subagents
- AI에 JSON Schema가 필요한 이유 Schema / Function Calling / Structured Output
- JSONSort 로컬 도구상자 포맷, 검증, Diff
- 모든 글 JSON과 AI 개발 메모
변경 기록: 최초 게시