StructuredOutputParser는 LangChain의 출력 파싱 모듈로, LLM의 텍스트 출력을 JSON, 딕셔너리, 또는 기타 구조화된 형식으로 변환합니다. 이를 통해 모델의 출력을 애플리케이션에서 쉽게 처리하거나 데이터베이스에 저장할 수 있습니다. EXAONE 3.5와 같은 고성능 모델은 복잡한 텍스트를 생성할 수 있지만, 이 텍스트를 구조화된 데이터로 변환하려면 명확한 파싱 전략이 필요합니다.
주요 특징
- 스키마 정의: 사용자가 원하는 출력 형식을 ResponseSchema 객체로 정의.
- 자동 파싱: LLM의 텍스트 출력을 정의된 스키마에 맞게 자동으로 매핑.
- 에러 처리: 잘못된 출력 형식을 처리하거나 기본값을 제공하는 기능.
- 프롬프트 통합: 프롬프트 템플릿에 파싱 지침을 포함하여 모델이 구조화된 출력을 생성하도록 유도.
StructuredOutputParser를 사용하려면 먼저 LangChain과 Ollama 환경을 설정해야 합니다. 아래는 EXAONE 3.5 모델을 사용한 기본 설정 예제입니다.
from langchain_ollama import OllamaLLM
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
from langchain.prompts import PromptTemplate
# Ollama 모델 초기화 (EXAONE 3.5)
llm = OllamaLLM(model="exaone3.5")
ResponseSchema 정의
ResponseSchema는 출력의 각 필드와 그에 대한 설명을 정의합니다. 예를 들어, 책 추천 시스템에서 책 제목과 저자를 추출하려면 다음과 같이 설정할 수 있습니다.
# 응답 스키마 정의
response_schemas = [
ResponseSchema(name="title", description="추천된 책의 제목"),
ResponseSchema(name="author", description="추천된 책의 저자")
]
프롬프트 템플릿 생성
StructuredOutputParser는 프롬프트에 출력 형식을 명시적으로 포함시켜야 합니다. 이를 위해 PromptTemplate을 사용합니다.
# 프롬프트 템플릿
format_instructions = output_parser.get_format_instructions()
prompt_template = PromptTemplate(
template="다음 주제에 맞는 책을 추천해 주세요: {topic}\n{format_instructions}",
input_variables=["topic"],
partial_variables={"format_instructions": format_instructions}
)
get_format_instructions() 메서드는 JSON 형식의 출력 지침을 생성하며, EXAONE 3.5가 이를 따라 구조화된 출력을 생성하도록 유도합니다.
StructuredOutputParser 사용 예제
아래는 사용자가 “인공지능” 주제에 대한 책 추천을 요청했을 때 StructuredOutputParser를 사용하여 결과를 파싱하는 예제입니다.
# 체인 구성
chain = prompt_template | llm | output_parser
# 사용자 입력
topic = "인공지능"
# 체인 실행
response = chain.invoke({"topic": topic})
# 결과 출력
print(response)
{‘title’: ‘Artificial Intelligence: A Guide for Thinking Humans’, ‘author’: ‘Melanie Mitchell’}
이 예제에서 EXAONE 3.5는 프롬프트에 포함된 형식 지침을 따라 JSON 형식의 텍스트를 생성하고, StructuredOutputParser는 이를 파싱하여 Python 딕셔너리로 반환합니다.
고급 사용 사례
더 복잡한 출력이 필요할 경우, 추가 필드와 데이터 유형을 정의할 수 있습니다. 예를 들어, 책 추천에 출판 연도와 장르를 추가하려면:
response_schemas = [
ResponseSchema(name="title", description="추천된 책의 제목"),
ResponseSchema(name="author", description="추천된 책의 저자"),
ResponseSchema(name="year", description="출판 연도", type="integer"),
ResponseSchema(name="genre", description="책의 장르")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
에러 처리
EXAONE 3.5가 예상과 다른 형식을 반환할 경우, StructuredOutputParser는 예외를 발생시킵니다. 이를 방지하기 위해 try-except 블록을 사용하거나, 기본값을 설정할 수 있습니다.
try:
result = chain.invoke({"topic": topic})
except Exception as e:
result = {"title": "추천 없음", "author": "없음"}
다중 출력 처리
여러 추천을 요청할 경우, ResponseSchema에 리스트 형태의 필드를 정의할 수 있습니다.
response_schemas = [
ResponseSchema(name="recommendations", description="추천 책 목록", type="list")
]
EXAONE 3.5와의 최적화 팁
EXAONE 3.5는 고성능 한국어 처리 능력을 갖추고 있지만, 구조화된 출력을 생성하려면 프롬프트 디자인이 중요합니다. 다음은 최적화를 위한 팁입니다.
- 명확한 지침: 프롬프트에 JSON 형식의 예제를 포함하여 모델이 출력 형식을 이해하도록 돕습니다.
template = """다음 주제에 맞는 책을 추천해 주세요: {topic}
출력은 다음 JSON 형식으로 제공해 주세요:
{{"title": "책 제목", "author": "저자"}}
{format_instructions}"""
- 짧고 간결한 출력: EXAONE 3.5는 간결한 출력을 선호하므로, 불필요한 설명을 최소화합니다.
- 반복 테스트: 모델이 예상대로 구조화된 출력을 생성하는지 반복적으로 테스트합니다.
한계와 대안
StructuredOutputParser는 강력하지만, EXAONE 3.5가 프롬프트 지침을 완벽히 따르지 않을 경우 파싱 오류가 발생할 수 있습니다. 이 경우, 다음 대안을 고려할 수 있습니다.
- PydanticOutputParser: Pydantic 모델을 사용하여 더 엄격한 데이터 검증을 수행.
- Custom Parser: 특정 출력 패턴에 맞춘 사용자 정의 파서를 구현.
- 후처리 스크립트: 모델 출력에서 필요한 데이터를 추출하는 정규 표현식 또는 스크립트를 사용.