LangChain 독학 가이드 6 - 출력 파서

learning by Seven Fingers Studio 15분
LangChainAIPythonLLM챗봇

출력 파서가 왜 필요할까요?

AI와 대화를 하다 보면, 받은 답변을 그냥 텍스트로만 보기엔 아쉬울 때가 많아요. 예를 들어 “사과, 바나나, 오렌지를 추천해줘”라고 했을 때, AI가 자연스러운 문장으로 답변하면 프로그램에서 각 과일을 분리하기 어렵죠.

이럴 때 출력 파서(Output Parser)를 사용하면 AI의 답변을 우리가 원하는 형식으로 정확하게 받을 수 있어요. 리스트로 받을 수도 있고, JSON 객체로 받을 수도 있고, 심지어 타입 검증까지 자동으로 할 수 있답니다.

제 경험상 출력 파서를 제대로 활용하면 AI 응답을 처리하는 코드가 훨씬 깔끔해져요. 실제로 프로젝트에서 가장 많이 쓰는 기능 중 하나입니다.

StrOutputParser - 가장 기본적인 파서

가장 간단한 파서는 StrOutputParser예요. 이름 그대로 AI의 응답을 문자열로 깔끔하게 정리해줍니다. 이전 글에서도 봤던 파서인데, 다시 한번 자세히 살펴볼게요.

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

# 모델과 프롬프트 설정
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
prompt = ChatPromptTemplate.from_template("'{topic}'에 대해 한 문장으로 설명해줘")

# 체인 구성
chain = prompt | model | StrOutputParser()

# 실행
result = chain.invoke({"topic": "블랙홀"})
print(result)

실행 결과:

블랙홀은 중력이 너무 강해서 빛조차 빠져나올 수 없는 우주의 천체입니다.

StrOutputParser는 별다른 설정 없이 깔끔한 문자열만 반환해요. 대부분의 간단한 작업에서는 이것만으로도 충분합니다.

JsonOutputParser - 구조화된 데이터 받기

이제 좀 더 복잡한 데이터가 필요할 때를 생각해볼까요? 예를 들어 영화 정보를 받을 때 제목, 감독, 장르를 각각 분리해서 받고 싶다면 JSON 형식이 딱이죠.

from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate

# JSON 파서 생성
json_parser = JsonOutputParser()

# 프롬프트에 형식 지정 포함
prompt = PromptTemplate(
    template="""영화 '{movie}'의 정보를 JSON 형식으로 알려줘.
다음 형식으로 답변해줘:
{{
  "title": "영화 제목",
  "director": "감독 이름",
  "genre": "장르",
  "year": 개봉년도
}}

{format_instructions}
""",
    input_variables=["movie"],
    partial_variables={"format_instructions": json_parser.get_format_instructions()}
)

# 체인 구성
chain = prompt | model | json_parser

# 실행
result = chain.invoke({"movie": "인셉션"})
print(result)
print(f"\n제목: {result['title']}")
print(f"감독: {result['director']}")

실행 결과:

{'title': '인셉션', 'director': '크리스토퍼 놀란', 'genre': 'SF/액션', 'year': 2010}
제목: 인셉션
감독: 크리스토퍼 놀란

JSON 형식으로 받으면 딕셔너리처럼 각 값을 쉽게 꺼내 쓸 수 있어요. 웹 API를 만들 때 특히 유용합니다.

PydanticOutputParser - 타입 검증까지 완벽하게

JsonOutputParser도 좋지만, 더 엄격하게 데이터 타입을 검증하고 싶을 때가 있어요. 그럴 때는 Pydantic을 사용한 파서가 완벽한 해답이 됩니다.

from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

# 데이터 모델 정의
class MovieInfo(BaseModel):
    title: str = Field(description="영화 제목")
    director: str = Field(description="감독 이름")
    genre: str = Field(description="영화 장르")
    year: int = Field(description="개봉 연도")
    rating: float = Field(description="평점 (0-10)")

# Pydantic 파서 생성
pydantic_parser = PydanticOutputParser(pydantic_object=MovieInfo)

# 프롬프트 구성
prompt = PromptTemplate(
    template="""영화 '{movie}'의 정보를 알려줘.

{format_instructions}
""",
    input_variables=["movie"],
    partial_variables={"format_instructions": pydantic_parser.get_format_instructions()}
)

# 체인 실행
chain = prompt | model | pydantic_parser
result = chain.invoke({"movie": "타이타닉"})

print(f"제목: {result.title}")
print(f"감독: {result.director}")
print(f"개봉년도: {result.year}")
print(f"평점: {result.rating}")

실행 결과:

제목: 타이타닉
감독: 제임스 카메론
개봉년도: 1997
평점: 7.9

