구조적 출력 및 제약된 생성 (Structured Output & Constrained Generation)

LLM이 비정형 텍스트 대신 JSON, XML, 또는 특정 프로그래밍 언어와 같이 사전에 정의된 구조를 가진 데이터를 생성하도록 제어하는 기술입니다. 이는 LLM을 API, 데이터베이스, 또는 소프트웨어 워크플로우에 안정적으로 통합하기 위한 핵심 기술입니다.

1. 개요 (Overview)

LLM은 기본적으로 다음 토큰을 확률적으로 예측하는 생성 모델이므로, 단순히 “JSON으로 답해줘”라고 요청하더라도 형식이 깨지거나(Hallucinated Syntax) 필요한 필드가 누락될 수 있습니다. 이를 해결하기 위해 프롬프트 수준부터 엔진 수준까지 다양한 제어 기법이 사용됩니다.

필요성

  • 시스템 연동: API 응답, DB 쿼리 생성 등 기계가 읽을 수 있는 데이터 필요
  • 데이터 추출: 긴 본문에서 특정 정보(이름, 날짜, 가격 등)를 정형화된 틀로 추출
  • 신뢰성 보장: 파싱 에러(Parsing Error)를 방지하여 전체 시스템의 가동 중단 방지

2. 구현 방식 (Implementation Levels)

2.1 프롬프트 기반 (Prompt-based)

가장 단순한 방법으로, 시스템 메시지나 Few-shot 예시를 통해 특정 형식을 유도합니다.

  • 특징: 추가 인프라가 필요 없으나, 복잡한 스키마에서 실패 확률이 높음
  • : Markdown Code Block 사용, XML 태그 활용, 명확한 필드 설명 제공

2.2 엔진 수준 제약 (Inference-level Constraints)

추론 엔진(vLLM, sglang, llama.cpp 등)에서 다음 토큰을 선택할 때, 문법에 맞지 않는 토큰의 확률을 0으로 만들어 생성을 원천적으로 차단합니다.

  • FSM (Finite State Machine): JSON 스키마나 정규표현식을 유한 상태 머신으로 변환하여 토큰 단위로 마스킹
  • Grammar (CFG): BNF와 같은 문맥 자유 문법을 사용하여 복잡한 프로그래밍 언어 구조 강제
  • 특징: 100% 문법 준수를 보장하며, 불필요한 토큰 생성을 막아 속도가 향상되기도 함

2.3 API 기능 (Managed Features)

OpenAI, Anthropic 등 주요 모델 공급자가 제공하는 전용 기능입니다.

  • JSON Mode: 출력이 유효한 JSON임을 보장 (단, 스키마 준수는 보장하지 않을 수 있음)
  • Structured Outputs (JSON Schema): 제공된 JSON Schema를 모델이 완벽하게 따르도록 보장 (OpenAI 기준 100% 신뢰도)

3. 주요 도구 및 라이브러리 (Key Tools)

Instructor (Pydantic 기반)

Python의 Pydantic 라이브러리를 활용하여 가장 직관적으로 구조적 출력을 구현합니다.

  • 장점: 모델 독립적 (OpenAI, Anthropic, Gemini, Local LLM 지원), 타입 힌트와 자동 완성 지원
  • 작동 방식: 프롬프트에 스키마 자동 주입 + 실패 시 자동 재시도(Retry)

Outlines (FSM 기반)

로컬 모델이나 vLLM 등에서 가장 강력한 제약 기능을 제공합니다.

  • 장점: 토큰 레벨에서 마스킹을 수행하므로 형식이 절대 깨지지 않음
  • 작동 방식: 정규표현식이나 JSON Schema를 FSM으로 컴파일하여 추론 프로세스에 개입

PydanticAI

에이전트 개발 프레임워크 내에 구조적 출력을 기본 내장하고 있습니다. (PydanticAI 상세 보기)

4. 비교 및 선택 가이드

방식 신뢰도 유연성 구현 난이도 주요 대상
Prompting 낮음 매우 높음 매우 낮음 간단한 챗봇, 요약
JSON Mode 보통 높음 낮음 범용 API 연동
Instructor 높음 높음 보통 프로덕션 데이터 추출
Outlines 최고 보통 높음 로컬 모델 기반 정밀 제어

5. 베스트 프랙티스 (Best Practices)

  1. 스키마 단순화: 모델이 한 번에 이해하기 힘든 너무 깊은 중첩 구조는 피하십시오.
  2. 필드 설명 추가: Pydantic의 Field(description=...) 등을 통해 각 필드의 의미를 모델에게 상세히 설명하십시오.
  3. Chain-of-Thought 결합: 복잡한 추출 작업은 “생각 과정”을 먼저 텍스트로 내뱉게 한 뒤, 마지막에 JSON 구조를 채우도록 설계하십시오. (예: thinking 필드 추가)
  4. 검증 및 재시도: 형식이 맞더라도 데이터 내용이 틀릴 수 있으므로, 런타임 검증과 연동된 자동 재시도 로직을 구축하십시오.

This site uses Just the Docs, a documentation theme for Jekyll.