InMemoryStore 에 사용자 프로필을 put 으로 넣고 get / search 로 꺼내 본 뒤,
그래프의 chat_node 가 주입받은 store 에서 그 프로필을 읽어 system 메시지에 넣습니다.
thread_id 를 바꿔 같은 질문을 두 번 해도 같은 기억이 실리는 과정을 한 단계씩 따라갑니다.
config 의 thread_id 는 체크포인터의 칸을, user_id 는 Store 의 namespace 를 고릅니다. 체크포인터는 thread 마다 따로이고, Store 는 thread 바깥에 하나입니다.
thread_id 로 칸 선택
Store: user_id 로 namespace 선택
그래프 밖에서 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 는 SQLite 에 memories 테이블(user, memory, created)을 직접 만들고 WHERE user = ? 로 사용자를 구분해 같은 일을 했습니다. Store 는 그 "직접 만든 기억 테이블"을 LangGraph 가 정한 규격(namespace · key · value)으로 바꾼 것입니다. 다만 5일차는 프로그램 시작 때 한 번 읽어 system 프롬프트를 만들었고, 여기서는 chat_node 가 호출될 때마다 store.get 으로 읽습니다. 또 5일차에는 모델이 save_memory 도구로 기억을 쓰는 단계가 있었지만 이 파일에는 대화 중에 기억을 쓰는 단계가 없습니다.
InMemorySaver 라서 같습니다. 이 파일이 확인하는 것은 "두 thread 가 같은 기억을 본다"는 범위의 차이이고, 재시작 후에도 남게 하려면 DB 기반 Store 가 필요합니다.haneul.kim@…)을 user_id 로 그대로 쓰면 namespace 검사에서 걸립니다. 그래서 "haneul_kim" 을 씁니다.user_id 가 없으면 53줄에서 KeyError 입니다. config["configurable"]["user_id"] 로 바로 꺼내기 때문입니다. 그리고 이 값이 곧 기억의 격리 경계이므로 사용자가 입력한 값이 아니라 인증된 서버 쪽 값이어야 합니다.query 도 filter 도 없습니다. 게다가 InMemoryStore() 를 인자 없이 만들었으므로 임베딩 index 가 없어 query 유사도 검색은 동작하지 않습니다.chat_node 는 모델에 보낼 리스트를 따로 만들어 쓰고, 반환하는 것은 AIMessage 하나뿐입니다. 그래서 체크포인터에는 Human/AI 만 남고, 기억은 매 호출마다 Store 에서 새로 읽어 붙입니다.day7_practice/long_term_memory.py Store 저장 · 회수, 그래프 노드에서 읽기, 두 thread 로 확인 (이 자료의 대상)day5_practice/memory_chat.py SQLite 기억 테이블을 직접 만들어 새 대화방에서도 기억을 불러오던 5일차 판day7_practice/final_scenario copy.py Supervisor 그래프의 compile 에 체크포인터와 Store 를 연결만 해 본 사본 (기억을 읽는 노드는 없음)