☰
claude-mem:为AI编程助手构建长期记忆系统
2026/10/26 16:12:05 网站建设 项目流程

1. 项目缘起与核心定位

第一次看到claude-mem这个名字,我脑子里蹦出来的第一反应是:终于有人把这件事单独拎出来做了。做过一段时间 AI 辅助开发的人都知道,跟大模型结对写代码最让人抓狂的地方,从来不是它写不出代码,而是它记不住。你上午跟它聊清楚了整个项目的目录结构、命名规范、数据库表设计,下午开个新会话,它就像失忆一样,又问你“请问你的项目用的是什么框架”。这种反复交代背景的体验,消耗的耐心比写代码本身还多。

claude-mem要解决的就是这个痛点。从名字拆开看,claude指向的是 Anthropic 家的 Claude 系列模型以及围绕它构建的对话式开发工作流,mem则是 memory(记忆)的缩写。合起来,它是一套给 Claude 这类对话式 AI 编程助手外挂长期记忆的方案。它做的事情说白了就是:把你在会话里说过的关键信息——项目背景、技术栈、约定俗成的规则、踩过的坑、已经确定的设计决策——抽取出来存到一个可以持久化的地方,等下一次开新会话时,再把这些信息按需喂回给模型,让它“记得”之前发生过什么。

这套东西适合谁?我梳理了一下,大概三类人收益最明显。第一类是重度依赖 AI 结对编程的独立开发者,一个人同时推进好几个项目,上下文切换频繁,靠脑子记根本记不住每个项目的细节。第二类是小团队里负责搭建 AI 工作流的工程师,需要让团队里每个人用的 AI 助手都共享同一套项目知识,而不是每个人各自调教。第三类是做 AI 应用开发的同行,想研究“记忆层”到底该怎么设计,claude-mem是一个很好的参考实现。

需要提前说明的是,claude-mem本身不是一个官方大厂出品的东西,它更像是社区里一群被“AI 失忆症”折磨久了的人,自发攒出来的一套工程实践和工具集合。所以它的形态可能是一个 CLI 工具、一组配置文件、一套提示词模板,或者几者兼有。下面我基于这类记忆增强方案的通用设计思路,结合我自己搭类似系统时踩过的坑,把整套逻辑给你拆透。你完全可以照着这套思路,搭一个属于自己的claude-mem。

2. 记忆系统的整体架构设计

2.1 为什么不能只靠“把历史对话全塞进去”

很多人第一反应是:记忆嘛,简单,把之前所有对话记录拼起来一起发给模型不就行了。我一开始也这么干过,结果很快就撞墙了。原因有三个,而且一个比一个致命。

第一个是上下文窗口的硬限制。哪怕现在主流模型动辄支持几十万 token 的上下文,但你真把几周的对话历史全塞进去,token 消耗是惊人的。假设一次会话平均 5000 token,一天开 10 次会话,一周就是 35 万 token,早就爆了。而且就算没爆,成本也扛不住,每次请求都带着几十万 token 的输入,账单会让你怀疑人生。

第二个是信噪比问题。历史对话里 90% 是废话——“好的”“明白了”“那我们来改一下这里”——真正有价值的决策信息可能只占 10%。把这些噪音一起喂给模型,不仅浪费 token,还会稀释关键信息,让模型抓不住重点,甚至被过时的、已经废弃的方案误导。

第三个是信息冲突。你周一决定用 PostgreSQL,周三又改成了 MySQL,如果两段对话都在记忆里,模型到底听谁的?没有一套结构化的记忆管理机制,模型很容易精神分裂。

所以claude-mem这类方案的核心,不是“存更多”,而是“存得对、取得准”。它必须包含三个关键环节:抽取、存储、检索。抽取负责从对话流里捞出有价值的信息,存储负责把这些信息结构化地保存下来,检索负责在需要的时候精准地把相关信息取出来。这三个环节缺一不可,任何一个做砸了,整套记忆系统就废了。

