第09章:上下文与记忆 (2)

2、短期记忆

LangChain1.x 的短期记忆是三者的组合:

State(会话内部状态) + Checkpointer(持久化机制) + Thread ID(会话作用域)

  • State :默认 存储历史消息列表messages ,通过State 管理历史消息
  • Checkpointer :负责将State 作为检查点持久化保存,检查点是某个时刻的State 快照
  • Thread ID :用于唯一标识State ,LangChain运行时会按照 thread_id 读写State快照

这就像玩 RPG 游戏时的"自动存档":你不需要手动保存,系统在关键节点自动记录,下次进入游 戏随时可以从上次的存档点继续。

1 基于内存的持久化器

这是最便捷的使用方式,适合快速测试或调试。

举例1:没有记忆

复制代码
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from dotenv import load_dotenv
load_dotenv(verbose=True)

agent = create_agent(
    model="deepseek:deepseek-v4-pro",
    tools=[]
)

print("\n第一轮对话:")

response1 = agent.invoke({
    "messages": [
        HumanMessage("我叫张三")
    ]
})

print(f"Agent: {response1['messages'][-1].content}")


print("\n第二轮对话:")

response2 = agent.invoke({
    "messages": [
        HumanMessage("我叫什么?")
    ]
})

print(f"Agent: {response2['messages'][-1].content}")

第一轮对话:

Agent: 你好,张三!有什么我可以帮你的吗?

第二轮对话:

Agent: 我目前不知道您的名字,因为我看不到您的个人信息。您可以告诉我您叫什么,我会记住并在对话中称呼您。

举例2:拥有记忆

步骤1:第一二轮对话

复制代码
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from dotenv import load_dotenv
from  langgraph.checkpoint.memory import InMemorySaver
load_dotenv(verbose=True)

checkpointer = InMemorySaver() # 1.创建了内存级别的会话记忆

agent = create_agent(
    model="deepseek:deepseek-v4-pro",
    tools=[],
    checkpointer=checkpointer, # 2.让agent具备了存储的能力
)

#3.同一个thread_id共享记忆的
config={
    "configurable":{
        "thread_id":"1"
    }
}
print("\n第一轮对话:")

response1 = agent.invoke({
    "messages": [
        HumanMessage("我叫张三")
    ]
},
config=config)

print(f"Agent: {response1['messages'][-1].content}")


print("\n第二轮对话:")

response2 = agent.invoke({
    "messages": [
        HumanMessage("我叫什么?")
    ]
},
config=config)

print(f"Agent: {response2['messages'][-1].content}")

第一轮对话:

Agent: 你好,张三!有什么可以帮你的吗?

第二轮对话:

Agent: 你叫张三。

说明:你只需传入 checkpointer 和 config,Agent 就能自然具备连续对话能力

步骤2:第三轮对话

复制代码
print("\n第三轮对话:")

response3 = agent.invoke({
    "messages": [
        HumanMessage("我叫啥?")
    ]
},
config=config1)

print(f"Agent: {response4['messages'][-1].content}")

说明:第三轮对话中的 "我刚才问了什么问题?" 就能在第二轮存储的消息历史中找到答案。所有消息 历史都会自动追加到 AgentState 的 messages 字段中,无需手动维护。

步骤3:更新线程ID

而如果更新线程ID,则会重新开启对话:

复制代码
config1={
    "configurable":{
        "thread_id":"2"
    }
}
print("\n第三轮对话:")

response3 = agent.invoke({
    "messages": [
        HumanMessage("我叫啥?")
    ]
},
config=config1)

print(f"Agent: {response4['messages'][-1].content}")

Agent: 我不知道你的名字哦,你可以告诉我,我就可以用名字称呼你啦。

说明:thread_id 隔离不同会话空间。

关键步骤说明

第1步:初始化记忆引擎: checkpointer = InMemorySaver() ------创建一个内存级的记忆存储

注意:InMemorySaver内存中保存,进程结束就丢失数据,适合测试。生产环境可换成数据库持 久化的 SqliteSaver 、 PostgresSaver 等

第2步:绑定 Agent:在 create_agent 时传入 checkpointer ,让 Agent 具备状态存储能力。

第3步:设定会话 ID:通过 config = {"configurable": {"thread_id": "1"}} 为每次调用指定线程标识。 同一个 thread_id 共享记忆,不同 thread_id 完全隔离。

复制代码
# 会话 1
config1 = {"configurable": {"thread_id": "1"}}
agent.invoke({...}, config=config1)
# 会话 2
config2 = {"configurable": {"thread_id": "2"}}
agent.invoke({...}, config=config2)
# 两个会话完全独立

thread_id 是记忆管理的核心开关:在会话2里询问会话1的会话信息,Agent 会表示不知道------因为双 方记忆空间完全隔离。

生产环境中:

场景1:多用户聊天

不同 thread_id = 不同会话,Agent 能正确记住每个会话的内容

