이 글의 기술 정보는 2026년 4월 기준으로 검증되었습니다. AI·LLM 분야는 변화가 빠르므로, 6개월 이상 경과 시 공식 문서를 재확인하세요.
이런 분이 읽으면 좋습니다
요약: LLM 에서 구조화된 데이터를 받는 방법이 3가지다. Structured Output(제약 디코딩)은 스키마 준수 100%, JSON Mode 는 유효 JSON 보장이지만 스키마 미보장, Function Calling 은 도구 호출용. 2026년에는 Structured Output 이 모든 주요 제공자에서 지원되므로 대부분의 경우 이것이 정답이다.
이 글은 LLM API 를 호출해서 프로그래밍 가능한 데이터를 받아야 하는 백엔드 개발자를 위해 썼다.
3가지 방법 비교
| JSON Mode | Function Calling | Structured Output | |
|---|---|---|---|
| JSON 문법 보장 | 보장 | 보장 | 보장 |
| JSON Schema 준수 | 미보장 | 미보장 (strict 없으면) | 100% 보장 |
| 주 용도 | 간단한 JSON 추출 | 에이전트 도구 호출 | 스키마 기반 데이터 추출 |
| 오버헤드 | 거의 없음 | 약간 (도구 정의 토큰) | 거의 없음 (XGrammar) |
| OpenAI 지원 | GPT-3.5+ | GPT-4+ | GPT-4o, 4.1 (strict) |
| Anthropic 지원 | — | Tool use | Claude 3.5+ (2025.11~) |
| 오픈소스 지원 | vLLM, TGI | 제한적 | vLLM + XGrammar |
JSON Mode — 가장 간단하지만 불완전
response_format: { type: "json_object" } 를 설정하면 LLM 이 문법적으로 유효한 JSON 을 반환한다. 하지만 스키마를 지정할 수 없다. { "name": "홍길동" } 을 기대했는데 { "user": "홍길동", "extra": true } 가 나올 수 있다.
프로덕션에서 JSON Mode 만 쓰면 응답 파싱 코드에 방어 로직이 필요하고, 스키마 불일치로 인한 런타임 에러가 발생한다. 간단한 프로토타이핑에만 적합.
Function Calling — 에이전트 도구 호출
Function Calling 은 “LLM 이 외부 함수를 호출하겠다고 결정”하는 메커니즘이다. 데이터 추출이 아니라 행동 결정이 목적.
// OpenAI Function Calling
const response = await openai.chat.completions.create({
model: 'gpt-4.1',
messages: [{ role: 'user', content: '서울 날씨 알려줘' }],
tools: [{
type: 'function',
function: {
name: 'get_weather',
parameters: {
type: 'object',
properties: { city: { type: 'string' } },
required: ['city'],
},
},
}],
});
// → model decides to call get_weather({ city: "Seoul" }) strict: true 를 추가하면 스키마 준수가 보장되지만, 이건 사실상 Structured Output 과 같은 메커니즘이다.
Structured Output — 2026년 프로덕션 표준
제약 디코딩(Constrained Decoding): LLM 이 토큰을 생성할 때, JSON Schema 를 위반하는 토큰의 확률을 0 으로 만들어서 구조적으로 불가능하게 한다. “검증 후 재시도”가 아니라 “애초에 잘못된 토큰이 선택될 수 없는” 방식.
// OpenAI Structured Output
const response = await openai.chat.completions.create({
model: 'gpt-4.1',
messages: [{ role: 'user', content: '이 리뷰에서 감성과 키워드를 추출해' }],
response_format: {
type: 'json_schema',
json_schema: {
name: 'review_analysis',
strict: true,
schema: {
type: 'object',
properties: {
sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
keywords: { type: 'array', items: { type: 'string' } },
confidence: { type: 'number', minimum: 0, maximum: 1 },
},
required: ['sentiment', 'keywords', 'confidence'],
},
},
},
});
// → 100% 스키마 준수 보장 XGrammar, llguidance 같은 엔진이 제약 디코딩의 성능 오버헤드를 거의 0 으로 줄였다. 2026년 기준 프로덕션에서 Structured Output 을 안 쓸 이유가 없다.
피해야 할 상황
다음에 읽을 글
- RAG 파이프라인 설계: 청킹부터 검색 품질 모니터링까지 — 구조화 출력을 RAG 파이프라인에 통합하는 아키텍처
- 프로덕션 AI 서비스의 프롬프트 버전 관리 — 스키마가 바뀔 때 프롬프트를 어떻게 관리할 것인가
- REST vs GraphQL vs tRPC: 2026 선택 가이드 — 구조화 출력을 감싸는 API 레이어 선택