AI 앱 개발에서 가장 까다로운 작업 중 하나는 LLM의 자유로운 텍스트 출력을 구조화된 데이터로 변환하는 것입니다. 저는 지난 2년간 다양한 production 환경에서 LangChain의 output parsing 기능을 활용해 왔으며, 오늘 그 과정에서 얻은 실전 경험을 공유하겠습니다.

왜 Output Parsing이 중요한가?

LLM은 본질적으로 텍스트 생성 모델입니다. 그러나 실제 애플리케이션에서는 JSON, Pydantic 모델, 열거형 등의 구조화된 출력이 필요합니다. LangChain의 output parsing은 이 문제를 체계적으로 해결합니다.

비용 비교: 월 1,000만 토큰 기준

모델가격 ($/MTok)월 10M 토큰 비용
GPT-4.1$8.00$80.00
Claude Sonnet 4.5$15.00$150.00
Gemini 2.5 Flash$2.50$25.00
DeepSeek V3.2$0.42$4.20

HolySheep AI를 사용하면 단일 API 키로 위 모든 모델에 접근 가능하며, 지금 가입하면 무료 크레딧을 받을 수 있습니다.

PydanticOutputParser 활용

PydanticOutputParser는 LLM 출력을 Python 클래스로 자동 변환합니다. 저는 이 기능을 상품 리뷰 분석, 사용자 피드백 분류, API 응답 구조화 등에 광범위하게 사용합니다.

from pydantic import BaseModel, Field
from typing import Optional, List
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate

1. Pydantic 모델 정의

class ProductReview(BaseModel): sentiment: str = Field(description="리뷰의 감성: positive, negative, neutral") score: int = Field(description="평점 1-5") key_points: List[str] = Field(description="주요 언급 포인트") recommended: bool = Field(description="제품 추천 여부")

2. Parser 및 LLM 설정

