따라하기 — "그 상품 지난달은?" 이어서 묻기
한 줄 요약
대화를 다섯 턴으로 늘려 봅니다. 상품명 없이 "그거"·"그 상품" 만으로 계속 물어도 답이 이어집니다. 그리고 쌓인 메시지를 세어 비용이 어떻게 늘어나는지 확인합니다.
1. 다섯 턴 대화
ch07_memory.py 의 [3] 질문 목록을 이렇게 늘려 보세요.
직접 고쳐 보기 —
agentic_ai/code/ch07_memory.py를 열어[3]의 질문 목록에 두 줄을 덧붙인 뒤 다시 실행하세요.
for q in ["P0003 스마트워치 재고가 얼마나 남았나요?",
"그거 재주문 기준은요?",
"그럼 지금 발주해야 하나요?",
"몇 개를 발주해야 하죠?", # ← 추가
"그 상품 리뷰 평점은 어떤가요?"]: # ← 추가
print(f"\n 손님: {q}")
print(f" 봇 : {ask_analyst(q, thread_id='재고담당-1')}")
실행 결과입니다.
손님: P0003 스마트워치 재고가 얼마나 남았나요?
봇 : P0003 스마트워치 재고는 3개 남았습니다.
손님: 그거 재주문 기준은요?
봇 : P0003 스마트워치의 재주문 기준은 30개입니다.
손님: 그럼 지금 발주해야 하나요?
봇 : 네, 발주해야 합니다.
손님: 몇 개를 발주해야 하죠?
봇 : 27개를 발주해야 합니다.
손님: 그 상품 리뷰 평점은 어떤가요?
봇 : P0003 스마트워치의 리뷰 평점은 3.8점입니다.
2. 네 번째 질문이 흥미롭습니다
"몇 개를 발주해야 하죠?" → "27개를 발주해야 합니다."
질문에 숫자가 하나도 없습니다. 그런데 27이 나왔습니다.
30 (재주문 기준) - 3 (현재 재고) = 27
두 숫자 모두 앞선 대화에 있습니다. 모델이 기록에서 꺼내 뺀 것입니다.
그런데 잠깐 — 5장에서 "숫자는 반드시 도구로 계산한다" 고 했는데, 이건 모델이 머릿속으로 뺀 걸까요, 도구를 쓴 걸까요? 확인해 봅시다. (같은 절 4번에서 방법을 씁니다)
3. 다섯 번째 질문 — "그 상품"
"그 상품 리뷰 평점은 어떤가요?" → "P0003 스마트워치의 리뷰 평점은 3.8점입니다."
네 턴 전에 나온 상품을 여전히 기억합니다. 그리고 이번엔 새로운 계산(리뷰 평점)을 합니다.
reviews.csv 를 조회한 것이니 도구를 새로 불렀습니다. 기억은 "무엇에 대해 묻는지"를 알려 줬고, 계산은 도구가 했습니다.
역할 분담이 유지되고 있습니다.
4. 쌓인 것을 세어 봅시다
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
config = {"configurable": {"thread_id": "재고담당-1"}}
snapshot = analyst_with_memory.get_state(config)
from collections import Counter
print("쌓인 메시지:", len(snapshot.values["messages"]))
print(Counter(type(m).__name__ for m in snapshot.values["messages"]))
쌓인 메시지: 20
Counter({'AIMessage': 10, 'HumanMessage': 5, 'ToolMessage': 5})
다섯 번 물었는데 20개가 쌓였습니다.
손님이 한 번 물으면 메시지 4개가 쌓입니다.
① HumanMessage "그거 재주문 기준은요?"
│
▼
② AIMessage (run_pandas 를 불러 주세요) ← 모델의 첫 번째 말
│
▼
③ ToolMessage 30 ← 우리 코드가 실행한 결과
│
▼
④ AIMessage "재주문 기준은 30개입니다" ← 모델의 두 번째 말
②와 ④가 둘 다 AIMessage 입니다. 모델이 한 턴에 두 번 말하는 것이죠 — 한 번은 "도구를 불러 주세요", 한 번은 "답은 이렇습니다". 사람 눈에는 답이 하나뿐이라 이상해 보이지만, 도구를 쓰는 에이전트는 항상 이렇게 두 번 말합니다.
1턴 ████ 4개
2턴 ████████ 8개
3턴 ████████████ 12개
4턴 ████████████████ 16개
5턴 ████████████████████ 20개
턴마다 4개씩, 다섯 턴이면 20개. 뜯어보면 이렇습니다.
| 종류 | 개수 | 무엇 |
|---|---|---|
HumanMessage |
5 | 손님의 질문 5개 |
AIMessage |
10 | 도구 호출 요청 5개 + 최종 답변 5개 |
ToolMessage |
5 | 도구 실행 결과 5개 |
AIMessage 가 10개인 것을 보세요. 질문 하나마다 모델이 두 번 말합니다 — "도구를 불러 주세요"와 "답은 이렇습니다".
4장에서 history 에 기록을 쌓던 작업이 자동으로 이루어지고 있는 것입니다.
ToolMessage가 5개 = 다섯 질문 모두 도구를 썼다는 뜻입니다. 네 번째 질문(27개)도 도구를 썼습니다. 2번의 궁금증이 풀렸네요 — 시스템 지시의 "숫자는 반드시 도구로 계산한다"가 지켜졌습니다.
5. 비용은 어떻게 늘어나나
2장 7절의 그 이야기가 여기서 실제 수치로 드러납니다.
1턴째 질문: 모델이 받는 것 = 시스템 지시 + 메시지 0개 + 이번 질문
2턴째 질문: 시스템 지시 + 메시지 4개 + 이번 질문
3턴째 질문: 시스템 지시 + 메시지 8개 + 이번 질문
4턴째 질문: 시스템 지시 + 메시지 12개 + 이번 질문
5턴째 질문: 시스템 지시 + 메시지 16개 + 이번 질문
턴마다 4개씩 늘어납니다. (질문 1 + AI 2 + 도구 1)
그리고 한 질문당 모델 호출이 2번입니다(도구를 쓰므로). 그러니 실제로는 이보다 더 나갑니다.
직접 재 보려면 마지막 AIMessage 의 사용량을 보면 됩니다.
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
last_message = snapshot.values["messages"][-1]
print(last_message.usage_metadata)
6. 그래서 어디까지 기억해야 하나
정답이 없습니다. 상황에 따라 다릅니다.
| 상황 | 얼마나 |
|---|---|
| 고객 상담 (한 문의 처리) | 그 문의가 끝날 때까지 |
| 데이터 분석 대화 | 주제가 바뀔 때까지 |
| 장시간 어시스턴트 | 최근 N개 + 요약 |
가장 단순한 방법은 앞 절에서 본 자르기입니다.
개선안 — 원하면 고쳐 보세요 ·
agentic_ai/code/ch07_memory.py
실습 기본 코드에는 없는 내용입니다. 지금 안 고쳐도 다음 절로 넘어갈 수 있습니다.
def counselor(state: State) -> dict:
recent = state["messages"][-10:]
answer = llm.invoke([{"role": "system", "content": SYSTEM}] + recent)
return {"messages": [answer]}
주의할 점 — 도구를 쓰는 에이전트에서는 자를 때 조심해야 합니다. AIMessage(도구 호출 요청)와 ToolMessage(결과)가 짝인데, 중간에서 자르면 짝이 깨져 오류가 날 수 있습니다.
이것도 사람이 판단하는 자리입니다. 라이브러리는 자동으로 안 잘라 줍니다. 어디서 자를지, 무엇을 남길지는 우리가 정합니다.
7. 실제 서비스라면
이 실습에서 안 다룬 것들입니다. 알아만 두세요.
| 문제 | 실무에서는 |
|---|---|
| 프로그램을 끄면 사라짐 | SqliteSaver·PostgresSaver 로 교체 |
| 대화가 무한정 길어짐 | 자르기 + 요약 |
| 손님이 "새 대화" 원함 | 새 thread_id 발급 |
| 오래된 대화 정리 | 일정 기간 후 삭제 (개인정보) |
| 대화 내용이 개인정보 | 저장 위치·기간·암호화를 정책으로 |
마지막 줄이 특히 중요합니다. 고객과의 대화를 저장한다는 것은 개인정보를 저장한다는 뜻입니다. 실제 서비스라면 무엇을 얼마나 보관할지가 기술 문제가 아니라 정책 문제가 됩니다.
스스로 해 보기
- 위의
Counter코드로 메시지 구성을 확인하세요.ToolMessage가 5개인가요? - 대화를 열 턴으로 늘려 보세요. 메시지가 몇 개까지 쌓이나요?
- 마지막 답변의
usage_metadata를 찍어, 첫 턴과 마지막 턴의 입력 토큰을 비교해 보세요. - 중간에 다른 상품을 물어 보세요.
text "P0003 재고는?" → "P0009 재고는?" → "그거 재주문 기준은?"
"그거"가 어느 상품을 가리키나요? 예측하고 확인하세요.
4번이 중요합니다. 기억이 꼬이는 상황을 직접 만들어 보는 것입니다. 사람도 헷갈릴 만한 대화라면 모델도 헷갈립니다.
핵심 정리
- 다섯 턴 대화에서 "그거"·"그 상품" 만으로 계속 답이 이어집니다.
- "몇 개를 발주해야 하죠?" — 숫자 없는 질문에 27개가 나옵니다. 앞선 두 숫자를 도구로 계산했습니다.
- 다섯 번 물으면 메시지 20개가 쌓입니다 — 질문 5 + AI 10 + 도구 결과 5.
AIMessage가 두 배인 이유 — 질문마다 모델이 "도구 불러 주세요"와 "답은 이렇습니다"를 따로 말하기 때문입니다.- 턴마다 4개씩 늘어납니다. 대화가 길어질수록 입력 토큰 수가 늘어납니다.
- 어디까지 기억할지는 정답이 없습니다. 자르기·요약·
thread_id교체 중에 상황에 맞게 고릅니다. - 도구를 쓰는 에이전트에서 자를 때는
AIMessage와ToolMessage의 짝이 깨지지 않게 조심합니다. - 대화를 저장한다는 것은 개인정보를 저장한다는 뜻입니다. 실제 서비스에서는 정책 문제입니다.