47개 행짜리 비교 스프레드시트를 뒤져봤자 결국 "it depends"로 끝납니다. 실제로 중요한 건 프레임워크가 아니라 여러분 팀이 풀려는 문제입니다. 그 문제부터 정확히 짚고 코드로 비교합니다.
핵심 요약 → LangGraph (25K stars, 34.5M 월간 다운로드): 상태 머신 기반, 최고 통제력, 가장 가파른 학습 곡선 → PydanticAI (16.8K stars): 타입 안전 + DI, 단순 에이전트에 FastAPI 느낌, 멀티에이전트 성숙도 낮음 → CrewAI (47K stars): 역할 기반 가장 빠른 프로토타입, 내장 메모리, 복잡해지면 디버깅 어려움 → Google ADK: A2A·MCP·AG-UI 프로토콜 선도, GCP 네이티브, 커뮤니티 가장 작음 → 월간 검색량: LangGraph 27,100 > CrewAI 14,800 (관심도 기준) → Uber·Klarna·JPMorgan 등 400+ 기업 프로덕션 사용 = LangGraph → "빠른 프로토타입 → 나중에 벽 만남" = CrewAI의 대표적 패턴 → 결론: 단일 정답 없음 — 문제 유형·팀 성향·스택에 따라 명확히 다름
4파전 한눈 요약
# 철학 비교
LangGraph:
"에이전트 = 상태 머신"
노드(작업) + 엣지(전환) + 상태(공유 데이터)
→ 완전한 통제, 감사 가능, 복잡 워크플로
PydanticAI:
"에이전트 = 타입 안전 FastAPI 함수"
Agent + deps_type + output_type
→ 간결한 코드, 테스트 용이, IDE 지원 최강
CrewAI:
"에이전트 = 역할이 있는 팀원"
Agent(역할) + Task(임무) + Crew(팀)
→ 가장 빠른 프로토타입, 자연어 정의
Google ADK:
"에이전트 = 계층적 트리"
RootAgent → SubAgents → Tools
→ GCP 네이티브, A2A 프로토콜, 멀티모달
1. LangGraph — 최고의 통제력, 최고의 학습 곡선
LangGraph는 LangChain의 그래프 기반 오케스트레이션 레이어입니다. 에이전트 워크플로를 명시적 노드와 엣지를 가진 상태 머신으로 모델링합니다. Uber, Klarna, LinkedIn, JPMorgan 등 400개 이상 기업이 프로덕션에서 사용하며, Klarna의 AI 어시스턴트는 8,500만 사용자의 지원을 처리하면서 해결 시간을 80% 단축했습니다.
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langgraph.constants import Send
import operator
# ── 상태 정의 ──
class AgentState(TypedDict):
messages: list[str]
results: Annotated[list[str], operator.add] # 병렬 누적
final_report: str
iteration: int
should_retry: bool
# ── 노드 함수들 ──
def analyze_node(state: AgentState) -> AgentState:
"""분석 노드"""
# Claude/GPT/Gemini 호출
analysis = call_llm(state["messages"])
return {"results": [analysis], "iteration": state["iteration"] + 1}
def check_quality(state: AgentState) -> str:
"""조건부 엣지 — 품질 검사 후 다음 노드 결정"""
if state["iteration"] > 3:
return "end"
if needs_revision(state["results"]):
return "revise" # → revise_node로
return "synthesize" # → synthesize_node로
def synthesize_node(state: AgentState) -> AgentState:
return {"final_report": merge_results(state["results"])}
# ── 그래프 구성 ──
builder = StateGraph(AgentState)
builder.add_node("analyze", analyze_node)
builder.add_node("synthesize", synthesize_node)
builder.set_entry_point("analyze")
builder.add_conditional_edges(
"analyze",
check_quality,
{"revise": "analyze", "synthesize": "synthesize", "end": END}
)
builder.add_edge("synthesize", END)
graph = builder.compile(
checkpointer=..., # 상태 영속성 (PostgreSQL, Redis)
interrupt_before=["synthesize"] # HITL: synthesize 전 인간 승인
)
# ── 실행 ──
config = {"configurable": {"thread_id": "session-123"}}
result = graph.invoke(
{"messages": ["분석해줘"], "results": [], "iteration": 0, "should_retry": False},
config=config
)
# ── LangGraph가 빛나는 이유 ──
# 1. 체크포인터: 서버 재시작해도 정확히 이전 상태에서 재개
# 2. interrupt_before: 특정 노드 전 인간 승인 강제
# 3. 조건부 엣지: 복잡한 분기 로직 명시적 표현
# 4. LangSmith: 모든 노드 실행 트레이스 자동 저장
# LangGraph 선택 기준
✅ 선택해야 할 때:
- 규제 환경 (금융, 의료): 모든 결정 감사 추적 필수
- 복잡한 조건부 워크플로: if-else 분기가 많은 에이전트
- Human-in-the-Loop: 특정 단계에서 인간 승인 필요
- 장시간 실행 에이전트: 체크포인터로 중간 상태 저장
- 이미 LangChain/LangSmith 사용 중
❌ 피해야 할 때:
- 빠른 프로토타입 (학습 곡선 가파름)
- 단순 Q&A 에이전트 (오버킬)
- TypeScript 팀이지만 Python LangGraph 쓰려는 경우
(JS 버전은 Python 대비 기능 부족)
2. PydanticAI — 타입 안전, 단순함, 테스트 가능성
from dataclasses import dataclass
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
import asyncpg
# ── 의존성 정의 ──
@dataclass
class Deps:
db: asyncpg.Pool
user_id: int
# ── 출력 타입 ──
class AnalysisResult(BaseModel):
summary: str
risk_level: str = Field(pattern="^(low|medium|high)$")
action_items: list[str]
confidence: float = Field(ge=0.0, le=1.0)
# ── 에이전트 정의 ──
agent = Agent(
"anthropic:claude-sonnet-4-6",
deps_type=Deps,
output_type=AnalysisResult,
system_prompt="당신은 데이터 분석 전문가입니다.",
)
@agent.instructions
async def inject_user_context(ctx: RunContext[Deps]) -> str:
profile = await ctx.deps.db.fetchrow(
"SELECT * FROM users WHERE id = $1", ctx.deps.user_id
)
return f"분석 대상 사용자: {profile['name']}, 등급: {profile['tier']}"
@agent.tool
async def fetch_data(ctx: RunContext[Deps], days: int = 30) -> list[dict]:
"""최근 데이터를 가져옵니다. Args: days: 조회 기간(일)"""
rows = await ctx.deps.db.fetch(
"SELECT * FROM events WHERE user_id=$1 AND date > NOW()-$2*'1 day'::interval",
ctx.deps.user_id, days
)
return [dict(r) for r in rows]
# ── 실행 ──
async def run():
async with asyncpg.create_pool(DSN) as pool:
result = await agent.run(
"이 사용자의 최근 활동을 분석해줘",
deps=Deps(db=pool, user_id=42)
)
print(result.output.risk_level) # "low" | "medium" | "high" 타입 보장
# ── PydanticAI가 빛나는 이유 ──
# 1. output_type 검증 실패 시 자동 재시도 (LLM에게 피드백)
# 2. deps_type 타입 불일치 → IDE가 작성 시점에 에러 표시
# 3. TestModel로 LLM 없이 에이전트 로직 테스트
# 4. 툴 파라미터도 Pydantic 검증 → 잘못된 인자 자동 거부
# PydanticAI 선택 기준
✅ 선택해야 할 때:
- FastAPI 쓰는 팀 (동일 패턴, 빠른 온보딩)
- 타입 안전이 최우선 (프로덕션 코드 품질)
- 단순~중간 복잡도 에이전트
- CI/CD에서 LLM API 없이 테스트 필요
❌ 피해야 할 때:
- 복잡한 그래프 워크플로 (LangGraph로)
- 내장 메모리가 필요한 경우 (직접 구현 필요)
- 비개발자도 에이전트 정의에 참여하는 환경
3. CrewAI — 가장 빠른 프로토타입, 역할 기반
from crewai import Agent, Task, Crew, Process
from crewai.tools import BaseTool
# ── 툴 정의 ──
class WebSearchTool(BaseTool):
name: str = "web_search"
description: str = "웹에서 최신 정보를 검색합니다"
def _run(self, query: str) -> str:
return search_web(query) # 실제 검색 로직
# ── 에이전트 정의 (자연어로) ──
researcher = Agent(
role="수석 리서처",
goal="주어진 주제에 대한 최신 정보를 수집하고 분석",
backstory="""당신은 10년 경력의 AI 리서처입니다.
복잡한 기술 트렌드를 명확하게 분석하는 전문가입니다.""",
tools=[WebSearchTool()],
llm="anthropic/claude-sonnet-4-6",
verbose=True,
memory=True, # ← 내장 메모리 (세션 내)
)
writer = Agent(
role="기술 작가",
goal="리서처의 결과를 바탕으로 명확한 리포트 작성",
backstory="기술 문서 전문가. 복잡한 내용을 쉽게 설명합니다.",
llm="openai/gpt-5.5", # 다른 모델 사용 가능
)
fact_checker = Agent(
role="팩트 체커",
goal="리포트의 모든 주장을 검증",
backstory="정확성을 최우선으로 하는 검증 전문가입니다.",
tools=[WebSearchTool()],
llm="google/gemini-3.5-flash",
)
# ── 태스크 정의 ──
research_task = Task(
description="2026년 AI 에이전트 프레임워크 트렌드 조사",
expected_output="주요 프레임워크와 트렌드를 정리한 리서치 노트",
agent=researcher,
)
writing_task = Task(
description="리서치 노트를 바탕으로 기술 블로그 포스트 작성",
expected_output="2000자 이상의 구조화된 기술 블로그 포스트",
agent=writer,
context=[research_task], # research_task 결과를 입력으로 사용
)
fact_check_task = Task(
description="블로그 포스트의 사실 관계 검증",
expected_output="검증 완료된 최종 포스트 + 수정 사항 목록",
agent=fact_checker,
context=[writing_task],
)
# ── 크루 구성 + 실행 ──
crew = Crew(
agents=[researcher, writer, fact_checker],
tasks=[research_task, writing_task, fact_check_task],
process=Process.sequential, # sequential | hierarchical
verbose=True,
memory=True, # 크루 레벨 공유 메모리
embedder={
"provider": "openai",
"config": {"model": "text-embedding-3-small"}
}
)
result = crew.kickoff(
inputs={"topic": "LLM 에이전트 프레임워크 2026"}
)
print(result.raw) # 최종 결과 텍스트
# ── CrewAI가 빛나는 이유 ──
# 1. 가장 적은 코드로 멀티 에이전트 팀 구성
# 2. 내장 메모리 (short-term, long-term, entity, user)
# 3. backstory + goal = 에이전트 성격 자연어 정의
# 4. hierarchical process: 매니저 에이전트가 자동 위임
# CrewAI 선택 기준
✅ 선택해야 할 때:
- 스테이크홀더 데모, PoC, 빠른 프로토타입
- 역할 기반 협업 에이전트 (연구→작성→검증)
- 비개발자도 에이전트 정의 이해 가능해야 할 때
- 내장 메모리가 필요한 경우
❌ 피해야 할 때:
- 복잡해질수록 추상화 레이어 디버깅이 어려움
- 세밀한 상태 제어 필요 (LangGraph로)
- 타입 안전이 최우선 (PydanticAI로)
- "CrewAI 벽": 48K stars지만 복잡 워크플로에서 이탈 많음
4. Google ADK — 프로토콜 선도, GCP 네이티브
Google ADK는 A2A(Agent-to-Agent) 프로토콜 네이티브 지원으로 LangGraph, CrewAI 등 타 프레임워크로 만든 에이전트와 표준화된 태스크 인터페이스로 통신할 수 있습니다. 50개 이상의 파트너(Salesforce, ServiceNow 포함)가 A2A를 지원합니다.
from google.adk.agents import LlmAgent, SequentialAgent
from google.adk.tools import google_search, code_executor
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google import genai
# ── 서브 에이전트 정의 ──
research_agent = LlmAgent(
name="research_agent",
model="gemini-3.5-flash", # Gemini 네이티브
instruction="""당신은 리서치 전문 에이전트입니다.
Google 검색으로 최신 정보를 수집하세요.""",
tools=[google_search], # Google 서비스 네이티브 통합
output_key="research_result",
)
code_agent = LlmAgent(
name="code_agent",
model="gemini-3.5-flash",
instruction="리서치 결과를 바탕으로 Python 코드를 작성하고 실행하세요.",
tools=[code_executor], # 코드 실행 샌드박스
output_key="code_result",
)
# ── 오케스트레이터 (계층적 트리) ──
root_agent = SequentialAgent(
name="root_agent",
sub_agents=[research_agent, code_agent],
# ADK는 계층적 트리 구조
# 루트 → 서브 에이전트들 순차 또는 병렬 실행
)
# ── 세션 + 러너 설정 ──
session_service = InMemorySessionService()
runner = Runner(
agent=root_agent,
app_name="my-agent-app",
session_service=session_service,
)
# ── A2A 프로토콜로 타 프레임워크 에이전트 호출 ──
# ADK 에이전트가 LangGraph로 만든 에이전트를 호출하는 것이 가능
from google.adk.tools.a2a import A2ATool
external_agent_tool = A2ATool(
agent_url="http://langgraph-agent.internal/a2a",
# → LangGraph 에이전트를 ADK 툴로 사용
)
hybrid_agent = LlmAgent(
name="hybrid",
model="gemini-3.5-flash",
tools=[google_search, external_agent_tool], # 다른 프레임워크 에이전트 포함
)
# ── 멀티모달 (ADK 특화) ──
multimodal_agent = LlmAgent(
name="vision_agent",
model="gemini-3.5-flash", # 네이티브 멀티모달
instruction="이미지를 분석하고 관련 코드를 생성하세요.",
)
# 이미지 + 텍스트 동시 입력
from google.genai import types
response = runner.run(
session_id="session-1",
new_message=types.Content(parts=[
types.Part(text="이 UI 스크린샷을 보고 React 컴포넌트 만들어줘"),
types.Part(inline_data=types.Blob(
mime_type="image/png",
data=screenshot_bytes
))
])
)
# ── Google ADK가 빛나는 이유 ──
# 1. A2A: 다른 프레임워크 에이전트와 표준 통신
# 2. Gemini 멀티모달 네이티브 (이미지·오디오·영상 입력)
# 3. GCP Vertex AI, Cloud Run 배포 완전 통합
# 4. MCP + A2A + AG-UI 3가지 프로토콜 선도
# Google ADK 선택 기준
✅ 선택해야 할 때:
- GCP/Vertex AI 올인 팀
- 멀티모달 에이전트 (이미지·영상·음성 입력)
- A2A: 여러 프레임워크 에이전트 간 통신 필요
- Salesforce·ServiceNow 등 A2A 파트너 연동
❌ 피해야 할 때:
- GCP 외 클라우드 (AWS, Azure 배포 어려움)
- 커뮤니티 작음 → 디버깅 자료 부족
- OpenAI 모델 중심 팀
5. 12개 축 전체 비교 매트릭스
FRAMEWORK_MATRIX = {
"항목": ["LangGraph", "PydanticAI", "CrewAI", "Google ADK"],
# 기본 정보
"GitHub Stars": ["25K", "16.8K", "47K", "미공개"],
"월 다운로드": ["34.5M", "높음", "높음", "낮음"],
"언어": ["Python/JS", "Python", "Python", "Python/JS"],
# 기술 특성
"오케스트레이션 모델": [
"그래프(노드+엣지)",
"단일/멀티 에이전트",
"역할 기반 크루",
"계층적 트리"
],
"타입 안전": ["중간", "최고", "낮음", "중간"],
"MCP 지원": ["어댑터", "네이티브", "어댑터", "네이티브"],
"A2A 지원": ["❌", "❌", "❌", "✅ 네이티브"],
"내장 메모리": ["체크포인터(상태)", "❌ 직접 구현", "✅ 4가지 타입", "✅ 3가지 타입"],
"멀티모달": ["❌", "모델 의존", "모델 의존", "✅ Gemini 네이티브"],
# 개발 경험
"학습 곡선": ["가파름", "FastAPI 팀은 쉬움", "가장 완만", "중간"],
"프로토타입 속도": ["느림", "중간", "가장 빠름", "중간"],
"테스트 용이성": ["중간(LangSmith)", "최고(TestModel)", "낮음", "중간"],
# 프로덕션
"프로덕션 성숙도": ["가장 성숙", "빠르게 성숙 중", "중간", "초기"],
"배포 유연성": ["높음", "높음", "높음", "GCP 최적화"],
"옵저버빌리티": ["LangSmith 최강", "Logfire/OTel", "제한적", "Cloud Trace"],
"프로덕션 레퍼런스": ["Uber·Klarna·JPMorgan", "증가 중", "스타트업", "Google 고객"],
}
6. 동일 태스크 코드 비교 — "고객 지원 에이전트"
4개 프레임워크로 동일한 태스크(고객 문의 → DB 조회 → 답변)를 구현하면 코드 차이가 극명하게 드러납니다.
# ── LangGraph ──
from langgraph.graph import StateGraph, END
class State(TypedDict):
query: str
customer_data: dict
response: str
def fetch_customer(state):
data = db.query(state["query"])
return {"customer_data": data}
def generate_response(state):
resp = llm.call(state["query"], state["customer_data"])
return {"response": resp}
builder = StateGraph(State)
builder.add_node("fetch", fetch_customer)
builder.add_node("respond", generate_response)
builder.set_entry_point("fetch")
builder.add_edge("fetch", "respond")
builder.add_edge("respond", END)
graph = builder.compile()
# → 명시적, 완전한 통제, 코드 많음
# ── PydanticAI ──
@dataclass
class Deps:
db: Database
class Response(BaseModel):
answer: str
confidence: float
agent = Agent("anthropic:claude-sonnet-4-6",
deps_type=Deps, output_type=Response)
@agent.tool
async def get_customer(ctx: RunContext[Deps], query: str) -> dict:
"""고객 정보를 조회합니다."""
return await ctx.deps.db.fetch(query)
result = await agent.run("고객 문의 처리", deps=Deps(db=db))
# → 간결, 타입 안전, 중간 코드량
# ── CrewAI ──
support_agent = Agent(
role="고객 지원 전문가",
goal="고객 문의를 신속하고 정확하게 해결",
backstory="5년 경력 고객 지원 전문가입니다.",
tools=[DBQueryTool()],
llm="anthropic/claude-sonnet-4-6"
)
task = Task(
description="다음 고객 문의를 처리하세요",
agent=support_agent
)
crew = Crew(agents=[support_agent], tasks=[task])
result = crew.kickoff(inputs={"query": "고객 문의 내용"})
# → 가장 적은 코드, 자연어 정의
# ── Google ADK ──
support_agent = LlmAgent(
name="support_agent",
model="gemini-3.5-flash",
instruction="고객 지원 전문가로서 문의를 처리하세요.",
tools=[db_query_tool],
)
runner = Runner(agent=support_agent,
session_service=InMemorySessionService())
result = runner.run(session_id="s1", new_message=Content(...))
# → GCP 연동 쉬움, Gemini 최적화
7. 의사결정 트리 — 지금 어떤 걸 선택해야 하나
def choose_framework(requirements: dict) -> str:
"""
팀과 태스크에 맞는 프레임워크 선택
"""
# GCP 네이티브 또는 멀티모달
if requirements.get("gcp_native") or requirements.get("multimodal"):
return "Google ADK"
# 규제 환경 또는 복잡한 워크플로
if (requirements.get("regulated_env") or # 금융, 의료, 법률
requirements.get("complex_workflow") or # 많은 조건 분기
requirements.get("audit_trail") or # 모든 결정 감사 필요
requirements.get("hitl_required")): # 인간 승인 단계
return "LangGraph"
# 빠른 프로토타입 또는 데모
if (requirements.get("fast_prototype") or
requirements.get("role_based_team") or # 연구→작성→검증 역할 분담
requirements.get("built_in_memory")): # 내장 메모리 필요
return "CrewAI"
# 타입 안전 또는 FastAPI 팀
if (requirements.get("type_safety") or
requirements.get("fastapi_team") or
requirements.get("testability")): # CI/CD 테스트 중요
return "PydanticAI"
# 기본값: 팀 규모와 복잡도에 따라
if requirements.get("team_size", 5) > 20:
return "LangGraph" # 큰 팀 = 프로덕션 성숙도 중요
else:
return "PydanticAI" # 작은 팀 = 빠른 개발 + 타입 안전
# 실제 사용 케이스 → 프레임워크 매핑
use_case_map = {
"고객 지원 챗봇 (단순)": "PydanticAI",
"금융 거래 승인 파이프라인": "LangGraph",
"리서치→작성→검증 멀티에이전트": "CrewAI",
"이미지 분석 에이전트": "Google ADK",
"스프린트 내 MVP 데모": "CrewAI",
"Klarna 수준 프로덕션 에이전트": "LangGraph",
"FastAPI 기반 서비스에 AI 추가": "PydanticAI",
"GCP Vertex AI 배포 에이전트": "Google ADK",
}
8. 2026년 현실 — 팀들이 실제로 선택하는 것
# 실제 채택 패턴 (2026년 Q2 기준)
프로덕션 엔터프라이즈:
LangGraph + LangSmith
"체크포인터, 감사 추적, 400개 기업 레퍼런스"
Uber, Klarna, LinkedIn, JPMorgan 사용
스타트업 PoC/데모:
CrewAI → 한 달 후 LangGraph 마이그레이션
"CrewAI 벽": 처음엔 빠른데 복잡해질수록 한계
FastAPI Python 팀:
PydanticAI 빠르게 증가 중
"같은 패턴, 타입 안전, 테스트 가능"
GCP 올인 팀:
Google ADK
"Gemini + Vertex AI + A2A 패키지 딜"
현실적 조합:
프로토타입: CrewAI
↓ 복잡해지면 마이그레이션
프로덕션: LangGraph (복잡 워크플로)
또는 PydanticAI (단순 에이전트)
결론
✅ 4파전 한줄 요약
- LangGraph: 가장 많은 프로덕션 레퍼런스, 복잡한 워크플로의 정답, 학습 비용 감수
- PydanticAI: 타입 안전의 정석, FastAPI 팀의 자연스러운 선택, 단순~중간 에이전트
- CrewAI: 역할 기반 프로토타입 최강, 빠른 데모, 복잡해지면 벽 만남
- Google ADK: A2A 프로토콜 선도, 멀티모달, GCP 올인 팀만
✅ 2026년 선택 원칙
- 프레임워크를 먼저 고르지 말 것 — 풀려는 문제의 복잡도가 먼저
- "CrewAI로 시작 → 복잡해지면 LangGraph"가 가장 흔한 실전 경로
- 단일 정답 없음 — 투트랙(프로토타입용 + 프로덕션용) 전략이 현실적
❌ 흔한 실수
- GitHub Stars로 선택 (CrewAI 47K > LangGraph 25K지만 프로덕션은 LangGraph가 앞섬)
- 복잡 워크플로에 CrewAI 고집 → 6개월 후 마이그레이션 비용
- 프로덕션 레디 전에 Google ADK 선택 → 커뮤니티 얇아서 디버깅 고통
관련 글
'AI Agent' 카테고리의 다른 글
| Pydantic Evals 실전 — 타입 안전 LLM 평가 데이터셋 구축과 프로덕션 회귀 탐지 (0) | 2026.05.29 |
|---|---|
| PydanticAI 완전가이드 2026 — FastAPI 철학의 에이전트 프레임워크 (0) | 2026.05.29 |
| OpenTelemetry로 LLM 에이전트 추적 — 스팬 계측, 토큰 비용 추적, 프로덕션 디버깅 (0) | 2026.05.29 |
| Instructor 라이브러리로 구조화 출력 실전 2026 — LLM에서 신뢰할 수 있는 JSON을 뽑는 법 (0) | 2026.05.29 |
| 멀티에이전트 시스템: 오케스트레이터-워커 병렬 에이전트 패턴 — N개 서브태스크 동시 실행, 비용·레이턴시 트레이드오프 계산 (0) | 2026.05.29 |