news 2026/10/20 12:41:32

给Claude加外置记忆:跨会话记忆层的设计与实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
给Claude加外置记忆:跨会话记忆层的设计与实践

你有没有遇到过这种情况:用 Claude 处理一个跨周期的分析任务,聊到第三天,它已经完全不记得第一天的结论;或者你精心打磨了一段系统提示词,每次新建会话都得原封不动地重新粘贴一遍。我在实际项目里被这个问题折磨了很久,后来干脆给自己的应用加了一层外置记忆服务,代号就叫 claude-mem。这篇文章不是官方文档翻译,而是我把这套“给 Claude 加记忆”的方案从设计到落地完整跑通后的记录,包含架构思路、最小可用实现、以及几个只有真正踩过坑才知道的细节,适合正在做 AI 应用、想给模型加上跨会话记忆能力的朋友参考。

1. 为什么 Claude 需要一块“外置记忆”——API 会话的失忆问题

1.1 上下文窗口再大,也只是临时工作台

很多人对长上下文有误会,以为上下文窗口足够大,模型就“记得住”了。实际上,上下文窗口更像一块会议白板:当前这场会议里,你可以在上面写很多东西,模型也能随时查阅;但会议一结束,白板就被擦干净了。下一次开会,它又是一块崭新的板子。

Claude API 本身就是无状态的。每一次请求,你都必须把“它需要知道的一切”重新放进 messages 数组里。窗口再大,也只是让这“一场会议”变得更长,并不能让结论在下一场会议里继续生效。更麻烦的是,长对话会把窗口塞满,早期的重要背景会被后续的讨论逐渐挤出去,模型真正用到的时候已经找不到相关线索了。

1.2 会话隔离带来的重复成本

真实项目里,会话隔离造成的浪费远比你想的严重。我最初只是在做一个资料整理自动化脚本,每次调用 Claude 都要在系统提示里重新说明资料分类规则、输出格式、甚至语调偏好。

更难受的是跨多个步骤的任务。上午让 Claude 分析了一组数据,输出了一份中间结论;下午想基于这个结论继续做图表方案,又得把上午的内容重新整理后传一遍。这不仅是 token 开销的问题,更重要的是工作流被切成了一个个孤岛,无法形成连续推进。

1.3 claude-mem 的定位:模型之外的记忆中间层

claude-mem 这个名字其实已经说明了它的做法:不是去改模型,而是在模型外面包一层独立的记忆服务。

它的核心职责只有三件事:

  • 记录:从每次对话中提取值得长期保留的信息。
  • 存储:把信息整理成易于检索的结构化数据。
  • 召回:在下一次对话开始前,把与本次问题相关的记忆重新注入上下文。

也就是说,模型依然是那个模型,但你的应用从一个“每次都失忆的对话者”,变成了一个“带着历史档案的对话者”。这套方案适合做长期项目助理、自动化机器人、需要个性化连续交互的软件;如果只是做一次性问答,那确实不需要记忆,加了反而画蛇添足。

2. 记忆层整体架构:记录、存储、召回三件事

2.1 记忆写入:不是所有对话都值得记

这是整个方案里最容易走偏的地方。很多人一开始会把“所有对话原文”都扔进存储里,结果没几天存储就爆炸了,检索时返回的也是大量无关内容。

我自己的经验是,只有四类信息值得进入长期记忆:

  • 用户偏好:比如“报告里图表要放在最后”“回复要简洁不要开场白”。
  • 项目事实:比如“当前使用的数据源来自某内部系统”“生产环境部署在某个区域”。
  • 决策结论:比如“方案确定为定期同步而非实时同步”“数据库选型是轻量嵌入式方案”。
  • 待办与变更:比如“下一步要处理的三个问题”“昨天把分类规则从两级调整成了三级”。

操作上,我会让 Claude 自己完成抽取,而不是写一堆正则去匹配。给模型一个明确的抽取指令,让它把对话中符合这些类别的内容提取成结构化 JSON,然后由程序入库。这样既能过滤掉寒暄和通用问答,也不会漏掉那些藏在对话里的关键结论。

2.2 记忆存储:按类型分库,而不是一股脑塞进一个表

存储层我分了两个区:

  • 结构化记录区:存放上面那四类信息,字段包括内容、类型、时间戳、来源会话 ID、置信度、访问次数。用轻量嵌入式数据库就够,个人项目用 JSONL 文件也完全能跑。
  • 语义检索区:处理“这种说法和之前哪条记忆相关”的问题。比如用户说“上次那个速度问题怎么解决的”,这个描述和入库时的原文“同步任务卡在数据拉取环节”字面完全不同,必须靠向量相似度才能匹配上。

