How thedotmack/claude-mem Works
作为 Claude Code 的一个本地优先插件,Claude-Mem 在市场上定位为一个增强 AI 编程助手长期记忆能力的专业工具。与简单的聊天记录器不同,它的核心竞争力在于其“记忆压缩”系统:它不仅记录原始交互,还通过 AI 自我反思,将非结构化的工具使用事件,提炼成结构化的、包含语义的“记忆”(Observations)。其竞争优势体现在: 1. **智能压缩而非简单记录**:通过 AI 生成摘要和结构化数据,用更少的 Token 表达更丰富的信息。 2. **本地优先架构**:所有数据存储在用户本地(SQLite + Chroma),解决了企业和个人开发者对代码隐私的担忧。 3. **混合搜索能力**:结合了基于元数据(SQLite)的精确过滤和基于向量(Chroma)的语义搜索,实现了既快又准的记忆检索。 4. **AI 自我查询**:提供了一套分层搜索工具(MCP Tools),让 Claude 能以节约 Token 的方式主动查询自己的记忆,形成一个完整的认知闭环。该项目不是一个通用聊天插件的克隆,而是一个针对编程领域深度优化的、技术驱动的解决方案。
Overview
作为 Claude Code 的一个本地优先插件,Claude-Mem 在市场上定位为一个增强 AI 编程助手长期记忆能力的专业工具。与简单的聊天记录器不同,它的核心竞争力在于其“记忆压缩”系统:它不仅记录原始交互,还通过 AI 自我反思,将非结构化的工具使用事件,提炼成结构化的、包含语义的“记忆”(Observations)。其竞争优势体现在: 1. **智能压缩而非简单记录**:通过 AI 生成摘要和结构化数据,用更少的 Token 表达更丰富的信息。 2. **本地优先架构**:所有数据存储在用户本地(SQLite + Chroma),解决了企业和个人开发者对代码隐私的担忧。 3. **混合搜索能力**:结合了基于元数据(SQLite)的精确过滤和基于向量(Chroma)的语义搜索,实现了既快又准的记忆检索。 4. **AI 自我查询**:提供了一套分层搜索工具(MCP Tools),让 Claude 能以节约 Token 的方式主动查询自己的记忆,形成一个完整的认知闭环。该项目不是一个通用聊天插件的克隆,而是一个针对编程领域深度优化的、技术驱动的解决方案。
为 AI 编程助手(Claude Code)提供一个持久化、可压缩、可搜索的记忆系统,使其能够跨会话记住项目上下文,从而转变为一个更高效、更具连续性的开发伙伴,为开发者节省重复提供背景信息的时间和精力。
How It Works: End-to-End Flows
核心流程:跨会话的知识捕获与复用
该流程是产品的核心价值闭环。当开发者在Claude Code中进行编程操作时,系统像一个勤奋的学徒,在后台默默地捕获每一次重要的工具使用。它并不满足于简单记录,而是通过AI进行反思,将原始操作提炼成结构化的“记忆”。这些记忆被安全地存入本地数据库。当开发者日后开启一个新的会话时,系统又化身为一个得力的助手,主动在记忆库中检索与当前工作最相关的信息,并将其摘要注入到新会话的开场白中。这使得AI能够“记起”之前的上下文,无缝衔接工作,极大地提升了开发效率和与AI协作的流畅度。整个过程自动化、无感知,但价值却在每一次新会话的顺畅开启中得以体现。
- 开发者在IDE中使用工具,触发钩子捕获事件
- 事件被安全地推入后台的防丢失处理队列
- AI智能体处理队列中的事件,生成结构化的“记忆观察”
- 系统通过原子事务将记忆和摘要持久化到本地数据库
- 系统异步更新语义检索引擎
- 开发者开启新会话,系统自动检索并注入相关历史记忆
交互流程:AI助手主动查询自身记忆
此流程展示了Claude-Mem最独特的AI交互模式。在与开发者的对话中,当AI意识到需要历史信息来更好地回答问题时,它不再是无助地询问用户,而是能主动使用系统提供的一套专用“记忆搜索工具”。这个过程被设计成一个高效的、分层探索的模式:AI首先用`search`工具获取一个简短的记忆索引,就像翻阅书的目录;然后,它可能会用`timeline`工具查看某个它感兴趣条目周围的上下文;最后,当它锁定目标后,才会调用`get_observations`工具来获取那几条关键记忆的全部细节。这种“由浅入深”的查询方式,使得AI能以极低的Token成本在浩如烟海的记忆库中精准导航,展现出真正智能的“思考”和“调查”能力。
- AI在对话中决策需要查询历史信息,调用`search`工具获取记忆索引
- 系统执行混合搜索(语义+元数据)并返回紧凑的结果列表
- AI分析索引后,调用`timeline`工具探索特定记忆的上下文
- AI最终确认目标,调用`get_observations`工具批量获取完整记忆详情
- AI利用获取的记忆信息,给出更精准、更具上下文的回答
监控与配置流程:通过Web UI观察和调整记忆系统
为解决后台服务“黑箱”问题,该流程为用户提供了一个直观的本地Web界面。用户打开浏览器访问`localhost:37777`,即可进入一个实时仪表盘。在这里,记忆不再是抽象概念,而是一个不断更新的信息流,每一次AI的“学习”都清晰可见。用户可以像使用搜索引擎一样,筛选和浏览全部的历史记忆。更重要的是,当用户需要调整AI的“记忆力”(如注入多少上下文)时,可以在设置界面中实时预览修改后的效果,确认无误后再一键保存。这个流程将复杂的后台系统变得透明、可控,极大地增强了用户的信任感和对产品的掌控感。
- 用户在浏览器打开Web UI,看到实时的记忆信息流
- 用户使用筛选器或滚动加载,浏览特定项目的历史记忆
- 用户进入设置页面,调整上下文注入参数
- 系统根据用户的调整,实时生成并展示上下文注入的预览效果
- 用户确认预览效果后,保存设置,配置被后台服务持久化
- 用户在遇到问题时,打开内置的日志查看器进行故障排查
Key Features
事件集成与数据捕获
该模块是产品的“五官”,负责与多种开发环境(如 Claude Code、Cursor)深度集成,通过监听其生命周期事件(如会话开始、工具使用、会话结束)来捕获原始数据。它通过适配器模式解决了多平台输入格式不一的问题,将所有事件标准化后,再通过本地网络请求安全地发送给后台的记忆处理引擎。设计核心在于无感、可靠地捕集所有有价值的交互数据,为后续的记忆形成提供源源不断的素材。
- 多平台钩子集成与适配 — 【用户价值】让 Claude-Mem 可以在开发者选择的多种主流 AI 编程环境中无缝工作,提供一致的记忆体验。 【设计策略】采用适配器模式,将平台差异在入口处隔离。为每个支持的平台(如 Claude Code, Cursor)创建一个专门的适配器,负责将该平台特定的输入数据结构,转换为系统内部统一的“标准化事件”格式。 【业务逻辑】 - Step 1: 系统启动时,根据命令行传入的平台标识(如 'claude-code')加载对应的适配器。 - Step 2: 适配器读取来自平台的原始输入(JSON 格式),并将其字段(如会话ID、工作目录、工具名称/输入/输出)映射到内部标准化的数据结构上。 - Step 3: 所有后续的处理模块(如会话初始化、观察记录)均只与此标准化数据结构交互,无需关心原始平台是什么。 【权衡】好处是核心逻辑与平台解耦,便于维护和未来扩展到新平台;代价是每支持一个新平台,都需要开发一个新的适配器。
- 鲁棒的输入流处理 — 【用户价值】确保在某些平台(如 Claude Code)的输入流(stdin)永不关闭的特殊情况下,插件依然能准确、无延迟地读取完整的输入数据,而不会永久挂起等待。 【设计策略】采用“自界定JSON检测”和“安全超时”相结合的策略。不等流关闭,而是在接收到数据块后持续尝试解析,一旦成功解析出合法的JSON,就立即停止等待并进入后续处理流程。 【业务逻辑】 - Step 1: 监听标准输入流的数据事件,将收到的数据块累加到缓冲区。 - Step 2: 每当新数据块到达后,立即尝试对缓冲区内的全部内容进行 JSON 解析。 - Step 3: 如果解析成功,立即将解析出的对象返回,并停止监听输入流。 - Step 4: 如果解析失败,则继续等待下一个数据块。 - Step 5: 启动一个30秒的安全定时器。如果30秒内仍未成功解析出JSON,则主动超时失败,防止无限期挂起。 【权衡】此设计极大地提升了在特殊环境下的响应速度和可靠性。代价是依赖于输入数据是一个完整的JSON对象;对于流式多JSON对象的场景不适用。
- 项目级记忆排除 — 【用户价值】给予用户控制权,可以指定某些项目(如包含敏感信息或不重要的临时项目)不被记忆系统追踪,保护隐私并避免无关信息干扰。 【设计策略】提供一个基于Glob模式的路径匹配过滤器。用户可以在配置文件中定义一个项目路径的排除列表,系统在处理任何事件前,会先检查其所属项目是否匹配该列表。 【业务逻辑】 - Step 1: 用户在配置文件中设置需要排除的项目路径,支持通配符(如 `~/projects/personal/*`)。 - Step 2: 当捕获到一个新的会话或工具使用事件时,系统首先获取该事件关联的工作目录路径。 - Step 3: 系统将工作目录路径与配置的排除列表进行匹配。Glob模式会被转换为正则表达式进行匹配,支持 `*`, `**`, `?` 等通配符。 - Step 4: 如果路径匹配成功,则立即中止当前事件的处理流程,并记录一条调试日志,不会将事件发送给记忆引擎。
记忆处理与持久化引擎
这是产品的核心“大脑与海马体”,负责将从前端捕获的原始、非结构化的事件,加工成结构化、可检索的长期记忆。它首先通过一个防丢失的消息队列确保所有事件都能被可靠处理;然后利用AI智能体对事件进行“反思”,生成包含标题、叙述、事实和概念的“记忆观察(Observation)”;最后,通过原子性的数据库事务将这些结构化记忆和会话摘要安全地存入本地SQLite数据库。整个模块的设计核心是实现从原始数据到高质量、持久化记忆的无损、自动化转化。
- 防丢失的事件处理队列 — 【用户价值】确保用户的每一次重要操作都不会因为系统瞬时崩溃或重启而丢失,保证记忆的完整性和可靠性。 【设计策略】采用“先持久化、后处理”的模式,并设计了一个基于数据库的状态机来追踪每个事件的处理进度。所有进入系统的事件首先被存入一个专用的数据库表中,而不是直接在内存中处理。 【业务逻辑】 - Step 1: 当接收到一个新的事件(如工具使用)时,系统立即将其存入SQLite的`pending_messages`表,并标记状态为`pending`(待处理)。 - Step 2: 一个后台处理器从该表中认领一个`pending`状态的事件,并将其状态更新为`processing`(处理中)。 - Step 3: 处理器对事件进行耗时的AI加工(如生成记忆观察)。 - Step 4: 处理成功后,将结构化记忆存入主数据表,然后将`pending_messages`表中对应的事件状态更新为`processed`(已处理)或直接删除。 - Step 5: 如果处理器在`processing`状态时崩溃,该事件会留在数据库中。系统重启后,会自动检测这些“卡住”的`processing`事件,并将其状态重置为`pending`,以便重新处理。 - Step 6: 若处理失败,系统会记录失败原因,并根据重试策略(最多3次)决定是重置为`pending`还是标记为`failed`。
- AI驱动的记忆压缩与结构化 — 【用户价值】将原始、冗长的工具使用日志,自动提炼成简洁、结构化、富有语义的记忆片段,便于AI后续的理解和检索,实现信息的“有损压缩,无损认知”。 【设计策略】利用一个AI智能体(Agent)对捕获的原始事件进行“事后反思”。通过精心设计的提示词(Prompt),引导一个大语言模型(如Claude)分析工具的输入和输出,并以标准的XML格式生成结构化的“记忆观察(Observation)”。 【业务逻辑】 - Step 1: 系统将原始的工具使用事件(包括工具名称、输入、输出)作为上下文,构建一个特定的提示词。 - Step 2: 调用大语言模型,要求其扮演一个“分析师”角色,回答“这次操作的目标是什么?”、“学到了什么关键信息?”、“涉及哪些核心概念?”等问题。 - Step 3: 模型根据指令,生成一段包含特定标签的XML文本。这些标签包括:记忆类型(如 bug修复、功能开发)、标题、副标题、关键事实列表、叙述性描述、核心概念列表以及涉及的文件列表。 - Step 4: 系统解析这段XML,提取出各个字段的数据,形成一个结构化的“记忆观察”对象,准备存入数据库。
- 原子性的结构化记忆存储 — 【用户价值】保证每一次记忆的产生都是完整且一致的,避免数据库中出现只有一半数据(例如只有观察,没有对应的摘要)的“幽灵记忆”。 【设计策略】将一次事件处理所产生的所有数据库写入操作(如存储多个记忆观察、一个会话摘要、更新消息队列状态)包裹在一个单一的数据库事务(Transaction)中。 【业务逻辑】 - Step 1: 在将AI生成的结构化记忆存入数据库之前,系统开启一个数据库事务。 - Step 2: 在该事务内,依次执行多个`INSERT`或`UPDATE`操作: - a. 将所有生成的“记忆观察”插入到 `observations` 表。 - b. 如果有会话摘要,则将其插入到 `session_summaries` 表。 - c. 更新 `pending_messages` 表中对应事件的状态为 `processed`。 - Step 3: 只有当所有这些操作都成功完成后,才提交(Commit)整个事务,使更改永久生效。 - Step 4: 如果中途任何一个操作失败,整个事务将回滚(Rollback),数据库状态恢复到事务开始之前,就像什么都没发生过一样。
- 自动化会话摘要 — 【用户价值】在用户结束一次长时间的编程会话时,自动生成一段高质量的总结,记录本次工作的核心内容和后续计划,便于未来快速回顾。 【设计策略】在会话结束(`Stop`)的钩子事件中,提取当前会话的最后一段AI交互内容,并将其发送给AI进行总结,然后存储生成的摘要。 【业务逻辑】 - Step 1: 当会话结束事件被触发时,系统从Claude Code的交互记录文件(Transcript JSONL)中,解析并提取出最后一次AI助手的回复内容。 - Step 2: 系统将这段回复内容作为上下文,通过一个“总结”提示词,请求AI生成一个结构化的会话摘要。 - Step 3: 摘要内容包含:原始请求、调研过程、学习到的知识、已完成的工作、下一步计划等字段。 - Step 4: 这个结构化的摘要被存入`session_summaries`数据库表中,与本次会话关联。
- 数据库 schema 的版本化迁移 — 【用户价值】确保用户在升级 Claude-Mem 插件版本时,其本地存储的记忆数据能够平滑、无损地适配到新版本的数据结构,无需手动干预。 【设计策略】建立一个版本化的数据库迁移(Migration)机制。每一次数据库结构的变更都对应一个带版本号的迁移脚本,系统启动时会自动检测并按顺序执行所有未应用的脚本。 【业务逻辑】 - Step 1: 数据库中设有一个`schema_versions`表,用于记录当前已成功应用的迁移版本号。 - Step 2: 系统代码中包含一个迁移脚本列表,每个脚本都有一个唯一的版本号和对应的数据库修改操作(如增加列、创建新表、修改约束)。 - Step 3: 当系统启动初始化数据库时,它会读取`schema_versions`表,确定当前版本。 - Step 4: 系统会依次执行所有版本号高于当前版本的迁移脚本,以更新数据库结构。 - Step 5: 每成功执行一个脚本,就将其版本号记录到`schema_versions`表中,确保下次启动时不会重复执行。
记忆搜索与检索引擎
该模块是产品的“记忆提取”系统,它为AI和用户提供了多种访问长期记忆的途径。其核心是一个为大语言模型量身定制的“分层搜索”工作流,通过一系列工具(MCP Tools)让AI能以极低的Token成本高效检索信息。为了支持这一点,模块实现了一套复杂的混合搜索策略,能智能地结合基于关键词的精确过滤(SQLite)和基于向量的语义模糊搜索(Chroma),并能根据系统状态优雅降级。最终,它还将检索到的相关记忆自动注入到新会话中,完成记忆的闭环。
- 为LLM设计的代币高效分层搜索 — 【用户价值】解决大语言模型(LLM)上下文窗口有限且成本高昂的问题。让AI在查询海量记忆时,能像人类一样先看索引,再看摘要,最后才看原文,从而以最低的Token开销找到最相关的信息,节省约90%的成本。 【设计策略】设计并提供了一套三层递进的搜索工具(MCP Tools),供AI在对话中调用。 【业务逻辑】 - **第一层:索引浏览 (低成本)** - Step 1: AI调用 `search` 工具,并提供查询关键词(如 “身份验证bug”)和过滤条件。 - Step 2: 系统返回一个非常紧凑的结果列表,每条只包含记忆的ID、标题和类型,消耗极少Token。 - **第二层:上下文探索 (中成本)** - Step 3: AI分析索引列表后,如果对某个结果(如 ID #123)的上下文感兴趣,它会调用 `timeline` 工具,并传入该ID。 - Step 4: 系统返回ID #123前后发生的事件时间线,帮助AI理解该记忆产生的背景。 - **第三层:详情深挖 (高成本)** - Step 5: 当AI最终确定某几个ID(如 #123, #456)是解决当前问题所必需的,它会调用 `get_observations` 工具,批量传入这些ID。 - Step 6: 系统这才返回这些ID对应的完整、详细的记忆内容(包括事实、叙述等)。
- 混合搜索策略与优雅降级 — 【用户价值】同时利用传统数据库的精确过滤能力和向量数据库的语义理解能力,提供既精准又智能的搜索结果。并在语义搜索不可用时,自动降级为关键词搜索,保证搜索功能的基本可用性。 【设计策略】实现一个搜索编排器,根据用户输入和系统状态,动态选择最优的搜索策略组合。 【业务逻辑】 - **场景1:仅有过滤条件(无关键词)**: 系统直接使用SQLite进行精确的元数据查询(如项目、日期、类型),速度最快。 - **场景2:既有关键词又有过滤条件(混合搜索)**: - Step 1: 先使用SQLite根据过滤条件(如项目、日期)筛选出一批候选的记忆ID。 - Step 2: 然后将用户的关键词在向量数据库(Chroma)中进行语义搜索,对这批候选ID进行相关性排序。 - Step 3: 最终按相关性排序后的结果返回,实现了“先精确圈定范围,再在范围内做智能排序”。 - **场景3:语义搜索不可用时(优雅降级)**: 如果向量数据库(如在Windows上被禁用)不可用,搜索编排器会丢弃用户的关键词,仅执行场景1的精确过滤,并告知用户当前为降级搜索模式。
- 自动化语义索引同步 — 【用户价值】确保开发者最近的工作内容能够被立即用于语义搜索,使得记忆的检索总是“新鲜”的。 【设计策略】采用“事后异步同步”机制。在核心的记忆存储流程完成后,非阻塞地触发一个将新记忆同步到向量数据库的任务。 【业务逻辑】 - Step 1: 当一条新的结构化记忆被成功存入主数据库(SQLite)后。 - Step 2: 系统会立即(但异步地)启动一个同步任务,将该记忆的文本内容和元数据发送给向量数据库(Chroma)。 - Step 3: 向量数据库会为该文本生成一个“向量嵌入”,并将其与记忆ID一同存入索引。 - Step 4: 这个同步任务是“即发即忘”的,即使失败也只会记录一条错误日志,绝不会阻塞或影响核心的记忆存储流程,保证了系统的健壮性。 - Step 5: 系统启动时还会进行一次“智能回填”,检查并同步所有在主数据库但不在向量索引中的历史记忆。
- 上下文时间线生成 — 【用户价值】帮助开发者或AI快速理解某一个特定记忆(如一个重要的决策)是在什么样的前后背景下产生的。 【设计策略】提供一个专门的接口,能够根据一个“锚点”(特定的记忆ID或查询)来检索其在时间上相邻的记忆序列。 【业务逻辑】 - Step 1: 用户或AI提供一个记忆ID作为“锚点”。 - Step 2: 系统查询该ID的创建时间戳。 - Step 3: 系统以该时间戳为中心,在数据库中检索出时间上紧邻的N条记忆(包括之前和之后)。 - Step 4: 将这些记忆按时间顺序排列,形成一个“上下文时间线”并返回。这使得用户可以追溯“在做出这个决定之前,我们正在讨论什么?”以及“做出决定之后,我们又做了什么?”。
- 自动化上下文注入 — 【用户价值】在新会话开始时,自动将最相关的历史记忆喂给AI,使其“瞬间回忆起”关于这个项目的一切,省去开发者手动“唤醒”AI的麻烦。 【设计策略】在会话开始的钩子事件中,调用后台的搜索服务,根据当前项目信息检索最相关的历史记忆,并将其格式化为一段文本注入到AI的初始提示词中。 【业务逻辑】 - Step 1: 当开发者在某个项目中开启一个新的Claude会话时,`SessionStart`钩子被触发。 - Step 2: 钩子向后台的`/api/context/inject`接口发起请求,并附上当前的项目路径和工作区信息。 - Step 3: 后台服务执行一次智能搜索,综合考虑记忆的类型、新近度、项目关联度等因素,筛选出最重要的一组历史记忆和会话摘要。 - Step 4: 将这些记忆组合并格式化成一段对AI友好的、信息密集的文本。 - Step 5: 钩子将这段文本输出到标准输出,Claude Code平台捕获该输出并自动将其作为初始上下文添加到新会话中。
用户控制与可观测性中心 (Web UI)
该模块为用户提供了一个本地的Web界面(默认在`localhost:37777`),作为与Claude-Mem后台服务交互的“仪表盘”和“控制台”。用户可以通过它实时观察记忆的生成,浏览、筛选和搜索完整的记忆历史,直观地调整和预览上下文注入配置,并进行故障排查。它的核心价值在于将后台复杂的记忆处理过程透明化,并赋予用户简单、安全的配置能力,从而建立起用户对这个“黑箱”系统的信任。
- 实时记忆流 — 【用户价值】让用户可以像看社交媒体信息流一样,实时看到后台正在生成的新记忆、摘要和处理状态,直观地感受到系统正在“学习”。 【设计策略】采用服务器发送事件(Server-Sent Events, SSE)技术。Web前端与后台服务建立一个长连接,后台一旦有新的事件(如生成新记忆),就立即通过这个连接将数据推送给前端。 【业务逻辑】 - Step 1: Web前端页面加载时,使用浏览器原生的`EventSource` API与后台的`/stream`端点建立一个持久连接。 - Step 2: 后台服务在处理完一个新记忆、摘要或状态变化时,会向所有连接的客户端发送一个带事件类型的消息(如 `new_observation`)。 - Step 3: 前端监听到这些事件后,解析消息中的数据,并以动画效果将其插入到记忆列表的顶部。 - Step 4: 如果连接因网络问题断开,前端会自动在固定延迟(如3秒)后尝试重连,保证了实时流的持续性。
- 历史记忆的分页浏览与筛选 — 【用户价值】允许用户高效地浏览可能长达数月甚至数年的全部记忆历史,并能通过项目名称快速筛选,准确定位到特定工作的记忆。 【设计策略】采用“无限滚动”式的服务器端分页加载机制。当用户滚动到列表底部时,前端向后台请求下一页数据。同时,筛选逻辑完全在服务器端执行。 【业务逻辑】 - Step 1: 页面首次加载时,前端向后台API(如 `/api/observations`)请求第一页数据(如20条)。 - Step 2: 当用户将页面滚动至接近底部时,触发加载函数,向后台请求下一页数据(通过 `offset` 和 `limit` 参数)。 - Step 3: 后台从数据库中查询相应分页的数据并返回,前端将新数据追加到列表末尾。 - Step 4: 当用户在UI的下拉菜单中选择一个项目进行筛选时,前端会清空现有列表,并带上 `project` 参数重新从第一页开始请求数据。此时,前端会忽略实时SSE推送的数据,以保证列表内容的纯净性(只显示该项目的数据)。
- 交互式设置与实时预览 — 【用户价值】让用户在调整复杂的上下文注入参数时,能够立即看到修改后的效果,避免了“盲调”带来的高昂试错成本(如过多的Token消耗)。 【设计策略】提供一个“所见即所得”的配置界面。用户的每一次参数调整都会触发一次对后台“预览”接口的调用,后台会模拟生成注入的上下文并返回给前端展示。 【业务逻辑】 - Step 1: 用户在设置弹窗中修改参数,如“注入最近的5条观察”或“注入最近的2个会话摘要”。 - Step 2: 每当表单内容发生变化,前端立即将当前所有设置项和选定的预览项目,发送到后台的 `/api/context/preview` 接口。 - Step 3: 后台服务根据收到的临时配置,执行一次真实的上下文检索和格式化逻辑,并将生成的最终文本结果返回给前端。 - Step 4: 前端在一个模拟终端的窗口中展示这个预览文本,让用户可以直观判断注入内容的质量和长度。 - Step 5: 用户对预览效果满意后,点击“保存”按钮,前端才会将配置通过 POST 请求发送到 `/api/settings` 接口进行持久化。
- 应用内日志查看器 — 【用户价值】为高级用户和开发者提供一个内置的故障排查工具,无需离开浏览器或查看本地文件,即可检查系统的详细运行日志。 【设计策略】在Web UI中内嵌一个可以拉出的抽屉式日志面板,该面板从后台API获取原始日志文本,并在客户端进行解析、着色和过滤。 【业务逻辑】 - Step 1: 用户点击日志按钮,UI向后台的 `/api/logs` 接口请求最新的日志文件内容。 - Step 2: 前端获取到纯文本的日志后,按行解析,并根据预设的格式(时间戳、日志级别、组件名、消息)提取结构化信息。 - Step 3: UI将结构化的日志信息渲染成带颜色高亮的列表(如错误为红色,调试为灰色)。 - Step 4: 用户可以通过复选框按日志级别(如只看错误)或来源组件(如只看数据库日志)进行客户端筛选。 - Step 5: 提供手动刷新、自动刷新(每2秒)和清空日志(需要确认)的功能。
系统生命周期与编排
该模块是产品的“中枢神经系统”,负责管理后台常驻工作进程(Worker)的整个生命周期。它确保系统有且仅有一个工作实例在运行(守护进程化),处理优雅的启动、关闭与重启,并在发生崩溃后能自动进行现场清理和状态恢复(如清理僵尸进程、重置卡住的任务)。其设计核心是为上层应用提供一个可靠、稳定、具备自愈能力的后台服务,让用户感觉不到后台的存在,却能一直享受其带来的价值。
- 常驻工作进程管理 — 【用户价值】确保记忆处理服务在后台作为一个独立的守护进程持续运行,不受终端关闭的影响,并避免因重复启动而产生多个实例冲突。 【设计策略】采用PID文件锁机制来协调进程。每次启动时,检查是否存在一个有效的PID文件;退出时,清理该文件。 【业务逻辑】 - Step 1: 当工作进程启动并成功监听HTTP端口后,它会将自己的进程ID(PID)和端口号写入到一个固定的文件(如 `~/.claude-mem/worker.pid`)中。 - Step 2: 在下一次启动尝试时,系统会先读取这个PID文件。 - Step 3: 如果文件存在,系统会检查该PID对应的进程是否仍在运行。如果仍在运行,则本次启动中止,避免重复实例。 - Step 4: 在Windows上,为防止快速失败重启导致烦人的弹窗,额外增加了一个“启动冷却”机制:如果在2分钟内已有过启动尝试,则跳过本次启动。 - Step 5: 当进程通过正常途径关闭时,它会在退出前主动删除该PID文件。
- 优雅的启动与关闭 — 【用户价值】保证系统在关闭或重启时,能安全地完成手头的工作并释放所有资源(如数据库连接、网络端口),防止数据损坏或资源泄露。 【设计策略】通过监听操作系统信号(如 SIGINT, SIGTERM)来触发一个多阶段的、有序的关闭流程。 【业务逻辑】 - Step 1: 系统在启动时注册对`SIGINT`(用户按 Ctrl+C)和`SIGTERM`(系统关闭请求)信号的监听。 - Step 2: 当接收到关闭信号时,触发一个统一的`shutdown`函数。 - Step 3: `shutdown`函数会按相反的初始化顺序,依次执行清理操作: - a. 首先关闭HTTP服务器,停止接收新请求。 - b. 等待现有请求处理完毕。 - c. 关闭与向量数据库等子进程的连接。 - d. 关闭主数据库连接。 - e. 删除PID文件。 - f. 最后退出进程。
- 自动崩溃恢复与孤儿进程清理 — 【用户价值】系统具备自愈能力。在意外崩溃后再次启动时,能自动清理上次运行时留下的“烂摊子”,恢复到一致的状态,对用户完全透明。 【设计策略】在每次启动的初始化阶段,执行一系列的“现场清理”和“状态恢复”任务。 【业务逻辑】 - **孤儿进程清理**: - Step 1: 系统启动时,会扫描当前用户的所有进程。 - Step 2: 通过命令行关键词(如 'mcp-server.cjs', 'worker-service.cjs')识别出可能是上次残留的Claude-Mem相关进程。 - Step 3: 为了避免误杀,它只杀死那些已经运行超过特定时间(如30分钟)的“陈旧”进程。 - **卡住的任务恢复**: - Step 4: 在初始化数据库后,系统会查询事件处理队列(`pending_messages`表)。 - Step 5: 将所有状态为`processing`(处理中)的事件,全部重置回`pending`(待处理)状态,以便新的工作进程可以重新接手处理。
- API就绪状态门控 — 【用户价值】防止插件的钩子脚本或其他客户端在后台服务尚未完全准备就绪时就调用其API,导致请求失败或数据不一致。 【设计策略】服务启动时,HTTP服务器立即开始监听端口以快速响应“存活”探测,但同时用一个中间件“门卫”拦截所有核心API请求,直到所有后台组件(数据库、AI服务连接等)都初始化完毕才“开门”。 【业务逻辑】 - Step 1: 工作进程启动后,Express HTTP服务器立即开始监听端口。 - Step 2: 一个中间件被挂载到所有`/api/*`路径下。 - Step 3: 该中间件检查一个全局标志位 `initializationCompleteFlag`(默认为`false`)。 - Step 4: 如果标志位为`false`,所有进入的API请求都会被暂时挂起,或在等待超时(如30秒)后返回一个 `503 Service Unavailable` 的错误,提示客户端稍后重试。 - Step 5: 在后台,系统依次进行耗时的初始化(如数据库连接、加载模型、连接MCP服务)。 - Step 6: 只有当所有初始化任务全部成功完成后,该标志位才被设为`true`,此时中间件“开门”,后续的API请求才能正常访问到后端的服务逻辑。 - Step 7: 少数“心跳”接口(如 `/api/health`)被排除在该门控之外,允许客户端随时检查进程是否存活。
基础架构:配置与隐私
该模块是整个系统的基石,提供统一的配置管理、安全的凭证隔离、可靠的日志系统和用户可控的隐私保护机制。它通过一个分层级的配置系统,让用户可以灵活地通过环境变量或文件来定制系统行为。同时,通过严格的凭证隔离和内容过滤机制,确保了API密钥和用户敏感数据不会被意外泄露或记录。这一系列基础能力,共同保证了上层功能模块的稳定、安全和可维护。
- 分层合并的统一配置管理 — 【用户价值】为用户提供了既简单又灵活的配置方式。普通用户开箱即用,高级用户则可以通过多种方式(如环境变量、配置文件)进行深度定制,且规则清晰,不会混淆。 【设计策略】实现一个三层优先级覆盖的配置加载系统。 【业务逻辑】 - **第一优先级:环境变量**。系统会首先检查环境变量(如 `process.env.CLAUDE_MEM_WORKER_PORT`),其值会覆盖任何其他来源的设置。这对于容器化部署和CI/CD环境非常方便。 - **第二优先级:用户配置文件**。系统会读取用户主目录下的 `~/.claude-mem/settings.json` 文件。用户可以在此文件中持久化自己的定制设置。 - **第三优先级:硬编码的默认值**。代码中为所有57个配置项都提供了一套合理的默认值。如果环境变量和配置文件中都没有指定某个选项,则使用此默认值。 - **加载流程**:系统启动时,首先加载默认值,然后用配置文件中的值覆盖它,最后用环境变量中的值再次覆盖,从而实现清晰的优先级合并。
- 凭证隔离与安全注入 — 【用户价值】防止开发者在项目 `.env` 文件中配置的API密钥被Claude-Mem无意中读取和使用,确保记忆系统只使用其专门配置的密钥,解决了潜在的安全风险(如密钥泄露到错误的项目记忆中)。 【设计策略】为Claude-Mem的子进程创建一个“纯净”的、受控的运行环境,切断其从父进程继承不相关环境变量的路径。 【业务逻辑】 - Step 1: Claude-Mem将自己的API密钥(如ANTHROPIC_API_KEY)存储在一个专属的、位于用户主目录的 `.env` 文件中(`~/.claude-mem/.env`)。 - Step 2: 当需要启动一个子进程(如AI Agent)时,系统不会直接继承当前的环境变量。 - Step 3: 相反,它会手动创建一个全新的环境变量集合:首先,只拷贝24个必需的系统级变量(如 `PATH`, `HOME`);然后,仅从Claude-Mem专属的`.env`文件中读取API密钥并添加进去。 - Step 4: 子进程在这个“隔离”的环境中启动,因此它无法访问到用户在当前项目或Shell中定义的任何其他API密钥。
- 基于标签的内容隐私控制 — 【用户价值】让用户能够精细地控制哪些内容不被存入长期记忆。例如,在与AI讨论一段包含密码或私钥的代码时,可以简单地用标签将其包裹,确保这部分敏感信息“阅后即焚”。 【设计策略】设计了一对特殊的XML风格标签 `<private>` 和 `<claude-mem-context>`,并在数据存入数据库之前的最后一刻,对所有内容进行过滤,移除这些标签及其包裹的内容。 【业务逻辑】 - **用户控制**:用户可以在与AI的对话中,将任何不想被记忆的内容用 `<private>...</private>` 标签包裹起来。 - **系统控制**:系统在将会话历史注入到新会话时,会自动用 `<claude-mem-context>...</claude-mem-context>` 标签包裹注入的内容,以防止这些被注入的“记忆”本身又被当作新的信息再次记忆,造成无限循环。 - **过滤执行**:在事件数据被发送到后台的记忆处理引擎之前,一个预处理器会使用正则表达式,查找并删除这两个标签以及它们之间包裹的所有文本。这个操作发生在数据持久化之前,从而确保敏感内容和系统标记永远不会进入数据库。
- 带关联ID的结构化日志 — 【用户价值】为系统的故障排查提供了极大便利。通过唯一的关联ID,可以将一个请求从进入系统到最终处理完成的整个生命周期中的所有相关日志串联起来,快速定位问题所在。 【设计策略】实现一个支持多组件、多级别的结构化日志系统,并为每个核心处理单元(如一次记忆观察)生成一个唯一的关联ID。 【业务逻辑】 - Step 1: 当一个需要被追踪的业务流程开始时(如处理一个新观察),系统会生成一个唯一的关联ID,格式如`obs-{sessionId}-{observationNum}`。 - Step 2: 在该流程的每一个关键步骤打印日志时,都必须附上这个关联ID。 - Step 3: 日志信息被结构化地记录到本地日志文件中(`~/.claude-mem/logs/claude-mem-{YYYY-MM-DD}.log`),包含时间戳、日志级别、来源组件(如WORKER, DB, HTTP)、关联ID和消息文本。 - Step 4: 当出现问题时,开发者只需在日志文件中搜索特定的关联ID,就可以筛选出与该次操作相关的所有日志,清晰地看到数据流转和处理的全过程。
Core Technical Capabilities
基于持久化队列的崩溃安全工作流处理
Problem: 如何确保从IDE钩子接收到的事件,在被后台漫长的AI处理流程消费时,不会因为服务器意外崩溃或重启而丢失?如果直接在内存中处理,任何中断都会导致数据丢失。
Solution: 采用“先进库,再处理”的设计范式,并结合数据库实现了一个持久化的任务队列。 - Step 1: 所有从外部接收到的请求,第一步不是送去处理,而是立即被序列化并作为一个“待处理(pending)”任务存入SQLite数据库的`pending_messages`表中。 - Step 2: 一个独立的后台处理器,从数据库中“认领(claim)”一个待处理任务,并立即在数据库事务中将其状态更新为“处理中(processing)”。 - Step 3: 只有在任务的所有处理步骤(包括AI调用、存入主数据表等)全部成功完成后,该任务才最终被从队列中删除或标记为“已完成(processed)”。 - Step 4: 服务在每次启动时,都会检查队列中是否有处于“处理中”状态的任务。这些任务是上一次异常退出的遗留物,系统会将它们全部重置回“待处理”状态,从而被新的处理器重新接管。 核心价值:这一设计将任务的生命周期状态持久化,使得整个处理流具备了事务性和可恢复性,从根本上保证了即使在服务频繁崩溃重启的恶劣环境下,数据也能“零丢失”。
Technologies: SQLite, 状态机, 原子事务
Boundaries & Risks: 该方案的性能瓶颈在于SQLite的写入速度。在高并发场景下,频繁的入队和状态更新可能成为瓶颈。此外,如果某个任务本身存在逻辑错误导致反复失败,它可能会在队列中不断被重试,需要有良好的“毒丸消息”处理和监控机制。
为LLM定制的代币高效分层搜索架构
Problem: 大语言模型(LLM)的上下文窗口是宝贵的有限资源,直接将大量搜索结果喂给它既昂贵又低效。如何让LLM能像人类一样,以最低的成本(Token消耗)在海量记忆库中进行探索式搜索?
Solution: 设计并提供给LLM一套遵循“渐进式信息披露”原则的工具集,引导其进行三层式搜索。 - **第一层:索引(Index) - `search`工具**:此工具只返回一个极其紧凑的结果列表,每条仅含ID和标题。LLM调用它,就像人类翻阅书籍的目录,只需极小的Token开销就能对海量记忆有一个宏观了解。 - **第二层:上下文(Context) - `timeline`工具**:当LLM对某个索引条目产生兴趣,它调用此工具传入ID。工具返回该记忆点前后相关的事件序列。这如同人类定位到章节后,快速浏览该页的上下文,用中等成本建立背景认知。 - **第三层:细节(Details) - `get_observations`工具**:只有当LLM最终确认某几条记忆是解决问题的关键时,它才会调用此工具批量获取这些ID的完整内容。这如同人类精读关键段落,是最高成本但信息最丰富的操作。 核心价值:该架构将搜索的主动权交还给LLM,使其能自主决策信息获取的深度和广度,相比于一次性返回所有细节的“投喂”模式,可以节省超过90%的Token成本,是为LLM原生设计的经济高效的信息检索范式。
Technologies: 工具调用(Tool Use), LLM Prompt Engineering, API设计
Boundaries & Risks: 该方案的有效性高度依赖于LLM的工具使用能力和意图理解能力。如果LLM无法理解或不遵循这个分层搜索的最佳实践,其优势将无法发挥。此外,多次工具调用也引入了额外的网络延迟。
结合语义与元数据的混合搜索与优雅降级
Problem: 纯语义搜索(向量搜索)虽然智能,但无法进行精确的元数据过滤(如“过去7天内”、“仅限A项目”)。纯关键词/元数据搜索又缺乏对自然语言的理解。如何将二者结合,提供既智能又精准的搜索体验,并在部分组件失效时保持可用性?
Solution: 通过一个搜索编排器,实现“先过滤,后排序”的混合策略,并内置降级逻辑。 - **混合执行路径**:当收到一个包含关键词和元数据过滤的请求时: - Step 1: 首先,使用SQLite执行元数据过滤(如`project='A' AND date > '...'`),快速筛选出一批符合条件的候选记忆ID。 - Step 2: 然后,将用户的搜索关键词输入到向量数据库(Chroma)中,对这批候选ID进行语义相关性计算和排序。 - Step 3: 最终,按语义相关性得分,返回排序后的结果。 - **优雅降级路径**:系统在设计上预见了向量数据库可能不可用(例如在Windows上被禁用,或Python依赖出问题)的情况。在这种场景下,搜索编排器会自动忽略用户的搜索关键词,仅执行第一步的元数据过滤,并明确告知用户当前运行在“仅过滤”的降级模式下。 核心价值:该方案融合了关系型数据库的精确性和向量数据库的模糊性,提供了远超单一数据库的搜索质量。同时,通过优雅降级保证了在任何情况下搜索功能的核心可用性。
Technologies: 向量数据库(Chroma), 关系型数据库(SQLite), 策略模式
Boundaries & Risks: 混合搜索的延迟是两个数据库查询延迟之和,性能略低于单一查询。结果质量依赖于向量嵌入的质量。降级逻辑虽然保证了可用性,但返回的结果集可能与用户的语义意图有较大偏差,需要清晰地向用户传达当前的状态。
零停机时间的API就绪状态门控
Problem: 后台服务启动时需要执行耗时的初始化(连接数据库、加载模型等),这个过程可能长达数分钟。如何在这段时间内,既能让外部客户端(如IDE钩子)立即知道服务“活着”(避免超时),又能阻止它们调用尚未准备就绪的功能(避免数据不一致)?
Solution: 将“服务存活”和“服务就绪”两个概念在架构层面分离。 - **立即存活**:服务进程一启动,就立即让HTTP服务器开始监听端口。这样,像`/api/health`这样的“心跳”检测接口可以马上响应,客户端通过简单、快速的HTTP请求就能确认进程已启动。 - **延迟就绪**:在所有核心API路由(如`/api/search`)前,设置一个“门控”中间件。该中间件内部持有一个在后台执行的、漫长的初始化`Promise`。 - **门控逻辑**:当请求到达时,如果初始化`Promise`尚未完成,中间件会挂起请求,或在短暂等待后返回一个`503 Service Unavailable`状态码,告知客户端“服务正在初始化,请稍后重试”。只有当初始化`Promise`成功完成后,“门控”才会打开,让请求通过并访问真正的业务逻辑。 核心价值:此设计完美解决了服务启动过程中的“竞态条件”,为客户端提供了清晰、一致的可用性信号,既保证了系统的健壮性,也改善了客户端的集成体验。
Technologies: HTTP中间件, Promise, 异步编程
Boundaries & Risks: 客户端需要被设计成能够理解并处理`503`状态码(例如通过重试机制),否则可能会将服务初始化误判为永久性故障。初始化过程中的任何失败都可能导致服务永久处于“未就绪”状态,需要有相应的监控和告警。
