多会话交接


文档摘要

多会话交接 本节摘要:会话会结束,工作不会。交接包(handoff packet)是把「Agent 干了一小时」变成「下一会话第一分钟就出活」的工件。要有意建它,而非事后补。诊断很经典:会话结束,Agent 说「很好,我们取得了进展」;下次会话打开,下一个 Agent 问「我们上回到哪了?」——第一个 Agent 的答案没了。下一个 Agent 重新发现、重跑同样命令、重问人同样问题,烧 30 分钟去恢复上回会话最后 30 秒。坏交接的代价,在任务寿命里每次会话都要付。修法是一份会话结束时自动生成的包:改了什么、为什么、试了什么、失败了什么、还剩什么、下次先做什么。

多会话交接

本节摘要:会话会结束,工作不会。交接包(handoff packet)是把「Agent 干了一小时」变成「下一会话第一分钟就出活」的工件。要有意建它,而非事后补。诊断很经典:会话结束,Agent 说「很好,我们取得了进展」;下次会话打开,下一个 Agent 问「我们上回到哪了?」——第一个 Agent 的答案没了。下一个 Agent 重新发现、重跑同样命令、重问人同样问题,烧 30 分钟去恢复上回会话最后 30 秒。坏交接的代价,在任务寿命里每次会话都要付。修法是一份会话结束时自动生成的包:改了什么、为什么、试了什么、失败了什么、还剩什么、下次先做什么。本节定义交接包的七个字段(summary 一段总结、changed_files 一眼 diff、commands_run 真跑过的、failed_attempts 试过且为何不成的、open_risks 可能咬下次会话的带严重度、next_action 下次第一个具体步、verdict_pointer 验证+审查报告路径)——其中 next_action 是承重的:有它一切却没它的交接是状态报告,不是交接。核心纪律是交接是生成的,不是写的(手写的交接是艰难日里被跳过的;生成器读工作台工件发包,Agent 的活是把工作台留在生成器能总结的状态,而非写总结);两种形式(handoff.md 人读、handoff.json 下个 Agent 加载,同源,分歧时 JSON 赢);反馈日志裁剪(全日志可能上百条,包只带最后 K 条加每条非零退出)。本节还强调留干净状态:交接描述工作,干净状态让工作可续——不是同一件事;完美的 handoff.md 在下一会话对着半个 diff、临时文件、游离分支、跑不起来的测试时一文不值;所以清理是交接前独立的一阶段,发 clean_state.json 阻塞问题清单,空列表是交接生成器写包前断言的前置条件。读完本节,你能用生成器把会话结尾变成下次会话的快启动。

对应原课程:Phase 14 · Lesson 40 · multi-session-handoff(原英文 phases/14-agent-engineering/40-multi-session-handoff/docs/en.md)。前置:第 34 节(仓库记忆)、第 38 节(验证)、第 39 节(审查者)。

学习目标

阅读完本节,你应当能够:

  1. 识别每个交接包都需要的七个字段
  2. 从工作台工件生成交接,而非手写散文。
  3. 把大反馈日志裁剪成交接大小的摘要。
  4. 让下一会话的第一个动作确定性
  5. 在交接前执行清理阶段,留干净可续的状态。

一、问题与直觉

会话结束。Agent 说「很好,我们取得了进展」。下次会话打开。下一个 Agent 问「我们上回到哪了?」第一个 Agent 的答案没了。下一个 Agent 重新发现、重跑同样命令、重问人同样问题,烧 30 分钟恢复上次会话的最后 30 秒。

坏交接的代价,在任务寿命里每次会话都要付。修法是一份会话结束时自动生成的包:改了什么、为什么、试了什么、失败了什么、还剩什么、下次先做什么。

七个字段

字段 回答的问题
summary 做了什么的一段总结
changed_files 一眼的 diff
commands_run 真正执行了什么
failed_attempts 试了什么、为何不成
open_risks 什么可能咬下次会话,带严重度
next_action 下次会话迈出的第一个具体步
verdict_pointer 验证 + 审查报告的路径

next_action承重的那个。一个有了一切却没 next_action 的交接是状态报告,不是交接。

交接是生成的,不是写的

手写的交接是艰难日里被跳过的交接。生成器读工作台工件发包。Agent 的活是把工作台留在生成器能总结的状态,不是写总结