parser = PydanticOutputParser(pydantic_object=ProductReview) llm = ChatOpenAI( model="gpt-4.1", base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY", temperature=0.3, max_tokens=1024 )

3. 프롬프트 템플릿 구성

template = """다음 상품 리뷰를 분석하여 구조화된 정보를 추출하세요. 리뷰: {review} {format_instructions}""" prompt = PromptTemplate( template=template, input_variables=["review"], partial_variables={"format_instructions": parser.get_format_instructions()} )

4. 체인 실행

chain = prompt | llm | parser result = chain.invoke({"review": "배터리 수명이 짧고 화면 밝기가 부족하지만, 가격 대비 전반적 성능은 좋습니다."}) print(f"감성: {result.sentiment}") print(f"평점: {result.score}/5") print(f"추천: {'예' if result.recommended else '아니오'}")

JSON 모듈로 간단한 구조화

복잡한 검증이 필요하지 않은 경우, 간단한 JSONOutputParser가 더 효율적입니다. 저는 빠른 프로토타이핑이나 일회성 데이터 추출에 이 방법을 선호합니다.

from langchain.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
import json

llm = ChatOpenAI(
    model="gemini-2.5-flash",
    base_url="https://api.holysheep.ai/v1",
    api_key="YOUR_HOLYSHEEP_API_KEY",
    temperature=0.2
)

parser = JsonOutputParser()

template = """{query}의 결과를 다음 JSON 스키마로 반환하세요:
{format_instructions}"""

prompt = PromptTemplate(
    template=template,
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

chain = prompt | llm | parser

기술 블로그 포스트 구조 추출

result = chain.invoke({ "query": "인공지능의 미래에 대한 500단어 기술 블로그 포스트 구조를 만들어줘" }) print(json.dumps(result, indent=2, ensure_ascii=False))

복합 구조: 중첩된 Pydantic 모델

실제 production 환경에서는 단일 평면 구조보다 중첩된 데이터 구조가 필요합니다. 저는 이런 경우 복잡한 Pydantic 모델을 정의하여 사용합니다.

from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI

class Priority(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"

class TaskItem(BaseModel):
    title: str = Field(description="작업 제목")
    priority: Priority
    estimated_hours: Optional[float] = None

class ProjectPlan(BaseModel):
    project_name: str
    total_estimated_hours: float
    tasks: List[TaskItem]
    risk_factors: List[str] = Field(default_factory=list)

parser = PydanticOutputParser(pydantic_object=ProjectPlan)

llm = ChatOpenAI(
    model="deepseek-v3.2",
    base_url="https://api.holysheep.ai/v1",
    api_key="YOUR_HOLYSHEEP_API_KEY",
    temperature=0.4,
    max_tokens=2048
)

DeepSeek V3.2는 월 10M 토큰 시僅 $4.20으로 매우 경제적

고비용 모델로 작업하기 부담스러운 반복 작업에 적합

Lazy Output Parsing: 대용량 응답 처리

대규모 문서 처리 시 전체 응답을 한 번에 파싱하면 메모리 문제가 발생할 수 있습니다. 이때 LazyOutputParser를 사용하면 스트리밍 방식으로 효율적으로 처리됩니다.

from typing import Iterator
from langchain.output_parsers import LazyOutputParser
from langchain_core.outputs import Generation
import json

class StreamingJSONParser(LazyOutputParser):
    def parse(self, tokens: Iterator[str]) -> dict:
        """토큰 스트림에서 JSON 객체 직접 파싱"""
        buffer = ""
        json_start = False
        
        for token in tokens:
            buffer += token
            
            # JSON 시작 감지
            if not json_start and buffer.strip().startswith('{'):
                json_start = True
            
            if json_start:
                try:
                    return json.loads(buffer)
                except json.JSONDecodeError:
                    continue
        
        raise ValueError("유효한 JSON을 찾을 수 없습니다")

대규모 문서에서 구조화된 데이터 추출 시 사용

파싱 실패 시 메모리 효율적으로 처리

저자의 실전 경험: 비용 최적화 사례

저는 이전에 모든 LLM 호출에 GPT-4o를 사용했습니다. 월간 비용이 $2,000를 초과하면서 비용 최적화가 시급해졌죠. 저는 HolySheep AI의 단일 API 키로 여러 모델을 전환하기 시작했습니다.

변경 전: GPT-4o로 모든 작업 ($3.00/MTok × 20M = $60)

변경 후: 반복 작업은 DeepSeek V3.2 ($0.42/MTok), 복잡한 추론은 Gemini 2.5 Flash ($2.50/MTok)

결과: 월간 비용 65% 절감, 지연 시간 40% 개선

자주 발생하는 오류와 해결책

1. 파싱 실패: incomplete JSON

# ❌ 오류 발생 코드
parser = PydanticOutputParser(pydantic_object=ProductReview)
chain = prompt | llm | parser
result = chain.invoke({"review": "..."})

OutputParserException: Failed to parse...

✅ 해결: 재시도 로직 추가 + max_tokens 증가

from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10)) def safe_parse(inputs): chain = prompt | llm | parser return chain.invoke(inputs) llm = ChatOpenAI( model="gpt-4.1", base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY", max_tokens=2048 # 출력 길이 충분히 확보 )

2. 타입 불일치: enum 값 오류

# ❌ 오류 발생: LLM이 예상하지 않은 enum 값 반환
class Status(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"

✅ 해결: union 타입으로 유연하게 처리

from typing import Union class Status(str, Enum): PENDING = "pending" APPROVED = "approved" REJECTED = "rejected" class Response(BaseModel): status: Union[Status, str] = Field(description="상태: pending/approved/rejected") # LLM이 다른 값을 반환해도 문자열로 받아들임 parser = PydanticOutputParser(pydantic_object=Response)

3. 선택적 필드 누락

# ❌ 오류 발생: optional 필드가 누락된 경우
class User(BaseModel):
    name: str
    email: Optional[str] = None  # None 허용

LLM이 email 필드를 아예 출력하지 않으면 파싱 실패

✅ 해결: 프롬프트에 필드 명시적 포함 지시

template = """사용자 정보를 추출하세요. 반드시 모든 필드를 포함해야 합니다: - name: 필수 - email: 없으면 null {format_instructions}"""

또는 parser 설정 변경

parser = PydanticOutputParser( pydantic_object=User, strict=False # 엄격한 검증 비활성화 )

4. base_url 잘못 설정

# ❌ 오류: Wrong base URL
llm = ChatOpenAI(
    api_key="YOUR_HOLYSHEEP_API_KEY",
    base_url="https://api.openai.com/v1"  # ❌ HolySheep 주소 아님
)

✅ 해결: HolySheep AI 공식 엔드포인트 사용

llm = ChatOpenAI( model="gpt-4.1", base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY" )

Claude 사용 시에도 동일한 base_url

Anthropic Claude도 HolySheep 게이트웨이 통해 사용 가능

결론

LangChain의 output parsing은 LLM 출력을 구조화된 데이터로 변환하는 강력한 도구입니다. PydanticOutputParser, JsonOutputParser, 그리고 커스텀 파서를 적절히 조합하면 다양한 시나리오에 대응할 수 있습니다.

비용 측면에서 HolySheep AI는 월 1,000만 토큰 사용 시 DeepSeek V3.2 기준 $4.20으로 기존 대비 최대 97% 비용 절감이 가능하며, 단일 API 키로 모든 주요 모델을 관리할 수 있어 인프라 복잡성도 크게 줄어듭니다.

👉 HolySheep AI 가입하고 무료 크레딧 받기