실무 Multi-Agent 오케스트레이션 18장 · 그래프 기반 워크플로우 3 / 6 ← 이전목차다음 → TechLead Cro

18장. 그래프 기반 워크플로우

그래프 조립과 실행 — 등록하고, 잇고, 굳히고, 돌린다

한 줄 요약

그래프는 네 단계로 만듭니다. 노드를 등록하고, 엣지로 잇고, compile()로 굳히고, invoke()로 실행합니다. 다 만든 그래프는 노드와 엣지가 그대로 한 장의 그림이 됩니다.


1. 조립 — 노드 등록, 엣지 연결

builder = StateGraph(CSState)
builder.add_node("classify", classify_node)
builder.add_node("answer", answer_node)
builder.add_node("log", log_node)

builder.add_edge(START, "classify")
builder.add_edge("classify", "answer")
builder.add_edge("answer", "log")
builder.add_edge("log", END)
코드 하는 일
StateGraph(CSState) "이 그래프의 상태는 CSState 모양이다"라고 알려 주며 조립을 시작합니다
add_node("classify", classify_node) 노드에 이름을 붙여 등록합니다. 앞이 이름, 뒤가 함수입니다
add_edge("classify", "answer") 등록한 이름으로 두 노드를 잇습니다

엣지는 함수가 아니라 이름을 가리킵니다. 그래서 나중에 "answer"라는 이름에 다른 함수를 등록하면, 엣지는 한 줄도 고치지 않고 그 단계의 내용만 바뀝니다.


2. compile — 실행할 수 있는 그래프로 굳힌다

graph = builder.compile()

builder는 설계도이고, compile()을 거친 graph가 실행할 수 있는 물건입니다. 컴파일하지 않은 그래프는 실행할 수 없습니다.

이때 구조도 함께 점검됩니다. 엣지가 가리키는 노드가 모두 등록되어 있는지를 compile()이 확인합니다. 모델을 한 번도 부르기 전에 흐름이 제대로 이어져 있는지 검사받는 셈입니다.


3. invoke — 처음 상태를 넣어 실행한다

result = graph.invoke({
    "question": "단순 변심 반품 배송비 얼마예요?",
    "intent": "", "urgency": "", "answer": "", "log": [],
})

invoke()에는 처음 상태를 넣습니다. question만 채우고 나머지 칸은 빈 값으로 시작합니다. 돌아오는 result는 END에 도착했을 때의 상태 전체입니다.

상태가 지나가는 길을 따라가 봅니다.

시점 intent answer log
시작 "" "" []
classify 뒤 채워짐 "" 1줄
answer 뒤 채워짐 채워짐 2줄
log 뒤 (= 결과) 채워짐 채워짐 3줄

빈 칸까지 넣는 이유가 있습니다. 우리 노드들은 state["log"] + [...]처럼 기존 값을 읽어서 이어 붙입니다. 읽을 칸이 처음 상태에 있어야 하므로, log는 빈 리스트로, 나머지는 빈 문자열로 채워서 시작합니다.


4. 구조가 그대로 그림이 된다

우리가 조립한 그래프를 그림으로 옮기면 이렇습니다.

18장의 상태 그래프

상자 하나가 add_node 한 줄이고, 화살표 하나가 add_edge 한 줄입니다. 화살표를 이어 보면 시작 → classify → answer → log → 끝입니다.

그래프는 노드와 엣지를 선언해서 만들기 때문에, 코드를 읽으면 곧바로 그림을 그릴 수 있습니다. if문 방식에서 "그림으로 보여 줄 수 없다"던 문제가 여기서 풀립니다.


5. 상태가 한 곳에 모여 있으면 생기는 것

흐름이 쓰는 데이터가 전부 상태라는 한 자리에 있으면, 어느 시점의 상태든 통째로 저장해 둘 수 있습니다. 저장할 수 있으면 멈췄다가 그 자리에서 다시 이어 갈 수도 있습니다.

LangGraph는 이 기능을 체크포인트(checkpoint) 라는 이름으로 제공합니다. 16장에서 대화 이력을 우리가 직접 보관했던 일을, 그래프는 실행 상태 전체에 대해 할 수 있게 되는 것입니다. 이번 장에서는 이름만 알아 둡니다. "여기서 멈추고 사람의 승인을 기다린다"가 필요해지는 23장에서 실제로 씁니다.


6. 언제 그래프를 쓰는가

같은 일을 하는 if문 코드보다 그래프 코드가 깁니다. 상태를 선언하고, 노드를 등록하고, 엣지를 잇는 줄이 더 듭니다. 흐름이 직선 하나일 때는 함수 세 개를 차례로 부르는 편이 짧고 빠릅니다.

흐름이 단순할 때 흐름이 복잡해질 때
if문 짧고 빠르다 갈래가 늘수록 읽기 어렵고 고치기 무섭다
그래프 선언하는 줄이 더 든다 노드와 엣지를 보태는 일이 된다

그래프의 이득은 흐름이 복잡해질수록 커집니다. 이번 장의 직선에 갈림길이 생기는 19장부터 그 차이가 보이기 시작합니다.


핵심 정리

  • 조립은 add_node로 이름을 붙여 등록하고 add_edge로 이름끼리 잇는 일입니다.
  • compile() 을 해야 실행할 수 있고, 이때 엣지가 등록된 노드를 가리키는지 구조가 점검됩니다.
  • invoke(처음 상태) 로 실행하고, END에 도착했을 때의 상태가 결과입니다.
  • 노드와 엣지를 선언해서 만들기 때문에 구조가 그대로 그림이 됩니다.
  • 상태가 한 곳에 모여 있어 저장하고 이어 가기(체크포인트) 가 가능합니다.
  • 그래프는 선언하는 줄이 더 드는 대신, 흐름이 복잡해질수록 이득이 커집니다.
← 이전 절상태·노드·엣지 — 그래프를 이루는 세 가지다음 절 →따라하기 — 첫 상태 그래프
오명운 · macro@prag-ai.com