LangGraph의 Edge와 병렬 실행 이해하기
Control Flow와 State Update의 분리 개념
앞선 글에서 State와 Node를 살펴봤다면, 이번에는 LangGraph의 또 다른 핵심 구성 요소인 Edge를 중심으로 살펴본다.
LangGraph에서 Edge는 단순한 연결선이 아니라, 에이전트의 실행 흐름과 병렬성을 정의하는 핵심 메커니즘이다.
Edge란 무엇인가?
Edge는 한 노드에서 다음 노드로 제어 흐름(control flow)을 전달하는 역할을 한다.
이는 전통적인 프로그램에서의 if, for, fork/join 같은 제어 구조에 해당한다.
- 직렬(edge in series): 이전 노드가 끝난 뒤 다음 노드 실행
- 병렬(edge in parallel): 여러 노드를 동시에 실행
직렬 실행과 병렬 실행의 차이

직렬 실행 (Serial Execution)
- 첫 번째 노드가 종료되면
- LangGraph 런타임이 다음 노드를 초기화하고 실행
병렬 실행 (Parallel Execution)
- 여러 downstream 노드가 동시에 실행
- 서로를 기다리지 않음
- 동일한 State 스냅샷을 입력으로 받음
이처럼 여러 노드가 동시에 실행되는 하나의 실행 단위를 LangGraph에서는 Super Step이라고 부른다.

Super Step이란?
Super Step이란 다음 조건을 만족하는 실행 단위이다.
- 해당 단계에서 활성화된 모든 노드가 실행 완료
- 각 노드가 State에 대한 업데이트를 반환
- 모든 업데이트가 State에 반영된 뒤 다음 단계로 진행
즉, Super Step은 병렬 실행의 경계 단위이다.
경로 길이가 다른 경우의 실행 제어
그래프에서는 경로 길이가 서로 다를 수 있다.
LangGraph는 이 경우에도 실행 시점을 유연하게 제어할 수 있다.

- 기본 동작: upstream 노드가 끝나면 downstream 노드 실행
(일반적으로 오른쪽 노드는 녹색 노드가 완료될 때 활성화되고, 그 출력은 보라색 노드의 입력으로 들어간다.)
- 옵션: downstream 노드 실행을 지연시켜 같은 Super Step에서 병합
(혹은 실행을 연기하여 오른쪽 노드의 출력이 보라색 노드와 동일한 Super Step 상태에서 활성화되도록 할 수도 있다)
Static Edge와 Conditional Edge
Static Edge
- 항상 실행되는 Edge
- 조건 없이 다음 노드로 제어 전달
- 실선으로 표현됨
Conditional Edge

- 조건에 따라 실행 여부가 결정
- 점선으로 표현됨
- 특정 조건이 만족될 때만 노드 실행
조건부 Edge는 의사결정 로직을 그래프에 직접 표현할 수 있게 해준다.
Conditional Edge의 확장: MapReduce
Conditional Edge의 특수한 형태로 MapReduce 패턴이 있다.
- 입력 값에 따라 가변 개수의 downstream 노드 생성
- 각 노드는 서로 다른 입력 값을 받음
- 결과는 이후 단계에서 병합 가능
이는 대규모 병렬 작업이나 fan-out/fan-in 구조에 매우 유용하다.
병렬 실행에 대한 Detail
병렬 실행에서 State는 어떻게 업데이트될까?

병렬 실행 시 중요한 질문이 하나 있는데 바로,
여러 노드가 동시에 같은 State 키를 업데이트하면 어떻게 되는지에 대한 것이다.
기본 동작은 단순하다. 바로 마지막에 실행된 노드의 값이 덮어쓰는 것 (overwrite)
하지만 이는 병렬 실행에서는 거의 항상 문제가 된다.
Reducer 함수로 State 병합하기
이 문제를 해결하기 위해 LangGraph는 Reducer 함수를 제공한다.

