LLM 이후 2025년부터 가장 핫한 키워드는 Agent입니다. Agent는 단순히 질문에 답변하는 LLM을 넘어, 목표(Task)를 달성하기 위해 여러 도구와 모델을 조합하여 문제를 해결하는 시스템을 의미합니다. 이제 특정 Task만을 처리하는 걸 넘어서 여러 LLM 기능을 조합하여 사용자의 요구사항을 스스로 분석하고 필요한 작업을 '알잘딱깔센'으로 수행하는 Agent 시스템에 대한 관심이 높아지고 있습니다. 이때 여러 Agent를 잘 설계하고 동작하기 위한 프레임워크가 존재하는데 그중 가장 많이 사용되는 LangGraph에 대해 자세히 설명해보고자 합니다.
1. 기존 Chain 기반 LLM Workflow의 한계
기존 LLM 애플리케이션은 대부분 LangChain의 Chain 구조처럼 단방향 파이프라인 방식으로 구성되어 복잡한 의사결정을 처리하기 어려웠습니다. 아래 그림처럼 유저의 쿼리가 입력되면 검색 후, LLM이 답변을 내놓는 단방향 파이프라인 구조를 가지는 경우를 가정해 보겠습니다. 이 구조는 단순한 Q&A 시스템에는 적용될 수도 있겠지만, 현실적인 AI 시스템을 만들기에는 여러 한계가 존재합니다. 검색이 실패하더라도 LLM은 문서가 없는 상태에서 자신의 사전지식만으로 답변을 생성하려고 합니다. 이때 Hallucination 문제가 발생할 수 있습니다. 또한, 검색된 답변이 잘못되었을 경우 이를 검증하고 재검색하거나 쿼리를 재작성하는 등의 프로세스를 추가하기 어렵습니다.

LangGraph는 이러한 한계를 해결하기 위해 그래프 기반 워크플로우로 LLM Agent 시스템을 설계할 수 있도록 만든 LangChain 생태계의 프레임워크입니다. 특히 Self-RAG, Multi-Agent, 복잡한 의사결정 시스템을 구현할 때 LangGraph의 장점이 돋보입니다.
위 단방향 파이프라인을 랭그래프를 이용한다면 아래와 같이 구조를 설계할 수 있습니다.
문서를 검색한 후, 검색된 문서에 대해서 관련있는지 평가하여 쿼리를 재작성하거나 웹서치를 통해 관련 있는 맥락을 추가할 수 있습니다. 최종 답변에 대해서도 평가를 거쳐 문제가 있으면 다시 쿼리를 다시 작성하도록 하여 답변 퀄리티를 보장할 수 있게 파이프라인을 구축할 수 있습니다.

위 그림처럼 LangGraph의 핵심 아이디어는 LLM Workflow를 단순한 파이프라인이 아닌 Graph 구조로 설계하자는 것입니다.
2. LangGraph의 핵심 구조
LangGraph는 다음 3가지 개념으로 구성됩니다.
- node : 작업수행
- Edge : 실행 흐름
- State : 공유 데이터
1) Node: 작업 단위
Node는 하나의 작업(Task)을 의미합니다. 예를 들면 다음과 같은 작업이 Node가 됩니다.
- 문서 검색
- Query 재작성
- 답변 생성
- 답변 평가
노드는 Python 함수로 구현되며, 입력으로 State를 받고 업데이트된 State를 반환하는 방식으로 동작합니다.
def retrieve_docs(state):
question = state["question"]
docs = retriever.invoke(question)
return {
"context": docs
}
2) Edge: 실행 흐름
Edge는 노드 간 실행 흐름을 정의합니다. 그래프의 화살표에 해당하는 것으로 A라는 작업 후에 어떤 작업을 할지를 명시합니다. 예를 들어, 검색 노드 실행 후 검색에 대한 평가 노드 실행한다면 아래와 같이 각 노드를 엣지로 연결합니다.
builder.add_edge("retrieve", "document_evaluator")
무조건 연계된 작업이라면 엣지로 연결하면 되지만, 조건에 따라 다른 작업을 하고 싶다면 조건부 edge를 이용할 수 있습니다. LangGraph의 핵심 기능 중 하나로, 특정 조건에 따라 노드를 이동할 수 있습니다. LangGraph는 노드 간 순환 구조(Cycle)를 허용하기 때문에 특정 조건이 충족될 때까지 작업을 반복하는 Agent workflow를 자연스럽게 구현할 수 있습니다.
예
답변평가
↓
OK → 종료
BAD → 재검색
코드
builder.add_conditional_edges(
"check_answer",
decide_next,
{
"good": END,
"bad": "rewrite_query"
}
)
3) State: 노드 간 데이터 공유
LangGraph는 State 객체를 통해 정보를 공유합니다. 보통 TypedDict로 정의하며 작업을 진행하면서 계속 간직하고 있어야 할 데이터를 명시합니다. 해당 State에 정의된 데이터는 모든 노드가 공유합니다. 기본적으로는 값을 덮어쓰는 방식으로 동작하지만, Reducer를 사용하면 메시지처럼 데이터를 누적하여 저장할 수도 있습니다.
from typing import TypedDict
class GraphState(TypedDict):
question: str
context: str
answer: str
relevance: str
3. LangGraph 기본 구현 예제 : 숫자 판별 그래프
간단한 조건 분기 그래프를 구현해 보며 LangGraph가 어떻게 workflow를 설계하는지 이해해 보겠습니다.
구현하고자 하는 그래프는 숫자 판별 그래프로 5를 넘는 숫자가 입력되면 승리, 이하면 패배를 출력하는 간단한 조건 분기 그래프입니다.
그래프 생성 과정
1 State 정의
2 Node 정의
3 Graph 생성
4 Edge 연결
5 Compile 및 실행
설치
pip install langgraph
기본 코드 예제
Python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
# 1. 상태 정의 (모든 노드가 공유할 데이터 구조)
class MyState(TypedDict):
number: int
result: str
# 2. 노드 정의 (실제 작업을 수행하는 함수)
def check_number(state: MyState):
print(f"입력된 숫자: {state['number']}")
return state
def win_node(state: MyState):
return {"result": "승리!"}
def lose_node(state: MyState):
return {"result": "패배..."}
# 조건부 로직 정의 (어떤 노드로 갈지 결정)
def decide_path(state: MyState):
return "win" if state["number"] > 5 else "lose"
# 3. 그래프 구축
builder = StateGraph(MyState)
# 노드 추가
builder.add_node("check", check_number)
builder.add_node("win", win_node)
builder.add_node("lose", lose_node)
# 4. 경로(엣지) 연결
builder.add_edge(START, "check") # 시작점을 check 노드로 설정
builder.add_conditional_edges(
"check",
decide_path,
{"win": "win", "lose": "lose"} # 결과에 따라 win 또는 lose 노드로 분기
)
builder.add_edge("win", END) # 종료
builder.add_edge("lose", END)
# 5. 컴파일 및 실행
app = builder.compile()
output = app.invoke({"number": 8})
print(output["result"]) # 출력: 승리!`
# 그래프 그리기
app.get_graph(xray=True).draw_mermaid_png(output_file_path='graph_simple.png')

