首页
/ Mem0 插件 mem0-tour 技能实战:在 OpenCode 中分门别类地巡检 Agent 记忆库

Mem0 插件 mem0-tour 技能实战:在 OpenCode 中分门别类地巡检 Agent 记忆库

2026-09-04 22:52:51作者:秋泉律Samson

在编码 Agent 的长期记忆体系中,"存进去容易,看全了难"。Mem0 插件(integrations/mem0-plugin)提供的 mem0-tour 技能解决的就是"看全"这件事:它以 /mem0-tour 命令为入口,把当前项目下已存储的全部记忆按类别分组、按数量排序并紧凑呈现,让你在一次会话启动前就能掌握这个项目的架构决策、踩坑教训、编码约定与工具链配置。读完本文,你将掌握该技能的三种运行模式(完整巡检、跨项目巡检、Peek 紧凑搜索)的完整执行协议,理解其背后的 user_id/app_id 身份解析机制、Mem0 平台的类别自动分类体系,以及"全量拉取 + 三路语义检索 + 按 ID 去重归组"这套记忆盘点算法的设计考量。

技能定位:mem0-tour 是什么

mem0-tour 是 mem0 插件为 OpenCode 环境注册的一个 skill,其定义文件位于 mem0-tour/SKILL.md。技能 frontmatter 中的描述明确了它的适用场景:

Browses all stored memories grouped by category with full content display. Use when reviewing all project memories, exploring stored knowledge, onboarding to a project, or getting an overview of captured decisions, conventions, and learnings.

也就是:审阅当前项目的全部记忆、探索已存储的知识、项目 onboarding,或对已捕获的决策/约定/经验获得全景概览。它与插件通用技能目录中的 tour/SKILL.md 是"同源异体"的关系——两者逻辑骨架一致(跨项目模式、Peek 模式、完整巡检三步流程相同),差异主要在展示层:通用版要求展示记忆全文、每组最多 10 条,而 OpenCode 版(本文主角)针对 OpenCode TUI 的渲染特性改为截断到 100 字符、每组最多 5 条,并增加了一张类别汇总表。这正对应 plugin.json 中对该插件的定位:"Persistent semantic memory... 16 slash commands, lifecycle hooks for auto-capture and metadata enforcement"——/mem0-tour 是其中负责"读侧总览"的命令。

技能运行所依赖的记忆身份(谁、哪个项目、哪个分支)不是技能自己现场计算的,而是由插件入口在每次工具调用时解析注入。从 opencode-mem0.ts 的源码结构看:

  • getUserId():优先取环境变量 MEM0_USER_ID,否则取系统用户名(userInfo().username$USER),兜底为 unknown。这与 Python 侧钩子脚本 scripts/_identity.pyresolve_user_id() 的解析优先级(MEM0_USER_ID$USER"default")保持一致。
  • getProjectId()(即技能中的 app_id):优先取 MEM0_APP_ID 环境变量;否则执行 git remote get-url origin 并解析出 owner-repo 形式的 slug,跨克隆、worktree 与子目录都保持稳定;没有 remote 时退化为 git 仓库根目录名,再退化为当前目录名。Python 侧的 scripts/_project.py 还额外提供了 ~/.mem0/project_map.json 手工映射与"remote hash 自愈"(目录改名/移动后仍能命中同一 project_id)两级增强。
  • getBranch():执行 git branch --show-current,失败时回退为 main

理解了这三个值,才能理解下文所有 filters={"AND": [...]} 中占位符 <active_user_id><active_project_id><active_branch> 的真实来源。

模式一:跨项目巡检(--all-projects

/mem0-tour --all-projects/mem0-tour --all-projects auth middleware 这类带 --all-projects 标志的方式调用时,技能切换到跨项目模式——同一个用户可能同时维护多个仓库,此模式把所有项目下的记忆一次拉出对比:

  1. 调用 get_memories,过滤条件为 filters={"AND": [{"user_id": "<active_user_id>"}]}page_size=200——注意不带 app_id 过滤,以此覆盖该用户名下的所有项目;
  2. 如果同时提供了搜索 query(如 auth middleware),再执行 search_memoriesquery=<query>filters={"AND": [{"user_id": "<active_user_id>"}]}top_k=20,同样不带 app_id
  3. 结果先按 app_id 分组(项目级),每个项目内再按类别分组;
  4. 按如下格式展示:
## <app_id_1> (<N> memories) ← current
**Architecture Decisions** — <memory content>
...

## <app_id_2> (<N> memories)
...

<N> memories across <M> projects
  1. 当前项目所在的分节标题用 ← (current) 标注,方便快速定位。

若未提供 --all-projects,则不进入此模式,走下文的标准单项目流程。

模式二:Peek 紧凑搜索(带 query 但不跨项目)

/mem0-tour 收到一个搜索参数(例如 /mem0-tour auth middleware)且没有 --all-projects 时,进入 Peek 模式,输出为紧凑的单行结果:

  1. 并行发起两个 search_memories 调用,一个宽口径、一个定向:
    • 宽口径(Broad):query=<query>filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}top_k=10rerank=true
    • 定向(Targeted):在宽口径基础上追加 {"metadata": {"type": "decision"}} 条件,top_k=5rerank=true——单独把"决策类"记忆捞出来,因为架构决策往往比一般性陈述更有价值。
  2. 按记忆 ID 去重后,输出紧凑格式:
## mem0 search: "<query>" (<N> results)

1. [decision] Auth module uses JWT with RS256 keys (2025-05-15) [mem0:a3f8b2c1]
2. [anti_pattern] Don't use symmetric HS256 — leaked in env (2025-05-10) [mem0:7e2d9f4a]
3. [convention] All middleware in src/middleware/ (2025-05-08) [mem0:c4d5e6f7]

每行的固定格式为 <number>. [<type>] <content, 80 chars> (<date>) [mem0:<short_id>]:先给类型标签,正文截断到 80 字符,附日期与短 ID(mem0:<short_id> 方便后续用 /mem0-forget 等命令精确定位这条记忆)。

  1. 若无命中结果,输出:No memories matching "<query>" for project <project_id>.

从插件 Python 侧的检索辅助层 scripts/_search.py 可以看到,这套 {"AND": [...]} 过滤格式与 app_id + metadata 子条件的拼接方式正是钩子脚本调用 POST /v3/memories/search/ 时使用的原生格式——技能文档与底层实现使用的是同一套平台 API 语义。另值得注意的是 should_rerank() 的注释说明:平台 REST 检索端点在不显式传 rerank 时不做重排,结果仅按原始向量相似度排序,最相关的一条记忆可能跌出 top_k 窗口;因此钩子注入路径默认开启 rerank(额外约 150–200ms 延迟在钩子的 curl 预算之内),可用环境变量 MEM0_RERANK 关闭。这也解释了为什么 tour 的各路检索调用都显式带上 rerank=true

若既无 query 参数也无 --all-projects 标志,则进入下面的完整巡检流程。

模式三:完整巡检(Full Tour)六步执行协议

完整巡检是技能的主流程,共六步。它的设计核心是"全量拉取保证不漏、语义检索保证排序、按 ID 合并去重保证一致"。

Step 1: 拉取本项目全部记忆

调用 get_memories

filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}, page_size=100

这一步不依赖语义相似度,确保项目下的每条记忆(无论内容形态如何)都进入工作集。

Step 2: 并行三路补充语义检索

并行执行三个 search_memories 调用,为关键主题拿到相关性排序的结果:

query top_k rerank
"architecture decisions design choices" 10 true
"bugs errors failures anti-patterns" 10 true
"project setup tooling conventions preferences" 10 true

三者的过滤条件均为 filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}

技能文档中有一条关键约束:在这三路调用中不要metadata.type 过滤。原因是平台会自动为每条记忆分配 categories 字段(自动分类),部分记忆虽有类别却没有显式的 metadata.type,一旦加该过滤就会系统性漏掉这批"自动分类记忆"。

Step 3: 合并去重并按三级优先规则归组

把 Step 1 的全量结果与 Step 2 的三路检索结果按记忆 ID 合并去重。对每条记忆,按以下优先级确定它所属的分组:

  1. 平台 categories 字段(每条记忆上的数组,由 Mem0 平台自动分配)——取第一个类别值;
  2. metadata.type 字段(若存在,通常由钩子/Agent 显式写入)——无 categories 时作为兜底;
  3. 两者皆无的记忆归入 "other" 桶。

平台类别名/metadata.type 值到展示名的映射表(原文档完整继承):

Platform category / metadata.type Display name
architecture decisions, architecture_decisions, decision Architecture Decisions
anti patterns, anti_patterns, anti_pattern Anti-Patterns
task learnings, task_learnings, task_learning Task Learnings
coding conventions, coding_conventions, convention Coding Conventions
user preferences, user_preferences, user_preference User Preferences
project profile, project_profile Project Profile
tooling setup, tooling_setup, environmental Tooling & Setup
technology, professional_details Tooling & Setup
session_state Session State
compact_summary Compact Summaries
其他一切值 Other