Pydantic을 사용하면 year는 반드시 정수(int)여야 하고, rating은 실수(float)여야 한다는 걸 자동으로 검증해줘요. 만약 AI가 잘못된 형식으로 답변하면 에러를 내주니까 훨씬 안전하죠.

CommaSeparatedListOutputParser - 리스트로 받기

간단하게 여러 항목을 리스트로 받고 싶을 때는 CommaSeparatedListOutputParser가 편리해요. 이름처럼 쉼표로 구분된 값들을 자동으로 리스트로 변환해줍니다.

from langchain_core.output_parsers import CommaSeparatedListOutputParser

# 리스트 파서 생성
list_parser = CommaSeparatedListOutputParser()

# 프롬프트 구성
prompt = PromptTemplate(
    template="""'{topic}' 관련 추천 키워드를 5개만 알려줘.

{format_instructions}
""",
    input_variables=["topic"],
    partial_variables={"format_instructions": list_parser.get_format_instructions()}
)

# 체인 실행
chain = prompt | model | list_parser
result = chain.invoke({"topic": "파이썬 학습"})

print("추천 키워드:")
for i, keyword in enumerate(result, 1):
    print(f"{i}. {keyword}")

실행 결과:

추천 키워드:
1. 기본 문법
2. 데이터 타입
3. 함수
4. 라이브러리
5. 프로젝트 실습

리스트로 받으면 반복문으로 바로 처리할 수 있어서 정말 편해요. 태그나 카테고리 같은 걸 추출할 때 자주 사용합니다.

실전 활용 - 여행 계획 생성기

이제 배운 파서들을 조합해서 실용적인 예제를 만들어볼게요. 여행지를 입력하면 구조화된 여행 계획을 만들어주는 프로그램입니다.

from langchain_core.pydantic_v1 import BaseModel, Field
from typing import List

# 여행 계획 모델 정의
class TravelPlan(BaseModel):
    destination: str = Field(description="여행지")
    duration: str = Field(description="권장 여행 기간")
    must_visit: List[str] = Field(description="필수 방문지 리스트")
    budget: str = Field(description="예상 예산")
    best_season: str = Field(description="최적 여행 시기")

# 파서 생성
travel_parser = PydanticOutputParser(pydantic_object=TravelPlan)

# 프롬프트 구성
prompt = PromptTemplate(
    template="""'{destination}'로 여행을 가려고 해. 여행 계획을 추천해줘.

{format_instructions}
""",
    input_variables=["destination"],
    partial_variables={"format_instructions": travel_parser.get_format_instructions()}
)

# 체인 실행
chain = prompt | model | travel_parser
result = chain.invoke({"destination": "제주도"})

print(f"=== {result.destination} 여행 계획 ===\n")
print(f"권장 기간: {result.duration}")
print(f"예상 예산: {result.budget}")
print(f"최적 시기: {result.best_season}")
print(f"\n필수 방문지:")
for place in result.must_visit:
    print(f"  - {place}")

실행 결과:

=== 제주도 여행 계획 ===
권장 기간: 3박 4일
예상 예산: 1인당 50만원 내외
최적 시기: 4~5월, 9~10월
필수 방문지:
- 한라산
- 성산일출봉
- 우도
- 애월 카페거리
- 섭지코지

파서 선택 가이드

어떤 상황에 어떤 파서를 쓸지 헷갈릴 수 있어요. 제가 실제로 사용하는 기준을 알려드릴게요:

StrOutputParser: 단순한 텍스트 답변이 필요할 때. 가장 기본이고 가장 많이 씁니다.

JsonOutputParser: 여러 필드를 가진 데이터가 필요하지만 타입 검증은 굳이 필요 없을 때. 빠르게 프로토타입을 만들 때 좋아요.

PydanticOutputParser: 프로덕션 환경이나 데이터 정확성이 중요할 때. 타입 검증이 자동으로 되니까 안전합니다.

CommaSeparatedListOutputParser: 태그, 키워드, 카테고리처럼 간단한 리스트만 필요할 때. 가볍고 편리해요.

다음 단계

출력 파서를 마스터했다면, 이제 AI와의 대화를 기억하는 방법을 배울 차례예요. 다음 글에서는 대화 메모리(Memory)를 다루면서 문맥을 유지하는 챗봇을 만들어볼 거예요.

실제로 메모리 없는 AI는 금방 전에 했던 말을 잊어버려서 답답할 때가 많거든요. 다음 글에서 이 문제를 완벽하게 해결해봅시다!


다음 글 보기

← 이전 글
LangChain 독학 가이드 5 - 다양한 LLM 연결하기
다음 글 →
LangChain 독학 가이드 7 - 대화 메모리
← 블로그 목록으로