4. LangGraph의 장점
1. 그래프 기반 아키텍처
- 워크플로우를 노드(Node, 작업 단위)와 엣지(Edge, 실행 경로)로 정의하여 작업이 단순 일직선이 아닌, 순환, 분기 및 병렬로 실행되는 복잡한 구조 구현이 가능합니다.
- 예를 들어, 노드 간 순환 구조를 허용하기 때문에 "검색 → 답변 생성 → 검증 → 재검색"과 같은 반복적인 워크플로우도 자연스럽게 구현할 수 있습니다.
- LangGraph는 명확하게 정의된 그래프 구조를 기반으로 Agent의 실행 흐름을 제어할 수 있습니다. 이를 통해 복잡한 Agent 시스템에서도 예측 가능한 실행 흐름을 설계할 수 있습니다.
- 또한, LangGraph로 구현하는 workflow를 시각화하여 저장도 가능합니다.
from IPython.display import Image, display
display(
Image(app.get_graph(xray=True).draw_mermaid_png())
)
2. 세밀한 상태 관리 (State Management)
- 모든 노드가 공유하고 업데이트할 수 있는 중앙 집중식 '상태(State)' 객체를 사용해 에이전트가 수행 중인 작업의 맥락을 잃지 않도록 돕는 공유 메모리 역할을 합니다.
3. 지속성 및 체크포인팅 (Persistence & Checkpointing)
- 워크플로우의 매 단계마다 상태를 자동으로 저장하는 '체크포인터' 기능을 지원하여 시스템 장애 시 중단된 지점부터 복구하거나, 며칠 뒤에 대화를 재개하는 등의 구현이 가능합니다.
- MemorySaver를 체크포인터로 사용하면 특정 thread_id를 기반으로 대화 내용을 기억할 수 있습니다.
from langgraph.checkpoint.memory import InMemorySaver
# 체크포인터 생성
memory = InMemorySaver()
# 그래프 컴파일 시 체크포인터 등록
app = builder.compile(checkpointer=memory)
# 실행 시 thread_id를 포함한 설정 전달
config = {"configurable": {"thread_id": "user_session_123"}}
app.invoke({"number": 10}, config=config)
4. 인간 개입 (Human-in-the-Loop)
- Agent의 특정 행동 전에 실행을 일시 중지하고 사람의 승인이나 수정을 기다리는 '인터럽트(Interrupt)' 기능을 제공합니다.
- interrupt_before 설정을 사용하면 특정 노드가 실행되기 직전에 그래프를 멈추고 사람의 입력을 기다리게 할 수 있습니다.
# 'win' 노드 실행 전에 멈추도록 설정
app = builder.compile(checkpointer=memory, interrupt_before=["win"])
# 실행 도중 'win' 노드 직전에서 일시 정지됨
app.invoke({"number": 10}, config=config)
# 사람이 확인 후 다시 실행하려면 input에 None을 넣어 호출
app.invoke(None, config=config)
5. 서브그래프 (Subgraph)
- LangGraph는 Subgraph 기능을 제공하여 복잡한 워크플로우를 여러 개의 작은 그래프로 분리하여 모듈화할 수 있습니다.
- 이를 통해 Multi-Agent 시스템 설계를 용이하게 합니다.
이번 포스팅에서는 Agent 설계에 많이 사용되는 LangGraph의 구성요소와 장점, 구현코드를 다뤄 봤습니다. 다음 포스팅에는 본격적으로 LangGraph를 활용해 실제 Multi-Agent 시스템을 설계하는 방법을 구체적인 예제와 함께 살펴보겠습니다.
'AI' 카테고리의 다른 글
| [논문 리뷰] : Selective review of offline change point detection methods - (1) 변화점 탐지와 비용함수 (1) | 2026.02.15 |
|---|---|
| [논문리뷰] ALCM: Autonomous LLM-Augmented Causal Discovery Framework (7) | 2025.07.23 |
| [Causal Analysis] PC 알고리즘 (1) | 2025.03.30 |
| 효과적인 프롬프트 엔지니어링 (기초) : 프롬프트 구성요소와 효과적인 프롬프트 구조 (0) | 2025.03.02 |
| LLM 기법(Fine-tuning, RAG) 설명 및 적용 가이드 (0) | 2025.02.16 |