2.2 三层记忆模型:短期、工作、长期

我在设计自己的记忆系统时,参考了认知科学里人类记忆的分层模型,把它落成了三层结构。这个分层是claude-mem这类方案能不能真正好用的关键,我强烈建议你一开始就按这个思路来,别偷懒。

短期记忆(Short-term Memory)就是当前这次会话的完整上下文。它不需要任何特殊处理,模型自带的上下文窗口就是短期记忆。它的特点是生命周期短,会话结束就清空,但信息密度最高,因为都是当下正在讨论的内容。

工作记忆(Working Memory)是跨会话但有时效性的信息。比如你正在做的这个功能模块,最近三天讨论的内容。它比短期记忆长,但会随着项目推进逐渐过期。工作记忆通常以“最近 N 次会话摘要”的形式存在,N 一般取 5 到 10。

长期记忆(Long-term Memory)是那些稳定的、不随会话变化的核心信息。比如项目的技术栈、代码规范、架构决策、领域术语表。这部分一旦确定,就长期保留,除非项目发生重大变更。

这三层的关系是:短期记忆实时产生,工作记忆定期从短期记忆里提炼,长期记忆从工作记忆里沉淀。检索的时候,优先级是长期 > 工作 > 短期,因为越稳定的信息越可信。这个分层设计的好处是,你可以针对不同层用不同的存储介质和检索策略,成本和质量都能兼顾。

2.3 存储介质选型:文件、向量库还是数据库

存储介质的选择直接决定了系统的复杂度和检索能力。我试过三种方案,各有优劣,给你摆出来对比一下。

存储方案优点缺点适用场景
纯 Markdown 文件零依赖、可读性强、方便手动编辑、能进 Git 版本管理检索靠关键词匹配,语义检索能力弱个人项目、记忆条目少于 500 条
向量数据库语义检索强、能按相似度召回需要额外服务、有运维成本、调试不直观团队协作、记忆条目上千
关系型数据库结构化查询强、支持复杂过滤语义检索需要额外扩展、schema 变更麻烦需要严格分类和统计的场景

我个人的建议是:从 Markdown 文件起步,等真的不够用了再升级。原因很简单,绝大多数个人开发者的记忆条目根本到不了需要向量检索的量级。我自己的项目跑了半年,长期记忆也就攒了两百多条,用文件加关键词检索完全够用。过早引入向量库,纯属给自己找运维麻烦。等你发现关键词检索经常召回不准、或者条目超过一千条时,再迁移到向量方案也不迟,而且那时候你已经很清楚自己的检索需求了,选型会更准。

3. 记忆抽取:从对话流里捞出金子

3.1 什么信息值得被记住

抽取环节最容易犯的错,就是什么都想记。我见过有人把每一句对话都存下来,结果记忆库变成了垃圾场,检索的时候全是噪音。判断一条信息值不值得记,我用一个简单的“三问法则”。

第一问:这条信息下次开新会话时还需要吗?如果只是当下这次讨论的临时细节,比如“这个变量名先叫 temp”,那就不用记。如果是“项目统一用 snake_case 命名”,那就得记。

第二问:这条信息是决策还是过程?决策要记,过程可以不记。比如“我们决定用 Redis 做缓存”是决策,要记;“我们讨论了半小时 Redis 和 Memcached 的优劣”是过程,摘要一句就行。

第三问:这条信息会不会过期?会过期的信息要标记时效,比如“当前正在重构用户模块”这种状态,一个月后可能就失效了,得带上时间戳和过期标记。

按这三问筛下来,真正值得进长期记忆的信息其实不多,主要是这几类:技术栈与依赖版本、代码规范与命名约定、架构决策与理由、领域术语与业务规则、已知的坑与规避方案、外部接口约定。这几类信息构成了项目的“宪法”,是每次新会话都必须让模型知道的。

3.2 抽取时机:实时、会话结束还是定时

抽取什么时候触发,也是个需要想清楚的问题。我试过三种时机,最后选了混合策略。

