Mem0 Pi Agent Plugin forget 技能指南:为 AI Agent 记忆设计"搜索—确认—删除"的安全工作流
本文以 forget 技能文档 为主体,讲解 Mem0 Pi Agent 插件(@mem0/pi-agent-plugin)中 "forget" 技能的完整工作流:如何按自然语言查询或记忆 ID 定位待删除的记忆、如何在删除前强制用户确认、以及底层 mem0_memory 工具 search / delete 两个动作的源码实现。读完本文,你可以完整理解该技能五步流程的每一步依据,并结合 插件源码 与 测试用例 验证"绝不未经确认删除"这一核心安全约束是如何在代码层面落实的。
forget 技能定位:8 个技能中唯一的删除入口
Pi Agent 插件通过 8 个 SKILL.md 技能文件指导 Agent 使用各自的记忆能力。其中 forget 技能的 frontmatter 声明如下:
---
name: forget
description: Deletes memories by search query or memory ID with confirmation before removal. Use when removing outdated information, incorrect memories, sensitive data, or cleaning up after experiments.
---
它明确了技能的三个要点:
- 两种删除方式:按搜索查询(search query)或按记忆 ID(memory ID);
- 强制确认:删除前必须经过用户确认(confirmation before removal);
- 适用场景:清理过时信息、错误记忆、敏感数据,或实验结束后的数据清理。
在 插件 README 的技能表中,forget 被概括为 "Delete memories with confirmation",与面向人类用户的 /mem0-forget <query> 斜杠命令("Search and delete memories (with confirmation)")构成同一能力的两条使用路径:一条是 Agent 被自然语言驱动执行技能流程,另一条是用户在终端直接敲命令。
五步删除流程:从原文档完整继承
以下按 forget SKILL.md 的原始步骤逐节展开,并补充源码层面的取值与行为细节。
Step 1: Parse input —— 解析两种输入形态
用户通过 /mem0-forget 提供两种参数之一:
- 搜索查询:
/mem0-forget travel plans - 记忆 ID:
/mem0-forget <memory_id>
若没有参数,技能要求 Agent 主动询问:"What should I forget? Provide a search query or memory ID."。对照斜杠命令的实现,commands.ts 中无参数时直接以 warning 提示 Usage: /mem0-forget <query> 并终止,且 测试用例 验证了此时 mem0.search 根本不会被调用——即"先解析、后检索"的顺序是硬性保证。
Step 2: Find memories —— 用 mem0_memory 工具定位目标
技能文档将"找记忆"分为两个分支:
分支 A:提供了记忆 ID(形如 UUID 或十六进制字符串)
- 使用
mem0_memory工具,action="search",把 ID 作为查询词传入,或直接查找; - 向用户展示:
Found: "<memory content first 120 chars>" (created <date>)。
分支 B:提供了搜索查询
- 使用
mem0_memory工具,action="search",query=<用户查询>; - 以编号列表展示结果:
Found <N> memories matching "<query>":
1. <content, 120 chars> [<category>] [ID: <short_id>]
2. ...
从源码看,mem0_memory 工具的 search 动作要求 query 必填(缺失时抛出 query is required for search),返回 result.results 并用 formatMemoryList 渲染为编号列表,见 tools.ts 的 search 分支。其中两个值得注意的实现细节:
- 输出截断保护:工具输出限制在 200 行 / 50KB(
MAX_OUTPUT_LINES = 200、MAX_OUTPUT_BYTES = 50_000,见 tools.ts 截断逻辑),防止大量匹配撑爆 Agent 上下文——技能文档要求内容截到 120 字符,正是这一防御思路在展示层的体现; - 实际渲染格式:编号列表的每一项由
formatMemoryList→formatMemoryCompact生成,真实格式为[<category>] <memory> (<age>) [mem0:<id>],例如[preferences] Prefers window seats (2d ago) [mem0:a3f8b2c1],见 formatting.ts。末尾的[mem0:<id>]就是 ID 引用,恰好为下一步的按 ID 删除提供句柄。
Step 3: Confirm —— 强制确认,"绝不未确认删除"
技能文档给出两条确认规则,并加粗强调 "Never delete without confirmation. This is destructive.":
- 多个匹配时问:
Delete which memories? Enter numbers (e.g., 1,3,5), 'all', or 'cancel'.——用户可以一次指定多条编号、all全选,或cancel取消; - 单个记忆 ID 时问:
Delete this memory? [y/N]——默认值为否(N大写)。
这条约束在斜杠命令路径上有完整的代码与测试佐证。commands.ts 的 mem0-forget handler 中:
- 单条匹配:先
ctx.ui.confirm("Delete this memory?", ...),用户拒绝时只发送Cancelled — no memories deleted.,不调用删除; - 多条匹配:通过
ctx.ui.select让用户选中一条后再删除;select返回空同样只提示取消。
commands.test.ts 的测试块 用两条断言把这个安全边界钉死:
does not delete when user cancels confirmation:mock 的mem0.delete断言not.toHaveBeenCalled();does not delete when user cancels select:多选界面取消后同样断言删除未发生。
Step 4: Delete —— 用 action="delete" 逐条执行
技能规定:对每条已确认的记忆,使用 mem0_memory 工具 action="delete" 加上记忆 ID。源码中 delete 动作的实现非常直接(tools.ts):
case "delete": {
if (signal?.aborted) throw new Error("Cancelled");
if (!params.memory_id) throw new Error("memory_id is required for delete");
const result = await mem0.delete(params.memory_id);
return {
content: [{ type: "text" as const, text: result.message ?? "Memory deleted." }],
details: {},
};
}
要点有三:memory_id 必填(缺失即抛错);支持 AbortSignal 取消;返回 Mem0 客户端的 message(无则兜底为 "Memory deleted.")。工具的参数 schema 也在 registerMemoryTool 的 Type 定义 中明确 memory_id 说明为 "required for update and delete. Use an ID returned by a prior search or get_all"——即 ID 必须来自前序搜索,与技能流程中"先找到、再删除"的顺序一致。
注意技能文档刻意未使用 delete_all 动作:该动作虽然存在(见 tools.ts),但其描述明确标注 "destructive, only on explicit request",属于另一层级的批量清空能力,不在 forget 技能的正常流程内。
Step 5: Report —— 汇报结果与失败项
流程最后一步的输出规范:
Deleted <N> memories.
且若有任何删除失败,必须报告失败的是哪几条、原因是什么。斜杠命令路径对应的实现是发送 "Forgotten from memory" 加上被删条目的紧凑格式(commands.ts),测试 验证了该可见消息确实发出——删除这种破坏性操作必须有留痕反馈。
检索的过滤范围:forget 只能删到当前 scope 内的记忆
forget 技能不显式传 scope,因此继承插件的 defaultScope(默认 project)。scope 如何转化为 Mem0 检索过滤器,由 scoping.ts 决定:
| Scope | 检索 filters | 用途 |
|---|---|---|
project(默认) |
user_id + app_id(git 仓库根目录名) |
本项目专属记忆 |
session |
user_id + app_id + run_id |
仅本次会话的临时上下文 |
global |
user_id + app_id: "*" |
跨所有项目的全部记忆 |
其中 app_id 通过 git rev-parse --show-toplevel 取仓库根目录名得到(detectAppId),失败时回退为当前目录名——这意味着 monorepo 各子目录共享同一记忆池,也意味着在 project scope 下执行 forget,搜索查询只会命中本项目的记忆,天然限定了删除的爆炸半径。
另一个影响"能不能找到"的旋钮是 searchThreshold:README 中说明其默认值 0.3 是记忆计入匹配的最低相似度(0–1),被 /mem0-search、/mem0-forget、/mem0-pin 共享,并配合 reranking 做更高精度排序——相似度不够高的查询会报"无匹配"而不是返回最接近的无关记忆(见 README 的 searchThreshold 说明)。斜杠命令的检索参数同样可见于 commands.ts:topK = 10(SEARCH_TOP_K)、rerank: true。调高该值更严格(少误删风险但可能漏找),调低则召回更多。
两种路径、一套安全模型
综合原文档与源码,forget 能力在插件中有两条实现路径,安全模型一致:
| 维度 | forget 技能(Agent 路径) | /mem0-forget 命令(用户路径) |
|---|---|---|
| 触发方式 | 用户自然语言要求 Agent 删除记忆 | 终端直接输入斜杠命令 |
| 定位 | mem0_memory 工具 action="search" |
同一 Mem0 客户端的 search(topK=10、rerank、threshold) |
| 确认 | Agent 按技能指令询问编号 / all / cancel 或 y/N |
UI confirm(单条)或 select(多条) |
| 删除 | 对每条确认项调用 action="delete" |
mem0.delete(id) |
| 汇报 | Deleted <N> memories. + 失败明细 |
"Forgotten from memory" 消息 |
| 遥测 | 工具调用经 captureToolEvent 记录成功/延迟 |
captureCommandEvent("mem0-forget", { deleted_count: 1 }) 等,见 telemetry 调用 |
技能路径的优势是灵活(可一次指定 1,3,5 多条或 all),命令路径的优势是确定性(确认对话框是 UI 强制的,不存在 Agent 跳步的可能)。二者共同的红线是 Step 3 的那句 "Never delete without confirmation"。
上手路径:安装、配置与验证
若要在 Pi Agent 中实际使用 forget 技能,按 README 的步骤操作:
- 获取 API key:在 Mem0 平台创建 API key;
- 安装插件:
pi install npm:@mem0/pi-agent-plugin; - 配置凭据:
export MEM0_API_KEY="m0-your-key-here",或在~/.pi/agent/mem0-config.json中写入:
{
"apiKey": "m0-your-key-here",
"userId": "your-username",
"autoCapture": true,
"defaultScope": "project",
"searchThreshold": 0.2,
"dream": {
"enabled": true,
"auto": true,
"minHours": 24,
"minSessions": 5,
"minMemories": 20
}
}
环境变量 MEM0_API_KEY、MEM0_USER_ID 优先级高于配置文件。
配置完成后,先用 /mem0-remember <text> 写入一条记忆(原文写入、无推理),再执行 /mem0-forget <query> 走一遍"搜索 → 确认 → 删除 → 汇报"的完整闭环;也可以直接对 Agent 说"帮我忘掉关于 XX 的记忆",触发 forget 技能流程。删除前可用 search 技能 的紧凑输出复核将要删除的内容——其 ID 引用 [mem0:<id>] 与 forget 所需的 memory_id 是同一种句柄。
适用前提小结:forget 流程作用于当前 scope(默认 project)内的记忆,删除经 Mem0 客户端按 ID 执行、不可由该命令直接回滚;对跨项目记忆的清理需要用户显式切到 global scope(/mem0-scope global)后再操作。
相关文件索引
- 技能文档:forget SKILL.md
- 记忆工具注册与 search/delete 实现:memory/tools.ts
- 斜杠命令实现(含 mem0-forget):src/commands.ts
- scope 过滤器解析:memory/scoping.ts
- 记忆紧凑格式与 ID 引用:memory/formatting.ts
- 确认/取消不删除的测试:commands.test.ts
- 插件总览(命令表、scope 表、分类表、配置):README.md
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