news 2026/10/1 3:01:38

(LangGraph教程)5. Long-Term Memory长期记忆——Lesson 1(2):LangGraph Store记忆存储(未索引)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(LangGraph教程)5. Long-Term Memory长期记忆——Lesson 1(2):LangGraph Store记忆存储(未索引)

https://academy.langchain.com/courses/intro-to-langgraph

https://github.com/shangxiang0907/langchain-academy

文章目录

  • Chatbot with Memory 带记忆功能的聊天机器人
    • Review 复习
    • Goals 目标
    • Introduction to the LangGraph Store LangGraph Store 简介
    • Chatbot with long-term memory 带长期记忆的聊天机器人
    • Viewing traces in LangSmith 在 LangSmith 中查看追踪记录
    • Studio

Chatbot with Memory 带记忆功能的聊天机器人

Review 复习

Memory is a cognitive function that allows people to store, retrieve, and use information to understand their present and future.

记忆 是一种认知功能,使人们能够存储、检索和使用信息,以理解当下与未来。

There are various long-term memory types that can be used in AI applications.

存在多种长期记忆类型,可用于人工智能应用。

Goals 目标

Here, we’ll introduce the LangGraph Memory Store as a way to save and retrieve long-term memories.

此处,我们将介绍 LangGraph Memory Store,作为一种保存与检索长期记忆的方式。

We’ll build a chatbot that uses bothshort-term (within-thread)andlong-term (across-thread)memory.

我们将构建一个同时使用短期(线程内)和长期(跨线程)记忆的聊天机器人。

We’ll focus on long-term semantic memory, which will be facts about the user.

我们将重点关注长期语义记忆,即关于用户的事实性信息。

These long-term memories will be used to create a personalized chatbot that can remember facts about the user.

这些长期记忆将用于创建一个个性化聊天机器人,使其能够记住有关用户的事实。

It will save memory “in the hot path”, as the user is chatting with it.

它将在用户与其聊天时,“在热路径中” 保存记忆。

%%capture--no-stderr%pip install-U langchain_openai langgraph langchain_core

We’ll use LangSmith for tracing.

我们将使用 LangSmith 进行追踪。

importos,getpassdef_set_env(var:str):ifnotos.environ.get(var):os.environ[var]=getpass.getpass(f"{var}: ")_set_env("LANGSMITH_API_KEY")os.environ["LANGSMITH_TRACING"]="true"os.environ["LANGSMITH_PROJECT"]="langchain-academy"

Introduction to the LangGraph Store LangGraph Store 简介

The LangGraph Memory Store provides a way to store and retrieve informationacross threadsin LangGraph.

LangGraph Memory Store 提供了一种在 LangGraph 中跨线程存储与检索信息的方式。

This is an open source base class for persistentkey-valuestores.

这是一个开源基类,用于持久化的键值(key-value)存储。

importuuidfromlanggraph.store.memoryimportInMemoryStore in_memory_store=InMemoryStore()

When storing objects (e.g., memories) in the Store, we provide:

向 Store 中存储对象(例如记忆)时,我们需要提供:

  • Thenamespacefor the object, a tuple (similar to directories)

    • 对象的命名空间(namespace),为一个元组(类似于目录结构)
  • the objectkey(similar to filenames)

    • 对象的键(key)(类似于文件名)
  • the objectvalue(similar to file contents)

    • 对象的值(value)(类似于文件内容)

We use the put method to save an object to the store bynamespaceandkey.

我们使用 put 方法,按命名空间和键将对象保存至存储中。

# Namespace for the memory to saveuser_id="1"namespace_for_memory=(user_id,"memories")# Save a memory to namespace as key and valuekey=str(uuid.uuid4())# The value needs to be a dictionaryvalue={"food_preference":"I like pizza"}# Save the memoryin_memory_store.put(namespace_for_memory,key,value)

We use search to retrieve objects from the store bynamespace.

我们使用 search 方法,按命名空间从存储中检索对象。

This returns a list.

该方法返回一个列表。

