
LangGraph 완전 가이드: AI 에이전트를 위한 그래프 기반 오케스트레이션의 모든 것
LLM 에이전트는 직선 파이프라인이 아니라 '생각하고, 행동하고, 관찰하고, 다시 생각하는' 루프다. LangGraph는 이 루프를 그래프 기반 상태 머신으로 구현한다. 핵심 개념부터 실전 패턴, Klarna·Uber의 프로덕션 사례, 커뮤니티 베스트 프랙티스까지 총정리한다.

LLM 에이전트는 직선 파이프라인이 아니라 '생각하고, 행동하고, 관찰하고, 다시 생각하는' 루프다. LangGraph는 이 루프를 그래프 기반 상태 머신으로 구현한다. 핵심 개념부터 실전 패턴, Klarna·Uber의 프로덕션 사례, 커뮤니티 베스트 프랙티스까지 총정리한다.
LangChain의 Chain은 직선 파이프라인이다. 프롬프트 → LLM → 출력 파서. A → B → C. 단순하고 예측 가능하다.
하지만 AI 에이전트는 이렇게 작동하지 않는다.
에이전트에게 "내일 서울 날씨를 확인하고, 비가 온다면 실내 데이트 코스를 추천해줘"라고 하면:
분기, 루프, 조건부 실행 — Chain의 직선 구조로는 표현할 수 없다. 이것이 2024년 1월, LangChain 팀이 LangGraph를 만든 이유다.
LangGraph는 장기 실행(long-running), 상태 유지(stateful) AI 에이전트를 위한 그래프 기반 오케스트레이션 프레임워크다.
핵심 차이를 비유로 표현하면:
LangGraph를 설계한 팀은 LLM 에이전트의 세 가지 근본적 특성을 파악했다:
| 특성 | 의미 | 필요한 것 |
|---|---|---|
| 느리다 | LLM 호출에 수 초 소요 | 병렬화, 스트리밍 |
| 불안정하다 | 장시간 에이전트는 중간에 실패 | 체크포인팅, 재시도 |
| 비결정적이다 | 같은 입력에 다른 출력 | 사람 개입, 추적 |
기존 도구로는 이 세 가지를 동시에 해결할 수 없었다. DAG 기반 워크플로(Apache Airflow)는 루프를 지원하지 않고, 내구성 실행 엔진(Temporal)은 스트리밍을 지원하지 않았다. LangGraph는 루프 + 체크포인팅 + 스트리밍을 모두 지원하는 에이전트 런타임으로 설계되었다.
내부적으로는 Bulk Synchronous Parallel(BSP)/Pregel 알고리즘 위에 구축되어, 결정론적 동시성과 완전한 루프 지원을 보장한다.
State는 그래프의 모든 노드가 공유하는 데이터 구조다. 질문, 중간 결과, 에러 카운트, 대화 기록 등이 담긴다.
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[list, add_messages] # 대화 기록
search_results: list[str] # 검색 결과
retry_count: int # 재시도 횟수
Annotated[list, add_messages]가 핵심이다. add_messages는 리듀서(reducer) — 노드가 반환한 부분 업데이트를 기존 상태에 어떻게 병합할지 정의한다. add_messages는 새 메시지를 기존 목록에 추가하고, 같은 ID의 메시지는 덮어쓴다.
핵심 원칙: 노드는 전체 상태가 아니라 변경할 부분만 반환한다. LangGraph가 리듀서를 통해 자동으로 병합한다.
Node는 현재 상태를 받아 작업을 수행하고, 상태 업데이트를 반환하는 Python 함수다.
def search_node(state: AgentState):
"""관련 문서를 검색하는 노드"""
query = state["messages"][-1].content
results = search_engine.search(query)
return {"search_results": results}
def generate_node(state: AgentState):
"""검색 결과를 바탕으로 답변을 생성하는 노드"""
context = "\n".join(state["search_results"])
response = llm.invoke(
f"컨텍스트: {context}\n질문: {state['messages'][-1].content}"
)
return {"messages": [response]}
일반 엣지는 무조건적 이동, 조건부 엣지는 상태에 따라 다음 노드를 결정한다.
from langgraph.graph import StateGraph, START, END
builder = StateGraph(AgentState)
builder.add_node("search", search_node)
builder.add_node("generate", generate_node)
builder.add_node("evaluate", evaluate_node)
# 일반 엣지: 항상 이 경로로
builder.add_edge(START, "search")
builder.add_edge("search", "generate")
# 조건부 엣지: 상태에 따라 분기
builder.add_conditional_edges(
"evaluate",
lambda state: "retry" if state["retry_count"] < 3
else "end",
{"retry": "search", "end": END}
)
LangGraph는 매 노드 실행 후 자동으로 상태를 저장한다. 에이전트가 3번째 단계에서 실패해도, 1번부터 다시 시작할 필요 없이 3번째부터 재개할 수 있다.
from langgraph.checkpoint.memory import MemorySaver
# 개발용: 메모리 체크포인터
graph = builder.compile(checkpointer=MemorySaver())
# 프로덕션: PostgreSQL 체크포인터
from langgraph.checkpoint.postgres import PostgresSaver
graph = builder.compile(checkpointer=PostgresSaver(conn))
체크포인팅은 대화 메모리도 자연스럽게 해결한다. thread_id로 대화를 식별하면, 같은 스레드에서의 이전 상태가 자동으로 복원된다.
에이전트가 이메일을 보내거나, 주문을 실행하거나, 코드를 배포하기 전에 사람의 승인을 받아야 하는 경우가 많다.
from langgraph.types import interrupt, Command
def send_email_node(state: AgentState):
# 여기서 실행이 멈추고 사람에게 확인 요청
approval = interrupt({
"message": "이 이메일을 보내도 될까요?",
"draft": state["email_draft"]
})
if approval == "승인":
send_email(state["email_draft"])
return {"status": "sent"}
else:
return {"status": "cancelled"}
interrupt()에서 그래프 실행이 일시 정지된다. 사람이 승인/거절을 보내면 Command(resume="승인")으로 재개된다. 이 사이에 체크포인팅이 상태를 보존하므로, 아무것도 잃어버리지 않는다.
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""도시의 현재 날씨를 가져옵니다."""
return f"{city}: 흐림, 18°C, 강수확률 80%"
@tool
def search_places(query: str) -> str:
"""장소를 검색합니다."""
return f"'{query}' 검색 결과: 카페A, 영화관B, 미술관C"
agent = create_agent(
model="openai:gpt-4o",
tools=[get_weather, search_places],
prompt="날씨와 장소 추천을 도와주는 어시스턴트입니다.",
)
result = agent.invoke({
"messages": [{"role": "user",
"content": "내일 서울 날씨 보고 실내 데이트 추천해줘"}]
})
이전 글에서 다룬 Corrective RAG를 LangGraph로 구현하는 패턴이다.
이 패턴이 강력한 이유: 검색이 실패해도 포기하지 않고 다른 전략을 시도한다. 쿼리를 재작성하거나, 웹 검색으로 전환하거나, 여러 번 반복하여 답변 품질을 끌어올린다.
복잡한 작업을 전문화된 하위 에이전트에게 분배하는 패턴이다.
Swarm 패턴도 있다 — 감독자 없이 에이전트들이 직접 작업을 넘기는 분산형 구조. 벤치마크에서 Supervisor 대비 응답 시간 40% 단축을 보였다.
# 5가지 스트리밍 모드 중 선택
async for event in graph.astream(
input, config, stream_mode="messages"
):
# 토큰이 생성될 때마다 실시간으로 받음
print(event.content, end="", flush=True)
| 모드 | 용도 |
|---|---|
values | 각 노드 후 전체 상태 |
updates | 상태 변경분만 (대역폭 효율적) |
messages | 토큰 단위 LLM 출력 (챗봇 UX) |
custom | 앱 전용 이벤트 |
debug | 전체 실행 추적 |
from langgraph.prebuilt import ToolNode
from langgraph.types import RetryPolicy
# 레벨 1: 도구 에러를 LLM에 전달하여 자체 수정
tool_node = ToolNode(
tools,
handle_tool_errors=True # 에러를 ToolMessage로 변환
)
# 레벨 2: 노드 수준 자동 재시도
builder.add_node(
"api_call", call_external_api,
retry=RetryPolicy(
max_attempts=3,
initial_interval=1.0,
backoff_factor=2.0
)
)
# 레벨 3: 그래프 수준 루프 제한
def should_continue(state):
if state.get("retry_count", 0) >= 5:
return "fallback" # 안전한 대체 경로
return "retry"
복잡한 워크플로를 모듈화하기 위해 그래프 안에 그래프를 중첩한다.
# RAG 서브그래프
rag_subgraph = create_rag_graph()
# 메인 그래프에 서브그래프를 노드로 추가
main_builder = StateGraph(MainState)
main_builder.add_node("rag", rag_subgraph)
main_builder.add_node("code_gen", code_gen_graph)
체크포인터는 부모에서 자식 서브그래프로 자동으로 전파된다.
스웨덴 핀테크 기업 Klarna는 LangGraph로 AI 고객 지원 어시스턴트를 구축했다.
| 지표 | 개선 |
|---|---|
| 해결 시간 | 11분 → 2분 이내 (80% 감소) |
| 반복 문의율 | 25% 감소 |
| 자동화 비율 | 반복 업무의 70% 자동화 |
| 인력 효과 | 700명 FTE 상당 |
Uber는 LangGraph로 코드 마이그레이션 오케스트레이션 시스템을 구축했다. 전문화된 에이전트 네트워크가 유닛 테스트를 자동 생성하며, 대규모 코드베이스의 마이그레이션을 체계적으로 수행한다.
보안 기업 Elastic은 LangGraph로 AI 에이전트 네트워크를 오케스트레이션하여 실시간 보안 위협을 탐지한다. 여러 에이전트가 각각 다른 보안 데이터 소스를 모니터링하고, 이상 징후를 감지하면 조율된 대응을 실행한다.
부동산 관리 소프트웨어 기업 AppFolio는 LangGraph로 부동산 매니저용 코파일럿을 구축했다. 주당 10시간 이상 절약, 의사결정 정확도 2배 향상을 보고했다.
최소화하라. 상태에는 정말 필요한 것만 넣는다. "혹시 나중에 쓸지 모르니"라며 모든 것을 상태에 넣으면 체크포인팅 비용이 늘고, 디버깅이 어려워진다.
타입을 명시하라. TypedDict나 Pydantic으로 상태를 정의하면 런타임 에러를 예방하고, IDE 자동완성도 지원된다.
리듀서를 이해하라. add_messages를 쓰면 메시지가 누적되고, 리듀서 없이 쓰면 덮어쓴다. 이 차이를 모르면 대화 기록이 사라지는 버그가 발생한다.
단순하게 시작하라. 처음부터 복잡한 멀티 에이전트를 만들지 말고, 가장 간단한 직선 그래프에서 시작해 필요할 때만 분기를 추가한다.
루프에 반드시 탈출 조건을 넣어라. 가장 흔한 실수 — 무한 루프. max_steps 카운터를 상태에 넣고, 제한에 도달하면 강제 종료한다.
def should_retry(state):
if state["retry_count"] >= 3:
return "give_up" # 반드시 탈출 경로
return "retry"
조건부 엣지 디버깅: 라우팅 함수가 반환하는 문자열이 매핑 딕셔너리의 키와 정확히 일치해야 한다. 오타 하나로 전체 그래프가 멈출 수 있다.
독립적인 작업은 병렬화하라. Send API로 여러 노드를 동시에 실행할 수 있다.
스트리밍 모드를 적절히 선택하라. 챗봇이라면 messages (토큰 단위), 백엔드 모니터링이라면 updates (변경분만), 디버깅이라면 debug.
비핵심 단계에는 저렴한 모델을 쓰라. 라우팅이나 평가 단계에 GPT-4o가 필요한가? 대부분 GPT-4o-mini로 충분하다.
대화 기록이 너무 길어지면 요약하라. 토큰이 계속 누적되면 비용이 급증한다. 일정 길이를 넘으면 과거 대화를 요약하는 노드를 추가한다.
그래프 수준 테스트를 작성하라. 개별 노드 단위 테스트뿐 아니라, 전체 그래프의 상태 흐름과 엣지 선택을 테스트하는 통합 테스트가 필수다.
LLM과 도구를 Mock하라. 결정론적 테스트를 위해 LLM 호출과 외부 도구를 모킹한다.
| 상황 | 더 나은 대안 |
|---|---|
| 단순 RAG 파이프라인 | 직접 코딩 또는 LangChain LCEL |
| 직선형 워크플로 | LangChain Chain |
| 빠른 프로토타입 | CrewAI (역할 기반 팀 구성) |
| 분기·루프·재시도가 필요한 복잡한 에이전트 | LangGraph ✓ |
LangGraph Studio는 에이전트 워크플로를 시각적으로 디버깅하는 도구다.
주요 기능:
2025년 10월부터 LangSmith Deployment로 리브랜딩되었으며, 클라우드(SaaS), 하이브리드, 완전 셀프호스팅 옵션을 지원한다. 약 400개 기업이 이 플랫폼으로 에이전트를 배포 중이다.
| 기준 | LangGraph | CrewAI | AutoGen |
|---|---|---|---|
| 아키텍처 | 그래프 (순환 가능) | 역할 기반 팀 | 대화 기반 |
| 학습 곡선 | 가파름 (1~2주) | 완만 (수 시간) | 중간 |
| 디버깅 | Studio + LangSmith | 도전적 | 중간 |
| 최적 사용 | 복잡한 상태 관리, 규제 산업 | 빠른 프로토타입, 역할 분담 | 코드 생성, 연구 |
| 커뮤니티 | 38M+ 다운로드 | 44K+ 스타 | Microsoft 후원 |
langgraph.prebuilt → langchain.agents로 이전그래프를 명시적으로 정의하지 않고, 일반 Python 함수처럼 에이전트를 작성하는 새로운 방식:
from langgraph.func import entrypoint, task
from langgraph.checkpoint.memory import MemorySaver
@task
def research(topic: str) -> str:
return llm.invoke(f"Research: {topic}")
@task
def write(research: str) -> str:
return llm.invoke(f"Write article: {research}")
@entrypoint(checkpointer=MemorySaver())
def workflow(topic: str) -> str:
data = research(topic).result()
return write(data).result()
@entrypoint와 @task 데코레이터만으로 체크포인팅, 재시도, 사람 개입이 모두 작동한다. 내부적으로는 같은 LangGraph 런타임 위에서 동작한다.
LangGraph 위에 구축된 장기 실행 에이전트 하니스:
write_todos 도구)ls, read_file, write_file, edit_file)task 도구)LangGraph를 시작하려면:
1단계 — 공식 무료 강의 (추천)
2단계 — 실전 튜토리얼
3단계 — 고급 주제
참고 자료
LangGraph의 핵심 가치는 한 문장으로 요약된다:
LLM 에이전트의 내재적 복잡성(분기, 루프, 실패, 비결정성)을 체계적으로 관리할 수 있게 해준다.
단순한 RAG 파이프라인이나 직선형 워크플로에는 필요 없다. 하지만 에이전트가 "생각하고, 행동하고, 관찰하고, 다시 생각하는" 루프를 돌기 시작하면 — 그 루프에서 실패가 발생하고, 사람의 승인이 필요하고, 여러 에이전트가 협업해야 하면 — LangGraph는 현재 가장 성숙한 선택이다.
Klarna의 700 FTE 상당 자동화, Uber의 대규모 코드 마이그레이션, Elastic의 실시간 위협 탐지 — 이 프로덕션 사례들이 증명하듯, LangGraph는 이미 "실험"이 아니라 "인프라"의 영역에 들어와 있다.
참고 자료