两种形式:人读与机读

handoff.md 是人读的。handoff.json 是下个 Agent 加载的。两者来自同样的源工件。若分歧,JSON 赢

反馈日志裁剪

feedback_record.jsonl 可能上百条。交接只带最后 K 条加每条非零退出。下次会话需要时加载全日志,但包保持小。

留干净状态

交接描述工作。干净状态让工作可续。不是同一件事。一个完美的 handoff.md,在下次会话对着半个应用的 diff、Agent 忘了的临时文件、游离分支、还没跑就报错的测试时,一文不值。下个 Agent 头十分钟花在给上个 Agent 擦屁股而非建造上,代价每次会话累积。

所以会话不在功能跑通时结束。它在工作台处于生成器能总结、下次会话能信任的状态时结束。清理是独立的一阶段,在交接跑,而且是一道检查,不是一个习惯——因为习惯是艰难日里被跳过的东西。

检查 干净意味着 脏会阻塞因为
工作树 每处改动已提交或显式带便签 stash 半个 diff 在下个 Agent 看着像有意的工作
临时工件 *.tmp、scratch 目录、debug 打印、注释块遗留 游离文件污染 diff 与下个 Agent 的心智模型
测试 绿,或红但失败名在 open_risks 静默的红测试是下个会话踩的陷阱
功能板 feature_list.json 状态反映现实(第 36 节) 过期板把下次会话派去已做完的工作
分支 在预期分支,无 detached HEAD,无孤儿分支 错分支意味着下次会话首次提交落错地方

清理阶段发一份阻塞问题清单的 clean_state.json;空列表是交接生成器写包前断言的前置条件。建在脏树上的交接不是交接,是转发的烂摊子。两工件配对:清理证明工作台可安全留下,交接证明下次会话知道从哪开始。

二、从零实现

原课程 code/main.py 实现:

  • 一个加载器,把状态、裁决、审查、反馈聚进单一 WorkbenchSnapshot
  • 一个 generate_handoff(snapshot) -> (markdown, payload) 函数。
  • 一个挑最后 K 条反馈加全部非零退出的过滤器。
  • 一个写 handoff.mdhandoff.json 到脚本旁的演示运行。

Step 1:快照加载

def load_snapshot(): return WorkbenchSnapshot( state = json.load(open("agent_state.json")), verdict = json.load(open("outputs/verification/latest.json")), review = json.load(open("outputs/review/latest.json")), feedback = read_jsonl("feedback_record.jsonl"), diff = git_diff_vs_main())

Step 2:清理检查(写包前的前置)

def cleanup_checks(): issues = [] if git_has_uncommitted_partial(): issues.append(block("工作树", "半个未提交 diff")) if find_temp_artifacts(): issues.append(block("临时工件", str(find_temp_artifacts()))) if tests_silent_red(): issues.append(block("测试", "静默红测试")) atomic_write("clean_state.json", json.dumps(issues)) return len(issues) == 0 # 空即干净,允许写包

Step 3:生成交接

def generate_handoff(snap): if not cleanup_checks(): raise DirtyTree("拒绝在脏树上写交接") failed = [r for r in snap.feedback if r["exit_code"] not in (0, None)] recent = snap.feedback[-5:] # 最后 K 条 payload = { "summary": summarize(snap.diff, snap.state), "changed_files": files_in(snap.diff), "commands_run": [r["command"] for r in recent], "failed_attempts": [{"cmd": r["command"], "why": r["stderr_tail"]} for r in failed], "open_risks": snap.state.get("blockers", []), "next_action": snap.state["next_action"], # 承重字段 "verdict_pointer": "outputs/verification/latest.json"} atomic_write("handoff.json", json.dumps(payload, indent=2)) atomic_write("handoff.md", to_markdown(payload))

运行 python3 code/main.py 会打印交接正文,并把两文件写盘。

生产模式(在野外)

Codex CLI、Claude Code、OpenCode 各发一套不同的压缩(compaction)故事;结构化交接包叠在三者之上。

压缩策略各异;包模式不变。 Codex CLI 的 POST /v1/responses/compact 是服务端不透明 AES blob(OpenAI 模型快路径);回退是本地「交接摘要」作 _summary 用户角色消息追加。Claude Code 在 95% 上下文跑五阶段渐进压缩。OpenCode 做基于时间戳的消息隐藏加 5 标题 LLM 摘要。三种不同机制,同一需求:把挺过压缩的东西序列化成可移植工件。包就是那个工件。

