AI의 답변을 프로그램에서 쓰려면 '자유로운 문장'이 아니라 '정해진 형식의 데이터'로 받아야 합니다. 이번 레슨에서는 모델을 다루는 표준 방법과, 답변을 JSON으로 받는 두 가지 기술을 배웁니다.
init_chat_model: 모델계의 만능 어댑터
해외여행용 멀티 어댑터를 아시나요? 나라마다 콘센트 모양이 달라도 어댑터 하나면 다 꽂을 수 있습니다. init_chat_model이 바로 그 어댑터입니다. OpenAI든 Anthropic이든 '제공사:모델이름' 문자열만 바꾸면 나머지 코드는 그대로입니다.
모델 갈아끼우기: 문자열 하나만 변경
from langchain.chat_models import init_chat_model
# OpenAI 모델 (OPENAI_API_KEY 필요)
gpt = init_chat_model('openai:gpt-4o-mini', temperature=0)
# Claude 모델 (ANTHROPIC_API_KEY 필요) — 코드는 동일!
claude = init_chat_model('anthropic:claude-sonnet-4-5', temperature=0)
# 같은 방식으로 호출합니다
print(gpt.invoke('안녕!').content)
print(claude.invoke('안녕!').content)
- temperature=0: 답변의 창의성. 0이면 일관된 답, 1에 가까울수록 다양한 답
- max_tokens: 답변 최대 길이 제한 (비용 통제에 유용)
- 모델 문자열 형식: 'openai:gpt-4o-mini'처럼 제공사:모델명
방법 1: JsonOutputParser로 JSON 받기
JSON 파서 체인
from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
prompt = ChatPromptTemplate.from_template(
'다음 리뷰의 감정을 분석해서 JSON으로만 답해. '
'키는 sentiment(positive/negative), score(0~1 숫자)야. '
'리뷰: {review}'
)
model = init_chat_model('openai:gpt-4o-mini', temperature=0)
chain = prompt | model | JsonOutputParser()
result = chain.invoke({'review': '배송도 빠르고 품질도 최고예요!'})
print(result['sentiment']) # positive
print(result['score']) # 0.95 (파이썬 딕셔너리로 바로 사용)
방법 2: with_structured_output (추천)
JsonOutputParser는 AI가 형식을 어기면 파싱 에러가 납니다. 더 안전한 방법은 with_structured_output입니다. Pydantic 클래스로 '답안지 양식'을 미리 정의하면, 모델이 그 양식에 강제로 맞춰 답하고 타입 검증까지 자동으로 됩니다.
구조화 출력: 답안지 양식 강제하기
from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
# 답안지 양식을 클래스로 정의합니다
class ReviewAnalysis(BaseModel):
sentiment: str = Field(description='positive 또는 negative')
score: float = Field(description='감정 확신도 0~1')
keywords: list[str] = Field(description='핵심 키워드 최대 3개')
model = init_chat_model('openai:gpt-4o-mini', temperature=0)
# 모델에 답안지 양식을 장착합니다
structured_model = model.with_structured_output(ReviewAnalysis)
result = structured_model.invoke('이 노트북 가볍고 배터리도 오래가요. 강추!')
print(result.sentiment) # positive
print(result.keywords) # ['가벼움', '배터리', '강추']
print(type(result)) # ReviewAnalysis 객체 (타입 검증 완료)
| 방법 | 장점 | 단점 |
|---|---|---|
| StrOutputParser | 가장 단순, 텍스트 그대로 | 구조화된 데이터 불가 |
| JsonOutputParser | 딕셔너리로 바로 사용 | 형식 어기면 파싱 에러 |
| with_structured_output | 타입 검증 자동, 가장 안전 | Pydantic 클래스 정의 필요 |
데이터 추출, 분류, 폼 채우기처럼 결과를 코드에서 다뤄야 하는 작업은 무조건 with_structured_output을 쓰세요. Field의 description이 사실상 프롬프트 역할을 하므로 구체적으로 적을수록 정확해집니다.
temperature를 높게 두고 JSON을 요구하면 형식이 자주 깨집니다. 구조화된 출력이 필요한 작업은 temperature=0으로 고정하는 것이 안전합니다.