AI 응답을 JSON으로 안전하게 받기 — Output Parser 실전

AI가 만든 답을 화면에 그냥 보여주기만 할 거면 문제가 없습니다. 그런데 그 답을 데이터베이스에 저장하거나 다른 시스템에 넘기려면 이야기가 달라집니다. 자유롭게 쓴 문장은 프로그램이 다루기 나쁘거든요. 이걸 해결하는 게 Output Parser입니다.

신입들이 꼭 한 번 겪는 실수

제가 팀에서 자주 보는 장면이 있습니다. 프롬프트에 "JSON으로 답해"라고만 적고 json.loads()로 바로 파싱하는 거예요. 데모에선 잘 됩니다. 그러다 어느 순간 모델이 ```json 코드블록으로 감싸거나 "네, 결과입니다:"를 앞에 붙이면서 파싱이 깨집니다. Output Parser는 이 "형식이 들쭉날쭉한 문제"를 표준화해 줍니다.

JsonOutputParser 기본 사용

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI

parser = JsonOutputParser()
prompt = ChatPromptTemplate.from_template(
    "다음 상품평에서 감정과 별점을 뽑아줘.\n{format}\n상품평: {review}"
).partial(format=parser.get_format_instructions())

chain = prompt | ChatOpenAI(model="gpt-4o-mini") | parser
print(chain.invoke({"review": "배송은 느렸지만 품질은 만족해요"}))
# {'sentiment': '긍정', 'rating': 4} 같은 dict로 바로 나옴

핵심은 get_format_instructions()입니다. 파서가 "이런 JSON 형식으로 답하라"는 지시를 프롬프트에 자동으로 심어줘서, 결과가 훨씬 안정적으로 나옵니다.

스키마까지 강제하고 싶다면

필드 타입까지 확실히 잡고 싶을 땐 Pydantic 스키마를 씁니다. 나이를 문자열 "30"이 아니라 정수 30으로 받는 것만으로도 뒤 코드가 편해집니다.

from pydantic import BaseModel

class Review(BaseModel):
    sentiment: str
    rating: int

model = ChatOpenAI(model="gpt-4o-mini").with_structured_output(Review)
r = model.invoke("이 상품평 분석: 가격 대비 훌륭합니다")
print(r.sentiment, r.rating)

그래도 방심은 금물

형식을 강제해도 "내용이 맞는지"는 별개입니다. 모델이 모르는 값을 억지로 채워 넣기도 하거든요. 그래서 중요한 배치에는 파싱 실패 시 1회 재시도 로직을 꼭 넣고, 애매한 필드는 Optional로 두어 "모르면 비워두게" 합니다. 이 두 가지만 해도 새벽에 배치가 죽는 일이 확 줄었습니다.

마무리

Output Parser는 "AI의 자유로운 말"과 "프로그램이 원하는 딱딱한 형식" 사이의 다리입니다. 서비스에 AI 결과를 저장·연동할 계획이라면, 문자열을 손으로 파싱하지 말고 처음부터 파서나 스키마를 끼워두시길 권합니다. 훨씬 덜 고생합니다.

댓글

이 블로그의 인기 게시물

지하철 노선도로 이해하는 LangGraph (분기·반복 설계)

LangGraph State란 무엇인가? 상태 관리 개념 쉽게 이해하기

LangGraph Node와 Edge 개념 쉽게 이해하기 (초보자 완전 정리)