实时抽取是在对话过程中,一旦识别到关键信息就立刻存下来。优点是信息新鲜、不会遗漏,缺点是打断对话流,而且判断“是不是关键信息”本身需要额外调用模型,成本高。

会话结束抽取是在一次会话收尾时,统一回顾整段对话,提炼出值得记的内容。优点是批量处理、成本低、有全局视角,缺点是如果会话中途崩溃,可能丢失信息。

定时抽取是每隔一段时间(比如每天)扫描一遍当天的所有会话记录,统一提炼。优点是彻底解耦、不影响对话,缺点是延迟高,当天讨论的内容第二天才能进记忆。

我最后采用的是会话结束抽取为主、实时抽取为辅的策略。会话正常结束时走批量提炼,成本低质量高;遇到特别重要的决策(比如“确定用微服务架构”这种),在对话里显式打个标记,触发实时抽取,确保不丢。这个标记可以是一个特殊的关键词,比如你说“记一下:xxx”,系统就立刻把 xxx 存进长期记忆。

3.3 抽取提示词的设计要点

抽取质量高低,八成取决于提示词写得好不好。我踩过的坑是:一开始提示词写得太笼统,让模型“提取重要信息”,结果它要么提取一堆废话,要么漏掉关键决策。后来我把提示词改成了结构化输出,效果立刻稳定了。

核心思路是:给模型明确的分类框架和输出格式。不要让它自由发挥,而是告诉它“请从以下六个维度提取信息,每个维度如果没内容就留空”。这六个维度就是我前面说的那几类:技术栈、代码规范、架构决策、领域术语、已知问题、外部约定。

输出格式我强烈建议用 JSON,因为后续要程序化处理。一个典型的抽取结果长这样:

{ "tech_stack": ["PostgreSQL 15", "Redis 7", "FastAPI"], "conventions": ["Python 代码用 black 格式化", "API 路径统一 /api/v1 前缀"], "decisions": [ {"content": "用户认证用 JWT 而非 session", "reason": "方便前后端分离", "date": "2024-01-15"} ], "domain_terms": [{"term": "活跃用户", "definition": "7 天内登录过的用户"}], "known_issues": ["Redis 连接池在高并发下会耗尽,需要调大 max_connections"], "external_contracts": ["支付回调地址 /webhook/pay,POST 方法,需验签"] }

用 JSON 的好处是,你可以直接把它解析后按字段存进不同的文件或表,检索的时候也能按字段精准过滤。比如查“架构决策”就只搜 decisions 字段,不用在全文里瞎找。

提示:抽取提示词里一定要加一句“如果某个维度本次对话没有涉及,返回空数组,不要编造”。我吃过亏,模型有时候会为了“凑数”把之前记忆里的内容又复述一遍,导致重复存储。

4. 记忆存储:结构化与版本管理

4.1 目录结构设计

存储这块,我推荐用文件系统,结构清晰、可读、可版本管理。下面是我用了很久的一套目录结构,你可以直接抄。

.claude-mem/ ├── long-term/ │ ├── tech-stack.md │ ├── conventions.md │ ├── decisions.md │ ├── domain-terms.md │ ├── known-issues.md │ └── external-contracts.md ├── working/ │ ├── 2024-01-15-session-summary.md │ ├── 2024-01-16-session-summary.md │ └── ... ├── index.json └── config.yaml

long-term目录放长期记忆,按类别分文件,每个文件就是一个 Markdown 列表,人可读、机器可解析。working目录放工作记忆,按日期命名,每次会话结束生成一个摘要文件。index.json是全局索引,记录每条记忆的 ID、类别、创建时间、最后访问时间,方便快速检索和淘汰。config.yaml放配置,比如保留多少天的工作记忆、检索返回多少条等。

这个结构的好处是,长期记忆和工作记忆物理隔离,检索时可以先查长期再查工作,优先级天然分明。而且所有内容都是纯文本,你随时可以打开看、手动改,不会出现“数据在数据库里但我不知道怎么查”的尴尬。