复制代码
agent = create_agent(
    model=model,
    tools=[],
    checkpointer=InMemorySaver()
)

# 用户 Alice
config_alice = {
    "configurable": {
        "thread_id": "user_alice"
    }
}

agent.invoke(
    {"messages": [...]},
    config_alice
)

# 用户 Bob
config_bob = {
    "configurable": {
        "thread_id": "user_bob"
    }
}

agent.invoke(
    {"messages": [...]},
    config_bob
)

# 两个会话完全独立

场景2:同一用户的不同任务

复制代码
# 任务 1:写代码
config_task1 = {
    "configurable": {
        "thread_id": "task_coding"
    }
}

agent.invoke(
    {"messages": [...]},
    config_task1
)

# 任务 2:写文档
config_task2 = {
    "configurable": {
        "thread_id": "task_docs"
    }
}

agent.invoke(
    {"messages": [...]},
    config_task2
)

工作原理

内存保存了什么?

复制代码
agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "你好"
            }
        ]
    },
    config
)

# InMemorySaver 保存:
# {
#     "thread_id": "xxx",
#     "messages": [
#         HumanMessage("你好"),
#         AIMessage("你好!有什么可以帮助你的吗?")
#     ]
# }


agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "天气"
            }
        ]
    },
    config
)

# InMemorySaver 更新:
# {
#     "thread_id": "xxx",
#     "messages": [
#         HumanMessage("你好"),
#         AIMessage("你好!有什么可以帮助你的吗?"),
#         HumanMessage("天气"),
#         AIMessage("...")
#     ]
# }

自动追加历史

复制代码
# 你只需要传新消息
agent.invoke(
    {"messages": [{"role": "user", "content": "新问题"}]},
    config
)

此时,checkpointer 自动:

① 读取之前的历史

② 追加新消息

③ 调用模型(传入完整历史)

④ 保存新的历史

说明:checkpointer 会自动管理历史

常见问题

为什么 Agent 不记得?

✅ 是否添加了 checkpointer=InMemorySaver() ?

✅ 是否传入了 config 参数?

✅ 两次调用的 thread_id 是否相同?

复制代码
# ❌ 错误:没有 checkpointer
agent = create_agent(
    model=model,
    tools=[]
)

agent.invoke({...})  # 不会记住


# ❌ 错误:没有 config
agent = create_agent(
    model=model,
    tools=[],
    checkpointer=InMemorySaver()
)

agent.invoke({...})  # 不会记住


# ❌ 错误:thread_id 不同
agent.invoke(
    {...},
    config={
        "configurable": {
            "thread_id": "1"
        }
    }
)

agent.invoke(
    {...},
    config={
        "configurable": {
            "thread_id": "2"
        }
    }
)  # 不同会话


# ✅ 正确
agent = create_agent(
    model=model,
    tools=[],
    checkpointer=InMemorySaver()
)

config = {
    "configurable": {
        "thread_id": "1"
    }
}

agent.invoke({...}, config)
agent.invoke({...}, config)  # 记得!

2、InMemorySaver 会丢失数据吗?

会! InMemorySaver 只保存在内存中

  • ✅ 同一进程内有效(不支持跨进程共享)
  • ❌ 程序重启后丢失(或进程重启后丢失)
  • ❌ 不同进程无法共享

解决方案:持久化(SQLite、PostgreSQL)

3、内存会无限增长吗?

会! 默认情况下,InMemorySaver 会保存所有消息

问题:

  • 消息越来越多(无限增长,需要管理上下文)
  • token消耗增加,甚至会超过模型的 token 限制
  • 响应速度变慢、成本增加

解决方案:上下文管理(修剪、摘要)

4、如何清空某个会话的历史?

目前 InMemorySaver 没有提供删除 API。

临时方案:

  • 使用新的 thread_id
  • 或重新创建 Agent
相关推荐
可乐鸡翅yeah_11 分钟前
第三方接口对接 M3U8 流媒体排坑实战,解决外部服务商流兼容难题
前端·javascript·python·django·html·m3u8·m3u8在线
2601_9622035113 分钟前
Java进阶07集合(续)
java·开发语言
CDN36021 分钟前
节点智能调度实操:解决出海区域访问快慢不均、节点拥堵、跨洋延迟高,CDN 全网择优落地方案
运维·服务器·网络
GoppViper25 分钟前
RDF资源描述框架深度解析:语义Web的数据基石与实战逻辑
前端·数据库
郑州光合科技余经理33 分钟前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
IT_陈寒36 分钟前
Vue的嵌套组件竟然吃掉了我的事件?
前端·人工智能·后端
默_笙37 分钟前
🏠 「LLM Notes」:我用 Next.js + Redis 给自己造了个笔记博客
前端·javascript
风骏时光牛马43 分钟前
AI开发平台异常指标实时监控告警
前端
roman_日积跬步-终至千里1 小时前
【数据治理(6)】DataOps 不是调度工具,而是让数据产品长期可信的运行机制
java·服务器·网络