# Searchmemories=in_memory_store.search(namespace_for_memory)type(memories)
list
# Metatdatamemories[0].dict()
{'value': {'food_preference': 'I like pizza'}, 'key': 'a754b8c5-e8b7-40ec-834b-c426a9a7c7cc', 'namespace': ['1', 'memories'], 'created_at': '2024-11-04T22:48:16.727572+00:00', 'updated_at': '2024-11-04T22:48:16.727574+00:00'}
# The key, valueprint(memories[0].key,memories[0].value)
a754b8c5-e8b7-40ec-834b-c426a9a7c7cc {'food_preference': 'I like pizza'}

We can also use get to retrieve an object bynamespaceandkey.

我们还可以使用 get 方法,按命名空间和键检索单个对象。

# Get the memory by namespace and keymemory=in_memory_store.get(namespace_for_memory,key)memory.dict()
{'value': {'food_preference': 'I like pizza'}, 'key': 'a754b8c5-e8b7-40ec-834b-c426a9a7c7cc', 'namespace': ['1', 'memories'], 'created_at': '2024-11-04T22:48:16.727572+00:00', 'updated_at': '2024-11-04T22:48:16.727574+00:00'}

Chatbot with long-term memory 带长期记忆的聊天机器人

We want a chatbot that has two types of memory:

我们希望构建一个具备两种记忆类型的聊天机器人:

  1. Short-term (within-thread) memory: Chatbot can persist conversational history and / or allow interruptions in a chat session.
  • 短期(线程内)记忆:聊天机器人可在一次聊天会话中持续保存对话历史,或支持中断操作。
  1. Long-term (cross-thread) memory: Chatbot can remember information about a specific useracross all chat sessions.
  • 长期(跨线程)记忆:聊天机器人可跨所有聊天会话,记住特定用户的有关信息。
fromdotenvimportfind_dotenv,load_dotenv load_dotenv(find_dotenv(usecwd=True))_set_env("OPENAI_API_KEY")

Forshort-term memory, we’ll use a checkpointer.

对于短期记忆,我们将使用 检查点器(checkpointer)。

See Module 2 and our conceptual docs for more on checkpointers, but in summary:

更多关于检查点器的内容,请参阅模块 2 及我们的概念文档,简而言之:

  • They write the graph state at each step to a thread.

    • 它们在每一步都将图状态写入线程。
  • They persist the chat history in the thread.

    • 它们在线程中持久化聊天历史。
  • They allow the graph to be interrupted and / or resumed from any step in the thread.

    • 它们允许图从线程中的任意步骤被中断和/或恢复。

And, forlong-term memory, we’ll use the LangGraph Store as introduced above.

而对于长期记忆,我们将使用上文介绍的 LangGraph Store。

# Chat modelimportosfromlangchain_openaiimportChatOpenAI# Initialize the LLMmodel=ChatOpenAI(model=os.getenv("OPENAI_MODEL","qwen-plus"),base_url=os.getenv("OPENAI_BASE_URL","https://dashscope.aliyuncs.com/compatible-mode/v1"),temperature=0)

The chat history will be saved to short-term memory using the checkpointer.

聊天历史将通过检查点器保存至短期记忆。

The chatbot will reflect on the chat history.

聊天机器人将对聊天历史进行反思。

It will then create and save a memory to the LangGraph Store.

然后,它将创建一条记忆并保存至 LangGraph Store。

This memory is accessible in future chat sessions to personalize the chatbot’s responses.

该记忆可在未来的聊天会话中被访问,从而实现聊天机器人响应的个性化。

