LangGraph 입문 — 상태 기반 워크플로우 만들기
· LangGraph는 LangChain 위에서 동작하며, 작업 흐름을 그래프(노드와 엣지) 형태로 그려 복잡한 LLM 애플리케이션을 설계하도록 돕는 도구예요.
· 핵심은 상태(State)라는 공유 메모리로, 각 노드가 이 상태를 읽고 갱신하며 다음 단계로 넘겨 줍니다.
· 덕분에 조건 분기·반복·되돌아가기처럼 일직선 체인으로는 표현하기 어려운 흐름을 자연스럽게 만들 수 있습니다.
LangChain으로 체인을 엮다 보면, 어느 순간 일직선 흐름의 한계를 느끼게 됩니다. "이 조건이면 A 단계로, 아니면 B 단계로 보내고 싶다", "결과가 만족스럽지 않으면 앞 단계로 되돌아가 다시 시도하고 싶다" 같은 요구가 생기기 때문이죠. 이런 복잡한 흐름을 깔끔하게 표현하기 위해 등장한 것이 바로 LangGraph입니다. 오늘은 LangGraph가 무엇이고, 그 중심에 있는 상태(State)라는 개념이 어떻게 전체 흐름을 이끄는지 차근차근 살펴보겠습니다.
🤔 왜 체인만으로는 부족할까
기본적인 체인은 입력 → 처리 → 출력으로 이어지는 한 방향 흐름입니다. 간단한 질문-응답에는 충분하지만, 실제 애플리케이션은 그보다 훨씬 복잡한 경우가 많아요. 예를 들어 답을 만든 뒤 품질을 점검하고, 기준에 못 미치면 다시 생성하도록 되돌리는 흐름을 생각해 봅시다.
이런 분기와 반복은 일직선 체인으로 표현하기가 상당히 까다롭습니다. LangGraph는 작업 흐름을 그래프로 바라봅니다. 각 작업을 점(노드)으로 두고, 그 사이를 선(엣지)으로 이으면, 갈림길도 되돌아가는 길도 자연스럽게 그릴 수 있게 되죠.
LangGraph의 발상은 "흐름을 한 줄로 늘어놓지 말고, 지도처럼 그려 보자"는 것입니다.
🧩 LangGraph의 세 가지 재료 — 상태·노드·엣지
LangGraph를 이해하려면 세 가지 요소만 기억하면 됩니다. 이 셋이 어우러져 하나의 워크플로우를 이룹니다.
정리하면 노드가 일을 하고, 엣지가 길을 안내하며, 상태가 그 사이를 흐르는 데이터입니다. 이 셋을 조립하는 것이 곧 LangGraph로 워크플로우를 만드는 일이에요.
📦 상태(State)가 흐름을 이끈다
LangGraph에서 가장 중요한 개념은 단연 상태(State)입니다. 상태는 그래프가 도는 동안 계속 들고 다니는 데이터 묶음이에요. 보통 질문, 중간 결과, 최종 답변처럼 흐름에 필요한 값들을 담습니다.
각 노드는 이 상태를 입력으로 받아 자기 일을 한 뒤, 바뀐 부분을 돌려줍니다. 그러면 LangGraph가 그 변경분을 상태에 반영하고, 다음 노드로 넘겨 주죠. 즉 노드들은 서로 직접 대화하지 않고, 오직 상태를 통해서만 정보를 주고받습니다. 이 구조 덕분에 흐름이 아무리 복잡해져도 데이터가 지금 어떤 상태인지를 한곳에서 파악할 수 있습니다.
💻 코드로 보는 가장 작은 그래프
개념을 코드로 옮겨 보겠습니다. 상태의 모양을 정의하고, 노드 함수를 만든 뒤, 그래프에 노드와 엣지를 등록하는 순서입니다.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
# 1) 상태의 모양을 정의한다
class State(TypedDict):
question: str
answer: str
# 2) 노드 함수 — 상태를 받아 바뀐 부분을 돌려준다
def answer_node(state: State):
q = state["question"]
return {"answer": f"'{q}'에 대한 답변입니다"}
# 3) 그래프에 노드와 엣지를 등록한다
builder = StateGraph(State)
builder.add_node("answer", answer_node)
builder.add_edge(START, "answer")
builder.add_edge("answer", END)
graph = builder.compile()
result = graph.invoke({"question": "LangGraph가 뭐예요?"})
print(result["answer"])
흐름을 따라가 보면, START에서 출발해 answer 노드를 거쳐 END로 끝납니다. 노드는 상태에서 question을 꺼내 쓰고, answer라는 바뀐 부분만 돌려줬어요. 이렇게 상태의 모양 → 노드 → 엣지 순으로 조립하는 것이 LangGraph의 기본 패턴입니다.
🔀 조건 분기로 흐름 나누기
LangGraph의 진짜 강점은 갈림길을 만들 수 있다는 점입니다. 상태의 값에 따라 다음에 어느 노드로 갈지를 그때그때 결정할 수 있어요. 이를 조건부 엣지(conditional edge)라고 부릅니다.
# 상태를 보고 다음 노드 이름을 돌려주는 판단 함수
def route(state: State):
if state["answer"]:
return "done" # 답이 있으면 종료 쪽으로
return "retry" # 없으면 다시 시도 쪽으로
builder.add_conditional_edges(
"answer", # 이 노드 다음에
route, # 이 함수로 길을 고른다
{"done": END, "retry": "answer"},
)
여기서 route 함수는 상태를 들여다보고 다음에 갈 곳의 이름을 돌려줍니다. 답이 있으면 종료로, 없으면 다시 answer 노드로 돌아가게 되죠. 이렇게 상태에 기반해 길이 갈라지는 구조가, 일직선 체인과 LangGraph를 가르는 핵심 차이입니다.
🔧 실무 팁
- 상태 설계부터 시작하라 — 그래프를 그리기 전에 어떤 값을 들고 다닐지부터 정하면, 노드를 만들 때 훨씬 수월합니다.
- 노드는 작게 쪼개라 — 하나의 노드가 너무 많은 일을 하면 디버깅이 어렵습니다. 한 노드엔 한 가지 책임이 좋습니다.
- 반복 흐름엔 종료 조건을 꼭 두라 — 되돌아가는 경로를 만들 때는 언제 멈출지를 상태로 관리해, 무한 반복에 빠지지 않도록 하세요.
- 먼저 흐름을 그려 보라 — 코드를 쓰기 전에 노드와 엣지를 종이에 그려 보면, 복잡한 워크플로우도 머릿속이 정리됩니다.
❓ 자주 묻는 질문 (FAQ)
Q. LangGraph는 LangChain을 대체하나요?
A. 대체라기보다 보완에 가깝습니다. LangChain이 모델 호출·프롬프트 같은 부품을 제공한다면, LangGraph는 그 부품들을 복잡한 흐름으로 엮는 틀을 제공합니다.
Q. 간단한 질문-응답에도 LangGraph가 필요한가요?
A. 꼭 그렇지는 않습니다. 일직선 흐름으로 충분하다면 기본 체인이 더 간결해요. 분기·반복·되돌아가기가 필요해질 때 LangGraph가 빛을 발합니다.
Q. 상태에는 아무 값이나 담아도 되나요?
A. 흐름에 필요한 값을 담으면 됩니다. 다만 상태의 모양을 미리 정의해 두면, 어떤 데이터가 오가는지 명확해져 관리가 쉬워집니다.
마무리
정리하면, LangGraph는 LLM 애플리케이션의 흐름을 그래프로 그려 복잡한 워크플로우를 설계하게 해 주는 도구이고, 그 중심에는 모든 노드가 공유하는 상태(State)가 있습니다. 노드가 상태를 받아 일하고, 엣지가 다음 길을 안내하며, 조건부 엣지로 갈림길과 반복까지 표현할 수 있어요. 일직선 체인으로 답답했던 흐름이 있었다면, LangGraph의 상태 기반 설계가 좋은 돌파구가 될 것입니다. 다음 편에서는 그래프 안에서 스스로 도구를 골라 쓰는 에이전트를 LangGraph로 구성하는 이야기로 이어가 보겠습니다.
댓글
댓글 쓰기