Mem0 Pi Agent 插件的 context-loader 技能:如何在任务开始前把相关记忆预注入 Agent 上下文
本篇以 @mem0/pi-agent-plugin 插件中的 context-loader 技能定义文件 为主体,完整解析该"任务前记忆预加载"技能的工作流程:如何从当前消息中提取主题、如何发起 2–4 次并行语义搜索、如何按记忆 ID 去重、如何输出紧凑的上下文块,以及四条硬性约束(只读、最多 10 条、空结果静默、跳过已在上下文的记忆)。同时结合插件源码,说明该技能依赖的 mem0_memory 搜索工具、作用域(scope)过滤规则与记忆格式化输出的底层实现,读完即可掌握在 Pi Agent 中构建"先召回、再工作"记忆流水线的完整方案。
技能定位:context-loader 是什么
在 Mem0 的 Pi Agent 插件 中,skills/ 目录包含 8 个 SKILL.md 文件,每个文件定义一种指导 Agent 如何正确使用记忆能力的"技能"。context-loader 是其中负责**预取(pre-fetch)**的技能:
Pre-fetches relevant memories to prime context before working on a task or topic.(在工作于某个任务或主题之前,预取相关记忆以预热上下文。)
它解决的核心问题是:Agent 开始处理一个新任务时,往往不知道用户过去已经表达过哪些决策、偏好和背景知识。如果不先召回记忆,Agent 要么向用户重复提问,要么基于过时的假设工作。context-loader 的作用就是在动手之前,把与当前任务相关的记忆批量拉进上下文。
该技能的 YAML frontmatter 明确了触发描述:
name: context-loader
description: Searches and injects relevant memories into context before starting work
on a task or topic. Use when beginning a new task, switching context, or when
past decisions, preferences, or knowledge need to be loaded.
触发时机:何时启用 context-loader
技能文档给出了三类明确的触发场景:
- 会话启动——由扩展的
before_agent_start事件自动触发; - 用户开始处理某个特定主题或领域时;
- 用户显式询问——例如说 "what do we know about X" 或 "context for X"。
第一个触发点在插件源码中有对应实现。入口文件 中注册了 before_agent_start 事件处理器,每轮对话开始前它会做两件事:
- 把
MEMORY_POLICY(记忆使用策略)追加到系统提示词; - 调用 buildRecallContext 做一次自动预取:用用户的 prompt 直接搜索 project 作用域下的记忆,把命中的记忆格式化成
<mem0-relevant-memories>块注入系统提示词。
源码注释点明了设计意图:这是"shallow first pass"(浅层第一遍),且声明"This is a shallow first pass — search mem0_memory for more if you need it"——即自动预取只保证基础召回,深入的多角度检索正是交给 context-loader 技能来完成的。两者是互补关系:前者单次搜索、结果直接注入;后者是 Agent 按技能指引主动发起的 2–4 次并行搜索。自动预取由配置项 contextInjection 控制开关(默认 true,见 配置默认值)。
工作流:五步完成上下文预热
context-loader 技能文档定义了完整五步流程,以下是逐条继承与展开:
第 1 步:从当前消息/任务中提取主题
从当前消息或任务描述中识别四类要素:
- subject areas(主题领域)
- people mentioned(提到的人)
- project names(项目名)
- goal references(目标引用)
这一步是纯推理步骤,不产生任何工具调用。其质量直接决定后续搜索的覆盖面——提取遗漏会导致该方向的历史记忆无法被召回。
第 2 步:发起 2–4 次并行搜索
使用 mem0_memory 工具的 action="search",从不同角度(query angle)分别构造查询,并行执行:
| Query angle | 目的 |
|---|---|
| Topic/subject name(主题名) | 召回相关决策和偏好 |
| People mentioned(提到的人) | 召回关系上下文 |
| Project/goal references(项目/目标引用) | 召回进展和背景 |
| Broad context(宽泛上下文) | 兜底捕获任何相关内容 |
这种"多角度查询"策略与工具注册时的 prompt 指引一致:在 工具注册代码 的 promptGuidelines 中明确写道:
'For multi-part or comparative questions, run several searches with different phrasings and combine the results before answering -- one search is rarely enough'(单次搜索往往不够,应运行多次不同措辞的搜索再合并结果。)
也就是说,context-loader 技能把这条通用指引具体化为"主题/人物/项目/宽泛"四个标准角度。
第 3 步:跨搜索结果按记忆 ID 去重
多个查询角度的结果集必然存在重叠(同一条记忆可能同时命中主题查询和宽泛查询)。技能要求在所有搜索响应之间按 memory ID 去重,保证输出的上下文块中每条记忆只出现一次,也保证最终数量统计准确。
第 4 步:输出紧凑上下文块(最多 10 条)
去重后,按相关性只保留最重要的记忆,以紧凑格式输出(上限 10 条):
context-loader: loaded <N> memories for "<task summary>"
- [decisions] <content> [mem0:<short_id>]
- [preferences] <content> [mem0:<short_id>]
- [lessons] <content> [mem0:<short_id>]
这个输出格式与插件的记忆格式化实现一脉相承。格式化模块 的 formatMemoryCompact 生成的每条记忆形如:
[<category>] <memory content> (<age>) [mem0:<id>]
即"[分类] 内容 (距今时间) [mem0:ID]"。技能输出中的 [decisions]、[preferences]、[lessons] 等前缀,正是来自 Mem0 的自动分类。分类体系由 types.ts 中的 DEFAULT_CUSTOM_CATEGORIES 定义,共 10 个通用类目:identity、preferences、goals、projects、decisions、technical、relationships、routines、lessons、work。mem0:<id> 后缀的作用是在 Agent 后续需要对该记忆执行 update/delete 时,可以直接引用该 ID。
第 5 步:零结果时静默
如果所有搜索都返回空结果,什么都不输出——不要宣布"没有找到上下文"。这条规则避免了在无记忆可加载时污染上下文、干扰 Agent 正常工作节奏。
搜索的底层实现:mem0_memory 工具与 scope 过滤
context-loader 技能的全部检索都通过 mem0_memory 工具完成,其底层实现在 tools.ts 中可以完整验证:
搜索分支的实际调用链
buildToolExecute 中的 search 分支(tools.ts#L56-L66)逻辑为:
- 校验
query必填(否则抛出query is required for search); - 调用
resolveSearchFilters(scope, scopeCtx)生成 Mem0 搜索过滤器; - 执行
mem0.search(params.query, { filters }); - 用
formatMemoryList格式化结果,并经过truncateOutput截断后返回。
两个值得注意的工程细节:
- 输出截断:
MAX_OUTPUT_LINES = 200、MAX_OUTPUT_BYTES = 50_000(tools.ts#L17-L37)。防止单次搜索撑爆上下文窗口——这也是 context-loader 需要自己做"最多 10 条"精选的原因之一:工具层的截断是硬防线,技能层的 10 条上限是质量防线。 - 工具描述强调主动召回:工具描述 写明 'Use action "search" proactively -- before answering anything that may depend on what the user told you earlier',这与 context-loader"任务开始前先检索"的定位完全呼应。
scope 如何决定"搜到哪些记忆"
context-loader 技能未显式指定 scope 时,会使用插件的 defaultScope(默认 project)。作用域解析模块 为不同 scope 生成不同的 Mem0 过滤器:
| Scope | 搜索过滤器 | 适用场景 |
|---|---|---|
project(默认) |
user_id + app_id |
项目专属知识:决策、架构、配置 |
session |
user_id + app_id + run_id |
仅当前会话的临时上下文 |
global |
user_id + app_id: "*" |
跨所有项目 |
其中 app_id 的确定方式由 detectAppId 实现:执行 git rev-parse --show-toplevel 取 git 仓库根目录名(3 秒超时),非 git 目录则回退到当前工作目录名。这使得 monorepo 的所有子目录共享同一个记忆池。对 context-loader 而言这意味着:在仓库中执行任务时预取的记忆天然限定在本项目内,不会把其他项目的决策错误地注入当前任务上下文。
相关参数在 配置文件解析逻辑 中合并:配置文件 ~/.pi/agent/mem0-config.json 与环境变量(MEM0_API_KEY、MEM0_USER_ID 优先)共同决定 defaultScope、contextInjection 等取值。完整配置项说明可参考 Pi Agent 集成文档。
四条硬性约束及其设计动机
技能文档的 Constraints 一节列出了四条不可违反的约束,逐条分析其动机:
| 约束 | 内容 | 设计动机 |
|---|---|---|
| Read-only(只读) | 绝不修改或删除记忆 | context-loader 只负责"加载";写入由 remember 技能和自动捕获(auto-capture)负责,删除由 forget 技能(含确认对话框)负责。职责分离避免预取流程产生副作用 |
| Max 10 memories | 最多返回 10 条,只保留最相关的 | 控制上下文注入量。10 条是"信息密度"与"上下文预算"的折中,且远低于工具层 200 行/50KB 的截断上限 |
| Silent on empty | 仅在存在相关上下文时才呈现结果 | 空召回不是异常,不应打扰用户或改变 Agent 行为 |
| 跳过已可见记忆 | 当前会话上下文中已可见的记忆不再重复加载 | 避免同一事实在系统提示词的自动召回块和本技能输出中重复出现 |
前三条约束共同保证该技能是一个低噪声、零副作用的上下文增强器:有相关记忆就安静地注入,没有就保持沉默,任何时候都不会改动记忆存储本身。
与自动召回的分工:两条互补的召回路径
从源码结构看,插件实际提供两条记忆注入路径,context-loader 属于第二条:
- 被动自动召回(guaranteed recall):
before_agent_start事件用当前 prompt 做一次 project 作用域搜索,命中结果直接包在<mem0-relevant-memories>标签里追加到系统提示词(entry.ts#L113-L120)。它是"保证有"但"只有一遍"的浅层召回,且失败时静默降级(best-effort,绝不阻塞对话轮次)。 - 主动技能召回(context-loader):Agent 在开始任务/切换主题时,按技能定义的"提取主题 → 多角度并行搜索 → 去重 → 精选 10 条 → 紧凑输出"流程自行执行。它覆盖面更广(多个查询角度),但依赖 Agent 正确遵循技能指引。
两条路径的分工清晰:自动召回保证"每次回答前至少有一遍记忆检索",context-loader 保证"新任务开始时上下文被系统性预热"。自动召回注释中的提示语("search mem0_memory for more if you need it")正是把 Agent 引向 context-loader 这类深度检索的衔接点。
使用与验证方式
- 技能文件:查看 skills/context-loader/SKILL.md,其余 7 个技能(remember、search、forget、dream、tour、pin、status)位于同目录的 skills/ 下,可在 README 的 Skills 表中对照各自职责。
- 插件安装:
pi install npm:@mem0/pi-agent-plugin,并设置MEM0_API_KEY(m0-前缀的密钥),详见 插件 README 与 官方集成文档。 - 验证连接:启动新会话后执行
/mem0-status查看用户 ID、检测到的项目(app_id)与记忆数量。 - 典型效果场景:Session 1 中用户说"I prefer dark mode and concise answers",自动捕获存入偏好类目;Session 2 开始新任务时,context-loader 以"主题/偏好"角度搜索命中该记忆,Agent 无需用户重新解释即可按既有偏好工作。
小结
context-loader 是 Mem0 Pi Agent 插件中"记忆预加载"的标准作业流程:它以 mem0_memory 的 search 动作为检索底座,以 project/session/global 三级作用域过滤器保证召回范围正确,以 10 类自动分类和 [category] content [mem0:id] 的紧凑格式控制输出规模,并以"只读、限量、空则静默、去冗余"四条约束把预取过程变成一个零副作用的上下文增强步骤。结合源码可见,它与 before_agent_start 的自动浅层召回互补,共同构成该插件"保证记忆可用 + 按需深度预热"的双层召回架构。
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