fromIPython.displayimportImage,displayfromlanggraph.checkpoint.memoryimportMemorySaverfromlanggraph.graphimportStateGraph,MessagesState,START,ENDfromlanggraph.store.baseimportBaseStorefromlangchain_core.messagesimportHumanMessage,SystemMessagefromlangchain_core.runnables.configimportRunnableConfig# Chatbot instructionMODEL_SYSTEM_MESSAGE="""You are a helpful assistant with memory that provides information about the user. If you have memory for this user, use it to personalize your responses. Here is the memory (it may be empty): {memory}"""# Create new memory from the chat history and any existing memoryCREATE_MEMORY_INSTRUCTION=""""You are collecting information about the user to personalize your responses. CURRENT USER INFORMATION: {memory} INSTRUCTIONS: 1. Review the chat history below carefully 2. Identify new information about the user, such as: - Personal details (name, location) - Preferences (likes, dislikes) - Interests and hobbies - Past experiences - Goals or future plans 3. Merge any new information with existing memory 4. Format the memory as a clear, bulleted list 5. If new information conflicts with existing memory, keep the most recent version Remember: Only include factual information directly stated by the user. Do not make assumptions or inferences. Based on the chat history below, please update the user information:"""defcall_model(state:MessagesState,config:RunnableConfig,store:BaseStore):"""Load memory from the store and use it to personalize the chatbot's response."""# Get the user ID from the configuser_id=config["configurable"]["user_id"]# Retrieve memory from the storenamespace=("memory",user_id)key="user_memory"existing_memory=store.get(namespace,key)# Extract the actual memory content if it exists and add a prefixifexisting_memory:# Value is a dictionary with a memory keyexisting_memory_content=existing_memory.value.get('memory')else:existing_memory_content="No existing memory found."# Format the memory in the system promptsystem_msg=MODEL_SYSTEM_MESSAGE.format(memory=existing_memory_content)# Respond using memory as well as the chat historyresponse=model.invoke([SystemMessage(content=system_msg)]+state["messages"])return{"messages":response}defwrite_memory(state:MessagesState,config:RunnableConfig,store:BaseStore):"""Reflect on the chat history and save a memory to the store."""# Get the user ID from the configuser_id=config["configurable"]["user_id"]# Retrieve existing memory from the storenamespace=("memory",user_id)existing_memory=store.get(namespace,"user_memory")# Extract the memoryifexisting_memory:existing_memory_content=existing_memory.value.get('memory')else:existing_memory_content="No existing memory found."# Format the memory in the system promptsystem_msg=CREATE_MEMORY_INSTRUCTION.format(memory=existing_memory_content)new_memory=model.invoke([SystemMessage(content=system_msg)]+state['messages'])# Overwrite the existing memory in the storekey="user_memory"# Write value as a dictionary with a memory keystore.put(namespace,key,{"memory":new_memory.content})# Define the graphbuilder=StateGraph(MessagesState)builder.add_node("call_model",call_model)builder.add_node("write_memory",write_memory)builder.add_edge(START,"call_model")builder.add_edge("call_model","write_memory")builder.add_edge("write_memory",END)# Store for long-term (across-thread) memoryacross_thread_memory=InMemoryStore()# Checkpointer for short-term (within-thread) memorywithin_thread_memory=MemorySaver()# Compile the graph with the checkpointer fir and storegraph=builder.compile(checkpointer=within_thread_memory,store=across_thread_memory)# Viewdisplay(Image(graph.get_graph(xray=1).draw_mermaid_png()))

When we interact with the chatbot, we supply two things:

当我们与聊天机器人交互时,需提供两样东西:

  1. Short-term (within-thread) memory: Athread IDfor persisting the chat history.
  • 短期(线程内)记忆:一个用于持久化聊天历史的线程 ID。
  1. Long-term (cross-thread) memory: Auser IDto namespace long-term memories to the user.
  • 长期(跨线程)记忆:一个用于将长期记忆按用户命名空间隔离的用户 ID。

Let’s see how these work together in practice.

让我们在实践中看看它们如何协同工作。