4.2 记忆条目的标准化格式

每条记忆条目我都用统一的格式,方便解析和去重。格式如下:

## [MEM-20240115-001] 用户认证方案 - 类别: decision - 创建时间: 2024-01-15 14:30 - 最后访问: 2024-01-20 09:15 - 访问次数: 7 - 状态: active 用户认证采用 JWT 方案,而非传统的 session。 理由:前后端分离架构下,JWT 无状态、易扩展,且方便移动端复用。 相关文件:src/auth/jwt_handler.py

这个格式里,MEM-xxx是唯一 ID,方便引用和去重。访问次数和最后访问是给淘汰策略用的,长期没人访问的记忆可以考虑归档。状态字段标记 active、deprecated、archived,处理信息冲突时特别有用——如果新旧两条决策冲突,把旧的标成 deprecated,检索时就不会取到。

4.3 去重与冲突处理

去重和冲突是记忆系统里最容易被忽视、但一旦出问题就很致命的地方。我踩过的坑是:同一个决策被记了三遍,措辞还不一样,检索时全返回给模型,模型直接懵了。

去重的思路是:新记忆入库前,先跟已有记忆做相似度比对。如果相似度超过阈值(比如 0.85),就不新增,而是更新已有条目的“最后访问”时间。相似度比对在文件方案下可以用简单的关键词重叠度,在向量方案下用余弦相似度。

冲突处理更微妙。当新记忆和旧记忆在同一个主题上给出不同结论时,不能简单覆盖,因为旧结论可能还有参考价值。我的做法是:把旧条目标记为 deprecated,新条目正常入库,并在新条目里加一个supersedes字段指向旧条目 ID。这样检索时默认只返回 active 的,需要追溯历史时还能顺着链接找到旧决策。这套机制让记忆库有了“演化”能力,而不是简单的覆盖写。

5. 记忆检索:在对的时候给对的信息

5.1 检索触发时机

检索什么时候发生,直接决定了记忆系统是“无感增强”还是“添乱”。理想状态下,用户开新会话,系统自动把相关记忆注入到系统提示词里,用户完全无感。但“相关”这两个字很难,注入太多会污染上下文,注入太少又没效果。

我的策略是分层注入。长期记忆里的核心信息(技术栈、代码规范、领域术语)每次会话都全量注入,因为这部分信息量不大(通常几百到一两千 token),而且是每次都必须知道的。工作记忆和长期记忆里的决策、已知问题,则按需检索——根据用户当前会话的第一句话,判断涉及哪个模块,再召回相关条目。

具体实现上,我在会话开始时先拿用户的第一条消息去检索,召回 top-K 条相关记忆(K 一般取 5 到 10),拼成一段“背景信息”注入系统提示词。如果用户第一句话很泛(比如“我们继续吧”),那就只注入长期记忆的核心部分,等对话展开后再动态补充。

5.2 检索排序策略

检索结果的排序,我用了三个维度的加权:相关性、时效性、重要性。

相关性就是语义或关键词匹配度,这个好理解。时效性是越新的记忆权重越高,但长期记忆里的核心决策不受时效影响,所以时效权重只对工作记忆和决策类记忆生效。重要性是我给每条记忆打的一个分,架构决策、已知坑这类重要性高,临时状态类重要性低。

权重分配上,相关性占 0.5,时效性占 0.2,重要性占 0.3。这个比例是我调了好几轮才定下来的,你可以根据自己的项目特点微调。比如你的项目决策变更频繁,就把时效性权重调高;如果项目很稳定,就把重要性权重调高。

5.3 检索结果的格式化注入

检索出来的记忆不能直接一股脑塞给模型,得格式化一下,让模型知道这是什么、该怎么用。我用的注入模板是这样的:

以下是你需要知道的项目背景信息,请在回答时参考,但不要主动复述这些内容: 【技术栈】 - PostgreSQL 15, Redis 7, FastAPI 【代码规范】 - Python 代码用 black 格式化 - API 路径统一 /api/v1 前缀 【重要决策】 - 用户认证用 JWT(2024-01-15 确定) 【已知问题】 - Redis 连接池高并发下会耗尽,需调大 max_connections

这个模板的关键是那句“不要主动复述这些内容”。不加这句,模型有时候会在回答开头把背景信息又念一遍,浪费输出 token 还显得啰嗦。加了之后,它就会默默把这些信息用在回答里,体验自然多了。

6. 实操搭建:从零到能用

6.1 环境准备与依赖

搭建这套系统,你需要的其实不多。核心依赖就三样:一个能调用的 Claude API(或者你用的任何对话式模型 API)、Python 3.9+、以及一个存放记忆的目录。如果你要用向量检索,再加一个向量库的依赖,但我建议第一版先别上。

我用的技术栈是 Python + 标准库为主,尽量少依赖。文件读写用 pathlib,JSON 处理用内置 json,HTTP 请求用 httpx。整个项目核心代码不到 500 行,非常轻量。这样设计的好处是,你随时能看懂每一行在干什么,出问题也好排查,不会被框架的黑盒坑到。

6.2 核心模块实现

整个系统我拆成四个模块:extractor(抽取)、storage(存储)、retriever(检索)、injector(注入)。下面把关键实现讲一下。

抽取模块的核心是一个函数,接收一段对话文本,返回结构化的记忆 JSON。它内部就是调一次模型 API,用前面说的结构化提示词。这里有个细节:抽取用的模型可以和对话用的模型不同。抽取是个相对简单的任务,用便宜的小模型就够了,能省不少钱。我实测下来,抽取质量对模型能力的要求没那么高,小模型完全够用。

存储模块负责把抽取结果写进文件。核心逻辑是:先读已有记忆,做去重比对,然后决定是新增还是更新。去重比对我用的是简单的关键词 Jaccard 相似度,够用了。写入时按类别分文件,同时更新index.json。

检索模块接收一个查询字符串,返回排序后的记忆列表。文件方案下,我用的是关键词匹配加 BM25 排序,Python 里有个rank_bm25库可以直接用,几行代码搞定。如果你不想引入依赖,自己写个简单的 TF-IDF 也行。

注入模块负责把检索结果拼成提示词,插到系统消息里。这个模块最简单,就是个字符串拼接。

6.3 与对话流程的集成

集成方式取决于你平时怎么用 Claude。如果你用的是命令行工具,可以在启动时加一个 hook,先跑检索再启动对话。如果你用的是 IDE 插件,可能得看插件支不支持自定义系统提示词。如果你是自己写脚本调 API,那就最灵活,在构造 messages 的时候把记忆注入进去就行。

我自己的做法是写了个包装脚本,每次启动对话前先跑一遍检索,把结果写到一个临时文件,然后启动对话时读取这个文件作为系统提示词的一部分。会话结束后再跑一遍抽取,更新记忆库。整个流程对用户来说就是多等一两秒,完全可接受。

注意:抽取和检索都会调用模型 API,会产生额外成本。我的经验是,抽取用最便宜的模型,检索如果只是关键词匹配就不花钱。整体算下来,记忆系统带来的额外成本大概占对话成本的 10% 到 20%,换来的是不用反复交代背景,我觉得很值。

7. 常见问题与排查实录

7.1 记忆污染:模型把错误信息记住了

这是最危险的问题。如果某次对话里模型理解错了,或者你自己说错了,错误信息被抽进长期记忆,之后每次会话都会被注入,导致模型一直按错误的前提工作。我就遇到过,一次口误把数据库说成了 MySQL,结果记忆库里存了 MySQL,后面好几次会话模型都按 MySQL 给建议,直到我发现不对劲。