新会话交接不是压缩。 压缩延长会话;交接干净关闭一个、开始下一个。Hermes Issue #20372(2026-04)的框定对:当原地压缩开始降质,Agent 应写紧凑交接、结束会话、在干净上下文里续。包让那切换便宜。错误是压缩到质量崩溃;修法是预算一次早而干净的交接。

每分支每话题一个活动交接。 多智能体协调在过期交接上崩,比在坏模型输出上崩得多。永远包含 branchlast_known_good_commit、与 active | superseded | archivedstatus。过期交接归档;只有活动的驱动下次会话。这是「交接即笔记」与「交接即状态」的差别。

50-75% 上下文时收尾,而非撞墙。 手写模式 playbook(CLAUDE.md + HANDOVER.md)报告:会话在 50-75% 上下文预算结束而非 95% 时结果最好。包生成器在压缩工件污染源状态前干净跑。上下文完整时便宜写;模型已经迷失时贵。

💡 设计要点:交接包的本质是把易失的会话状态序列化成持久的工件——这与第 34 节「聊天易失、仓库持久」、第 31 节「循环闭合在状态文件非聊天」一脉相承。生成而非写,是因为「手写的在艰难日被跳过」——这把纪律从「指望 Agent 自觉」变成「生成器强制」。清理作为独立阶段同理:它是一道检查,不是一个习惯,因为习惯是艰难日被跳过的东西。这两条纪律,把工作台的可靠性从「好日子」抬到「每一天」。

三、框架对比

运行时 交接如何用
会话结束钩子 运行时在用户关聊天时触发生成器;包进 outputs/handoff/<session_id>/
PR 模板 生成器的 markdown 也是 PR 体;审查者读它而无需开五个其他文件
跨 Agent 交接 用一个产品(Claude Code)建造,用另一个(Codex)续;包是通用语

包小、规整、便宜产出。成本节省每次会话累积。

四、可复用产物

原课程 outputs/skill-handoff-generator.md:产一个调到项目工件路径的生成器、一个跑它的会话结束钩子、一个下次 Agent 启动读的 handoff.json 模式。

五、练习

  1. (Easy)assumptions_to_validate 字段,浮现建造者记录但审查者未打超 1 分的每个假设。
  2. (Medium) 对失败运行与通过运行用不同方式裁剪反馈摘要。论证不对称。
  3. (Medium) 含一个「给人的问题」列表。一个问题进包 vs 进聊天消息的阈值是什么?
  4. (Hard) 让生成器幂等:跑两次产出同样的包。要它成立什么必须稳定?
  5. (Hard) 加「下次会话前置」节,精确列出下次会话行动前必须加载的工件。

本节要点回顾

  1. 会话结束工作不结束:交接包把「干了一小时」变成「下次第一分钟出活」;有意建非事后补。
  2. 坏交接代价每次会话付:30 分钟恢复上回最后 30 秒,任务寿命里累积。
  3. 七字段:summary/changed_files/commands_run/failed_attempts/open_risks/next_action/verdict_pointer。
  4. next_action 承重:有它一切却没它的是状态报告,不是交接。
  5. 生成非写:手写在艰难日被跳过;生成器读工件发包,Agent 的活是留可总结的状态。
  6. 两种形式:handoff.md 人读、handoff.json 机读,同源,分歧 JSON 赢。
  7. 反馈裁剪:最后 K 条 + 每条非零退出;包保持小。
  8. 留干净状态:交接描述工作,干净状态让工作可续,不是同一件事;完美交接在脏树上一文不值。
  9. 清理是独立阶段非习惯:发 clean_state.json 阻塞清单,空列表是写包前置;习惯是艰难日被跳过的。
  10. 生产模式:压缩策略各异包模式不变、新会话交接非压缩、每分支每话题一活动交接、50-75% 上下文收尾非撞墙。

下一节,我们把第 31~40 节的全部工作台面,落到真实仓库上——用一个端到端的最小实现,展示指令、状态、范围、反馈、验证、审查、交接如何在一个能改真实代码的工程级 Agent 里协同工作。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U