mem0 OpenCode 插件 mem0-remember 技能详解:逐字写入、类型分类与异步写入确认流程
mem0 仓库中的 integrations/mem0-plugin 为 OpenCode、Claude Code、Cursor、Codex 等 AI 编码工具提供跨会话持久记忆能力,其中 mem0-remember 是专门负责"把用户明确陈述的事实逐字(verbatim)存入记忆"的技能。本文以该技能的 SKILL.md 为核心,结合插件源码,完整拆解其四步执行流程、类型分类规则、add_memory 参数细节与异步事件确认机制,读完你可以理解该技能如何保证"用户说什么就存什么",并能独立复现其调用链。
技能定位与插件背景
mem0-remember 技能文件位于 mem0-remember/SKILL.md。其 YAML frontmatter 声明了触发条件:
name: mem0-remember
description: Stores a memory verbatim from user input with appropriate type
classification and metadata. Use when the user says remember this, save
this, store this, note that, or explicitly asks to record a decision,
preference, convention, or learning.
关键点在于 verbatim(逐字):当用户明确说"记住这个 / 保存一下 / 记下这个约定"时,Agent 不做任何改写或事实抽取,直接把原文作为记忆写入,只额外补充分类与元数据。
该技能是 OpenCode 插件体系的一部分。根据 插件 README,OpenCode 的安装方式为一行命令:
opencode plugin @mem0/opencode-plugin
安装后插件通过其 config 钩子自动注册原生记忆工具、生命周期钩子和技能,无需配置 MCP 服务器。插件清单 plugin.json 声明该插件面向 Antigravity agent 提供跨会话、用户级召回能力(版本 0.1.7,Apache-2.0 协议),而 mcp_config.json 则给出了远端 MCP 服务的连接方式(mcp.mem0.ai,鉴权头使用 ${MEM0_API_KEY} 环境变量插值)。同一套技能在 Claude Code 侧的对应版本是 skills/remember/SKILL.md,命令名为 /mem0:remember,流程完全一致,只是 OpenCode 版本命令名为 /mem0-remember,且多了 TUI 输出格式约束。
四步执行流程
Step 1:提取内容
用户以参数形式提供要记忆的内容:
/mem0-remember <text>
如果用户没有提供文本,技能要求 Agent 主动询问:"What should I remember?"。这一步保证写入的 text 一定来自用户明确陈述,而不是 Agent 的推断。
Step 2:对记忆分类
技能要求根据内容信号选择最合适的 metadata.type,完整分类规则如下:
| 内容信号 | 类型 |
|---|---|
| "we decided..."、"always use..."、"never..." | decision |
| "X doesn't work because..."、"don't try..." | anti_pattern |
| "I prefer..."、"use X instead of Y" | user_preference |
| "the convention is..."、"we always..." | convention |
| "learned that..."、"figured out..." | task_learning |
| setup、env、tooling、config 相关内容 | environmental |
| 其他任何情况 | task_learning |
这套类型体系服务于插件的检索设计:后续 search_memories 可以通过 filters 中的 {"metadata": {"type": "decision"}} 等条件做定向召回(参见同目录 mem0-search/SKILL.md 中"双路并行搜索:一路宽泛、一路限定 type=decision"的做法)。因此 remember 阶段的分类质量直接决定了之后按类型过滤检索的命中率,默认兜底 task_learning 也保证了任何输入都有确定的类型归属。
Step 3:调用 add_memory 写入
技能规定调用 add_memory 工具的完整参数:
text="<用户原文>"user_id=<active_user_id>app_id=<active_project_id>metadata={"type": "<分类类型>", "branch": "<当前分支>", "confidence": 1.0, "source": "remember_command"}infer=False
其中两个关键决策在文档中有明确解释:
infer=False:用户已明确陈述事实,不需要 LLM 再做事实抽取(fact extraction),写入即原文;confidence=1.0:因为是用户显式要求存储,可信度取最高值。
从源码可以印证这两个参数并非仅靠提示词约定。在 opencode-mem0.ts 中,add_memory 工具的实现逻辑为:
const meta = args.metadata ?? {};
if (meta.confidence === undefined) meta.confidence = 0.7;
if (!meta.source) meta.source = "opencode";
if (!meta.type) meta.type = "task_learning";
if (!meta.session_id) meta.session_id = sessionId;
if (!meta.files) meta.files = ["*"];
if (!meta.branch) meta.branch = branch;
let infer = args.infer;
if (meta.confidence >= 1.0 && infer === undefined) {
infer = false;
}
这说明:
- 技能指定
confidence: 1.0时,插件会自动把infer置为false(当 Agent 未显式传infer时),与 SKILL.md 中"infer=Falsebecause the user stated the fact explicitly"的语义完全一致——即"高置信度显式陈述 ⇒ 逐字写入"在工具层有代码兜底; - 元数据有完整默认值:不传
confidence时为 0.7(自动捕获场景的置信度),不传type时兜底为task_learning,并自动补session_id、files: ["*"]、当前 git 分支——所以技能中显式给出metadata是在覆盖这些默认值,使该条记忆可被识别为"remember 命令产生"(source: "remember_command"); user_id/app_id在插件启动时已解析并注入:opencode-mem0.ts 中getUserId()优先取MEM0_USER_ID环境变量,否则取系统用户名;getProjectId()优先取MEM0_APP_ID,否则解析git remote get-url origin得到owner/repo,再退化为 git 仓库根目录名。SKILL.md 中的<active_user_id>/<active_project_id>即来自这些解析结果,插件还会通过shell.env钩子把它们以MEM0_USER_ID、MEM0_APP_ID、MEM0_BRANCH等环境变量暴露给 shell(见 opencode-mem0.ts#L384-L395)。
Step 4:异步事件确认
技能强调:add_memory 的响应返回的是 event_id 而不是 memory_id,因为写入是异步的。确认后需要调用一次 get_event_status(event_id=...):
- 状态为
SUCCEEDED:输出结果中的 memory ID; - 状态为
PENDING或processing:以 event ID 作为兜底输出。
确认输出的固定格式为:
Remembered as <type>: "<内容,前 80 字符>"
Memory ID: <来自事件状态的 id>
仅当内容超过 80 字符被截断时才追加 ...。这一约定让用户在 TUI 中能快速看到"存了什么类型、存了什么内容",同时保留了可追溯的 ID。工具层同样有对应实现:opencode-mem0.ts#L616-L626 中 get_event_status 直接请求平台侧的 /v1/event/<event_id>/ 端点查询异步写入结果。
插件如何把技能变成可用命令
从 opencode-mem0.ts 的 registerCommands 函数可以看到技能与命令的接线方式:插件遍历 opencode-skills/ 目录下每个含 SKILL.md 的子目录,读取其 frontmatter 的 description 作为命令描述,并把目录名注册为 OpenCode 的斜杠命令(如 mem0-remember → /mem0-remember)。命令模板会附带插件启动时解析好的身份上下文(user_id、app_id、session_id、branch),指示 Agent 加载并执行对应 SKILL.md。源码注释特别说明:仅通过 skills.paths 发现的技能可以被 Agent 的技能工具使用,但不会出现在 TUI 斜杠菜单中,因此还需要 registerCommands 显式注册——这解释了为什么 SKILL.md 中用户入口写作 /mem0-remember <text>。
此外,插件在 chat.message 钩子里维护了一条"记忆触发"正则(opencode-mem0.ts#L175-L176):
const NUDGE_RE =
/\b(remember\s+(this|that)|memorize|save\s+this|note\s+(this|that)|don'?t\s+forget|always\s+remember|never\s+forget|keep\s+(this|that)\s+in\s+(mind|memory)|store\s+(this|that))\b/i;
当用户在自然对话(而非斜杠命令)中说"remember this / 别忘了这个"时,插件会向系统上下文注入提示 [MEMORY TRIGGER] User asked to remember something. Call add_memory with the user's statement, confidence=1.0, infer=false.——这与 SKILL.md frontmatter 描述的触发场景("remember this, save this, store this, note that")逐条对应,即使用户不输入斜杠命令,插件也能引导 Agent 按相同参数(confidence=1.0, infer=false)完成逐字写入。
实操:安装、配置与验证
完整可用的操作路径如下(依据 插件 README):
-
准备 API Key:从 Mem0 平台获取以
m0-开头的 API Key,并持久化到 shell 环境:echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc source ~/.zshrc echo $MEM0_API_KEY # 验证输出注意:OpenCode 桌面场景下,MCP 配置读取的是环境变量插值(
${MEM0_API_KEY}在会话启动时解析),因此必须持久化设置而非仅当前 shell 临时导出。 -
安装插件:
opencode plugin @mem0/opencode-plugin追加
--global可全局安装。安装后重启 OpenCode 会话。 -
执行 onboard(可选但推荐):
/mem0:onboard会校验 API Key 与连接、导入项目文件、安装面向编码场景的记忆分类,并可重复执行(幂等)。 -
使用 remember:
/mem0-remember "we decided to always use TypeScript for the API layer"按技能流程,Agent 应将其分类为
decision,以infer=False、confidence=1.0、source="remember_command"写入,并回显确认块。也可以用/mem0:remember "we use TypeScript"式的自然语句,或直接在对话中说"记住:我们的接口一律用 TypeScript 写"触发 NUDGE 路径。 -
验证写入:随后用
/mem0:tour(OpenCode 侧为/mem0-tour)按分类浏览全部记忆,或用/mem0-search <关键词>做语义检索确认该条可被召回。
输出格式约束:为什么技能禁止 Markdown
SKILL.md 末尾有一段 OpenCode 专属的格式约束:
IMPORTANT: Do NOT use markdown in your output. OpenCode TUI renders text verbatim — markdown like bold, ## headers, and | table | syntax appears as raw characters. Use plain text with indentation for structure. Use dashes for lists. Use spaces to align columns instead of markdown tables.
这是因为 OpenCode 的 TUI 终端逐字渲染文本,**加粗**、## 标题、| 表格 | 等语法会原样显示为可见字符。因此技能明确要求:用缩进表达结构、用短横线做列表、用空格对齐列来替代 Markdown 表格。这条约束体现了 SKILL.md 作为"写给 Agent 的执行手册"的定位——它不仅定义流程,还约束了最终呈现给用户的输出形态,确保确认块在不同终端环境下都可读。
小结
mem0-remember 技能的设计核心可以归纳为三点,且每一点都能在仓库中找到代码级佐证:
- 逐字写入:
text直接取用户原文,infer=False跳过 LLM 事实抽取;工具层在confidence >= 1.0时自动强制infer=false(opencode-mem0.ts#L446-L449); - 结构化分类:六种
metadata.type覆盖决策、反模式、偏好、约定、任务学习与环境配置,兜底task_learning,为后续按类型过滤的语义检索奠定基础; - 异步确认闭环:
add_memory返回event_id,通过get_event_status单次轮询拿到最终memory_id,并以固定纯文本格式回显,兼顾 TUI 可读性与可追溯性。
如果你要在此基础上做扩展(例如自定义分类或增加确认重试),建议直接参照 mem0-remember/SKILL.md 的四步结构修改 SKILL.md——插件会在下次会话启动时重新读取 description 并注册命令,无需改动插件 TypeScript 代码。
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