Anthropic《Effective harnesses for long-running agents》系统解读:跨会话交接与 PPT Master 的制品化 harness
原文:Effective harnesses for long-running agents
实践项目:PPT Master
前置阅读:《Building effective agents》 · 《Agent Skills》 · 《Effective context engineering》
上一篇解读的结尾提到,PPT Master 的 split mode 与制品链本质上是一个手工搭建的 harness。这一篇要回答的就是:官方设计的 harness 长什么样,两者的差距在哪里。 这里的对应关系特指启用 split 的 Default Generate;默认连续执行、Quick profile 和三条非 Generate 路线并不采用同一套双会话结构。
原文的问题定义非常干脆:
The core challenge of long-running agents is that they must work in discrete sessions, and each new session begins with no memory of what came before.
注意后半句——每个新会话开始时对之前发生的一切毫无记忆。上一篇讨论的 compaction 在这里被明确判定为不够:
Compaction isn't sufficient.
一、基本概念:harness 是什么
原文把 harness 定位为支撑 Agent 运行的框架系统,并以 Claude Agent SDK 为例:
The Claude Agent SDK is a powerful, general-purpose agent harness adept at coding, as well as other tasks that require the model to use tools to gather context, plan, and execute.
三者的分工可以这样区分:
| 层 | 负责 |
|---|---|
| 模型 | 执行任务的核心能力 |
| Agent | 在一次会话内使用工具收集上下文、规划、执行 |
| Harness | 让 Agent 能够跨越多个会话持续工作的框架 |
harness 解决的不是"这一轮怎么做对",而是"下一轮怎么接得上"。
二、两类失败模式
原文在实验中观察到的两个失败,值得单独记住,因为它们几乎必然出现在任何长任务系统里。
一次做太多
The agent tended to try to do too much at once—essentially to attempt to one-shot the app.
Agent 试图一口气完成整个应用,结果中途耗尽上下文窗口,留下一个半成品状态。
过早宣布完成
A later agent instance would look around, see that progress had been made, and declare the job done.
后续的 Agent 实例环顾四周,看到"已经有进展了",于是宣布任务完成。
第二种失败为什么更危险
第一种失败会留下明显的破损状态,容易被发现。第二种失败交付的是一个看起来完整的产物——只有逐项核对才知道少了什么。 一个没有清单的长任务系统,必然会在某个会话上提前收工。
三、解决方案:初始化 Agent 与编码 Agent
原文把职责拆成两个角色。
初始化 Agent(只在首次会话运行)
Set up the initial environment: an
init.shscript, a claude-progress.txt file that keeps a log of what agents have done, and an initial git commit.
它不写业务代码,只负责让后续会话有一个可以接手的环境。
编码 Agent(后续每次会话)
Make incremental progress, then leave structured updates.
做增量进展,然后留下结构化的更新。 两个动作缺一不可——只做不留,下一个会话就得重新摸索。
四、环境中的四件关键制品
1. 特性清单(feature_list.json)
200 多项详细特性,初始全部标记为失败:
{
"category": "functional",
"description": "New chat button creates a fresh conversation",
"steps": [...],
"passes": false
}配套一条硬规则:
It is unacceptable to remove or edit tests because this could lead to missing or buggy functionality.
选择 JSON 而非 Markdown 是有意的——原文指出 JSON 格式更难被不当篡改。这是一个容易被忽略的细节:清单的作用是约束 Agent,如果 Agent 可以顺手改写清单,约束就不存在了。
2. 进度文件(claude-progress.txt)
记录历次会话做了什么。原文把它和 git 历史一起视为整个方案的关键:
The key insight here was finding a way for agents to quickly understand the state of work when starting with a fresh context window, which is accomplished with the claude-progress.txt file alongside the git history.
3. 启动脚本(init.sh)
解决"新会话的 Agent 不知道怎么把应用跑起来"的问题。
4. Git 提交
每个会话结束提交一次,既是进度锚点也是回滚能力。原文要求代码达到"可以合并到主分支"的质量——环境必须是干净的,不能给下一班留下半截状态。
会话启动的标准流程
1. 运行 pwd 确认工作目录
2. 阅读 git log 和进度文件
3. 读取特性清单,选择优先级最高的未完成特性
4. 运行 init.sh 启动开发服务器
5. 做基础端到端测试失败模式与制品的对应
| 失败模式 | 初始化 Agent 提供 | 编码 Agent 使用 |
|---|---|---|
| 过早宣布完成 | 创建特性清单 | 读清单,只做一个特性 |
| 环境遗留 bug | 初始化 git 与进度笔记 | 开场检查,收尾提交并更新 |
| 特性标记不实 | 设置特性清单 | 自我验证,测试通过才标记 |
| 不知如何运行 | 编写 init.sh | 开场读取并运行 |
五、原文承认的开放问题
原文没有给出定论的地方也值得记录:
It's still unclear whether a single, general-purpose coding agent performs best across contexts, or if better performance can be achieved through a multi-agent architecture.
单一通用 Agent 与多 Agent 架构孰优,官方也还在观察。这对下面的对照分析是个有用的背景——PPT Master 选择的是角色分工路线,但这不是被原文验证过的最优解。
从概念转入实践
以下用 PPT Master 检验这套 harness 设计。它的任务形态与原文案例(全栈 Web 开发)不同,但跨会话交接的问题完全一致。
六、角色对应:split 规划会话承担初始化职责
原文的双角色划分,在 PPT Master 里有一个几乎精确的对应:
| 原文 | PPT Master | 产出 |
|---|---|---|
| 初始化 Agent | split 规划会话(Step 1–5,Strategist 主导) | design_spec.md、spec_lock.md、images/、templates/ |
| 编码 Agent | split 执行会话(Step 6–7,Executor 主导) | svg_output/、exports/ |
差别在于 触发方式。原文的初始化 Agent 只在首次运行,之后每次会话都是编码 Agent;PPT Master 只有在最终确认的 generation_mode 为 split 时,才会让规划会话产出全部计划并 主动终止,再由用户开新窗口输入「继续生成 projects/<项目名>」进入执行会话。这个选择既可能来自用户直接要求,也可能来自用户接受重上下文信号触发的建议;未选择 split 时,Default Generate 会在确认后自动连续进入页面生产。
resume-execute.md 的自我定位和原文的编码 Agent 完全一致:
This stage is context-independent: it owns the execution session starting from a fresh chat — no upstream conversation context required.
七、Default Generate 的页面清单就是特性清单
这是两个系统最强的对应关系。
原文用 feature_list.json 防止"过早宣布完成"。PPT Master 用的是 design_spec.md 第 IX 节的页面清单,并配了一条同等强度的硬规则:
Exact page roster: render
design_spec.md §IXone-for-one, in order. Any add/drop/merge/split/reorder requires Spec repair/refinement first.
对照原文那句"不可删除或编辑测试",两者的逻辑完全相同:清单是约束,不是建议。想改清单,必须先回到上游修复规格,而不能在执行过程中顺手调整。
这条规则在执行纪律上直接针对第二种失败模式。Executor 不能"看到已经画了 15 页觉得差不多了"就收工——清单要求 20 页就必须生成 20 页,少一页在工作流语义上仍是未完成。但当前普通 flat Generate 尚无把 §IX 与实际 SVG ordered roster 做通用交叉比较的自动门,不能把这条硬规则误写成现有工具已经完整强制。
但格式上有差异
原文特意选择 JSON,理由是"比 Markdown 更难被不当篡改"。PPT Master 的页面清单存在 design_spec.md 里,是 Markdown。
它靠 纪律(硬规则 + Gate 校验)而非 格式 来防止篡改。这个差异留到第十一节讨论。
八、split 恢复:以真实制品而不是审计日志重建状态
原文的方案是 claude-progress.txt 加 git 历史。PPT Master 已有 validation/workflow.log,但它是冷的命令/结果审计日志,不是规划状态、进度权威或恢复来源;resume-execute 明确禁止把它当作状态重放。在 split 或恢复执行时,Step 1 依靠真实制品重建上下文:
| 检查项 | 何时必需 | 说明 |
|---|---|---|
spec_lock.md | 始终 | 执行锚点与路由契约 |
design_spec.md | 始终 | 完整设计叙事与 §IX 页面清单 |
notes/total.md | §X 声明用户提供的最终/逐字旁白时 | 冻结的旁白输入,不能从旧对话重建 |
images/ 及相应文件 | lock 引用了图像时 | Existing / Generated / Sourced / Rendered 状态的文件必须存在 |
templates/ | lock 引用了版式时 | 执行所需的版式与镜像原型 |
| 解析器返回的 Chart/Table SVG | lock 引用了活动图表时 | 必须通过共享目录解析并验证真实文件存在 |
中途恢复时还会读取"最新完成的 SVG"和当前图像元数据。
笔者归纳
PPT Master 用的是 以真实制品为恢复状态,而非 以审计日志为进度权威。
svg_output/ 中的实际文件比 Agent 的自然语言自述更接近 outcome,但它也不是单独充分的完成证明:文件可能缺号、残缺、陈旧,存在也不表示已经通过质量门。恢复时必须结合 roster 纪律、文件内容、当前输入与 gate 结果解释。
代价是表达力:文件系统能告诉你"P07 存在",冷审计日志也可能保留相关命令或错误,但两者仍不能保证完整还原"P07 重画过三次,因为图表坐标一直对不上"。原文的 claude-progress.txt 保留的正是这类有意维护、面向接手者的历史。
九、验证:Default Generate 的质量门与恢复矩阵
原文的验证是"用浏览器自动化做端到端测试,通过后才标记特性为 passed"。PPT Master 的验证链条更长:
首页门(P01 完成后 svg_quality_checker --stage first-page)
→ 不间断生成剩余页面
→ 最终门(svg_quality_checker --stage final)
→ finalize_svg → svg_to_pptx
→ 导出回执(状态、页数、警告分类)其中"首页门"的设计意图与原文的增量哲学一致:不是等 20 页全画完才发现方法有问题,而是在第一页就暴露并校准。Quick profile 会跳过首页门和 Spec/lock 相关检查,只运行无锁的最终检查与导出,因此这条验证链也不是所有路线共享的固定流程。
超出原文的部分:failure-recovery.md
原文用一张四行表格覆盖失败模式。PPT Master 有一份专门的治理文档,其恢复矩阵包含 20 多个失败点,每个失败点声明四个属性:
| 属性 | 含义 |
|---|---|
| Blocking | 是否阻断下一个门 |
| Automatic recovery | 自动恢复动作 |
| User intervention | 是否需要人工介入 |
| Resume entry | 从哪一步恢复 |
配套一条全局硬规则:
A failed required artifact blocks the next gate. A failed convenience surface falls back to the canonical channel and does not block the active route.
区分"必需制品"和"便利设施"——在 Default Generate 中,Confirm UI 挂了可以退回聊天确认,但该 profile 所需的 spec_lock.md 缺失必须停止。这个区分让系统在部分组件失效时仍能推进,同时不会在当前 profile 的关键制品缺失时蒙混过关。
笔者观点
恢复矩阵的价值不在于列举了多少失败,而在于 每个失败都有一个声明好的恢复入口。原文提到"知道从哪里继续"是长任务的核心,PPT Master 把这件事从运行时判断变成了查表操作。
十、Default Generate 如何防止"一次做太多"
原文的第一种失败模式——试图一口气做完——PPT Master 用三个机制共同约束:
- 阻塞门:
SKILL.md的全局纪律规定,遇到⛔ BLOCKING必须停下等待用户明确确认,不得代替用户决定; - 禁止跨阶段打包:不得把未关闭的门两侧的工作合并处理;
- 禁止投机执行:不得在拥有某制品的步骤到来之前提前准备该制品。
第三条尤其对应原文的观察。Agent"想一次做完"的倾向,具体表现就是提前生成后续阶段的产物——比如在设计还没确认时就开始画页面。把这条写成显式禁令,比事后发现半成品要有效。
十一、对照原文校准三个差异
以下差异不自动等于 PPT Master 的待办项。是否需要改变,应先看现行校验、恢复机制是否出现可复现故障。
1. 页面清单没有单独的结构化副本
原文明确选择 JSON 是因为"比 Markdown 更难被不当篡改"。PPT Master 的 §IX 页面清单在 Markdown 文档里,当前主要依赖硬规则和规划制品校验约束修改。
但这也不等于完全依赖 Agent 自觉:规划制品的结构和枚举、SVG/profile 约束以及结构化模板的映射关系都有代码检查。边界在于,普通 flat Generate 的 §IX 与实际 SVG ordered roster 目前没有通用自动交叉校验。系统选择让经确认的 Design Spec 保持页面清单权威,而不是再维护一份可能漂移的平行 JSON;若要自动证明一一对应,需要另加一个读取双方的最小派生检查。
如果未来出现现有检查无法捕获的清单漂移,可以研究独立的派生校验制品或哈希;不宜直接把更完整的页面权威塞进 spec_lock.md,因为 lock 是面向 Executor 的投影,不应反向取代 Design Spec。
2. 项目目录没有连续版本历史,但已有有界快照
原文用 git 提交作为进度锚点,同时提供回滚能力。PPT Master 的 projects/ 是用户工作区,不在版本控制下。
这意味着它没有原文那种逐步 commit 的连续历史。不过“完全没有回滚机制”也不准确:使用默认输出路径导出时会把现有 svg_output/ 复制到 backup/<timestamp>/svg_output/(显式 -o 会跳过该备份),可选视觉审查会在修改每个 SVG 前写入 .review/backup/。这些是有界快照,不等同于通用版本控制。
projects/ 还是被主仓库忽略的用户工作区。是否在外部工作区使用 git 应由用户决定,不属于 harness 应自动初始化或提交的现行职责。
3. 没有完整的跨会话重试历史
第八节讨论过,PPT Master 已有冷审计日志,也以真实制品作为恢复权威。这在正常路径上更可靠,但仍不会保存完整的失败和重试历史;workflow.log、postflight、检查报告与视觉审查记录只能覆盖各自有限范围。
具体场景:某页因为图表坐标问题重画了三次,最终通过。这个信息在文件系统上不留痕迹。下一次遇到类似页面时,Agent 无从得知这是一个已知的困难点。
原文的 claude-progress.txt 保留的正是这类信息。不过新增全局 progress.md 会引入另一份需要维护的状态。只有真实任务反复需要跨会话追溯重试原因时,这类追加日志才有明确收益;目前更准确的结论是“没有通用重试历史”,而不是“必须补一份日志”。
十二、我的理解:harness 是把交接成本前置
原文与 PPT Master 的共同点,是都不指望模型"记住"什么。
核心观点
harness 的本质,是 把跨会话的交接成本从运行时前置到设计时。
设计时想清楚"下一个会话需要知道什么",把它写成固定结构的制品;运行时就不需要任何一方去回忆、推断或重建。
按这个标准,一个 harness 是否完备,可以用三个问题检验:
- 接手的 Agent 能否在不读任何对话历史的前提下知道当前状态?—— PPT Master 用
resume-execute的 Step 1 校验回答; - 它能否知道还有什么没做完?—— 用 §IX 页面清单与一一对应的硬规则回答;
- 它能否知道自己做的对不对?—— 用质量门与导出回执回答。
三个问题分别对应原文的进度文件、特性清单和端到端测试。对启用 split 的 Default Generate 而言,PPT Master 在第二、三问上使用清单纪律、质量门与恢复矩阵,在第一问上更轻:以真实制品而非冷审计日志重建状态,可靠性边界清楚,但不保留完整历史。
而原文留下的开放问题——单 Agent 还是多 Agent——PPT Master 事实上给出了一个中间答案:串行核心角色,加条件式并行支持阶段。Strategist 与 Executor 职责分离,核心页面生成保持主 Agent 串行;主题研究在宿主允许时使用隔离 worker,可选视觉审查也能分批并行。启用 split 时,规划与执行还会落在不同会话中。
十三、下一步
- Writing effective tools for agents— 本文第九节的质量门与回执,其接口设计质量直接决定 harness 是否可靠(系统解读);
- Demystifying evals for AI agents— 本文三个差异是否构成真实问题,需要评估证据而不是仅凭形式类比判断(系统解读)。