# We supply a thread ID for short-term (within-thread) memory# We supply a user ID for long-term (across-thread) memoryconfig={"configurable":{"thread_id":"1","user_id":"1"}}# User inputinput_messages=[HumanMessage(content="Hi, my name is Lance")]# Run the graphforchunkingraph.stream({"messages":input_messages},config,stream_mode="values"):chunk["messages"][-1].pretty_print()
================================[1m Human Message [0m================================= Hi, my name is Lance ==================================[1m Ai Message [0m================================== Hello, Lance! It's nice to meet you. How can I assist you today?
# User inputinput_messages=[HumanMessage(content="I like to bike around San Francisco")]# Run the graphforchunkingraph.stream({"messages":input_messages},config,stream_mode="values"):chunk["messages"][-1].pretty_print()
================================[1m Human Message [0m================================= I like to bike around San Francisco ==================================[1m Ai Message [0m================================== That sounds like a great way to explore the city, Lance! San Francisco has some beautiful routes and views. Do you have a favorite trail or area you like to bike in?

We’re using theMemorySavercheckpointer for within-thread memory.

我们正在使用MemorySaver检查点器来处理线程内记忆。

This saves the chat history to the thread.

该检查点器将聊天历史保存至线程。

We can look at the chat history saved to the thread.

我们可以查看已保存至线程的聊天历史。

thread={"configurable":{"thread_id":"1"}}state=graph.get_state(thread).valuesforminstate["messages"]:m.pretty_print()
================================[1m Human Message [0m================================= Hi, my name is Lance ==================================[1m Ai Message [0m================================== Hello, Lance! It's nice to meet you. How can I assist you today? ================================[1m Human Message [0m================================= I like to bike around San Francisco ==================================[1m Ai Message [0m================================== That sounds like a great way to explore the city, Lance! San Francisco has some beautiful routes and views. Do you have a favorite trail or area you like to bike in?

Recall that we compiled the graph with our the store:

请回顾一下,我们已使用该存储编译了图:

across_thread_memory=InMemoryStore()

And, we added a node to the graph (write_memory) that reflects on the chat history and saves a memory to the store.

并且,我们在图中添加了一个节点(write_memory),用于反思聊天历史并将记忆保存至存储。

We can to see if the memory was saved to the store.

我们可以验证该记忆是否已成功保存至存储。

# Namespace for the memory to saveuser_id="1"namespace=("memory",user_id)existing_memory=across_thread_memory.get(namespace,"user_memory")existing_memory.dict()
{'value': {'memory': "**Updated User Information:**\n- User's name is Lance.\n- Likes to bike around San Francisco."}, 'key': 'user_memory', 'namespace': ['memory', '1'], 'created_at': '2024-11-05T00:12:17.383918+00:00', 'updated_at': '2024-11-05T00:12:25.469528+00:00'}

Now, let’s kick off anew threadwith thesame user ID.

现在,让我们用相同的用户 ID启动一个新线程。

We should see that the chatbot remembered the user’s profile and used it to personalize the response.

我们应该能看到聊天机器人记住了用户的档案,并据此个性化其响应。

# We supply a user ID for across-thread memory as well as a new thread IDconfig={"configurable":{"thread_id":"2","user_id":"1"}}# User inputinput_messages=[HumanMessage(content="Hi! Where would you recommend that I go biking?")]# Run the graphforchunkingraph.stream({"messages":input_messages},config,stream_mode="values"):chunk["messages"][-1].pretty_print()
================================[1m Human Message [0m================================= Hi! Where would you recommend that I go biking? ==================================[1m Ai Message [0m================================== Hi Lance! Since you enjoy biking around San Francisco, there are some fantastic routes you might love. Here are a few recommendations: 1. **Golden Gate Park**: This is a classic choice with plenty of trails and beautiful scenery. You can explore the park's many attractions, like the Conservatory of Flowers and the Japanese Tea Garden. 2. **The Embarcadero**: A ride along the Embarcadero offers stunning views of the Bay Bridge and the waterfront. It's a great way to experience the city's vibrant atmosphere. 3. **Marin Headlands**: If you're up for a bit of a challenge, biking across the Golden Gate Bridge to the Marin Headlands offers breathtaking views of the city and the Pacific Ocean. 4. **Presidio**: This area has a network of trails with varying difficulty levels, and you can enjoy views of the Golden Gate Bridge and the bay. 5. **Twin Peaks**: For a more challenging ride, head up to Twin Peaks. The climb is worth it for the panoramic views of the city. Let me know if you want more details on any of these routes!
# User inputinput_messages=[HumanMessage(content="Great, are there any bakeries nearby that I can check out? I like a croissant after biking.")]# Run the graphforchunkingraph.stream({"messages":input_messages},config,stream_mode="values"):chunk["messages"][-1].pretty_print()
================================[1m Human Message [0m================================= Great, are there any bakeries nearby that I can check out? I like a croissant after biking. ==================================[1m Ai Message [0m================================== Absolutely, Lance! Here are a few bakeries in San Francisco where you can enjoy a delicious croissant after your ride: 1. **Tartine Bakery**: Located in the Mission District, Tartine is famous for its pastries, and their croissants are a must-try. 2. **Arsicault Bakery**: This bakery in the Richmond District has been praised for its buttery, flaky croissants. It's a bit of a detour, but worth it! 3. **b. Patisserie**: Situated in Lower Pacific Heights, b. Patisserie offers a variety of pastries, and their croissants are particularly popular. 4. **Le Marais Bakery**: With locations in the Marina and Castro, Le Marais offers a charming French bakery experience with excellent croissants. 5. **Neighbor Bakehouse**: Located in the Dogpatch, this bakery is known for its creative pastries, including some fantastic croissants. These spots should provide a delightful treat after your biking adventures. Enjoy your ride and your croissant!

Viewing traces in LangSmith 在 LangSmith 中查看追踪记录

We can see that the memories are retrieved from the store and supplied as part of the system prompt, as expected:

我们可以看到,记忆已按预期从存储中检索,并作为系统提示的一部分提供:

https://smith.langchain.com/public/10268d64-82ff-434e-ac02-4afa5cc15432/r

https://smith.langchain.com/public/10268d64-82ff-434e-ac02-4afa5cc15432/r

Studio

We can also interact with our chatbot in Studio.

我们还可以在 Studio 中与我们的聊天机器人进行交互。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 3:00:27

AI提示词总是答错?试试把问题重复输入一次

平时写AI提示词,很多人习惯加一大堆规则、背景和角色设定,生怕AI理解错。但最近看到一个挺简单的技巧:把完整的问题重复输入一次。Google Research 的论文《Prompt Repetition Improves Non-Reasoning LLMs》测试发现,对于部分非推…

作者头像 李华
网站建设 2026/10/1 3:00:18

响应式编程入门:从 Mono 到 Flux 的实战指南

一、什么是响应式编程传统编程是同步阻塞的:你调一个方法,线程停在那里等结果。响应式编程是异步非阻塞的:你把任务声明好,交给框架,有结果了再通知你。核心思想是:数据以流的形式流动,谁需要谁…

作者头像 李华
网站建设 2026/10/1 2:59:49

时序大数据预处理实战:从缺失值到异常检测的关键技术

搞大数据的人多半都听过一句话:垃圾进,垃圾出。模型再花哨、可视化再炫酷,只要喂进去的数据是脏的、缺的、乱的,最后的结果一定经不起推敲。而在整个大数据处理链路里,最容易被低估、又最直接决定项目成败的环节&#…

作者头像 李华
网站建设 2026/10/1 2:59:17

风格化渲染系统:从艺术规则到实时管线的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 2:58:42

无人机树木识别及病害分析数据集| 树种识别 树木损伤 无人机航拍 林业监测 多视角检测 9133期

无人机树木识别及病害分析数据集| 树种识别 树木损伤 无人机航拍 林业监测 多视角检测 9133期 数据集概述 本数据集专注于无人机航拍视角下的树种分类与树木损伤检测,服务于林业资源调查、病害监测及生态保护。数据涵盖五种树木类别与两类损伤状态,适配树…

作者头像 李华
网站建设 2026/10/1 2:58:18

KKT条件详解:从拉格朗日乘子法到支持向量机的约束优化核心

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华