그래프의 심장은 State다. 노드는 State 전체를 받아 바뀐 필드만 dict로 반환하고, LangGraph가 이를 기존 State에 병합한다. 이때 "어떻게 병합할지"를 정하는 것이 리듀서(reducer)다. 기본은 덮어쓰기지만, 메시지처럼 누적해야 하는 필드는 리듀서를 지정해야 한다.
이 강의 목표는 TypedDict로 State를 정의하고, Annotated로 필드별 리듀서를 붙이는 법을 익히는 것이다.
1. State 정의
State는 보통 TypedDict로 정의한다. 각 필드가 그래프가 들고 다니는 데이터다.
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages
import operator
class State(TypedDict):
messages: Annotated[list, add_messages] # 누적(append)
count: int # 덮어쓰기(기본)
logs: Annotated[list, operator.add] # 리스트 이어붙이기
2. 리듀서의 동작
리듀서가 없으면 노드가 반환한 값이 기존 값을 덮어쓴다. Annotated[타입, 함수]로 리듀서를 지정하면, 기존값·새값을 그 함수로 합친다.
- 없음(기본):
{"count": 3}→ count가 3으로 교체. add_messages: 메시지 목록에 새 메시지를 누적(id가 같으면 갱신).operator.add: 두 리스트를 이어붙임.
3. add_messages 가 특별한 이유
대화형 에이전트는 매 턴 메시지가 쌓여야 한다. add_messages는 이를 자동으로 처리하고, 같은 id의 메시지는 교체해 준다. 그래서 거의 모든 챗 그래프의 표준 필드가 messages: Annotated[list, add_messages]다.
핵심 명령·용어
| 이름 | 뜻 |
|---|---|
TypedDict |
State의 스키마 정의 |
Annotated[T, reducer] |
필드에 리듀서 부착 |
add_messages |
메시지 누적 리듀서 |
operator.add |
리스트/숫자 합산 리듀서 |
예제
from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage, AIMessage
# add_messages 는 두 목록을 누적 병합한다
old = [HumanMessage("안녕", id="1")]
new = [AIMessage("반가워", id="2")]
print(add_messages(old, new)) # [Human('안녕'), AI('반가워')]
해설) 노드가 {"messages": [AIMessage(...)]}만 반환해도, 리듀서 덕분에 전체 대화 이력에 자동으로 이어붙는다. State 설계가 곧 그래프 설계의 절반이다.
댓글 0
댓글은 운영자만 작성할 수 있어요.