정리 & 체크리스트
한 줄 요약
에이전트 네 종류에 기억까지 붙였습니다. 재료가 다 모였습니다. 8장에서 하나의 팀으로 묶습니다.
1. 7장에서 만든 것
code/ch07_memory.py — 기억하는 에이전트
| 만든 것 | 하는 일 |
|---|---|
State |
상태 정의 — messages + add_messages |
counselor(state) |
노드 — 대화 전체를 모델에 넘기고 답을 돌려줌 |
graph / chatbot |
START → counselor → END 를 조립·컴파일 |
say(text, thread_id) |
단순 챗봇 호출 |
analyst_with_memory |
5장 에이전트 + checkpointer 한 줄 |
ask_analyst(text, thread_id) |
멀티턴 CSV 분석 |
2. 이 장의 핵심 내용 — 말로 설명할 수 있어야 할 것들
- LangGraph는 프로그램을 "상태를 들고 노드 사이를 이동하는 그래프"로 본다.
- 상태는 딕셔너리, 노드는 함수, 엣지는 화살표다.
Annotated[list, add_messages]는 "덮어쓰지 말고 이어 붙여라"를 뜻한다. 2장의history.append(...)를 대신한다.- 리듀서를 안 붙이면 덮어쓴다. 8장에서 둘 다 쓴다.
- 노드는 바뀐 부분만 돌려준다. (전체를 돌려줘도
add_messages가id로 걸러 결과는 같지만, 리듀서가 하는 일이 가려지고 복사 비용이 붙는다.) compile(checkpointer=...)한 줄로 기억이 생긴다. 저장은 노드가 끝날 때마다 일어난다.- 우리는 이번 말 하나만 넣고, 체크포인터가 앞의 것을 붙여 준다.
InMemorySaver는 프로그램을 끄면 사라진다. 저장 위치를 바꾸려면 이 한 줄만 바꾼다.create_agent도 StateGraph 다. 그래서checkpointer인자를 그대로 받는다.thread_id는 "어느 서랍인가"를 가리킨다. 같은 질문이라도 서랍이 다르면 다른 답이 나온다.- 체크포인터와
thread_id는 짝이다. 하나만 있으면 동작하지 않는다. - 길이 관리는 여전히 사람의 일이다. 자르기·요약·
thread_id교체 중에 고른다. - 대화가 섞이는 사고는 오류 없이 조용히 일어나고, 그것은 개인정보 사고다. 그래서 검증한다.
3. 체크리스트
- [ ]
python code/ch07_memory.py가 끝까지 돌아간다 - [ ]
[1]에서 앞말을 기억하는 것을 확인했다 - [ ]
[2]에서thread_id를 바꾸면 기억이 없는 것을 확인했다 - [ ]
[3]에서 "그거" 가 통하는 것을 확인했다 - [ ]
get_state()로 쌓인 메시지를 직접 봤다 - [ ]
add_messages를 빼면 어떻게 되는지 직접 해 봤다 - [ ] 두 손님이 번갈아 대화해도 섞이지 않는 것을 코드로 검증했다
4. 지금까지 만든 것 전부
[에이전트 네 종류]
✓ ① 사내 데이터 조회 3장 ch03_order_agent.py
✓ ② 웹검색 4장 ch04_web_agent.py
✓ ③ CSV 데이터분석 5장 ch05_csv_agent.py
✓ ④ RAG 문서검색 6장 ch06_rag_agent.py
[기억]
✓ LangGraph StateGraph 7장 ch07_memory.py
[남은 것]
□ 팀으로 묶기 8장 ch08_multi_agent.py
재료가 전부 갖춰졌습니다.
5. 8장 예고 — 한 종류로는 답이 안 나오는 질문
"승승 스마트워치 Fit 5(P0003), 지금 어떻게 대응해야 할까요?"
지금까지 만든 에이전트에게 하나씩 질문해 보면 이렇습니다.
| 에이전트 | 답할 수 있는 것 | 여기서 멈춘다 |
|---|---|---|
| CSV 분석 | 재고 3개, 평점 3.8, 5월 판매 12개 | "평점이 낮네" |
| RAG 문서검색 | 배터리 일반 7일 / GPS 18시간 | "사양은 정상인데?" |
| 웹검색 | 시장에서 배터리가 경쟁 요소 | "그래서 뭘 하라고?" |
셋을 나란히 놓아야 판단이 나옵니다.
리뷰 불만: "GPS를 켜면 하루도 못 갑니다. 일주일 간다는 설명과 너무 달라요" (CSV)
매뉴얼 : 일반 7일 / GPS 18시간 (RAG)
↓
제품은 사양대로 동작한다. 고객은 "일주일"만 보고 샀다.
↓
결함이 아니라 표기 문제다 → 상세페이지에 GPS 18시간을 명시하라
이 판단은 한 종류만으로는 절대 안 나옵니다.
6. 어떻게 묶을까 — 두 갈래
방법이 둘 있습니다. 8장에서 둘 다 살펴보고 하나를 고릅니다.
① 한 명에게 도구를 다 준다
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
agent = create_agent(llm, tools=[order_tool, run_pandas, policy_tool, search_web], ...)
간단합니다. 그런데 4장 4절에서 본 문제가 생깁니다 — 도구가 많아지면 무엇을 쓸지 헷갈립니다. 그리고 어디서 틀렸는지 찾기 어렵습니다.
② 나눠서 맡긴다 — Planner–Worker
각 담당은 도구가 하나뿐이라 고민할 게 없습니다. 그리고 "규정담당이 잘못 보고했다"고 짚을 수 있습니다.
왜 Planner–Worker 라고 부르나 — 계획을 세우는 쪽(Planner, 플래너) 과 일을 하는 쪽(Worker, 워커) 을 나눠 놓았다고 해서 이렇게 부릅니다. 멀티에이전트 구성 방식 중 하나의 정식 이름이라 검색하면 자료가 나옵니다. 8장 내내 이 이름을 씁니다 — 한국어로는 "팀장–담당 방식" 이라고 읽으면 됩니다.
8장은 ②로 갑니다.
7. 그리고 이번 장이 얹힙니다
8장의 그래프도 체크포인터를 붙입니다.
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
team = graph.compile(checkpointer=InMemorySaver())
그래서 이렇게 됩니다.
질문 1: "승승 스마트워치 Fit 5(P0003), 지금 어떻게 대응해야 할까요?"
→ 계획: 데이터분석가 + 규정담당 + 시장조사원
→ 종합 답변
질문 2: "그 상품을 산 주문 O001203은 어떤 상태인가요? 재주문 기준을 채우려면 몇 개?"
→ "그 상품"이 통한다 (7장)
→ 계획: 주문담당 + 데이터분석가
→ "배송완료 상태이고, 27개를 발주해야 합니다"
계획은 실행할 때마다 조금씩 달라집니다. 위는 한 번 돌린 예입니다.
계획이 질문에 따라 달라지고, 앞 대화를 기억합니다. 멀티에이전트와 멀티턴이 함께 동작하는 것이죠.
이번 장의 State · add_messages · checkpointer · thread_id 가 그대로 쓰입니다. 다만 노드가 하나에서 셋(계획 → 실행 → 종합) 으로 늘어납니다.