agentmemory handoff 技能实战:基于 memory_sessions 与 memory_recall 跨会话无缝恢复 Agent 工作现场
【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory
导读
handoff是 agentmemory 仓库中一个面向 AI 编码 Agent 的持久记忆技能,解决的是「会话中断后如何无缝续接工作」这一核心问题:当用户说出 "where were we"、"resume"、"handoff"、"pick up where I left off",或开启一个没有任何新鲜上下文的新会话时,Agent 能够依据 handoff 技能定义 自动定位最近一次会话、把未回答的问题放在最前面,并给出明确的下一步动作。读完本文,你将掌握 handoff 的完整五步工作流、目录边界匹配的正确姿势、空会话与兄弟仓库等边界情况的处理,以及 MCP 工具不可用时的 REST 回退方案。
handoff 是什么:技能定位与触发时机
handoff定义于 plugin/skills/handoff/SKILL.md,是一个user-invocable: true的用户可调用技能,其元数据如下:
- name:
handoff - description:Resume the most recent agent session for the current working directory, leading with any unanswered question. Use when the user says "where were we", "resume", "handoff", "pick up where I left off", or starts a session with no fresh context.
- argument-hint:
[optional cwd override]
它与你可能已经熟悉的recap(汇总最近 N 个会话)、session-history(查看完整会话历史)、recall(检索历史上下文)共享同一份会话数据,只是视角不同:recap是"纵向滚动"的回顾,handoff是"单点续接"的恢复。技能内See also一节明确列出了这一关系:
recap、session-history、recall:same session data, broader views。
从实现层面看,该技能实际调用的两个 MCP 工具都注册在 src/mcp/tools-registry.ts 的CORE_TOOLS中:
memory_sessions(tools-registry.ts):List recent sessions with their status and observation counts,输入 schema 为空对象{},即无条件列出最近会话。memory_recall(tools-registry.ts):Search past session observations for relevant context,参数包括query(必填,支持关键词、文件名、概念)、limit(默认 10)、format(full/compact/narrative)。
Quick Start:两条命令完成一次恢复
技能的快速开始部分给出了最精简的恢复流程:
memory_sessions { "limit": 20 }选出cwd与当前项目匹配的最近一个会话,然后:
memory_recall { "query": "<session top concepts>", "limit": 10 }期望输出形如:
Resuming 7f3a9c2 "Auth refresh rework". Open question: should logout revoke all device tokens or just the current one? Next step: decide revoke scope, then update auth/logout.ts.注意其中两个参数的默认语义与源码一致:memory_recall的limit默认为 10、memory_sessions的limit传入 20 是为了给候选会话留出足够余量——因为后续还要按cwd过滤、按startedAt排序,窗口太窄可能漏掉"最近一次匹配项目"的会话。
为什么这样设计:两条核心原则
技能Why一节阐述了两个不可妥协的原则:
- 按目录边界匹配会话,而不是按原始前缀匹配:一个兄弟仓库(sibling repo)永远不会被误认成当前仓库。这是防串场(cross-project confusion)的关键设计。
- 永远不要为空的会话编造观察记录:如果会话里没有任何 observation,就如实报告"没有可交接的内容",而不是基于对话记忆脑补一段"productive week"。
这两条原则在实际工具与数据模型中都有据可查:
- 会话的
cwd字段由观察层记录,见 src/functions/observe.ts 中payload.cwd的校验与写入逻辑(仅当payload.cwd是非空字符串时才随观察一并落库)。 - 会话
status的类型定义为"active" | "completed" | "abandoned"(src/types.ts),这正是工作流第 2 步中"优先选择completed而非abandoned"的判断依据;会话结束后由 src/triggers/events.ts 等触发路径将status置为completed。
五步工作流详解
技能核心工作流(Workflow)共五步,每一步都有明确的判定标准:
第 1 步:解析项目路径若$ARGUMENTS提供了 cwd 覆盖参数,用path.resolve(process.cwd(), $ARGUMENTS)归一化为绝对路径;否则直接使用当前工作目录 cwd。
第 2 步:调用memory_sessions并匹配会话在返回的会话列表中,选出cwd与项目路径满足目录边界匹配的最近一个会话。匹配条件为三者之一:
session.cwd === projectPath OR session.cwd.startsWith(projectPath + sep) OR projectPath.startsWith(session.cwd + sep)其中sep是平台路径分隔符(POSIX 下为/)。在候选结果中优先选择completed状态的会话,abandoned次之。若没有任何匹配,则回退到全局最近的一个会话。
第 3 步:未回答的问题最先呈现如果该会话结束时遗留了面向用户的未回答问题,必须最先把它呈现出来。判定方法:查看summary字段,或近期conversation观察中narrative以?结尾的条目。这正是让用户能"直接接上上次的决策点"的关键动作。
第 4 步:摘要输出用memory_recall按会话顶层概念检索,limit为 10,概括出:标题/摘要、关键文件、关键决策或错误。检索查询词应取自会话的concepts(顶层概念),而不是凭印象自造关键词。
第 5 步:给出唯一的"下一步"指针以一个具体的next step?收尾,引导用户从断点继续,而不是泛泛地问"你想做什么"。
反模式:为什么原始前缀匹配是错的
技能明确给出了正反两个写法:
WRONG: session.cwd.startsWith(projectPath) // 当项目是 /repo-a 时,会匹配到 /repo-a-staging,恢复错仓库的会话 RIGHT: session.cwd === projectPath || session.cwd.startsWith(projectPath + sep) // 目录边界检查,不可能跨越兄弟仓库为什么startsWith(projectPath)危险?因为/repo-a是/repo-a-staging的字符串前缀,而startsWith(projectPath + sep)要求匹配位置后紧跟路径分隔符,/repo-a-staging中-不是分隔符,于是被正确拒绝。同理,projectPath.startsWith(cwd + sep)覆盖了"当前项目是历史会话的子目录"这类反向嵌套场景(例如曾在上层目录工作、现在进入子项目)。EXAMPLES.md 中的示例 2 完整演示了这一场景的判定与回退逻辑。
检查清单:输出前的四项自检
每次执行 handoff 后,对照以下清单确认没有遗漏:
- cwd 覆盖参数已解析为绝对且归一化的路径;
- 会话匹配使用的是目录边界检查,而非原始前缀;
- 未回答的问题(若有)已置于响应最前面;
- 空会话被如实报告,并提供"从当前状态重新开始"的选项。
实战示例:三种典型场景
plugin/skills/handoff/EXAMPLES.md 提供了三个可直接对照的工作示例。
示例 1:带未回答问题的恢复
用户说 "Where were we?",项目 cwd 为/Users/dev/app,调用:
memory_sessions { "limit": 20 }返回:
{ "sessions": [ { "id": "7f3a9c21", "cwd": "/Users/dev/app", "title": "Auth refresh rework", "status": "completed", "startedAt": "2026-06-07T09:00:00Z", "summary": "Reworked refresh rotation. Open: should logout revoke all device tokens?", "concepts": ["jwt-refresh-rotation", "logout"] } ] }随后拉取支撑上下文:
memory_recall { "query": "jwt-refresh-rotation logout", "limit": 10 }最终呈现:
Resuming
7f3a9c2"Auth refresh rework".Open question:should logout revoke all device tokens or just the current one? Touchedauth/refresh.ts,auth/logout.ts. Refresh rotation is done.Next step:decide the revoke scope, then finishauth/logout.ts.
注意示例中查询词jwt-refresh-rotation logout直接取自返回的concepts字段,这正是工作流第 4 步"按顶层概念检索"的落地方式。
示例 2:兄弟仓库守卫
项目 cwd 为/Users/dev/repo-a,而会话记录里存在cwd: /Users/dev/repo-a-staging的会话。原始前缀匹配会错误命中repo-a-staging;边界检查则因为/Users/dev/repo-a-staging既不等于/Users/dev/repo-a、也不以/Users/dev/repo-a/开头而将其拒绝。此时应挑选真正的repo-a会话;若仍无匹配,则回退到全局最近会话。
示例 3:空会话
用户说 "Resume.",但匹配到的会话没有任何观察记录。正确响应是如实说明:
The most recent session
c98f110for this project has no recorded observations. Nothing to hand off. Want to start fresh from the current state?
这正是Why原则二"Never invent observations for an empty session"的体现——空窗口是一个真实答案,而不是编造活动的借口。
与其他技能的关系
handoff 不是孤立存在的,它隶属于plugin/skills/下整套可调用技能体系。与其共享会话数据、视角互补的技能包括:
- recap 技能:按日期分组汇总最近 N 个会话,适合 "recap"、"what have we been doing" 等回顾诉求;
- session-history 技能:查看同一份会话数据的完整历史视图;
- recall 技能:按查询词检索过去的观察与决策。
实际编排时,可先handoff续接断点,再用recap补看整体脉络,用recall深挖某个决策的细节。
故障排查:MCP 工具不可用时的回退路径
技能末尾将通用排障指引指向共享文档 plugin/skills/_shared/TROUBLESHOOTING.md(技能内的../_shared/TROUBLESHOOTING.md链接即指该文件),避免每个技能重复维护一份排障块。
场景一:memory_*MCP 工具不出现
若某个memory_*工具未出现在工具列表中,说明 stdio MCP shim 未启动。按顺序排查:
- 在宿主中运行
/plugin list,确认agentmemory显示为 enabled; - 重启宿主——插件的
.mcp.json仅在启动时读取,新安装或重新启用的插件不会在会话中途注册工具; - 检查
/mcp,确认agentmemoryserver 显示为活连接。
场景二:REST 回退
当 MCP 工具始终不可用、但守护进程仍在运行时,可直接调用 REST API:
- 设置
AGENTMEMORY_URL为守护进程基地址(默认http://localhost:3111); - 仅当设置了
AGENTMEMORY_SECRET时才附加Authorization: Bearer $AGENTMEMORY_SECRET——默认的本地守护进程是开放的,多余的 header 会被拒绝。
与 handoff 相关的 REST 端点映射为:GET /agentmemory/sessions+POST /agentmemory/smart-search(前者等价于memory_sessions,后者等价于智能检索)。注意守护进程同样只在启动时读取.mcp.json,因此任何端口或认证变更都需要重启后,两个传输通道才会生效。
小结
handoff是 agentmemory 持久记忆能力在"会话续接"场景的标准答案:以目录边界匹配杜绝兄弟仓库串场,以"未答问题置顶 + 单一 next step"确保恢复的高信噪比,以空会话如实上报守住事实底线。配合memory_sessions/memory_recall两个 MCP 工具(定义见 src/mcp/tools-registry.ts)与 REST 回退机制(plugin/skills/_shared/TROUBLESHOOTING.md),无论宿主是 Claude Code、Codex 还是其他支持 MCP 的编码 Agent,都能在几秒内把用户带回到上一次离开的精确断点。
【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考