所以记忆写入时要同步做向量化:把结构化记录里的内容转成向量,存进本地向量索引。这样召回时既能用关键词精确匹配,也能用语义模糊匹配,两条腿走路比单一方式可靠得多。

2.3 记忆召回:在对话开始前把档案摆上桌

召回是整个流程里直接影响体验的一步。我的做法是在每次调用 Claude API 之前,先做好三件事:

  1. 拿当前用户消息去语义检索区查最相关的 N 条记忆。
  2. 对检索结果做重排:时间更近的、访问频率更高的排前面。
  3. 把选中的记忆拼成一段固定格式的文本,注入到 system prompt 的末尾。

注入的位置很关键。放在 system prompt 开头会被后续的详细指令稀释,放在末尾则更接近模型生成时正在关注的区域,实际召唤效果明显更好。当然,召回数量必须有硬上限,不能贪多,否则记忆本身就会反过来挤占掉主任务的空间。

3. 动手实现一个最小可用版本

3.1 目录结构与依赖

我建议直接用一个独立的 Python 包来承载,这样后续无论是接命令行工具还是 Web 服务,都能复用同一套逻辑。最小结构的目录如下:

claude-mem/ ├── mem/ │ ├── __init__.py │ ├── store.py # 结构化存储与向量索引 │ ├── extract.py # 记忆抽取 │ ├── recall.py # 记忆召回与注入 │ └── config.py # 配置项 ├── data/ # 本地存储文件 └── main.py # 接入示例

依赖方面我没有引入特别重的东西,核心就几个:请求库用来调模型接口,一个轻量数据库做结构化存储,一个本地向量索引库做语义检索。向量库不需要上重型的服务端方案,本地文件方式就够个人项目用了。

3.2 写入路径:从对话里抽取出结构化记忆

记忆写入入口是一个函数,输入是完整对话消息列表,输出是几条“待入库记忆”。抽取的逻辑依赖模型本身的能力:

def extract_memories(conversation): system = ( "你是记忆抽取器。从对话中抽取值得长期记住的信息," "分类为:偏好、事实、决策、待办。" "只输出 JSON 数组,数组元素为 {\"type\": \"偏好|事实|决策|待办\", " "\"content\": \"简洁的一句话\"}。" "没有值得记住的信息时输出空数组。" ) resp = call_llm( system=system, messages=conversation, temperature=0.1, ) return parse_json_array(resp)

抽取出来之后,入库前要做两个动作。

第一是去重:用内容哈希或者向量相似度判断是否已经存在同一条记忆,如果存在就直接更新时间戳和来源,而不是再插入一条。不然一次长对话里反复提到同一个结论,库里就会长出无数条重复记录。

第二是写入双份:一份带结构化字段放进数据库,一份做向量化放进检索索引。为了控制体积,向量化时用轻量模型即可,不需要把高成本的模型浪费在这里。

3.3 召回路径:把记忆拼成可注入的文本

召回函数是另一个核心入口。它的输入是当前用户问题,输出是一段可以直接拼进 system prompt 的记忆文本。

def build_memory_context(query, top_n=5): candidates = [] # 向量召回:语义相近的记忆 candidates += vector_index.search(query, k=top_n) # 关键词召回:字面匹配的记忆 candidates += keyword_search(query, k=top_n // 2) # 去重 + 按分数和时间衰减排序 seen = set() ranked = [] for c in candidates: key = c["content_hash"] if key in seen: continue seen.add(key) score = c["similarity"] + time_decay(c["timestamp"]) ranked.append((score, c)) ranked.sort(key=lambda x: x[0], reverse=True) selected = [c for _, c in ranked[:top_n]] if not selected: return "" lines = [f"[{c['type']}] {c['content']} (时间:{c['timestamp']})" for c in selected] return "以下是历史记忆,供参考:\n" + "\n".join(lines)

这一步有几个细节要留意。时间衰减权重不能给太大,否则新的记忆即便不相关也会压过真正有用的旧结论;但也不能完全不用时间信息,否则几个月前的失效结论会一直霸占前排。我的经验是相似度的主导权应该更高,时间只做小幅加成。

3.4 完整工作流拼装

有了写入和召回两条路径,主流程就非常清晰了。每次调用前先构建记忆上下文,调用后再把新对话传给抽取器,完成一次“召回-回答-记忆”循环:

def process_message(user_text): memory_ctx = build_memory_context(user_text) messages = build_messages( system=SYSTEM_PROMPT + "\n" + memory_ctx, history=session_history, user=user_text, ) answer = call_llm(messages=messages) # 把这次交互写入记忆库用于下次召回 extract_memories([*session_history, {"role": "user", "content": user_text}]) session_history.append({"role": "user", "content": user_text}) session_history.append({"role": "assistant", "content": answer}) return answer