- Reducer는 동일한 State 키에 대한 여러 업데이트를 병합
- MapReduce 개념에서 이름을 차용하였다.
예제에서는 operator.add를 reducer로 사용하여,
- 여러 노드가 반환한 리스트를 덮어쓰지 않고 누적(concatenate)
Reducer는 어떻게 정의하는가?
Reducer는 State 정의 시 애노테이션(annotation)으로 지정한다.
- 첫 번째 인자: State 변수의 타입
- 두 번째 인자: Reducer 메타데이터
LangGraph는 이 정보를 사용해 State 병합 방식을 자동으로 결정한다.
또한, 사용자는 자신만의 Custom Reducer를 정의할 수도 있다.
Edge 예제
In [1]:
from IPython.display import Image, display
import operator
from typing import Annotated, List, Literal, TypedDict
from langgraph.graph import END, START, StateGraph
# State 상태 정의 (TypeDict 타입 사용)
# 하나의 매개변수를 가짐 (nlist라는 문자열 목록 + 리듀서 도입)
# 리듀서 함수로 operator 모듈의 add 함수 사용 (이전 값을 덮어쓰지 않고 모든 리스트 업데이트를 State에 Concatenate)
class State(TypedDict):
nlist: Annotated[List[str], operator.add]
# Node 정의
# 각 Node는 상태를 받아서 자신의 이름과 입력값을 출력하고, 자신의 label을 nlist에 대한 update로 반환
def node_a(state: State) -> State:
print(f"Adding 'A' to {state['nlist']}")
return State(nlist=["A"])
def node_b(state: State) -> State:
print(f"Adding 'B' to {state['nlist']}")
return State(nlist=["B"])
def node_c(state: State) -> State:
print(f"Adding 'C' to {state['nlist']}")
return State(nlist=["C"])
def node_bb(state: State) -> State:
print(f"Adding 'BB' to {state['nlist']}")
return State(nlist=["BB"])
def node_cc(state: State) -> State:
print(f"Adding 'CC' to {state['nlist']}")
return State(nlist=["CC"])
def node_d(state:State) -> State:
print(f"Adding 'D' to {state['nlist']}")
return State(nlist=["D"])
builder = StateGraph(State)
# Node 추가
builder.add_node("a", node_a)
builder.add_node("b", node_b)
builder.add_node("c", node_c)
builder.add_node("bb", node_bb)
builder.add_node("cc", node_cc)
builder.add_node("d", node_d)
# Edge 추가
builder.add_edge(START, "a")
builder.add_edge("a", "b")
builder.add_edge("a", "c")
builder.add_edge("b", "bb")
builder.add_edge("c", "cc")
builder.add_edge("bb", "d")
builder.add_edge("cc", "d")
builder.add_edge("d", END)
# StateGraph 생성
graph = builder.compile()
# Display
display(Image(graph.get_graph().draw_mermaid_png()))
initial_state = State(
nlist = ["Initial_String:"]
)
# Graph 실행
graph.invoke(initial_state)
# 1. 맨 처음에는 Node A가 실행되어 A가 추가된다. (첫 번째 실행 순서)
# 2. 그런 다음 노드 b와 c가 같은 Super Step 내에서 실행된다.
# (이들은 실행될 때 동일한 State를 관찰했기 때문에 하나가 다른 하나보다 먼저 실행될 수 없다: 병렬 실행)
# (여기서 Edge는 제어 흐름을 정의하지만, 노드가 접근할 수 있는 데이터는 제어하지 않는다. 따라서 Node 실행 시 병렬 분기에서 작성된 값을 포함한 현재 Graph 상태에 접근할 수 있다. 즉, 노드 bb는 c가 만든 State에 접근 가능 + 노드 cc도 b가 만든 sState에 접근 가능)
# 3. 그런 다음 노드 bb와 cc가 실행된다. (bb와 cc가 State에 자신의 label을 추가한다.)
# 4. 그런 다음 d는 이전에 추가된 모든 상태를 받아들이고 d를 추가한다.
# 5. 마지막으로, 그래프는 모든 Node의 label이 포함된 최종 병합 State 목록을 반환한다.
Adding 'A' to ['Initial_String:']
Adding 'B' to ['Initial_String:', 'A']
Adding 'C' to ['Initial_String:', 'A']
Adding 'BB' to ['Initial_String:', 'A', 'B', 'C']
Adding 'CC' to ['Initial_String:', 'A', 'B', 'C']
Adding 'D' to ['Initial_String:', 'A', 'B', 'C', 'BB', 'CC']
{'nlist': ['Initial_String:', 'A', 'B', 'C', 'BB', 'CC', 'D']}
# 만약 bb와 cc에서 바로 END로 넘기려고 한다면 값이 Concatenate될까?
builder = StateGraph(State)
# Node 추가
builder.add_node("a", node_a)
builder.add_node("b", node_b)
builder.add_node("c", node_c)
builder.add_node("bb", node_bb)
builder.add_node("cc", node_cc)
# Edge 추가
builder.add_edge(START, "a")
builder.add_edge("a", "b")
builder.add_edge("a", "c")
builder.add_edge("b", "bb")
builder.add_edge("c", "cc")
builder.add_edge("bb", END)
builder.add_edge("cc", END)
# StateGraph 생성
graph = builder.compile()
# Display
display(Image(graph.get_graph().draw_mermaid_png()))
initial_state = State(
nlist = ["Initial_String:"]
)
# Graph 실행
graph.invoke(initial_state)
# BB와 CC의 상태 업데이트가 모두 반영됨을 확인할 수 있다.
Adding 'A' to ['Initial_String:']
Adding 'B' to ['Initial_String:', 'A']
Adding 'C' to ['Initial_String:', 'A']
Adding 'BB' to ['Initial_String:', 'A', 'B', 'C']
Adding 'CC' to ['Initial_String:', 'A', 'B', 'C']
{'nlist': ['Initial_String:', 'A', 'B', 'C', 'BB', 'CC']}
핵심 요점
- State를 설정할 때, State 정의에서 Reducer 함수를 사용해 State가 어떻게 축적되는지에 영향을 줄 수 있다.
- Graph를 구축할 때 add_edge 함수를 통해 병렬 경로를 만들 수 있다.
- 실행 중에 노드 B와 C는 병렬적으로 수행된다.
- Reducer 함수는 각 노드에서 반환된 값을 Concatenate하여 State에 저장하고 노드 BB와 CC를 수행한다.
- Control은 Edge를 따르지만, Data는 그렇지 않다.
'Agentic AI 구축 > LangChain & LangGraph' 카테고리의 다른 글
| [LangGraph 기초 4] Memory와 Checkpoint의 개념 (0) | 2026.01.03 |
|---|---|
| [LangGraph 기초 3] Conditional Edge의 개념 (Command 인자) (0) | 2026.01.03 |
| [LangGraph 기초 1] Node와 State의 개념 (0) | 2026.01.03 |
| LangChain과 LangChain 생태계 총정리 (LangChain, LangGraph, LangSmith) (0) | 2025.12.16 |
| LangChain에서 HuggingFace의 오픈소스 LLM 모델 (Llama 시리즈) 사용하기 (0) | 2025.12.11 |