LangGraph를 실무 흐름으로 이해하기
LangGraph로 상태를 가진 멀티스텝 Agent 워크플로우를 그래프로 설계합니다. 조건부 분기, 반복 루프, Human-in-the-loop 승인까지 — 단순 체인만으로는 어려운 복잡한 Agent 로직을 구축합니다. 이 가이드는 개념을 나열하기보다, 실제 프로젝트에서 판단해야 하는 순서대로 내용을 따라갈 수 있게 구성했습니다.
LangGraph로 상태를 가진 멀티스텝 Agent 워크플로우를 그래프로 설계합니다. 조건부 분기, 반복 루프, Human-in-the-loop 승인까지 — 단순 체인만으로는 어려운 복잡한 Agent 로직을 구축합니다.
LangGraph로 상태를 가진 멀티스텝 Agent 워크플로우를 그래프로 설계합니다. 조건부 분기, 반복 루프, Human-in-the-loop 승인까지 — 단순 체인만으로는 어려운 복잡한 Agent 로직을 구축합니다. 이 가이드는 개념을 나열하기보다, 실제 프로젝트에서 판단해야 하는 순서대로 내용을 따라갈 수 있게 구성했습니다.
모델과 프롬프트만 보지 않고, 데이터 흐름, 평가, 배포 이후의 운영 지표까지 한 번에 연결해서 봅니다.
글로 읽은 내용을 머릿속에 오래 남기려면 먼저 흐름을 그림으로 잡는 편이 좋습니다. 아래 두 그림은 LangGraph를 학습할 때 계속 되돌아볼 수 있는 기준 지도입니다.
LangGraph를 처음 펼칠 때는 세부 명령보다 큰 그림이 먼저입니다. 이 섹션에서는 앞으로 배울 개념들이 어떤 문제를 풀기 위해 등장했는지부터 잡아봅니다.
| 구분 | LangChain 체인 | LangGraph |
|---|---|---|
| 실행 흐름 | 고정된 선형 순서 | 조건에 따라 분기·반복하는 그래프 |
| 상태 관리 | 체인 호출 간 암묵적 전달 | 명시적 State 스키마로 공유 |
| 중단/재개 | 어려움 | checkpoint로 특정 지점에서 멈추고 재개 가능 |
| 적합한 경우 | 단순 순차 파이프라인 | ReAct 루프, 멀티에이전트, 승인 필요 워크플로우 |
여기서는 StateGraph 기본 구조을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, START, END
import operator
class AgentState(TypedDict):
messages: Annotated[list, operator.add] # 노드마다 리스트에 추가됨
step_count: int
def call_model(state: AgentState) -> dict:
# 실제로는 LLM 호출 — 여기선 개념만 표현
return {"messages": ["모델 응답"], "step_count": state["step_count"] + 1}
def call_tool(state: AgentState) -> dict:
return {"messages": ["도구 실행 결과"], "step_count": state["step_count"] + 1}
graph = StateGraph(AgentState)
graph.add_node("model", call_model)
graph.add_node("tool", call_tool)
graph.add_edge(START, "model")
graph.add_edge("model", "tool")
graph.add_edge("tool", END)
app = graph.compile()
result = app.invoke({"messages": [], "step_count": 0})
print(result["step_count"])여기서는 조건부 분기을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.
def should_continue(state: AgentState) -> str:
last_message = state["messages"][-1]
if "final_answer" in last_message:
return "end"
if state["step_count"] >= 5:
return "end" # 무한 루프 방지용 상한
return "continue"
graph.add_conditional_edges(
"model",
should_continue,
{"continue": "tool", "end": END},
)여기서는 반복 루프 (ReAct)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.
graph.add_edge("tool", "model") # 도구 실행 후 다시 모델로 — 사이클 형성
# model --(계속 필요)--> tool --> model --(완료)--> END
# ↑___________________________|여기서는 Human-in-the-loop을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.
app = graph.compile(interrupt_before=["tool"]) # 도구 실행 전 항상 멈춤
state = app.invoke({"messages": [], "step_count": 0})
# 여기서 그래프가 멈춤 — 사람이 검토 후 승인하면 재개
if input("도구 실행을 승인할까요? (y/n) ") == "y":
result = app.invoke(None) # 멈춘 지점부터 이어서 실행이 섹션은 상태 영속화을 실무 관점에서 정리합니다. 개념을 외우기보다, 어떤 상황에서 이 기준을 꺼내 쓸지에 초점을 맞춰보세요.