AI · LLM

LLM 구조화 출력: JSON 모드 vs 함수 호출 vs 제약 디코딩

LLM 에서 신뢰할 수 있는 JSON 을 받는 3가지 방법의 트레이드오프를 비교하고, 2026년 프로덕션에서 어떤 방식을 쓸지 판단 기준을 정리한다.

이 글의 기술 정보는 2026년 4월 기준으로 검증되었습니다. AI·LLM 분야는 변화가 빠르므로, 6개월 이상 경과 시 공식 문서를 재확인하세요.

이런 분이 읽으면 좋습니다

요약: LLM 에서 구조화된 데이터를 받는 방법이 3가지다. Structured Output(제약 디코딩)은 스키마 준수 100%, JSON Mode 는 유효 JSON 보장이지만 스키마 미보장, Function Calling 은 도구 호출용. 2026년에는 Structured Output 이 모든 주요 제공자에서 지원되므로 대부분의 경우 이것이 정답이다.

이 글은 LLM API 를 호출해서 프로그래밍 가능한 데이터를 받아야 하는 백엔드 개발자를 위해 썼다.

3가지 방법 비교

JSON ModeFunction CallingStructured Output
JSON 문법 보장 보장보장보장
JSON Schema 준수 미보장미보장 (strict 없으면)100% 보장
주 용도 간단한 JSON 추출에이전트 도구 호출스키마 기반 데이터 추출
오버헤드 거의 없음약간 (도구 정의 토큰)거의 없음 (XGrammar)
OpenAI 지원 GPT-3.5+GPT-4+GPT-4o, 4.1 (strict)
Anthropic 지원 Tool useClaude 3.5+ (2025.11~)
오픈소스 지원 vLLM, TGI제한적vLLM + XGrammar
2026년 4월 기준. Structured Output 이 사용 가능하면 항상 이것을 선택한다.

JSON Mode — 가장 간단하지만 불완전

response_format: { type: "json_object" } 를 설정하면 LLM 이 문법적으로 유효한 JSON 을 반환한다. 하지만 스키마를 지정할 수 없다. { "name": "홍길동" } 을 기대했는데 { "user": "홍길동", "extra": true } 가 나올 수 있다.

프로덕션에서 JSON Mode 만 쓰면 응답 파싱 코드에 방어 로직이 필요하고, 스키마 불일치로 인한 런타임 에러가 발생한다. 간단한 프로토타이핑에만 적합.

Function Calling — 에이전트 도구 호출

Function Calling 은 “LLM 이 외부 함수를 호출하겠다고 결정”하는 메커니즘이다. 데이터 추출이 아니라 행동 결정이 목적.

function-call.ts TypeScript
// 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 으로 만들어서 구조적으로 불가능하게 한다. “검증 후 재시도”가 아니라 “애초에 잘못된 토큰이 선택될 수 없는” 방식.

structured-output.ts TypeScript
// 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 을 안 쓸 이유가 없다.

피해야 할 상황

다음에 읽을 글