这张映射表并非凭空设计——这些类别名正是插件为编码场景定制的"编程类别体系"。从 scripts/setup_coding_categories.pyCODING_CATEGORIES 可见,插件在初始化时会通过 mem0ai SDK 的 client.project.update 把 Mem0 默认的"消费者取向"类别(food、hobbies、music 等)替换为面向代码工作的 12 类体系,包括 architecture_decisionsanti_patternstask_learningstooling_setupbug_fixescoding_conventionsuser_preferencesdependency_decisionsperformance_findingssecurity_constraintstesting_patternsdata_modelapi_contractsdeployment_runbook 等。tour 展示样例中出现的 bug_fixes (78)tooling_setup (119) 等分组,正是这一体系落地的结果;而映射表中"其他一切值归 Other"的兜底规则,也兼容了平台上未被该脚本覆盖的类别写法(空格变体、单复数变体)。

Step 4: 按数量降序展示

分组按记忆数降序排列。先输出类别汇总表:

mem0 tour

Session (ses_abc123)  branch: main
Project: my-project  -  349 memories

Category                   Count
-----------------------------------------
tooling_setup                119
bug_fixes                     78
architecture_decisions        32
task_learnings                14
...

然后逐类别输出编号单行记忆,每条截断到最多 100 字符:

tooling_setup (119)
  1. User requires that no git commit or push be performed without explicit permission...
  2. OpenCode plugins are loaded from ~/.config/opencode/plugins/ for global installation...
  3. Assistant determined that the symlink method for loading the Mem0 plugin was failing...
  ... and 116 more

bug_fixes (78)
  1. Fixed getAll filter format from flat object to AND-wrapped array for mem0ai TS SDK v3...
  2. Root cause of user_id mismatch: plugin derived kartik.labhshetwar from git email...
  ... and 76 more

规则:每个类别按时间新近度展示前 5 条;超过 5 条的类别以 ... and <N> more 提示余量;空类别整段跳过,不输出无内容分组。

Step 5: 输出总计

<N> memories across <M> categories
project: <project_id>  branch: <active_branch>

Identity - user: <user_id>  project: <project_id>  branch: <branch>

最后一行把本次巡检的完整身份三元组(用户、项目、分支)回显出来,便于在多项目、多分支并存时确认"我看到的确实是这个项目的记忆"。

Step 6: 空态处理

若该项目下记忆数为零,输出:

No memories stored yet for project <project_id>.
Start working - mem0 captures learnings automatically, or use /mem0-remember to save something now.

即提示两条出路:正常开发(插件的生命周期钩子会自动捕获经验,auto_capture.pyon_stop.sh 等钩子负责),或立即用 /mem0-remember 手动存一条。

输出格式约束:为什么全文禁用 Markdown

技能文档末尾有一条强约束:输出中禁止使用任何 Markdown。原因是 OpenCode TUI 按字面量渲染文本——**bold**## 标题| 表格 | 语法都会以原始字符呈现出来,形成噪声。因此技能要求:用缩进表达结构、用短横线表达列表、用空格对齐列宽代替 Markdown 表格。

值得注意的是一个表面矛盾:跨项目模式与 Peek 模式的展示模板里写着 ## <app_id_1>**Architecture Decisions**,而格式约束又禁用 Markdown。从文档语义理解,这些模板片段是面向"内容组织"的示意(表明层级与加粗意图),真正落到 OpenCode TUI 时必须按末条约束改写为纯文本(如用大写标题行 + 缩进替代 ##**)。这也是 OpenCode 版技能相对通用版 tour/SKILL.md 的刻意分叉:通用宿主支持 Markdown 渲染时可保留原样,OpenCode 宿主则必须纯文本化。

小结

mem0-tour 是 mem0 插件"写侧自动捕获 + 读侧主动巡检"闭环中的总览入口。它的价值不在单条记忆的检索(那是 mem0-search/Peek 模式的活),而在于用一套确定性协议——全量拉取、三路语义检索、ID 去重、三级类别归组、数量降序展示——把分散在多轮会话中的记忆资产整理成一张可读的项目记忆地图。结合 scripts/setup_coding_categories.py 注入的编码类别体系、scripts/_project.py 保证 app_id 跨目录稳定的解析策略,以及平台 categories 自动分类能力,这一技能在 onboarding 新项目、跨项目对比知识沉淀、以及巡检记忆质量时都能直接复用。若你的 Agent 宿主同样是 OpenCode,部署该插件后直接输入 /mem0-tour/mem0-tour <关键词>/mem0-tour --all-projects 即可体验三种模式。

登录后查看全文
热门项目推荐
相关项目推荐