Ch 6. 구조화 출력¶
이 챕터에서 배우는 것
- 자유 텍스트 응답이 파이프라인의 적인 이유
- 세 가지 구조화 출력 방법 — 프롬프트 힌트 / Tool-use 스키마 / Native JSON mode
- Pydantic 으로 검증 + 실패 시 자동 재프롬프트
- Nested · Optional · Enum · List 등 실전 스키마 패턴
- 큰따옴표 이스케이프 · 날짜·통화 포맷 · 필드 누락 — 자주 터지는 파싱 지옥
전제
Ch 5 프롬프트 + CoT 에서 "JSON 힌트 프롬프트"까지 돌려본 상태.
1. 개념 — 왜 구조화 출력이 필요한가¶
앞 챕터까지는 모델이 자유 텍스트로 답했습니다. 이게 파이프라인에서 문제가 됩니다.
# ❌ 자유 텍스트를 후처리하는 코드
text = response.content[0].text # "주문번호는 A-123, 수량 2개, 주소 서울 강남구입니다."
# ... 정규식? 문자열 파싱? 다음 단계에 이걸 어떻게 넘기지?
# ✅ 구조화된 JSON
data = {"order_id": "A-123", "quantity": 2, "address": "서울 강남구"}
# 바로 DB에 저장 · API에 전달 · 조건 분기 가능
LLM이 말을 잘하는 것과 프로그램이 쓰기 좋은 형식을 출력하는 것은 다른 능력. 이 챕터는 후자를 확실히 확보하는 법.
2. 왜 필요한가 — 파이프라인 관점¶
Part 1 Ch 3의 8블록 구조를 다시 보면, 이해 → 검색 → 생성 → 검증 → 저장 모든 단계가 객체 단위의 데이터를 주고받습니다. 자유 텍스트면:
- 이해 블록: 의도·엔티티를 추출했는데 format이 흔들려 파싱 실패
- 검증 블록: 스키마 체크 불가능
- 저장 블록: DB에 넣을 컬럼을 어떻게 잡나
- 툴 호출 (Ch 8): 파라미터 추출 실패 → 툴 실행 불가
구조화 출력이 없으면 이후 모든 블록의 안정성이 낮아진다.
3. 어디에 쓰이는가¶
| 유즈케이스 | 출력 스키마 |
|---|---|
| 주문 정보 추출 | {item, quantity, address, request_date} |
| 이메일 분류 + 우선순위 | {category: "refund"\|"shipping"\|..., priority: 1-5} |
| 문서에서 엔티티 | {people: [...], dates: [...], amounts: [...]} |
| 사용자 의도 분석 | {intent, confidence, needs_human} |
| 툴 호출 파라미터 (Ch 8) | 툴이 정의한 파라미터 스키마 |
4. 최소 예제 — Pydantic 모델로 추출¶
- Pydantic이 JSON을 파싱하고 타입까지 검증.
quantity가 "two" 같은 문자열로 오면ValidationError.
이게 기본형. 하지만 LLM이 가끔 말을 섞어 반환하면 ("여기 JSON입니다: {...}") 파싱 실패. 그걸 막는 게 §5.
5. 실전 튜토리얼¶
5.1 세 가지 방법 비교¶
| 방법 | 구현 | 적중률 | 권장 시점 |
|---|---|---|---|
| 프롬프트 힌트 | 시스템 프롬프트에 스키마·예시 | 70~90% | 초기 프로토타입 |
| Tool-use 스키마 | Anthropic tools 파라미터 |
95~99% | 프로덕션 권장 |
| Native JSON mode | OpenAI response_format={json_schema} |
~100% | OpenAI 쓸 때 |
실전은 프롬프트 힌트부터 → 실패율이 크면 tool-use로 올림 순서.
5.2 Tool-use로 구조화 출력 (Anthropic 방식)¶
Anthropic의 tool_use 기능은 원래 "툴 호출"을 위한 것이지만, 스키마를 강제하는 용도로도 쓰입니다. 이때는 실제 툴 실행 없이 구조화된 JSON 입력을 끌어내는 용도.
- JSON Schema 표준.
type·properties·required필수. tool_choice로 반드시 이 툴을 쓰게 강제. 이렇게 하면 모델이 거의 100% 스키마를 따름.
5.3 Pydantic 검증 + 자동 재프롬프트¶
프롬프트 힌트 방식에서 가장 자주 깨지는 건 JSON 앞뒤에 말이 섞이는 것. 이를 막는 3단계:
핵심 패턴:
- 원본에서 JSON 블록만 추출 (앞뒤 말 섞임 방어)
- Pydantic으로 검증 (타입·필수 필드·제약)
- 실패 시 에러 메시지 포함해 재질의 — 모델이 스스로 수정
Tool-use 쓰면 §5.3의 1·2 단계가 거의 불필요
Tool-use 로 가면 JSON 블록 추출 문제가 사라짐 (Anthropic SDK가 이미 파싱). 그래도 Pydantic 검증은 유지 권장 — 모델이 필수 필드를 빠뜨리는 경우가 있음.
5.4 실전 스키마 패턴¶
Field(..., pattern=...)— 정규식 제약.
주의: LLM에게 이 스키마 전부를 전달할 땐 model.model_json_schema() 로 JSON Schema 를 뽑아 프롬프트나 tool_use에 주면 됩니다.
6. 자주 깨지는 포인트¶
실수 1. 큰따옴표 이스케이프 누락
모델이 텍스트 안에 큰따옴표가 있으면 "content": "그가 "안녕"이라 말했다" 같은 잘못된 JSON을 만들기도. json.JSONDecodeError.
대응: 시스템 프롬프트에 "쌍따옴표는 반드시 \\\" 로 이스케이프" 명시. 또는 tool-use 방식 사용 (SDK가 처리).
실수 2. 날짜·통화 포맷 혼란
"ship_date": "다음주 월요일" 이나 "price": "₩15,000" 같은 자연어가 섞여 들어옴.
대응: 스키마에 예시값 명시 ("예: 2026-04-18"), Pydantic Field description 적극 활용, 실패 시 §5.3 재프롬프트.
실수 3. 필수 필드 누락
모델이 가끔 어떤 필드를 빼먹음 (특히 Optional과 Required가 섞인 스키마).
대응: Pydantic 에서 ... 로 명확히 Required 지정, tool-use의 required 배열 명시, 검증 실패 시 재프롬프트에 어느 필드가 빠졌는지 에러 메시지에 포함.
실수 4. 스키마가 너무 깊고 복잡
5단계 이상 nested 스키마는 모델도 사람도 헷갈림. 재시도해도 개선 안 됨.
대응: 스키마를 2~3단계로 flat 하게 설계. 복잡한 구조는 여러 번 호출로 쪼개기 (각 호출당 하나의 작은 스키마).
실수 5. 재시도 무한 루프
검증 실패할 때마다 재질의. 키 요금 폭주.
대응: 재시도 상한 2~3회. 초과 시 fallback 경로 (규칙 기반 파서 · 기본값 · 사람 에스컬레이션).
7. 운영 시 체크할 점¶
- Pydantic 모델을 단일 모듈에 집중 (
schemas.py) — 파이프라인 전체가 공유 - tool-use 방식 기본 — 프롬프트 힌트만 쓰는 구간 있으면 마이그레이션 계획
- 검증 실패율 로깅 — 5% 이상이면 스키마/프롬프트 재설계 신호
- 재시도 상한 2~3회 + fallback 경로 필수
- 스키마 변경 시 하위 호환 고려 — Pydantic validator로 구버전 받아들이기
- LLM 응답 샘플을 테스트 fixture 로 저장 (파서·검증 회귀 테스트용)
- 민감 정보 필드 (주민번호·카드번호 등)는 스키마 레벨에서 거부 (Part 6 Ch 28)
8. 확인 문제¶
- §4의
Order스키마에color: str필드를 추가하고, 프롬프트도 업데이트해 성공적으로 추출되는지 확인 - 일부러 잘못된 입력 (
"그냥 뭐든 보내주세요") 으로 호출해 PydanticValidationError가 어떻게 뜨는지 기록 - §5.2 tool-use 방식으로 Ch 5 few-shot 감정 분류 예제를 적중률 100% 로 만들기
- §5.3 재시도 로직에 일부러 잘못된 스키마 힌트를 줘 2회 재시도 후
None반환 확인 - §5.4 nested Address 를 포함한 Order 를 추출. 모델이
address.city를 빠뜨렸을 때 어느 메시지가 뜨는지
9. 원전 · 더 읽을 거리¶
- Anthropic Tool Use: docs.anthropic.com/tool-use —
tools·tool_choice· JSON Schema 규격 - OpenAI Structured Outputs: platform.openai.com/docs/guides/structured-outputs
- Pydantic v2 공식: docs.pydantic.dev
- JSON Schema 스펙: json-schema.org
다음 챕터 → Ch 7. 스트리밍과 UX
지금까지 한 번에 전체 응답을 받았습니다. 사용자 체감 속도를 올리는 토큰 단위 스트리밍 으로.