day7_practice/long_term_memory.py

장기 기억 Store: thread가 바뀌어도 따라오는 사용자 기억

InMemoryStore 에 사용자 프로필을 put 으로 넣고 get / search 로 꺼내 본 뒤, 그래프의 chat_node 가 주입받은 store 에서 그 프로필을 읽어 system 메시지에 넣습니다. thread_id 를 바꿔 같은 질문을 두 번 해도 같은 기억이 실리는 과정을 한 단계씩 따라갑니다.

한눈에 보는 구조: 두 개의 저장소, 두 개의 열쇠

config 의 thread_id 는 체크포인터의 칸을, user_id 는 Store 의 namespace 를 고릅니다. 체크포인터는 thread 마다 따로이고, Store 는 thread 바깥에 하나입니다.

config["configurable"] thread_id: "thread-1" / "thread-2" user_id: "haneul_kim" START chat chat_node · config 와 store 를 주입받음 END 모듈 수준 코드 (28~48줄) store.put(...) store.get(...) · store.search(...) thread_id 로 고른 칸 user_id 로 고른 칸 put · get · search 체크포인터 · InMemorySaver 단기 기억 · thread_id 단위 · 그래프가 자동으로 저장 thread-1 HumanMessage AIMessage SystemMessage 는 저장 안 됨 thread-2 HumanMessage AIMessage thread-1 의 대화는 안 보임 Store · InMemoryStore 장기 기억 · namespace 단위 · 코드가 put 으로 저장 namespace ("users", "haneul_kim") └ key "profile" └ value {name, team, email, preferences, rules} thread-1 과 thread-2 가 같은 칸을 읽음
체크포인터: thread_id 로 칸 선택 Store: user_id 로 namespace 선택 그래프 밖에서 Store 를 직접 호출

범위의 차이: 체크포인터와 Store

체크포인터 (InMemorySaver)Store (InMemoryStore)
담는 것그래프 State 전체. 이 파일에서는 messages코드가 골라 넣은 사실. 이 파일에서는 프로필 dict 하나
칸을 고르는 열쇠config["configurable"]["thread_id"]namespace 튜플 + key. 여기서는 ("users", user_id) 와 "profile"
누가 쓰나그래프가 실행 단계마다 자동으로코드가 store.put(...) 으로 직접 (이 파일에서는 29줄 한 번뿐)
새 thread 에서비어 있음그대로 읽힘
그래프에 연결compile(checkpointer=...)compile(store=...), 노드는 *, store 인자로 받음
프로세스가 끝나면사라짐 (메모리)사라짐 (메모리). "장기"는 thread 를 넘는다는 뜻
5일차 memory_chat.py 와의 관계

5일차 memory_chat.py 는 SQLite 에 memories 테이블(user, memory, created)을 직접 만들고 WHERE user = ? 로 사용자를 구분해 같은 일을 했습니다. Store 는 그 "직접 만든 기억 테이블"을 LangGraph 가 정한 규격(namespace · key · value)으로 바꾼 것입니다. 다만 5일차는 프로그램 시작 때 한 번 읽어 system 프롬프트를 만들었고, 여기서는 chat_node 가 호출될 때마다 store.get 으로 읽습니다. 또 5일차에는 모델이 save_memory 도구로 기억을 쓰는 단계가 있었지만 이 파일에는 대화 중에 기억을 쓰는 단계가 없습니다.

함정·주의

관련 파일