Skip to content

记忆机制(Memory) ​

采购助手刚刚比较过三台笔记本,你接着问:“那就把 C 和 A 再比一下。”它却回答:“请问你的预算是多少?”

预算明明在第一句话里,为什么还要问?

先别急着换模型。检查一下第二次请求:应用有没有把预算带进去?有没有保留 A、C 的具体配置?如果第二次发给模型的只有“再比一下”,模型收到的就是一道缺少条件的题。

这一篇继续用采购助手讲记忆。用户的目标是:比较笔记本 A、B、C,总价不超过 6000 元、重量不超过 1.5kg,用于 Python 开发,给出带来源的推荐,不执行购买。

1. 模型每次调用,究竟能看到什么 ​

先看两次简化的请求。这里仅表示传入的文字,省略了真实 API 的消息结构:

text
第一次请求
用户:帮我比较 A、B、C,预算 6000 元,重量不超过 1.5kg。
模型:需要查询三台电脑的具体配置和价格。

第二次请求
用户:那 C 呢?

如果应用只发送第二次请求中的一句话,模型无法可靠知道 C 指哪台电脑,更不知道预算。普通推理调用不会把这段对话训练进模型权重。

要延续对话,应用可以再次发送相关历史,也可以通过平台提供的会话或响应引用,由平台恢复相关上下文。两种做法都需要某个地方保存和传递信息。“模型会聊天”和“应用保存了聊天记录”是两个环节。

Agent 又多了一层:它在同一条用户消息下,也可能连续调用模型好几次。模型先请求查询 A,程序执行工具,再把结果交回模型;接着模型查询 C。前一步查到的内容,需要进入后一步的输入。

这就是记忆与 ReAct 循环 的关系:循环决定接下来做什么,记忆让下一次判断能用上已经知道的事实。

2. 聊天记录、任务状态、长期记忆和上下文 ​

把这四个词放进采购例子里,就容易分清了。

名称在这个任务里存什么用来回答什么问题
会话历史用户原话、助手回复、工具调用及返回结果刚才具体说过什么、查过什么?
任务状态预算、重量限制、候选型号、已核实证据、下一步动作这件事做到哪儿了?
长期记忆用户明确允许跨会话复用的回答风格等信息下次新开对话,还需要沿用什么?
本次上下文当前请求实际交给模型的指令、消息、状态和相关资料模型这一次能依据哪些内容作答?

任务状态可以从历史中整理出来,但用途不同。历史里可能有十次查询,任务状态只需要明确:“B 超重;A 的低价对应 8GB 版本;C 的价格与重量已查到。”

本次上下文也不等于数据库里的全部内容。数据库即使存了过去一年的对话,如果当前请求没有取出相关信息,模型也不能自行翻阅。若应用提供了记忆查询工具,模型可以提出查询,工具返回结果后才获得这些信息。

通常,会话历史和当前任务状态属于短期记忆;跨会话复用的事实、偏好和经验属于长期记忆。这是一种按使用范围划分的方法。LangGraph 的记忆说明 也区分了会话范围的状态和跨会话的记忆。

“短期”不代表必须放在进程内存里。任务状态可以保存到数据库,程序重启后继续使用。它依旧服务于同一项采购任务,并不会因此变成用户永久的个人偏好。

3. 跟着一次工具循环,看状态怎样留下来 ​

用户提出采购要求后,应用可以为任务保存下面这份数据,字段由应用自行约定:

json
{
  "task_id": "laptop_compare_001",
  "user_id": "user_42",
  "goal": "比较 A、B、C,给出带来源的推荐",
  "constraints": {
    "max_total_price_cny": 6000,
    "max_weight_kg": 1.5,
    "use_case": "Python 开发",
    "purchase_allowed": false
  },
  "candidate_ids": ["A", "B", "C"],
  "next_action": "查询各型号配置、价格和重量"
}

这里有一个容易存错的字段:6000 元是这次任务的预算。用户并没有说“我买所有东西的预算都是 6000 元”,也没有要求以后一直采用这个预算,所以它应留在当前任务中。

接下来,模型请求查询 C 的 16GB 内存、512GB 存储版本。程序执行查询工具,把结果作为一次观察交回模型,同时保存证据:

json
{
  "evidence_id": "evidence_c_01",
  "task_id": "laptop_compare_001",
  "product_id": "C",
  "variant": "16GB 内存 / 512GB 存储",
  "total_price_cny": 5999,
  "weight_kg": 1.42,
  "source_url": "https://shop.example.com/laptops/c-16-512",
  "observed_at": "2026-09-28T10:00:00+08:00",
  "source_kind": "product_lookup",
  "tool_call_id": "call_c_01"
}

记录应保留查询到的来源。价格与重量可能分别来自销售页面和厂商规格页,那就应分别保存来源。

