PydanticAI vs LangChain vs instructor: 구조화된 LLM 출력 비교
요약
LLM으로부터 구조화된 데이터를 추출하기 위한 세 가지 Python 라이브러리인 PydanticAI, LangChain, instructor를 비교합니다. 각 라이브러리가 JSON 모드와 함수 호출을 처리하는 방식과 제어권, 편의성 측면의 차이점을 분석합니다.
핵심 포인트
- instructor는 최소한의 API로 OpenAI 호환 엔드포인트에서 높은 제어권을 제공함
- LangChain은 다양한 모델 제공자를 통합하는 계층화된 편리함을 제공함
- 구조화된 출력은 JSON 모드와 파싱 및 재시도 전략의 조합으로 구현됨
- 라이브러리 선택 시 제어권과 추상화 수준 사이의 트레이드오프 고려 필요
언어 모델(Language Model)로부터 구조화된 데이터를 안정적으로 추출하는 것은 보기보다 어렵습니다. 모델은 거의 유효한 형태의 JSON을 반환하거나, 필수 필드를 누락하거나, 객체를 마크다운(Markdown) 블록으로 감싸서 반환할 수 있습니다. 세 가지 Python 라이브러리인 instructor, LangChain의 구조화된 출력 (structured output), 그리고 PydanticAI는 이를 서로 다른 방식으로 해결하려고 시도합니다. 이 글은 문서가 아닌 실제 사용을 바탕으로 한 직접적인 비교입니다.
"구조화된 출력 (structured output)"의 실제 의미
언어 모델을 호출하면 문자열(String)이 반환됩니다. 만약 Python 객체 — 타입이 지정된 딕셔너리 (Typed Dict), Pydantic 모델, 데이터 클래스 (Dataclass) — 를 원한다면, 그 간극을 메워줄 무언가가 필요합니다. 여기에는 두 가지 광범위한 접근 방식이 있습니다:
- JSON 모드 (JSON mode) / 함수 호출 (Function calling): 모델에 스키마 (Schema)를 보내면, 모델은 해당 스키마와 일치하는 유효한 JSON을 반환하기로 약속합니다.
- 파싱 및 재시도 (Parse-and-retry): JSON을 요청하고 Pydantic으로 검증하며, 검증에 실패할 경우 에러를 다시 보내 모델이 이를 수정하도록 요청합니다.
세 라이브러리 모두 이러한 접근 방식들을 혼합하여 사용하지만, 사용자가 얼마나 많은 제어권을 유지할 수 있는지와 얼마나 많은 복잡성을 숨기는지에 따라 차이가 있습니다.
instructor: 최소한의 접점, 최대한의 제어권
instructor는 OpenAI (또는 호환 가능한) 클라이언트(Client)에 response_model 파라미터를 추가하도록 패치(Patch)합니다. 이것이 기본적으로 API의 전체 접점입니다.
import instructor
from openai import OpenAI
from pydantic import BaseModel, Field
...
instructor가 내부적으로 수행하는 작업은 다음과 같습니다: 사용자의 Pydantic 모델을 함수/도구 스키마 (Function/Tool schema)로 변환하여 모델에 보내고, 모델이 유효하지 않은 JSON을 반환하면 검증 에러를 대화 내용에 추가하여 자동으로 재시도합니다 (설정 가능한 max_retries까지).
강점: 매우 작은 API 크기, 모든 OpenAI 호환 엔드포인트 (Ollama, Mistral, Groq)에서 작동, 비용 및 지연 시간 (Latency) 조사를 위해 기본 클라이언트에 대한 완전한 접근 권한 제공.
약점: 기본적으로 OpenAI 호환 API에 종속됨. Anthropic 또는 Gemini 클라이언트를 네이티브로 추가하려면 특정 패치(instructor.from_anthropic() 등)가 필요하며, 이는 때때로 메인 SDK보다 업데이트가 늦어질 수 있음.
LangChain 구조화된 출력 (structured output): 편리하지만 계층화되어 있음
LangChain의 .with_structured_output()은 다양한 제공자(provider) 통합 환경에서 작동합니다:
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from typing import Literal
...
LangChain은 모델에 따라 함수 호출 (function calling) 또는 JSON 모드로 분기하며, 유연하게 폴백 (fallback)을 수행합니다. 통합 계층 (integration layer)이 가장 큰 장점입니다. 동일한 .with_structured_output() 호출이 추출 로직을 변경하지 않고도 ChatAnthropic, ChatGoogleGenerativeAI, ChatOllama 등에서 작동합니다.
강점: 제공자 불가지론적 (Provider-agnostic), 체인 및 그래프 (LCEL, LangGraph)에 깔끔하게 연결됨, 이미 LangChain을 사용하는 파이프라인에 적합함.
약점: 추상화 비용이 실제로 존재함. 추출 실패 시 디버깅을 하려면 모델에 실제로 무엇이 전송되었는지 이해하기 위해 여러 계층을 거쳐야 함. 라이브러리 자체가 방대하여, 단순히 구조화된 출력을 위해 이를 임포트하는 것은 단일 파일을 서빙하기 위해 웹 프레임워크를 사용하는 것과 같음. 유효성 검사 실패 시의 재시도 (retry) 동작이 instructor보다 덜 명시적임.
PydanticAI: 에이전트 우선, 내장된 구조화된 출력
PydanticAI는 세 가지 중 가장 최신입니다. 모든 것을 타입이 지정된 result_type 파라미터를 가진 에이전트 (agents)로 구성합니다:
from pydantic_ai import Agent
from pydantic import BaseModel, Field
...
PydanticAI는 또한 다단계 에이전트 (multi-step agents), 도구 사용 (tool use), 의존성 주입 (dependency injection), 그리고 스트리밍 (streaming)에 대한 퍼스트 클래스 지원을 제공합니다. 만약 사용 사례가 단순 추출을 넘어 모델이 도구를 호출하고 구조화된 최종 출력을 생성해야 하는 경우라면, PydanticAI가 세 가지 중 가장 인체공학적 (ergonomic)입니다.
강점: 깔끔한 비동기 네이티브 (async-native) 설계, 테스트를 위한 적절한 의존성 주입, 구조화된 출력 스트리밍, 내장된 멀티 에이전트 패턴.
약점: 비교적 어린 프로젝트 (API 변경이 잦을 수 있음), 적은 커뮤니티 예제, 순수 추출 작업의 경우 instructor보다 무거움.
실제 환경에서의 성능 및 신뢰성
프로덕션 추출 파이프라인 (production extraction pipelines)의 경우, 실질적인 차이점은 몇 가지 축으로 요약됩니다:
| instructor | LangChain | PydanticAI | |
|---|---|---|---|
| 유효성 검사 실패 시 재시도 (Retry on validation failure) | 명시적이며 설정 가능 | 제공자(Provider)에 따라 다름 | 자동 |
| ... |
문서를 타입이 지정된 Python 객체로 변환하는 순수 추출 작업의 경우, instructor가 가장 먼저 고려해야 할 기본 선택지입니다. 모델 API에 대해 가능한 가장 작은 표면적 (surface area)을 가지며, 유효성 검사 오류가 투명하고, 로컬 모델을 포함하여 OpenAI와 호환되는 모든 엔드포인트에서 작동합니다.
여러 단계, 조건부 로직, 또는 외부 도구 호출 (tool calls)이 포함된 전체 파이프라인을 구축 중이며 이미 LangChain 생태계에 있다면, .with_structured_output()이 자연스러운 선택입니다. 제공자별로 별도의 추출 코드를 유지 관리할 필요 없이 교차 제공자 호환성 (cross-provider compatibility)을 얻을 수 있습니다.
PydanticAI는 추론하고, 도구를 호출하며, 마지막에 구조화된 결과를 반환하는 에이전트 (agents)가 필요할 때 빛을 발합니다. 특히 의존성 주입 (dependency injection) 모델은 테스트에 매우 유용합니다. 에이전트 코드를 변경하지 않고도 테스트 경계에서 실제 LLM 클라이언트를 결정론적인 모의 객체 (deterministic mock)로 교체할 수 있습니다.
요약 (The takeaway)
만석적인 승자는 없습니다. 추출 단계 주변의 환경에 따라 선택하십시오:
- 문서나 원문 텍스트로부터의 독립적인 추출이 필요한가요? instructor를 사용하세요.
- 라우팅 (routing), 메모리 (memory), 또는 도구 호출을 이미 LangChain으로 사용 중인 파이프라인인가요?
.with_structured_output()을 사용하세요. - 추론을 수행하고 타입이 지정된 최종 출력을 생성하는 에이전트가 필요한가요? PydanticAI를 사용하세요.
세 가지 모두 공유하는 한 가지 사실은, 여러분이 정의한 Pydantic 모델의 품질이 추출 정확도에 직접적인 영향을 미친다는 점입니다. 잘 작성된 Field(description=...) 어노테이션은 모델이 보는 함수 스키마 (function schema)에 포함됩니다. 예를 들어 severity에 대해
특히 보안 관련 파이프라인 (security-adjacent pipelines)의 경우, 타입이 지정된 출력 (typed outputs)은 타협할 수 없는 필수 요소입니다. 추출된 데이터가 경고 (alerting) 또는 위험 점수 산정 (risk scoring)으로 이어질 때, 암묵적인 타입 강제 변환 (silent type coercion)이나 누락된 필드는 추적하기 어려운 다운스트림 장애 (downstream failures)를 유발합니다. 저희의 보안 강화 체크리스트 (security hardening checklists)에는 LLM 지원 분석이 방어 가능한 파이프라인 아키텍처 (defensible pipeline architecture)의 어느 부분에 적합한지에 대한 가이드가 포함되어 있습니다. 이를 프로덕션 워크플로 (production workflows)에 구축하고 있다면 살펴볼 가치가 있습니다.
저는 사이버 보안 컨설팅 기업인 AYI NEDJIMI Consultants를 운영하고 있습니다. 저희는 무료 보안 강화 체크리스트 (free security hardening checklists)를 PDF와 Excel 형식으로 발행하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기