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 결과를 저장·연동할 계획이라면, 문자열을 손으로 파싱하지 말고 처음부터 파서나 스키마를 끼워두시길 권합니다. 훨씬 덜 고생합니다.
댓글
댓글 쓰기