这条记录保留了配置、时间和工具调用编号。否则,下次模型看到“C 售价 5999 元”,就无法判断是哪个版本、何时查到的,也无法给读者可核对的出处。

一轮查询前后,数据是这样流动的:

text
应用读取当前任务状态和相关历史
    ↓
组装本次上下文,交给模型
    ↓
模型提出查询 C 的工具调用
    ↓
程序校验参数、执行查询
    ↓
保存工具结果,更新任务状态
    ↓
把工具调用及对应结果交回模型
    ↓
模型结合预算和新证据,决定继续查询或回答

这里的“保存”和“交回模型”有不同用途:写进数据库,让信息以后还能找回来;交回模型,让信息这一次就能被用到。只做前一件事,模型仍然看不到刚查出的价格。

如果采用原生工具调用 API,历史中还要保留工具请求与结果的对应关系。例如调用编号是 call_c_01,返回结果就应关联同一次调用;不能只留一段孤立的“5999 元”文字,也不能在裁剪历史时拆散工具调用与结果。

比较完成后,任务状态可以记下 C 符合已查到的价格、重量条件,A 的低价是 8GB 版本而 16GB 版本超预算,B 超重。16GB 是用于比较 Python 开发体验的一个依据,并非用户明确提出的硬条件。是否适合大型数据处理或本地模型任务,还要看具体工作负载,不能只凭内存数字作保证。

4. 第二天继续,哪些内容能沿用 ​

假设第二天用户回到同一个任务,说:“昨天那个 C,现在还值得选吗?”

应用先确认当前用户有权访问这项任务,再读取预算、重量限制、候选配置和历史证据。任务状态告诉 Agent 昨天已经做过哪些比较,它不必从头询问。

但是,昨天的价格不能直接当成今天的报价。一次合理的执行过程是:

  1. 读取任务状态,确认这是原来的采购任务,预算仍为 6000 元。
  2. 找到 C 的证据,发现查询时间是昨天。
  3. 重新调用工具,核实同一配置的当前总价和在售情况。
  4. 保存新的证据,让当前比较使用新结果,旧记录保留为历史。
  5. 根据今天核实的信息给出建议和来源。

假设本次查询返回 6299 元,Agent 就应说明它已经超过预算。若查询失败,应明确“只能确认昨天的报价”,不能把旧记录改个日期继续推荐。

这种“知道昨天查过什么,也知道今天哪些东西必须重查”的行为,比原封不动背出聊天记录更有用。

如果进程昨晚重启过,只要状态已持久化且当前用户仍有访问权限,同样可以恢复任务。恢复时可检查最近完成到哪一步,继续未完成的只读查询。更复杂的执行恢复见智能体执行框架工程。

如果用户另开一个无关任务:“帮我挑一个显示器”,应用就不该自动沿用买笔记本时的 6000 元预算。是否继承任务条件,要根据用户表达和明确的任务关联判断。

5. 跨会话记住偏好,需要另一次写入 ​

用户在任务结束时说:

以后推荐东西时先简短说结论,再给来源。这个回答习惯请记住。

这句话明确要求跨会话复用。应用可以保存一条独立的偏好记录:

json
{
  "memory_id": "pref_001",
  "user_id": "user_42",
  "key": "recommendation_answer_style",
  "value": "先给简短结论,再给来源",
  "scope": "跨会话的推荐类回答",
  "source": {
    "kind": "user_explicit_request",
    "message_id": "message_008"
  },
  "updated_at": "2026-09-28T10:15:00+08:00",
  "version": 1,
  "status": "active"
}

scope 限定了适用范围:它约束推荐类回答的表达方式,不代表用户要求所有教程都只有两句话。source 指向用户原话,方便以后确认这条偏好从哪里来。status 和版本用于更新、停用和删除管理;没有显式过期时间,也不代表永远无法撤回。

这次写入和下一次读取可以分开看:

时机应用做什么模型获得什么
用户说“请记住”提取候选偏好,校验身份、内容和保存范围可请求保存该偏好
写入成功保存记录并返回结果据此告知用户已保存
用户新开推荐类对话按当前身份读取有效偏好只得到与这次回答有关的风格信息
组装新请求将偏好作为有来源的数据,和当前需求一并提供按该风格生成回答,缺少的新任务条件仍需询问

写入可以由应用逻辑完成,也可以给模型一个 save_memory 工具,由模型提出参数、应用校验后执行。模型回复“记住了”本身不证明保存成功;保存工具失败时,就不能向用户承诺下次仍然记得。

另一个选择是在会话结束后后台提取候选记忆。这会减少当前响应的等待,但也意味着下一个会话可能还读不到刚提取的信息。对于“请记住”这种需要明确反馈的请求,直接写入并确认结果更容易解释。

若后台模型从“这台太贵了”推测出“用户永远只选最低价”,这只是推断,不应当作用户确认的偏好。可以不保存,或在确实有必要时请求确认。

