AI Agent가 JSON Schema를 필요로 하기 시작한 이유: Tool Calling에서 구조화 워크플로까지
2024년 이전의 많은 「Agent」는 prompt 한 줄과 함수 두세 개였습니다. 2026년에는 그걸로 부족합니다. Function Calling은 파라미터를 기술하고, MCP는 도구를 등록하고, Structured Outputs는 반환값을 제약하고, A2A는 능력을 협상하며, Agents SDK는 handoff 객체로 라우팅합니다. 각 층은 따로 진화했지만, 결국 같은 계약 언어로 모입니다——JSON Schema. 이 글은 그것이 「문서 속 검증 문법」에서 Agent의 런타임이 된 이유와, 단일 Tool Calling에서 다단계 워크플로로 갈 때 Schema를 어디에 둘지를 정리합니다.
읽기 전 요약
| 단계 | Schema가 없을 때 | Schema가 있을 때 |
|---|---|---|
| 단일 Tool Calling | 파라미터는 문자열, 타입은 운에 맡기고, 필드가 하나 더 있어도 통과 | parameters / inputSchema가 호출 전에 걸러 냄 |
| 다단계 Agent | 하류는 산문을 파싱하고, handoff는 「billing이 나왔다」에 의존 | handoff 객체에 output_type이 있어 라우팅을 테스트할 수 있음 |
| 프로토콜 간 재사용 | Function Calling, MCP, A2A를 각각 써서 갈수록 어긋남 | Git에 Schema 하나, 세 어댑터로 내보내기 |
결론부터: JSON Schema는 「모델이 읽는 문서」가 아니라, Agent 호스트가 매 단계 실행 전·인수인계·평가마다 돌리는 검증기입니다.
왜 「시작」한 필요인가, 원래부터 필요하지 않았나?
초기 Tool Calling이 버틴 이유는 체인이 짧았기 때문입니다. 모델이 함수 이름과 파라미터를 내고, 호스트가 실행한 뒤 결과를 대화에 넣습니다. 틀리면 재시도하고, 사용자가 봅니다. Schema는 기껏해야 README에 있었고, 「있으면 좋은」 수준이었습니다.
2025–2026년 체인이 길어졌습니다. 티켓 Agent는 먼저 분류하고, 주문을 조회하고, 환불 또는 상담원 이관을 결정한 뒤, 객체를 다른 Agent에 넘깁니다. 중간 한 홉이 「JSON처럼 보이기만」 하면, 이후 단계는 오류를 사실로 받습니다. 이때 Schema는 문서가 아니라 런타임 관문이 됩니다. 통과하지 못하면 다음으로 가지 않습니다.
또 다른 압력은 프로토콜 층입니다. MCP Tool Schema vs Function Calling에서 썼듯, 벤더 API는 parameters를, MCP는 inputSchema를 씁니다. A2A Extensions는 능력을 Agent Card에 넣습니다. 세 프로토콜은 런타임을 공유하지 않지만 JSON Schema 부분집합은 모두 인정합니다. 처음에 Schema를 고르지 않으면 세 곳에서 「거의 같은」 정의를 유지하다가, 셋째 주에 order_id가 어떤 곳은 string, 어떤 곳은 number인 걸 발견합니다.
DevDay 2026 예측은 같은 일을 더 직설적으로 말합니다. Structured Outputs, Function Calling, Agent 런타임이 하나의 JSON 파이프로 수렴하고 있습니다. Schema는 그 파이프의 구경입니다. 구경이 정해지지 않으면 뒤에 어떤 프로토콜을 붙여도 샙니다.
Tool Calling은 이미 「구조」가 있어 보이는데, 빈틈은 어디인가?
Function Calling의 tools[] 안에는 원래 Schema와 비슷한 parameters가 있습니다. 그래서 많은 팀이 「이미 구조화했다」고 생각합니다. 프로덕션에서 실제로 터지는 것은 대개 아래 네 가지입니다.
첫째, arguments는 여전히 문자열입니다. 모델이 반환하는 것은:
{
"tool_calls": [{
"id": "call_8f2a",
"type": "function",
"function": {
"name": "create_refund",
"arguments": "{\"order_id\":\"A-1042\",\"amount\":\"99.00\",\"reason\":\"late\"}"
}
}]
}
호스트는 JSON.parse를 한 번 더 해야 합니다. amount가 문자열인지 숫자인지, reason이 열거에 있는지, 여분의 note가 회계 시스템에 들어가도 되는지——parameters를 호스트 측에서 강제하지 않으면 전부 「오늘 모델 컨디션」에 달립니다. Schema를 썼다고 자동으로 적용되지 않습니다. strict: true는 모델 측만 제약하고, 호스트는 여전히 직접 검증해야 합니다.
둘째, 도구 결과에 Schema가 없습니다. role: tool은 대부분 자유 문자열입니다. 다음 단계 모델이 이 글을 다시 「이해」합니다. 조회 성공, 재고 0, 권한 부족——세 경우의 형태가 다르면 다단계 워크플로는 세 번째 홉에서 잘못된 분기로 갈라집니다.
셋째, 타입이 넓어 걸러 내는 힘이 없습니다. type: string만 있는 priority는 모델이 "urgent!!!"를 낼 수 있습니다. enum, required, additionalProperties: false가 없는 Schema는 주석에 가깝습니다.
넷째, 한 번의 성공이 워크플로 실패를 가립니다. 첫 단계 lookup_order가 status: "ok"를 하나 더 내고, 둘째 단계 환불 Agent가 status를 주문 상태로 읽습니다. 로컬에서 정상 경로 한 줄은 안 보이고, 회귀 세트에서야 터집니다. Schema의 가치는 여기 있습니다. 「이 홉이 다음 홉에 넘길 수 있는 객체」를 대화 기록이 아니라 단언 가능한 테스트로 만듭니다.
이런 중첩 JSON을 디버그할 때는 먼저 로컬에서 포맷하고 구문을 검사한 뒤, 지난주 돌아간 정의와 Diff 하세요. 사용자 데이터나 비밀이 든 tool 응답을 공개 JSON 사이트에 붙이지 마세요.
JSON Schema는 Agent 안에서 사실 네 층 역할을 한다
Schema를 「도구 파라미터 설명서」로만 보면 2026년에 실제로 자라는 세 층을 놓칩니다. 전체 그림은 이렇습니다.
- 도구 입력. Function Calling의
parameters, MCP의inputSchema. 모델이 「무엇을 요청할 수 있는지」를 정합니다. - 도구 출력. 조회, 쓰기, 외부 API의 반환 객체. 다음 홉이 「무엇을 믿을 수 있는지」를 정합니다. 지금 가장 자주 빠지는 층입니다.
- Agent 인수인계(handoff). 분류 결과, 의도, 신뢰도, 누구에게 넘길지. Agents SDK에서 이는 라우팅 근거이지 채팅 요약이 아닙니다.
- 워크플로 상태와 평가. 체크포인트, trace, eval fixture. 긴 작업은 대화 기록이 아니라 JSON에서 복구해야 합니다.
입력 Schema 예(환불 도구):
{
"$id": "https://example.com/schemas/tools/create_refund.json",
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^A-[0-9]{4,}$" },
"amount": { "type": "number", "exclusiveMinimum": 0 },
"reason": { "type": "string", "enum": ["late", "damaged", "duplicate", "other"] }
},
"required": ["order_id", "amount", "reason"],
"additionalProperties": false
}
handoff Schema 예(분류 → 빌링):
{
"$id": "https://example.com/schemas/handoffs/triage_to_billing.json",
"type": "object",
"properties": {
"intent": { "type": "string", "enum": ["refund", "exchange", "human"] },
"order_id": { "type": "string" },
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
"from": { "const": "triage" },
"to": { "const": "billing_agent" }
},
"required": ["intent", "order_id", "confidence", "from", "to"],
"additionalProperties": false
}
두 파일의 공통점이 차이보다 중요합니다. 둘 다 객체이고, 열거가 있고, 여분 필드를 금하며, Git에 넣을 수 있고, CI에서 ajv(또는 동등 라이브러리)로 돌릴 수 있습니다. 모델 스냅샷이 바뀌고 프로토콜이 MCP든 Function Calling이든, 검증기는 다시 쓰지 않습니다. 키워드 작성은 JSON Schema 튜토리얼을 보세요.
단일 호출에서 구조화 워크플로까지, Schema가 서는 문은 어디인가
단일 Tool Calling에는 문이 하나뿐입니다. 파라미터가 유효한가. 구조화 Agent 워크플로에는 적어도 네 개가 있습니다.
문 1: 도구를 고르기 전. 목록이 열 개를 넘으면 전체 Schema를 한 요청에 넣는 것은 비싸고 오선택하기 쉽습니다. 검색 후 호출할 때, 검색 결과 자체도 Schema가 있는 짧은 목록이어야 하며, 모델이 생성한 도구 소개 글이 아니어야 합니다.
문 2: 실행 전. parse → validate → execute. validate가 실패하면 구조화 오류(필드 누락, 타입 오류, 열거 밖)를 반환하고, 원본 문자열을 다음 홉에 던지지 마세요. 이 단계는 prompt 주입식 여분 키도 막습니다.
문 3: 인수인계 전. triage는 handoff Schema에 맞는 객체를 내야 billing이 시작됩니다. 라우팅 조건은 intent === "refund" && confidence >= 0.8로 쓰고, 「답에 환불이 나왔다」가 아닙니다.
문 4: 복구와 평가. 긴 작업은 체크포인트를 유효 JSON으로 씁니다:
{
"run_id": "run_20260903_014",
"step": "await_refund_ack",
"state": {
"order_id": "A-1042",
"intent": "refund",
"amount": 99.0
},
"schema": "https://example.com/schemas/state/refund_flow.json"
}
평가 세트도 같은 종류의 객체입니다. 입력을 주고, 출력이 Schema를 통과하며 핵심 필드가 같은지 단언합니다. Agent가 「멍청해졌다」면 먼저 이번 주와 지난주 Schema·fixture를 Diff한 뒤 모델을 의심하세요. 사고 상당수는 required가 하나 늘었거나 enum 값이 하나 빠진 것입니다.
한 Schema를 Function Calling, MCP, A2A에 어떻게 먹이나
프로토콜 층을 각각 쓰지 마세요. 권장 방향은 한 규격 파일, 세 투영입니다.
| 프로토콜 | Schema 위치 | 같은 파일에서 내보내는 법 |
|---|---|---|
| Function Calling | function.parameters |
type/properties/required를 복사하고 strict를 켬 |
| MCP | inputSchema |
같은 객체를 tools/list의 일부로 |
| Structured Outputs | text.format.json_schema |
handoff / 최종 답변에 같은 객체 정의 |
| A2A | Agent Card / Extension metadata | 대외 능력 선언이 같은 $id를 참조 |
투영할 때 부분집합 차이를 보세요. 벤더 strict 모드는 모든 property를 required에 넣고, 일부 oneOf / $ref를 막는 경우가 많습니다. 규격 파일은 더 완전할 수 있고, 내보내기가 대상에 맞게 자르며, CI에서 「규격 vs 투영」 구조 Diff를 한 번 돌려 한쪽만 손대지 않게 합니다.
MCP는 도구 공급, Function Calling은 모델이 호출 의도를 표현하는 방식, A2A는 Agent 사이 발견과 협상을 맡습니다. Schema는 이 세 층을 대체하지 않고, 세 층이 공유하는 필드 사전입니다. 앞 두 글의 결론과 같고, 「사전」을 개념에서 저장소 파일로 내릴 뿐입니다.
적용: JSON Schema를 단일 진실 원천으로
바로 할 수 있고, 어떤 발표회에도 의존하지 않는 일:
- 저장소에
schemas/tools/,schemas/handoffs/,schemas/state/를 만듭니다. 파일마다 안정적인$id와 버전이 있습니다. - 스크립트로 Function Calling / MCP / Structured Outputs 세 어댑터를 내보내고, 어댑터 파일에서 필드를 손대지 않습니다.
- CI에서 ajv(또는 동등 라이브러리)로 검증합니다. 예시 payload, 과거 fixture, 온라인 샘플(비식별화 후)이 현재 Schema를 통과해야 합니다.
- 새 도구는 기본으로
additionalProperties: false와 명시적enum. 개방 확장이 필요하면metadata객체를 따로 열고, 루트 객체를 넓히지 마세요. - 도구가 열 개를 넘으면 라우팅이나 검색을 넣고, 목록 전체를 한 요청에 넣지 마세요.
- 호스트는
arguments를 문자열 또는 객체로 받아, 벤더가 타입을 조인 뒤 사이트 전체가 죽지 않게 합니다. - 비밀이나 사용자 데이터가 든 payload는 브라우저 로컬에서만: 포맷, Diff, 업로드 없음.
디렉터리는 얇아도 됩니다. 중요한 것은 먼저 파일이 있고, 그다음 prompt를 쓰는 것입니다. prompt의 「JSON을 반환하세요」는 CI에서 실패하지 않습니다. Schema는 실패할 수 있습니다.
흔한 오해
- Schema를 시스템 프롬프트에 넣으면 끝난다고 생각하기. 모델 측 제약과 호스트 측 검증은 다릅니다. 호스트 검증이 없으면
strict를 끄거나 모델 스냅샷을 바꾼 뒤 계약이 사라집니다. - 입력만 검증하고 출력과 handoff는 검증하지 않기. 다단계 Agent 사고는 「이전 단계가 예상 밖 형태를 냈다」에서 더 자주 납니다.
- 프로토콜마다 「거의 같은」 Schema를 손으로 쓰기. 셋째 주면 갈라집니다. 복사하지 말고 내보내세요.
- 지나치게 넓은
type: object로 설계를 피하기. 개방 객체는 문이 없는 것과 같습니다. 정말 확장하려면 버전이나 명시적metadata를 쓰세요. - Schema를 모델 학습 코퍼스로 보기. 우선 검증기와 테스트가 돌리는 것입니다. 설명을 분명히 쓰면 도구 선택에 도움이 되지만,
enum과required를 대체하지 못합니다. - 시각 오케스트레이션에서 필드를 바꾸고 Git에 되돌리지 않기. 캔버스 노드는 진실 원천이 아닙니다. 먼저 Schema를 내보내고, 캔버스가 파일을 읽게 하세요.
FAQ
Schema 없이 Tool Calling을 올릴 수 있나?
프로토타입은 가능합니다. 도구가 고정이고 단계가 셋 미만이며 실패를 사람이 볼 수 있으면 문자열 파라미터로 충분한 경우가 많습니다. 분기, 자동 재시도, 두 번째 Agent가 나오면 Schema 없는 오류는 조용히 퍼집니다.
JSON Schema가 Structured Outputs나 MCP로 대체되나?
아닙니다. 그것들은 Schema를 소비하는 층이지 다른 타입 시스템이 아닙니다. 2026년 추세는 더 많은 프로토콜이 같은 Schema를 참조하는 것이지, 새 필드 언어를 발명하는 것이 아닙니다.
draft-07인가 2020-12인가?
검증 라이브러리와 벤더 부분집합을 따르세요. Agent 장면에서 실제로 쓰는 것은 type, properties, required, enum, additionalProperties입니다. 최신 draft를 쫓기보다 CI와 모델 API 사이에서 맞출 수 있는 부분집합을 고르는 것이 중요합니다.
사내 내부 API에도 MCP와 A2A가 필요하나?
꼭 그렇지는 않습니다. 내부 폐루프는 Function Calling + Schema면 됩니다. MCP / A2A를 남겨 두는 가치는, 같은 Schema를 저장소에 쓴 뒤 나중에 프로토콜을 꽂을 때 내보내기만 추가하면 되고 필드를 다시 발명하지 않는다는 점입니다.
실패한 tool / handoff JSON을 어떻게 디버그하나?
브라우저 로컬에서 포맷하고 Schema와 대조해 빠진 required를 본 뒤, 이전 버전과 Diff 하세요. JSONSort는 데이터를 업로드하지 않습니다. 비밀이 든 응답을 공개 사이트에 붙이지 마세요.
결론
AI Agent가 JSON Schema를 「시작」한 이유는 모델이 갑자기 자연어를 못 읽어서가 아니라, 워크플로가 길어지고 프로토콜이 늘었으며 오류를 호스트 측에서 막아야 하기 때문입니다. Tool Calling은 호출 의도를, Structured Outputs는 최종 객체를, MCP와 A2A는 공급과 협상을 줍니다. 이 층들을 붙이는 것은 저장소의 검증·Diff·내보내기가 가능한 Schema 파일입니다.
오늘부터 더 긴 prompt를 먼저 쓰기보다 schemas/tools/create_refund.json을 먼저 쓰세요. 모델은 바뀌고 프로토콜은 바뀝니다. 구경은 먼저 안정되어야 합니다.
더 읽기
- JSON Schema란? 사용법과 튜토리얼 키워드, required와 additionalProperties
- MCP Tool Schema vs Function Calling 도구 JSON의 프로토콜 경계
- A2A Extensions와 JSON 프로토콜 멀티 Agent 상호운용의 세 번째 층
- OpenAI DevDay 2026 예측 세 층이 하나의 JSON 파이프로 모이는 법
- JSONSort 로컬 도구함 포맷, 구문 검증, Diff
- 모든 글 JSON과 AI 개발 노트
변경 기록: 초고 게시