Mem0 插件 stats 技能:会话与项目级记忆统计、API 延迟测量与每周摘要的实现剖析
/mem0:stats 是 Mem0 官方插件(integrations/mem0-plugin/)内置的核心技能之一,用于在 Claude Code、Cursor、Codex 等客户端中以一条斜杠命令输出「当前会话 + 当前项目」两个维度的记忆统计仪表盘:会话内写了多少条记忆、检索了多少次、记忆按类别如何分布、记忆账龄(age distribution)、平台 API 往返延迟,以及可选的每周活动摘要(weekly digest)。读完本文,你将掌握该技能的完整执行流程(本地统计脚本 + MCP 工具调用 + 展示规则),理解其统计数据的采集链路(SessionStart/PostToolUse 钩子驱动 session_stats.py 落盘),并能依据 SKILL.md 的原始定义复现或定制一套记忆审计面板。
技能定位:一条 /mem0:stats 命令背后是什么
插件元信息 plugin.json 将 mem0 描述为「为 Agent 提供跨会话持久语义记忆的插件,包含 16+ 斜杠命令与生命周期钩子」;README 的技能列表中,/mem0:stats 的说明是「Session and project memory statistics」。技能的完整行为规范定义在 stats/SKILL.md 中,分为两大部分:
- 标准统计仪表盘:三步走 —— 采集本地会话统计(Step 1)→ 从 Mem0 Platform API 拉取项目级终身统计并测量 API 延迟(Step 2)→ 按固定规则渲染紧凑表格(Step 3);
- 每周摘要模式:以
--weekly参数(如/mem0:stats --weekly)触发,在标准仪表盘之后追加「本周新增记忆、最活跃类别、最活跃日期、亮点摘要」,并落盘摘要文件。
它的前置条件是整个 mem0 插件已完成安装与 /mem0:onboard 引导:MEM0_API_KEY 已导出、MCP 服务器(https://mcp.mem0.ai/mcp/,见 mcp_config.json)可连通、身份三元组(user_id / project_id / branch)可解析。这些前提决定了 stats 技能中 <active_user_id>、<active_project_id> 等占位符的取值来源。
Step 1:本地会话统计——session_stats.py peek
技能的第一步命令定义在 SKILL.md:
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}}/scripts"
python3 "$SCRIPT_DIR/session_stats.py" peek 2>/dev/null || echo "{}"
三个要点:
SCRIPT_DIR的多客户端兼容写法:依次回退CLAUDE_PLUGIN_ROOT→CODEX_PLUGIN_ROOT→CURSOR_PLUGIN_ROOT,使同一份技能文档在 Claude Code、Codex、Cursor 三种宿主环境下都能定位到插件的scripts/目录;- 为什么用
peek而不用report:文档明确说明peek返回 JSON 且不删除统计文件,而report会做清理(「unlikereport」)。这一点在源码中可印证——peek() 只读不写,注释直接写明 “Return current stats as JSON without clearing the file”; - 失败兜底:
2>/dev/null || echo "{}"保证脚本缺失或报错时命令不中断,技能继续执行并在输出中标注 “No session data available”。
统计文件的数据结构与生命周期
session_stats.py 是一个 138 行的独立脚本,其设计可以从源码直接读出:
- 单一文件、按用户隔离:STATS_FILE 为
/tmp/mem0_session_stats_${USER}.json(USER缺省为default)。每个用户在/tmp下只有一个统计文件,会话启动时重置; - 初始结构(init()):
adds(写入计数)、searches(检索计数)、categories(去重类别列表)、category_counts(类别计数映射)、recent_ids(近期写入的记忆 ID,上限 MAX_RECENT_IDS = 50)、started(ISO 时间戳); - record_add(category, memory_id):写入一次记忆时自增
adds,按类别累加category_counts,并在提供了memory_id时把{id, category, ts}追加进recent_ids,超出 50 条时裁剪最旧记录; - record_search():仅自增
searches; - CLI 入口:
init | add <category> | search | peek | report五个子命令(main()),report在无数据时返回空字符串,CLI 层会打印 “Session: no memory operations.”。
测试套件 test_session_stats.py 对上述行为逐条断言:peek 不清空文件(test_peek_returns_json_without_clearing)、recent_ids 上限裁剪(test_recent_ids_capped,写入 60 条后断言长度恰为 50 且最旧 10 条被丢弃)、空类别不入 category_counts(test_category_counts_empty_category_not_tracked)等,且通过 autouse fixture 将 STATS_FILE monkeypatch 到临时目录,避免污染真实 /tmp 状态。
统计数据是谁写入的:钩子采集链路
stats 技能只是「读者」,数据生产者插件的生命周期钩子。从 hooks.json 的钩子注册与脚本实现可以看到完整链路:
- SessionStart → init:on_session_start.sh 在
source == "startup"(新会话)时执行session_stats.py init重置计数——注意 resume/compact 场景不重置,保证会话统计跨恢复保持累计; - PostToolUse → add/search:钩子
mem0-post-tool匹配mcp__mem0__.*|mcp__plugin_mem0_mem0__.*(hooks.json),由 on_post_tool_use.sh 解析tool_name:命中*__add_memory时从tool_input.metadata.type或metadata.category提取类别并调用session_stats.py add "$CATEGORY";命中*__search_memories|*__get_memories时调用session_stats.py search。两条记录均为非阻塞(2>/dev/null || true); - 自动捕获旁路:auto_capture.py 在自动捕获记忆路径中也以
session_stats.record_add("auto_capture")记账,这解释了统计面板中auto_capture类别来源。
因此技能文档强调:本地统计文件「accurately tracks adds and searches for the current session」——它的准确性不依赖平台 API 的过滤能力,而依赖钩子事件流的完整性。
Step 2:项目级终身统计与 API 延迟测量
会话统计回答「这次会话做了什么」,终身统计回答「这个项目积累了什么」。SKILL.md 的 Step 2(原文)规定了三件事:
1. 用 get_memories 拉取全量记忆并分组
调用 MCP 工具 get_memories,参数为:
filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}page_size=100
分组优先级:
categories[0](平台自动分配的类别)——主分组;metadata.type(Agent 写入时标注的类型)——次分组,仅在记忆没有平台类别时使用;created_at日期——用于账龄(age)分析。
其中 user_id + app_id 的双重过滤是 mem0 插件的项目级作用域约定(on_session_start.sh 的启动横幅同样要求每次 search_memories/add_memory 都携带这两个字段)。类别来源则是 README 所述的「coding-tuned categories」机制:插件在会话启动时后台运行 setup_coding_categories.py 为项目安装 17 个面向开发场景的类别(architecture_decisions、bug_fixes、coding_conventions 等),这就是 stats 面板中类别列的取值集合。
类别归一化规则:auto_capture 与 uncategorized 必须合并为一行 uncategorized——它们代表平台未能分配有意义内容类别的记忆,文档特别强调“不要在表格中把 auto_capture 单独列行”。
2. 会话统计只信本地文件,禁止用 API 过滤会话
这是 SKILL.md 中一条关键的设计约束(原文):不要用 run_id 或 metadata.session_id 过滤去 API 查会话数据,原因是记忆存储时不携带 run_id,且 session_id 的 metadata 过滤结果不一致(“unreliable results”)。从 on_post_tool_use.sh 的记录方式看,会话维度的数据本来就只写在本地统计文件里,API 侧并无可靠的会话键——这条规则本质上是在规避「查询模型与写入模型不匹配」的问题,把会话统计的数据源锁定为钩子写入的本地文件。
3. 用一次最小检索测量 API 往返延迟
search_memories(
query="project",
filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]},
top_k=1
)
技能要求记录 MCP 调用前后的时间戳,二者之差即为面板上 API: 84ms 这类延迟指标,并明确禁止改用原始 HTTP 调用(必须走 MCP 工具通道,测得的才是 Agent 真实感受到的链路延迟)。这与 health 技能 的连通性检查使用同一套「top_k=1 最小查询」手法,形成插件内一致的诊断范式。
Step 3:仪表盘展示与渲染规则
SKILL.md 规定了固定的紧凑输出模板(原文),明确要求「No ASCII bar charts — use a clean table layout」:
## mem0 stats
**Session** (<session_id, first 12 chars>) — 3 written, 5 searches, categories: decision, convention
**Project: my-project** — 55 memories, API: 84ms
| Category | Count |
|----------------------|-------|
| decision | 24 |
| convention | 15 |
| anti_pattern | 6 |
| task_learning | 5 |
| user_preference | 3 |
| session_state | 2 |
**Age** — oldest: 2026-02-15, newest: 2026-05-23
< 7 days: 5 · 7–30d: 12 · 30–90d: 10 · > 90d: 8
**Identity** — user: kartik · project: my-project · branch: main
配套的五条展示规则(原文):
| 规则 | 说明 |
|---|---|
| 类别表排序 | 按 Count 降序,省略 0 条记忆的空类别 |
| 账龄行 | 单行点号分隔的分桶(< 7 days / 7–30d / 30–90d / > 90d),由 created_at 计算 |
| Session 行 | 本地统计文件不可得时整行跳过 |
| 小规模项目 | 总记忆数仅 1–2 条时跳过类别表,只展示总数 |
| 紧凑原则 | 不加装饰边框与填充内容 |
「Identity」行的 user / project / branch 三元组正是 Step 1 中 _identity.sh 解析出的 MEM0_RESOLVED_USER_ID、MEM0_PROJECT_ID、MEM0_BRANCH,与启动横幅展示的身份信息保持一致。
每周摘要模式(--weekly)
以 /mem0:stats --weekly 触发时,技能在标准仪表盘之后追加一个五步流程(W1–W5):
-
W1 拉取近期记忆:并行发起三个带时间窗(
created_at.gte= 7 天前,YYYY-MM-DD)的search_memories查询,top_k=20:query="decisions made this week"query="bugs errors fixes"query="patterns conventions learnings"
三者共用同一组
user_id+app_id过滤。三路查询的语义切分(决策 / 缺陷 / 模式学习)与插件默认的 coding-tuned 类别体系对齐,用自然语言查询覆盖结构化类别难以穷举的本周动态。 -
W2 分析:按记忆 ID 合并去重,按
categories[0]或metadata.type归组到「New this week」;计算近 7 天新增数、最活跃类别、最活跃日期。 -
W3 展示:在标准统计之后追加固定格式区块:
### This week (May 16 – May 23)
+12 memories — most active: Wednesday (5)
| Category | New |
|---------------|-----|
| decision | 5 |
| task_learning | 4 |
| bug_fix | 3 |
**Highlights**
- <2-3 sentence summary of most important decisions/learnings this week>
- W4 落盘:摘要写入
~/.mem0/weekly-digest.md(覆盖写),并向~/.mem0/digest-history.log追加一行历史记录:
<YYYY-MM-DD> | <project_id> | +<new_count> memories | top: <top_category>
- W5 空状态:7 天内无新增时仅输出一行
No new memories in the past week. Total: <N> memories in <project_id>.。
digest-history.log 的「一行一摘要」设计使其天然可被后续技能做趋势对比(例如连续几周的项目活跃曲线),相当于把每次 weekly 运行压成一个可 grep 的事件点。
与 health 技能的配合:统计文件也是诊断信号
stats 技能的 Step 1 依赖本地统计文件存在,而该文件的存在性本身就是一个可诊断信号。health 技能 的 Check 5 正是验证这一点:
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
其诊断逻辑:文件由 SessionStart 钩子创建、PostToolUse 钩子持续更新;若 stats 技能看到空数据而 health 又报告 FAIL,大概率是钩子尚未触发(会话尚未真正启动过工具调用),应先发送一条消息再复查。这构成了「stats 读数据 → health 查数据源 → hooks.json 定数据来源」的排障闭环。
适用前提与限制
- 运行环境:stats 技能依赖 mem0 插件完整安装(MCP 服务器 + 钩子)且已完成
/mem0:onboard引导;MEM0_API_KEY必须是m0-前缀的平台密钥。仅以「Direct MCP」方式接入(如 Codex 手动配置config.toml)而没有钩子的场景下,本地统计文件不会生成,仪表盘会退化为只剩 Project 行; - 会话统计的语义边界:
adds/searches统计的是「经过插件工具通道的 MCP 调用」(钩子只匹配mcp__mem0__*工具名),直接以 SDK 方式写入的记忆不计入会话统计;peek返回的recent_ids同样受 50 条上限约束; - 终身统计的规模假设:Step 2 使用
page_size=100的get_memories,SKILL.md 未定义翻页逻辑,可推断其面向「单项目记忆量级在百条上下」的典型开发场景,超大项目下类别计数以首页 100 条为样本; - 平台依赖:延迟指标与账龄数据均依赖 Mem0 Platform API 的可用性与
created_at字段的准确性,OSS 本地部署形态不在此技能的适配范围内。
小结
/mem0:stats 的价值不在「查一下有多少条记忆」,而在于它把三个本不互通的信息源拼装成了一致的审计视图:钩子采集的本地会话行为(session_stats.py 的 JSON 统计文件)、平台侧的终身记忆资产(get_memories + 类别归一化 + 账龄分桶)、以及一次 top_k=1 检索测得的真实链路延迟。其工程细节——peek 与 report 的读写语义区分、拒绝用不可靠 API 过滤查会话、auto_capture/uncategorized 合并、weekly 摘要的双文件落盘——都直接写在 SKILL.md 中并有 测试用例 与 钩子脚本 佐证,是研究「Agent 插件如何做运行时可观测性」的一个完整样本。
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 StartedRust0622
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