完整跑通这个最小版本之后,你会发现一个很重要的变化:原来每个新会话都要重复交代的背景信息,现在第一次说完之后,后续对话里已经不需要再出现第二遍了。

4. 记忆管理的四个核心问题:膨胀、污染、陈旧、权限

4.1 记忆膨胀与 token 预算

记忆并不是越多越好。哪怕召回时限制了条数,如果记忆库本身塞满了噪音,召回到的很可能全是废话。

我给记忆库设了几条硬规则:

  • 单条记忆长度控制在 50 字以内,超长内容强制拆分成多条或压缩。
  • 相同语义的记忆只保留一条,反复被命中的记忆提升权重,长期不被命中的定期降级。
  • 每条记忆分配一个“有效期”,不同类型的有效期不同。偏好可以保留很长,临时待办过两周就可以归档。

token 预算也需要硬约束。我在配置里规定记忆上下文最多占 system prompt 长度的 20%,超过就压缩召回条数,而不是无限往里面塞。这一步能防止“记忆反而成了主任务干扰源”的尴尬局面。

4.2 记忆污染:错误结论不能成为长期记忆

这是我踩过最深的一个坑。早期版本里,Claude 在对话中途随口说了一句“这个方案基本可以”,抽取器就把它当成决策记入库了。结果后面所有对话都带着这条“已确认”的决策在跑,而实际上那个方案当时还有重大隐患。

解决办法是给记忆加置信度和确认机制:

  • 只有同一结论在多次对话中被重复提到,置信度才会上升到“长期记忆”的标准。
  • 一次性的、带有不确定口吻的内容只能进入短期缓冲,不直接写入长期区。
  • 提供手动修正通道,用户可以说“忘掉刚才那条”,程序会按内容哈希定位并删除或标记废弃。

这个设计本质上是在模拟人的记忆方式:重要的信息需要重复和确认,而不是听完一句话就当成既定事实。

4.3 记忆陈旧与冲突

项目进行到中后期,旧的结论和新的事实经常会打架。比如第一天决定“月底做全量同步”,第三天改成“改成增量同步”。如果不处理旧记忆,召回时可能两条都返回,模型就会困惑到底该听哪条。

我的处理策略是:同主题的新记忆写入时,不直接物理删除旧记忆,而是把旧记忆标记为 conflicted,并在召回时只返回最新一条。同时保留旧记录的查询入口,方便溯源。这样既不会让模型看到矛盾信息,也不会因为删除而丢失历史线索。

4.4 隐私与权限

记忆系统最容易被忽视的是权限问题。一旦模型可以调取历史信息,就意味着它可能把不该知道的东西翻出来。

我在写入路径上加了两道过滤:

  • 正则过滤:识别常见的秘钥、令牌、密码格式,直接拦截不入库。
  • 语义过滤:在抽取指令里明确要求“忽略涉及机密凭证的内容”,让模型在抽取阶段就主动丢弃敏感字段。

存储位置默认在本地,绝不默认上传到外部服务。如果未来要做多端共享,也必须先加密再传输,并且给每条记忆设置可见范围。用户应该能随时查看记忆库的全部内容,并能一键清除指定类型或全部记忆。

我见过一些项目只做了召回和写入,却完全忽略了权限和清理机制,结果用户问“我上次说过什么”,系统把她三个月前输入的账号密码也翻出来了。这种体验不但糟糕,而且会直接摧毁用户对记忆功能的信任。

5. 实测效果与踩坑记录

5.1 接入前后的显著差异

我把这套 claude-mem 方案接入到一个资料整理与报表生成的工作流里做对比测试。接入前,每次运行都需要在系统提示中手工粘贴资料分类表、输出模板和最近三天的处理结论,系统提示部分经常超过 2000 字。

接入后,系统提示只保留通用的工作指令,其余动态信息全部由记忆层在运行时拼装。实测结果是:

对比项接入前接入后
系统提示固定部分约 2000 字约 400 字
重复交代背景次数每次会话约 2-3 次基本上零次
有用结论丢失情况经常发生未再发生
单次任务请求量波动大稳定下降约 35%

更直观的感受是,对话质量稳定了很多。因为模型每次回答时都能带着之前已经确认的决策和用户偏好,输出的结果不再是“从零开始思考”,而是“接着上次的进度继续推进”。

5.2 踩过的坑和最终解法