排查思路是:定期审查长期记忆库,尤其是决策类条目。我养成了每周花十分钟翻一遍decisions.md的习惯,看到不对的立刻改。另外,抽取提示词里可以加一句“只提取明确陈述的事实,不要提取疑问句和假设句”,能减少一部分误抽。

7.2 检索召回不准:该记的没记起来

有时候明明记忆库里有相关信息,但检索时没召回,模型还是“失忆”。这通常是查询词和记忆条目的措辞不匹配导致的。比如你问“登录怎么做的”,但记忆里存的是“用户认证方案”,关键词对不上。

解决办法有两个。一是给记忆条目加同义词标签,比如“用户认证”条目加上“登录、鉴权、auth”等标签,检索时标签也参与匹配。二是升级到向量检索,语义匹配能解决大部分措辞不一致的问题。我建议先加标签,成本低见效快,实在不行再上向量。

7.3 上下文超限:注入的记忆太多

如果检索返回太多记忆,拼起来超过模型上下文限制,请求会直接失败。这个问题的根源是检索的 top-K 设太大了,或者长期记忆核心部分太臃肿。

我的处理是加一个 token 预算控制:注入的记忆总 token 数不超过 3000。检索返回结果后,按排序依次累加,超过预算就截断。同时定期精简长期记忆,把过时的、重复的条目归档,保持核心部分精简。长期记忆的核心部分最好控制在 1500 token 以内,这样留给对话的空间才充足。

7.4 常见问题速查表

问题现象可能原因排查方向解决手段
模型反复问同样的问题记忆没注入或注入失败检查注入日志、系统提示词确认检索和注入流程正常
模型按过时信息回答旧记忆没标记 deprecated审查 decisions 类条目标记旧条目状态,加 supersedes
记忆库越来越大没有淘汰机制看 index.json 条目数加访问次数淘汰,归档冷数据
抽取结果全是废话提示词太笼统检查抽取提示词改结构化输出,加分类维度
检索召回不相关关键词不匹配看查询词和条目措辞加同义词标签或上向量检索

8. 进阶优化与个人体会

8.1 记忆的自动衰减与归档

记忆库不能只进不出,否则迟早变成垃圾场。我加了一套自动衰减机制:每条记忆记录访问次数和最后访问时间,超过 90 天没被访问、且访问次数低于 3 次的,自动从 active 移到 archived。归档的记忆不参与默认检索,但保留在文件里,需要时可以手动翻出来。

这套机制跑下来,我的长期记忆库一直稳定在两百条左右,核心信息始终清晰。如果不做衰减,半年下来能攒到上千条,检索质量会明显下降。

8.2 多项目记忆隔离

如果你同时推进多个项目,记忆必须隔离,否则 A 项目的技术栈会污染 B 项目。我的做法是按项目分目录,每个项目一个独立的.claude-mem目录。检索时只查当前项目的记忆库。如果有些记忆是跨项目通用的(比如你个人的代码风格偏好),可以单独放一个 global 目录,检索时先查项目库再查 global 库。

8.3 我个人的几点体会

搭这套系统最大的收获,不是省了多少 token,而是跟 AI 协作的体验变得连贯了。以前每次开新会话都像重新面试一个新人,现在更像跟一个记得上下文的同事继续聊。这种连贯性带来的效率提升,比单纯省下的 token 成本值钱得多。

另外我想说的是,别追求一步到位。我第一版就用了最简单的文件方案,连去重都没做,照样能用。后来遇到问题才一点点加功能:先加去重,再加衰减,再加冲突处理。每加一个功能都是因为真的遇到了对应的痛点,而不是因为“看起来应该要有”。这种渐进式的搭建方式,让系统始终贴合我的实际需求,也不会因为过度设计而变得难维护。

最后分享一个小技巧:在抽取提示词的最后加一句“用最简洁的语言描述,每条不超过 50 字”。我加这句之前,抽取出来的条目又臭又长,注入时特别占 token。加了之后,条目精炼了很多,信息密度反而更高了。记忆这东西,精炼比详尽重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询