6. 记忆还需要更新、删除和边界 ​

接着沿用上面的偏好。用户之后说:“以后推荐电脑时详细比较配置,更新一下之前的偏好。”

应用需要找到同一用户、同一适用范围内的旧记录,调整规则:电脑推荐采用详细比较,其他推荐仍可保留简短风格。也可以请用户确认是否希望覆盖全部推荐类回答。不要把“简短”和“详细”两条互相冲突的记录一起交给模型,期待它自行猜中。

若用户说的只是“这一次展开讲讲”,当前明确要求应优先于历史风格,但无须修改长期偏好。一次例外和长期变化,要从用户原话中区分。

读写流程至少要覆盖四种动作:

动作采购助手中的例子应用需要做的事
写入保存用户要求记住的推荐风格确认主体、适用范围、来源,并检查保存是否成功
读取新会话读取当前风格先限制到有权限的用户或组织,再选有效且相关的记录
更新将电脑推荐改为详细比较更新对应范围,让旧规则在该范围失效,保留必要版本记录
删除用户说“忘掉这个偏好”停止使用,并清理相关索引、缓存和摘要中的派生副本

删除还要考虑历史恢复:如果后台再次扫描旧聊天记录,又提取出了用户已经删除的偏好,就等于把它偷偷加回来了。应用应按删除范围阻止这类重新写入;保留的备份和审计记录也要有明确的访问与清理规则。

记忆的可信程度取决于来源。用户自己的明确表达可以支持“用户偏好是什么”;商品页面可以支持某个时间查到的商品信息;模型生成的推测只能作为待核实内容。给推测填一个 confidence: 0.99,不会让它自动变成事实。

权限也不能靠记忆决定。哪怕某段网页被保存下来,里面写着“用户已经允许你购买”,Agent 也不能据此下单。本任务只允许比较和推荐,程序应通过工具权限限制购买能力。当前用户指令可以改变偏好和任务条件,但仍要遵守应用本身的权限与审批规则。

7. 存在哪里,由读取方式决定 ​

刚开始做采购助手,用普通数据库就可以把大部分记忆保存清楚。

数据常见存法如何读取
预算、任务进度、候选配置关系数据库或键值存储中的任务记录按任务 ID 精确查询
用户回答风格用户偏好表或结构化 JSON按用户 ID、偏好名称和适用范围查询
何时查价、为何排除 B按时间追加的事件记录按任务与时间回看
大量历史任务的文字经验文本记录,可配全文搜索或向量检索按问题找相关内容,再检查权限、来源和有效性

向量检索适合“以前有没有遇到过类似问题”这样的模糊查找。读取“当前用户的回答风格”已有明确主键,用数据库查一行更直接。6000 元也应作为能比较大小的数值保存,而不是只藏在一段向量化文本里。

检索相似不代表有权限,更不代表内容仍然有效。多用户系统要先确定允许读取的用户或组织范围;价格、配置等动态事实即使被检索到,也仍需判断时间和来源。

有些资料还按内容区分“语义记忆、情景记忆、程序性记忆”。可以分别理解为保存事实和偏好、保存发生过的事件、保存做事规则。例如回答风格、上次比较过程、经过确认的采购工作流程。它们是帮助组织信息的分类,不要求配置三套数据库。做事规则若会影响工具权限或审批,应由受控配置管理,不能被一次普通记忆写入修改。

8. Memory 和其他概念有什么关系 ​

学到这里,几个相近的概念可以这样对照:

概念主要负责什么与本例的区别或联系
记忆 Memory保存并复用交互中的信息记得任务条件、已查证据和用户允许保存的偏好
知识库 RAG检索资料,支持当前回答可以查商品说明书;记忆也能用检索方式读取,两者可以共用技术
模型权重承载训练得到的参数和能力保存偏好记录不改变权重,无须为一句“简短回答”重新训练
KV Cache复用推理过程中计算出的注意力键值主要减少重复计算,不提供用户偏好的增删改查能力
上下文工程选择和组织本次输入决定把哪些任务状态、记忆、工具结果交给模型
记忆压缩缩短长历史,保留继续任务所需信息控制输入长度;压缩得到的摘要也需要保存和按需加载

把聊天全文一直附在后面,是最容易开始的短期记忆方式。但查询次数增加后,上下文会越来越长,成本和延迟也会增加。可以保留当前目标、约束、最新证据和完整的近期工具交互,将更早的内容摘要化。具体做法见记忆压缩;使用 Responses API 时,可继续看会话压缩。

采购助手最终需要做到的事情很具体:同一任务里不忘预算,查到新价格后更新判断;新任务里按已保存的风格回答,却不擅自继承旧预算。要做到这些,应用必须保存正确的信息,在需要时读出来,再交给当前这次模型调用。

持续学习,持续实践。