18차시. State 이해
5. Reducer — 덮어쓰지 않고 쌓기
출처: 원본 PDF 18차시_State이해.pdf 11~12쪽 · 쪽 그림 11쪽 12쪽
기본은 덮어쓰기입니다. 그런데 쌓아야 하는 값도 있습니다.
5-1) 덮어쓰기가 문제가 되는 경우
■ 실행 로그를 남기고 싶다면
──────────────────────────────────────
def retrieve(state):
return {"log": ["검색 완료"]}
def generate(state):
return {"log": ["생성 완료"]}
기대 : ['검색 완료', '생성 완료']
실제 : ['생성 완료'] ← 덮어써짐!5-2) Reducer로 해결하기
from typing import TypedDict, Annotated, List
import operator
class DemoState(TypedDict):
question: str
answer: str
# ★ Reducer 지정 — 덮어쓰지 말고 이어 붙여라
log: Annotated[List[str], operator.add]🔗 Annotated의 의미
Annotated[List[str], operator.add]
앞부분 List[str] → "이 키는 문자열 리스트다"
뒷부분 operator.add → "같은 키가 오면 더해라"
리스트끼리 더하면 이어 붙습니다.
['검색 완료'] + ['생성 완료']
= ['검색 완료', '생성 완료'] ✅
5-3) 어떤 키에 Reducer를 쓸까?
출처: 원본 PDF 12쪽
| 키 | Reducer | 이유 |
|---|---|---|
| question | 없음 (덮어쓰기) | 질문은 하나입니다 |
| documents | 없음 (덮어쓰기) | 재검색하면 새것으로 교체 |
| answer | 없음 (덮어쓰기) | 최신 답변만 필요합니다 |
| log | operator.add | 실행 이력은 쌓아야 합니다 |
| tried_queries | operator.add | 시도한 질의를 모두 기록 |
| retries | 없음 (덮어쓰기) | 카운터는 최신값만 유효 |
⚠️ 헷갈리기 쉬운 지점
"retries도 쌓아야 하는 거 아닌가?"
아닙니다. 카운터는 노드가 직접 +1해서 반환합니다.
return {"retries": state.get("retries", 0) + 1}
Reducer를 붙이면 오히려 [1, 2, 3] 처럼 리스트가 됩니다.