4장. 의도 분류기 - 구조화 출력
JSON 모드와 스키마 — 부탁하지 않고 강제한다
한 줄 요약
Gemini API에는 출력을 JSON으로 강제하는 설정이 있습니다. response_mime_type으로 "답은 JSON"이라고 정하고, response_schema로 "그 JSON은 이런 모양"이라고 정합니다. 이 설정은 프롬프트가 아니라 config= 안에 들어갑니다.
1. 스키마란
스키마(schema) 는 데이터가 가져야 할 모양의 명세입니다. 내용이 아니라 틀을 적습니다.
| 스키마가 정하는 것 | 예 |
|---|---|
| 어떤 칸(필드)이 있는가 | intent, urgency, order_id, summary |
| 각 칸의 타입은 무엇인가 | 문자열, 숫자, 참/거짓 |
| 칸에 들어갈 수 있는 값은 무엇인가 | urgency는 "낮음", "보통", "높음" 셋 중 하나 |
| 꼭 있어야 하는 칸은 무엇인가 | intent, urgency, summary |
세 번째 줄처럼 허용 값을 목록으로 못 박는 것을 열거형(enum) 이라고 합니다. 모델이 그 자리에서 지은 즉석 이름 대신 약속한 값만 오게 하는 장치가 이것입니다.
2. 설정 두 개
3장에서 config=에 system_instruction, temperature를 넣었습니다. 같은 자리에 두 줄을 더합니다.
config=types.GenerateContentConfig(
system_instruction=CLASSIFY_SYSTEM,
temperature=1.0,
response_mime_type="application/json", # 답은 JSON 이다
response_schema=IntentResult, # 그 JSON 은 이 모양이다
)
| 설정 | 뜻 |
|---|---|
response_mime_type="application/json" |
출력 형식을 JSON으로 정합니다. application/json은 "이 내용은 JSON"이라고 알리는 표준 표기입니다 |
response_schema=... |
JSON이 따라야 할 스키마를 넘깁니다. 이것을 쓰려면 위 설정도 함께 있어야 합니다 |
이 두 줄이 있으면 답은 다른 글이 섞이지 않은 JSON으로 오고, intent에는 스키마에 적은 값만 옵니다.
스키마를 넘겼으면 프롬프트에 같은 형식을 다시 적거나 JSON 예시를 붙이지 않습니다. 형식은 스키마가, 판단 기준은 프롬프트가 맡습니다.
3. 프롬프트로 부탁하는 것과 무엇이 다른가
| 프롬프트로 부탁 | 스키마로 강제 | |
|---|---|---|
| 적는 곳 | contents나 시스템 프롬프트 안의 글 |
config=의 설정값 |
| 형식 | 모델이 그때그때 정합니다 | API가 정해진 모양의 JSON으로 돌려줍니다 |
| 값 | 모델이 이름을 짓습니다 | 열거형에 적은 값만 옵니다 |
| 코드에서 | 받은 글을 다듬고 확인하는 코드가 필요합니다 | 바로 꺼내 쓸 수 있습니다 |
여기서 누가 무엇을 했는지 갈라 둡니다. 칸과 허용 값을 정한 것은 개발자이고, 그 칸에 무엇을 넣을지 고른 것은 모델입니다.
4. 스키마가 보장하지 않는 것
스키마는 모양을 보장합니다. 내용이 옳은지는 보장하지 않습니다.
intent에 일곱 라벨 중 하나가 오는 것은 보장됩니다. 그 라벨이 맞는 라벨인지는 별개입니다.order_id가 문자열이거나 비어 있는 것은 보장됩니다. 그 번호가 실제로 있는 주문인지는 별개입니다.
Gemini 공식 문서도 같은 말을 합니다. 출력은 문법상 올바른 JSON이지만, 값은 애플리케이션에서 검증하라고 안내합니다(2026년 10월 기준, https://ai.google.dev/gemini-api/docs/structured-output). 그래서 받은 데이터를 한 번 더 검사하는 층을 둡니다. 다음 절의 Pydantic이 그 일을 합니다.
5. 스키마를 무엇으로 쓰는가
스키마는 딕셔너리로 직접 쓸 수도 있습니다.
response_schema={
"type": "OBJECT",
"properties": {
"intent": {"type": "STRING", "enum": ["제품문의", "주문배송조회", "환불교환"]},
"urgency": {"type": "STRING", "enum": ["낮음", "보통", "높음"]},
},
"required": ["intent", "urgency"],
}
동작은 하지만 칸이 늘수록 중괄호가 겹겹이 쌓이고, 오타가 나도 실행 전에는 알 수 없습니다. 이 과정에서는 같은 내용을 파이썬 클래스로 씁니다.
핵심 정리
- 스키마는 데이터의 모양(칸, 타입, 허용 값, 필수 여부)을 적은 명세입니다.
response_mime_type="application/json"과response_schema를config=에 넣어 출력을 강제합니다.- 허용 값을 목록으로 고정하는 것이 열거형(enum) 입니다.
- 칸과 허용 값은 개발자가, 칸에 넣을 값은 모델이 정합니다.
- 스키마는 모양만 보장합니다. 값이 옳은지는 따로 확인해야 합니다.