mem0-plugin Health 技能详解:五项连通性体检与记忆质量深度审计
mem0-plugin 是 Mem0 为 Claude Code、Cursor、Codex 等编码智能体提供的插件(见 integrations/mem0-plugin/README.md),它通过 MCP 服务器与生命周期 Hook 为智能体提供跨会话的持久记忆。当记忆操作失败、搜索返回空结果、MCP 连接中断时,插件内置的 health 技能(integrations/mem0-plugin/skills/health/SKILL.md)提供了一套结构化的诊断流程:五项连通性检查逐项排查 API 密钥、身份解析、MCP 读写能力与会话统计状态,--deep 扩展模式还能对存量记忆做重复、过期、矛盾、孤儿四类质量扫描。读完本文,你可以掌握这套体检流程的每一步操作、判定标准,以及它背后的身份解析链、Hook 机制与统计文件实现。
技能定位与执行总原则
health 技能的元数据声明了它的触发场景(SKILL.md 的 frontmatter):
name: health
description: Diagnoses mem0 connectivity, API key validity, and memory read/write functionality.
Use when memory operations fail, searches return empty, add_memory errors occur,
MCP connection drops, or to verify the plugin is working correctly.
即:当记忆操作失败、搜索返回空、add_memory 报错、MCP 连接掉线,或只是想验证插件是否正常工作时应调用它。文档给出了一条关键执行原则:运行全部检查项后再展示单一汇总,不要在第一处失败时就停下("Run ALL checks, then display a single summary. Do not stop on the first failure.")。这样做的好处是用户可以一次拿到完整的故障面,而不是逐项排雷。
整个诊断体系由四条链路构成,下文按检查顺序逐一展开,并结合插件源码说明每项检查实际验证的底层机制。
检查一:API 密钥是否配置
第一步用最轻量的方式确认密钥存在,且只打印前 6 位以避免在会话日志中泄露完整密钥:
_KEY="${MEM0_API_KEY:-${CLAUDE_PLUGIN_OPTION_MEM0_API_KEY:-}}"
[ -n "$_KEY" ] && echo "${_KEY:0:6}..." || echo "NOT_SET"
判定标准很直接:
- 输出
NOT_SET:FAIL — "No API key configured"; - 已设置:PASS,命令本身只回显前 6 个字符(如
m0-dVe...)。
从源码看密钥解析的完整优先级链
检查一验证的是最终生效的 MEM0_API_KEY,而插件实际的密钥解析逻辑在 _identity.sh 中,优先级依次为:
MEM0_API_KEY环境变量(显式设置 / shell profile);CLAUDE_PLUGIN_OPTION_API_KEY(由 Claude Code 的 userConfig 注入,对应安装时提示输入的密钥);CLAUDE_PLUGIN_OPTION_MEM0_API_KEY(旧版 userConfig 变量名);- 从 shell profile 文件(
~/.zshrc、~/.bashrc、~/.zprofile、~/.bash_profile、~/.profile)中用grep提取export MEM0_API_KEY=...字面量。
第 4 条 fallback 值得注意:桌面应用(如 Claude Cowork)不会从 shell profile 继承环境变量,只读 PATH,因此 _identity.sh 特意做了基于 grep 的提取——只接受字面量值,跳过 ${OTHER_VAR} 这类变量引用,避免 source 整个 profile 产生副作用。这也解释了 health 检查只查 MEM0_API_KEY 和 CLAUDE_PLUGIN_OPTION_MEM0_API_KEY 两个变量的原因:其余来源最终都会归一到 MEM0_API_KEY。
MCP 连接本身的认证方式由 mcp_config.json 定义:服务器地址为 https://mcp.mem0.ai/mcp/,请求头 Authorization: Token ${MEM0_API_KEY}。所以检查一失败意味着后面所有 MCP 调用都会失败,它是整条诊断链的地基。
检查二:身份解析(user_id / project_id / branch)
mem0 的记忆是"按身份隔离"的,所有读写都要携带 user_id 与 app_id(项目 ID)。health 检查要求用插件自己的解析脚本来解析身份,确保诊断结果与 Hook 实际使用的值一致:
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}}/scripts"
source "$SCRIPT_DIR/_identity.sh" 2>/dev/null
echo "user_id=${MEM0_RESOLVED_USER_ID:-}"
echo "project_id=${MEM0_PROJECT_ID:-}"
echo "branch=${MEM0_BRANCH:-}"
注意这里用 CLAUDE_PLUGIN_ROOT / CODEX_PLUGIN_ROOT / CURSOR_PLUGIN_ROOT 三级变量逐级回退,以适配不同平台注入的插件根目录。当 CLAUDE_PLUGIN_ROOT 不可用时的退化路径为:
user_id:取自MEM0_USER_ID或$USER;project_id:取自MEM0_PROJECT_ID,或查~/.mem0/project_map.json中$PWD的映射;branch:git branch --show-current。
判定标准:三项全部非空为 PASS;任何一项退化为默认值则为 WARN。
源码级解析细节
_identity.sh 对 user_id 的处理极简(L48-L57):有 MEM0_USER_ID 就用它,否则用 $USER,再否则为 default。若 MEM0_USER_ID 与系统用户不同,还会导出 _MEM0_IDENTITY_ANNOTATION(形如 " (override; default: xxx)"),最终出现在会话启动横幅的状态行里,提醒当前用户身份是显式覆盖值。
project_id 与 branch 的解析在 _project.sh 中,项目 ID 的完整优先级为:
MEM0_PROJECT_ID环境变量(显式覆盖);~/.mem0/project_map.json按$PWD查找(需要jq);- Git remote slug:去掉协议前缀与
.git后缀,保留最后两级路径(owner/repo),其余/、:替换为-,例如git@github.com:mem0ai/mem0.git→mem0ai-mem0;解析成功后还会把该PWD → slug映射持久化回project_map.json(见 L56-L61),下次同目录启动直接命中第 2 级; - 兜底:
$PWD的 basename。
branch 取 git branch --show-current,失败则记为 unknown。
之所以要求"用插件自己的脚本解析"而非手工推导,是因为 on_session_start.sh 在会话启动时会把解析结果(MEM0_SESSION_ID、MEM0_RESOLVED_USER_ID、MEM0_PROJECT_ID、MEM0_BRANCH、MEM0_API_KEY)写入 CLAUDE_ENV_FILE,供后续 Bash 工具调用和 MCP 配置继承——health 检查直接 source 同一脚本,保证"诊断身份 = 运行时身份",不会出现"检查通过但 Hook 用错身份"的偏差。
另外,_identity.sh 还会从 ~/.mem0/settings.json 加载一组用户可改的配置并导出为环境变量,这些默认值与后文的保留策略直接相关:
| 配置项 | 环境变量 | 默认值 | 用途 |
|---|---|---|---|
auto_save |
MEM0_AUTO_SAVE |
true |
是否自动捕获记忆 |
auto_search |
MEM0_AUTO_SEARCH |
true |
是否自动检索记忆 |
search_limit |
MEM0_SEARCH_LIMIT |
10 |
检索返回条数上限 |
retention_session_days |
MEM0_RETENTION_SESSION_DAYS |
90 |
session 类记忆保留天数 |
confidence_threshold |
MEM0_CONFIDENCE_THRESHOLD |
0.3 |
置信度阈值 |
global_search |
MEM0_GLOBAL_SEARCH |
false |
是否全局搜索(跨用户/项目) |
debug |
MEM0_DEBUG |
false |
是否写 ~/.mem0/hooks.log 调试日志 |
检查三:MCP 服务器连通性(读路径)
通过 MCP 调用 search_memories 发一次最小化的真实查询:
query="health check"filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}top_k=1
判定标准:只要能成功返回(哪怕结果为空)即为 PASS——空结果只说明没有匹配记忆,不代表链路有问题;调用报错才是 FAIL,并需展示错误信息。输出格式中还包含实测延迟(如 PASS MCP Connection 142ms),这是唯一能真实验证 MCP 服务器(https://mcp.mem0.ai/mcp/)可达性、且同时验证密钥被服务端接受的一步:检查一只证明"本地有密钥",本检查才证明"密钥有效 + 网络通畅 + 服务在线"。
从源码结构看,这一步也顺带验证了 user_id + app_id 过滤语法是否可用——enforce_metadata_defaults.sh 这个 PreToolUse Hook 会在智能体遗漏身份参数时自动注入 filters.AND[](见 L78-L135),health 检查显式带上 filters,等价于验证了 Hook 注入后的最终形态。
检查四:记忆写入能力(写路径)
读通之后,再验证写链路。调用 add_memory 写入一条探针记忆:
text="Health check probe — safe to delete."user_id=<active_user_id>app_id=<active_project_id>metadata={"type": "health_check", "probe": true}infer=False
关键细节是 infer=False:探针写入不经过 LLM 抽取,直接落库,保证写入的是确定性数据而不是模型改写后的内容。
mem0 v3 API 的写入是异步的:add_memory 返回 event_id 而非记忆 ID,需要再调 get_event_status(event_id=<event_id>) 轮询处理状态。判定规则分三档:
| 事件状态 | 判定 | 后续动作 |
|---|---|---|
SUCCEEDED |
PASS | 从事件结果中提取记忆 ID,调用 delete_memory 清理探针,不留垃圾数据 |
PENDING(5 秒后仍未完成) |
PASS | 视为"写入已受理、处理延迟",服务端队列拥堵不等于链路故障 |
| 报错 | FAIL | 展示错误信息 |
"SUCCEEDED 后立即删除"构成一次完整的写→确认→读→删闭环:既然能从事件中取回记忆 ID 并成功删除,说明 delete_memory 这条路径同样可用,这正是汇总行 PASS Write/Read write + delete OK 的由来。
这里还有一个容易被忽略的机制:type: "health_check" 这个 metadata 字段是探针的"自报家门",与插件的元数据强制机制一脉相承。enforce_metadata_defaults.sh 在处理 add_memory 调用时,若 metadata 缺少字段会自动补齐默认值:confidence=0.7、files=["*"]、source="auto_capture"、type="task_learning",并注入 session_id(来自 /tmp/mem0_session_id_$USER)用于会话内追踪。探针显式带了 type,就不会被改写成 task_learning,从而在后续质量扫描(检查 metadata.type)中可被清晰识别为探针残留。
检查五:会话统计追踪器
最后确认本地统计文件是否正常工作:
STATS_FILE="/tmp/mem0_session_stats_${USER}.json"
if [ -f "$STATS_FILE" ] && python3 -c "import json; json.load(open('$STATS_FILE'))" 2>/dev/null; then
echo "OK"
else
echo "FAIL"
fi
该文件由 session_stats.py 维护(STATS_FILE = /tmp/mem0_session_stats_{USER}.json,每个用户单文件、会话初始化时重置)。它记录 adds(写入次数)、searches(检索次数)、categories / category_counts(按类别统计)、recent_ids(最近 50 条记忆 ID,见 L45)和 started 时间戳,供 /mem0:stats 类技能汇总会话内的记忆活动。
写入时机在 on_session_start.sh 中可以确认:SessionStart Hook 在 source = startup 时执行 session_stats.py init 重置统计,并在 CLAUDE_ENV_FILE 中持久化身份变量。之后 PreToolUse 阶段的 enforce_metadata_defaults.sh 在每次 add_memory / search_memories / get_memories 工具调用时异步记录 add / search 计数(源码注释说明:插件 MCP 工具不触发 PostToolUse Hook,故统计放在 PreToolUse 侧)。
判定要点:文件不存在不一定是故障——文档明确提示,它由 SessionStart Hook 创建、由后续 Hook 更新,如果它缺失,很可能是会话 Hook 还没触发过,应"先发一条消息,再重新检查"。只有"发过消息后仍缺失或 JSON 无法解析"才真正说明 Hook 链断裂。debug 配置开启后所有 Hook 的 stderr 会追加到 ~/.mem0/hooks.log(见 on_session_start.sh),可作为进一步排查入口。
诊断结果展示格式
五项检查全部跑完后,按如下格式输出单一汇总:
## mem0 health
PASS API Key m0-dVe...
PASS Identity user=kartik, project=mem0, branch=main
PASS MCP Connection 142ms
PASS Write/Read write + delete OK
PASS Session Tracker stats file active
All checks passed.
每行对应一项检查,值中携带最小化的证据(密钥前缀、身份三元组、延迟、读写结果、统计文件状态)。若任何一项失败,必须在汇总后追加 ## Troubleshooting 小节,逐项给出对应的具体修复步骤,而不是笼统建议"重新配置"。结合前文的机制,各失败项的典型修复方向是:API Key 失败 → 按 README 的 Step 1 重新配置(shell profile 或桌面应用本地环境变量编辑器);身份 WARN → 检查 MEM0_USER_ID / MEM0_PROJECT_ID 或清理 ~/.mem0/project_map.json;MCP 失败 → 核对网络与密钥有效性;会话追踪失败 → 触发一次对话再复查,并开 debug 看 ~/.mem0/hooks.log。
扩展模式:--deep 记忆质量审计
以 /mem0:health --deep 方式调用时,在标准五项检查之外追加一轮记忆质量扫描。数据源统一为:get_memories,filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]},page_size=200,拉取全量项目记忆后本地分析。
质量检查 1:重复记忆(Duplicates)
在同一 metadata.type 分组内两两比较文本重叠度(共享名词/关键词 > 60% 判定为疑似重复),输出:
Potential duplicates: <N> pairs
[mem0:<id1>] ≈ [mem0:<id2>] — both about "<shared topic>"
按类型分组比较是有意为之:decision 与 bug_fix 两条记忆即使措辞相近也可能记录不同事实,组内比较才能避免误报。
质量检查 2:过期记忆(Stale memories)
标记满足以下任一条件的记忆:
metadata.type为session_state或compact_summary且超过 90 天;metadata.confidence< 0.3 且超过 30 天。
Stale candidates: <N>
[mem0:<id>] — session_state, 142d old
90 天阈值与配置默认值呼应:retention_session_days 默认即 90(_identity.sh),而 0.3 的置信度下限对应 confidence_threshold 默认值(L72)。这两个数字同时出现在 dream 技能的内置保留策略表中(session_state / compact_summary 默认保留 90 天,见 dream/SKILL.md),说明 health 的"过期"判定与 dream 的"修剪"策略使用同一套标尺——health 负责发现,dream 负责处置。
质量检查 2b:低置信度记忆(Low-confidence)
独立于过期判断,凡 metadata.confidence < 0.5(不论年龄)单独列出:
Low-confidence memories: <N>
[mem0:<id>] — confidence=0.3, "<content preview>"
与 0.3 的"过期门槛"不同,0.5 是"值得人工审视"的提示线;单独成组报告可避免低置信度但仍在有效期内的记忆被误判为过期。
质量检查 3:矛盾记忆(Contradictions)
在同一 metadata.type 组内,标记就同一主题断言相反事实的配对。文档强调使用语义判断——寻找否定模式、冲突的工具/框架选型、被推翻的决策,而不是字面匹配:
Possible contradictions: <N>
[mem0:<idA>] vs [mem0:<idB>] — conflicting on "<topic>"
质量检查 4:孤儿记忆(Orphans)
未设置 metadata.type,或 metadata.type 不属于"17 个已知编码类别"的记忆,视为未经正确打标的孤儿数据:
Untagged/orphan memories: <N>
类别体系的自动安装由 auto_setup_categories.py 在会话启动后台完成(on_session_start.sh),正常情况下新写入的记忆都会带合法 type;出现孤儿通常意味着某次写入绕过了元数据强制 Hook(例如 global_search 模式或其他工具直写平台)。
质量汇总与处置
## Memory Quality
Duplicates: <N> · Stale: <N> · Contradictions: <N> · Orphans: <N>
- 全部为 0:输出
Memory quality: clean.; - 任一非零:追加一句
Run /mem0:dream to fix.
dream 技能(integrations/mem0-plugin/skills/dream/SKILL.md)是配套的自动整合流程:拉取全项目记忆 → 按保留策略(parse_mem0_config.py 解析项目 mem0.md,失败则用内置默认)识别近重复、矛盾与过期项 → 以 diff 形式展示全部拟议变更 → 经用户批准后才执行合并、修剪与冲突消解。health 与 dream 由此构成"体检—治疗"的分工闭环:health 的 --deep 输出量化问题面,dream 在用户确认下修复。
小结
health 技能把 mem0-plugin 的运行时链路拆成五个可独立判定的观测点,并刻意选择"与生产路径同源"的验证方式:检查二直接 source 生产 Hook 使用的 _identity.sh / _project.sh,检查三/四走与 Hook 注入后一致的 filters.AND[] 过滤语法,检查五验证 session_stats.py 所维护的统计文件。任何"诊断通过但实际不工作"的缝隙都源于诊断路径与生产路径不一致,该设计正是为消除这类缝隙。排查时建议按顺序执行:先标准五项定位断点(密钥 → 身份 → 读 → 写 → Hook 链),再以 --deep 评估存量记忆质量,发现问题后交由 dream 在用户确认下完成整合。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00