AI API가 엄격하고 검증된 JSON 형식으로만 응답하도록 강제하는 방법을 배우세요
Source: Dev.to
번역할 텍스트가 제공되지 않았습니다. 번역이 필요한 전체 내용을 알려주시면 한국어로 번역해 드리겠습니다.
Source: …
구조화된 출력 : AI에게 JSON을 말하게 하세요
이미 AI 응답을 애플리케이션(웹 또는 모바일)에 직접 통합하려고 시도해 본 적이 있다면, 서버 로그에서 다음과 같은 오류를 보았을 것입니다:
SyntaxError: Unexpected token 'V', "Voici le J"... is not valid JSON
AI에게 사용자의 이름과 나이를 포함한 JSON 객체를 반환하도록 요청했지만, AI는 다음과 같이 답했습니다:
« Voici le JSON que vous avez demandé :
json { "nom": "Paul", "age": 32 }
J’espère que cela vous aide ! »
백엔드가 JSON.parse() 로 이 문장을 파싱하려다 실패했습니다.
개발자는 95 % 정확한 응답만으로는 충분하지 않습니다; 결정론적이어야 합니다. 이를 얻는 방법은 다음과 같습니다.
1. 프롬프트의 한계
처음에는 프롬프트에 대문자 지시문을 추가합니다:
"TU DOIS RÉPONDRE UNIQUEMENT EN JSON. N'AJOUTE AUCUN TEXTE AVANT OU APRÈS."
대부분의 경우 작동하지만, 특수 상황에서는 AI가 역할을 벗어나 왜 답변할 수 없는지 설명하기도 하여 코드를 깨뜨립니다.
출력 형식은 단순 텍스트 지시가 아니라 API 수준의 기술적 제약이어야 합니다.
2. Structured Outputs와 Pydantic
2024년 중반부터 주요 공급업체(OpenAI, Anthropic 등)는 Structured Outputs를 제공합니다.
데이터 스키마를 API 요청에 직접 전달하면, 모델은 해당 스키마에 맞는 문자만 생성하도록 스스로 제한됩니다.
Python에서 표준 도구는 Pydantic이며, 데이터 검증 라이브러리입니다.
3. 실전: 절대 크래시하지 않는 코드
불안한 프롬프트는 잊어버리세요. 아래 예시는 OpenAI API를 사용해 텍스트에서 정보를 100 % 결정론적으로 추출하는 완전한 코드입니다. app.py에 저장하고 uv run app.py 로 실행하면(필요한 의존성이 자동 설치됩니다) 됩니다.
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "openai",
# "pydantic",
# ]
# ///
import os
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="sk-...",
)
# 1. 데이터 계약(스키마) 정의
class ProfilUtilisateur(BaseModel):
nom: str
age: int
tags_hobbies: list[str]
est_premium: bool
texte_brut = (
"Hier j'ai discuté avec Marc, il vient d'avoir 28 ans. "
"Il adore le tennis et la lecture, mais il refuse toujours de payer l'abonnement pro."
)
# 2. 응답 형식을 강제하며 API 호출
response = client.beta.chat.completions.parse(
model="qwen/qwen3-4b:free",
messages=[
{"role": "system", "content": "Extrait les informations du profil utilisateur."},
{"role": "user", "content": texte_brut}
],
response_format=ProfilUtilisateur, # )
# Premium ? : False (Type: )
response_format을 사용하면 AI는 JSON 주변에 텍스트를 추가하거나 tags_hobbies 키를 빼먹을 물리적으로 불가능합니다. 취미가 하나도 발견되지 않으면 빈 리스트 []를 반환하지만, 키 자체는 항상 존재합니다. 따라서 애플리케이션 코드는 크래시 위험에서 벗어납니다.
4. JSON 모드 vs Structured Output
API 문서에서는 종종 간단한 파라미터를 언급합니다:
{"type": "json_object"}
(JSON 모드). 이 모드는 응답이 유효한 JSON임을 보장하지만, 키가 존재한다는 보장은 하지 않습니다; AI가 {"utilisateur": "Marc", "annees": 28} 같은 형태를 반환할 수 있습니다.
따라서 Structured Outputs(Pydantic, JavaScript의 Zod 등)를 사용해 각 변수의 이름과 타입을 정확히 강제하는 것이 바람직합니다.
핵심 정리 3가지
- ✅ 간청하지 마세요: 대문자 프롬프트 “ONLY JSON”은 기술적 보장이 아니라 바람일 뿐입니다.
- ✅ 스키마를 강제하세요: API의 Structured Outputs를 활용해 AI의 응답을 수학적으로 제한합니다.
- ✅ 강한 타입을 사용하세요: 코드 안정성을 위해 타입을 명시하고 검증합니다.
* : Pydantic(Python) 또는 Zod(JavaScript)를 사용하여 AI 응답을 내부 데이터 모델에 직접 연결하세요.
그 다음은?
축하합니다, 이제 AI를 올바르게 호출하고, 메모리를 관리하며, 비용을 절감하고, JSON 형태로 응답을 타입 지정하는 방법을 알게 되었습니다.
더 나아가서: 모델 업데이트나 프롬프트 변경 후에도 Pydantic 추출이 신뢰성을 유지하도록 보장하려면 어떻게 해야 할까요? 시리즈의 다음 글에서는 **Test‑Driven Prompting (Evals)**을 사용한 배포 보안에 대해 다룰 예정입니다.