第一个坑是把完整对话历史塞进记忆。第一版方案图省事,直接把最近 N 轮对话原文放进 system,结果主任务的指令被大量历史噪音稀释,模型开始大量复述旧内容而不是推进新内容。最终改成“抽取关键信息 + 限制召回条数”才解决问题。

第二个坑是时间衰减系数调得太激。一开始想当然地设了一个比较大的衰减系数,结果隔一天客户之前明确提过的格式偏好就被遗忘了,需要重新说明。改成小衰减因子后,旧记忆保留时间变长了,但同时又要靠访问次数来压制不相关旧记忆,算法上需要多调几个参数才能平衡。

第三个坑是检测不到矛盾记忆。旧决策和新决策冲突时,早期版本没有处理,导致模型在“月底全量”和“改为增量”之间来回摇摆。加了 conflicted 标记和同主题覆盖规则之后,这个问题才彻底消失。

5.3 后续可以继续扩展的方向

当前这套 claude-mem 还只是单机版的最小实现,而且记忆的召回完全依赖向量相似度和时间信息,对复杂的上下文关系支持有限。我接下来的计划有两步:

一是把记忆层从“随应用内嵌”改造成“独立服务”。给记忆服务增加 HTTP 接口之后,多个应用可以共用同一个记忆库,比如日常问答、定时任务、代码辅助工具各自连接同一套记忆,真正形成个人 AI 工作台。

二是补充知识图谱层。向量检索擅长找“相似”但不懂“关系”,加上图谱之后,“项目A依赖项目B”“上周说好了要迁到方案C”这类依赖和因果语义才能被完整表达,召回质量还能再上一个台阶。

使用下来我的切身感受是:记忆功能的本质不是“存得多”,而是“记得准、删得掉、不越权”。Claude 本身已经很能打了,缺的只是一块能跟着工作节奏走的档案夹。claude-mem 这套思路就是把这个档案夹建起来,让模型从“每次都是陌生人”变成“每次都是那个见过世面的老同事”。如果你也被跨会话失忆问题折磨过,不妨按这个最小实现先跑起来,哪怕只加一个偏好记忆,日常体验也会有明显改善。

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

慕慕生鲜源码本地版:从零跑通生鲜电商业务闭环实战

简介:这是一套面向Java Web学习者与生鲜电商开发者的本地版慕慕生鲜项目源码,基于Maven构建、采用Spring框架,适合用于课程设计、毕业设计或二次开发练手。压缩包共434个文件,约14.11MB,以xml配置、class字节码、java源…

作者头像 李华
网站建设 2026/10/16 5:53:10

Linux线程同步实战指南:从竞态条件到死锁排查

不少写并发程序的人,最后都会在一个坑里摔一跤:单线程跑得好好的,换到多线程,数据就开始出乱子。明明加了锁,结果不对,或者进程直接卡死。线程同步这个话题,看起来翻来覆去就是互斥锁、条件变量…

作者头像 李华
网站建设 2026/10/19 14:31:30

Linux信号机制全解析:kill、sigaction与Core Dump实战

聊Linux进程管理的时候,信号(signal)是无论如何都绕不过去的一块。很多人最初接触它的契机是kill -9 pid杀进程,但kill背后的信号机制远不止“杀进程”这一个用处。信号本质上是一种异步事件通知机制,它告诉进程“有事…

作者头像 李华
网站建设 2026/10/16 16:00:22

OpenClaw智能体框架实战:云端与本地部署及聊天机器人接入指南

最近不止一个朋友跑来问我,OpenClaw(Clawdbot)这东西到底怎么摆弄,能不能从零开始搭起来,还得接进聊天软件里当私聊机器人用。说实话,2026年这个时间点,智能体框架已经不像前两年那么神秘了&…

作者头像 李华
网站建设 2026/10/16 10:47:18

Agent技能中心落地指南:AIBridge架构与技能生命周期管理

最近在跟进 OoderAgent 技能中心这套体系,看到白皮书更新到 v0.6.5,我这边也对照着把之前的一些实践重新捋了一遍。这版改动最明显的一点,是把 AIBridge 从单纯的“工具连接器”提升为技能全生命周期的管理枢纽,整个设计思路更接近…

作者头像 李华
网站建设 2026/10/16 10:41:32

玻璃热转印花膜:解锁玻璃器皿颜值与耐用的双重突破

伴随着国内家居消费、香氛美妆行业持续升温,玻璃杯、香氛蜡烛杯、香水瓶这类玻璃器皿的市场需求量正在逐年上涨。消费者在选购产品的时候,不再只看重玻璃本身的材质通透度,器皿外表的花纹、logo、装饰图案已经成为决定产品市场竞争力的关键因…

作者头像 李华