如何搭建一个长运行 Agent Harness

May . 23 . 2026

如何搭建一个长运行 Agent Harness

引言

过去一段时间,很多人对 AI Agent 的期待已经从“帮我写一段代码”,变成了“帮我把一个完整功能甚至一个完整应用做出来”。

这个期待并不过分。今天的模型已经能读代码、改代码、运行命令、调用浏览器、写测试、修 bug,也能在一次对话里完成相当复杂的开发任务。但只要你真的把它放进一个持续数小时的任务里,就会发现一个很现实的问题:模型能力变强以后,失败不再主要表现为“它完全不会做”,而是表现为“它做着做着失去工程秩序”。

它可能一开始写得很快,界面也很像样;但再往下推进,状态开始混乱,功能清单不完整,某些核心路径没有跑通,半成品被当成完成品,后续修复又引入新问题。最后你得到的不是一个可交付应用,而是一个看起来接近完成、实际需要大量人工收尾的项目。

Anthropic 关于 long-running agents 的两篇工程博客,真正值得学习的地方就在这里:它们没有只讨论“模型有多强”,而是把问题推进到了工程系统层面。也就是说,长时间运行的 Agent 需要 Harness,需要一套外部流程来帮它拆任务、保存状态、验证结果、引入评审,并在失败后回到正确轨道。

本文会用一个完整实战案例,把这套 Harness 的设计方法讲清楚。

案例目标:

做一个个人任务看板,支持任务创建、状态流转、截止日期、搜索筛选和基础统计。

不会一上来就让 Agent 直接写代码,而是搭出一个可长期运行的开发 Harness。

模型变强了,瓶颈却换了位置

早期使用 AI 写代码时,瓶颈很直接:模型经常不会写、写不对、理解不了项目结构。所以我们主要关心提示词怎么写、上下文怎么喂、代码片段怎么补。

但到了更强的编码模型阶段,瓶颈发生了迁移。

很多时候,模型已经能完成单个局部任务。它会实现一个组件,会写一个接口,会修一个报错,也会根据错误日志继续调试。真正困难的是:当任务跨度变长、功能数量变多、上下文不断变化时,它能不能持续保持正确方向。

长运行任务里的核心瓶颈,通常变成了这些:

  • 目标管理:它是否始终知道最终要交付什么。
  • 范围控制:它是否能一次只推进一个可闭环的小目标。
  • 状态交接:新一轮上下文是否能准确理解上一轮进度。
  • 质量判断:它是否能发现“看起来完成但实际没通”的问题。
  • 恢复能力:当一轮实现失败时,它是否能回到稳定状态继续修。

所以,模型越强,越不能只把它当成一个聊天窗口。它更像一个能力很强、但仍需要工作流约束的工程师。

Harness 的作用,就是把这些工作流约束外部化:用规格文件承载目标,用功能清单承载验收项,用进度记录承载交接,用 Sprint Contract 限制范围,用独立 Evaluator 承担 QA,用 git commit 保留可恢复状态。

也就是长运行 Agent 的竞争力,不只来自模型本身,也来自模型外面的工程系统。


1. What Harness

Harness 可以理解为 Agent 外面的一层“工程约束系统”。

裸 Agent 的工作方式通常是:

用户给一句需求
Agent 开始写代码
Agent 写了一堆文件
Agent 自己判断完成
用户打开后发现一堆核心路径没通

长运行 Harness 的工作方式是:

用户给一句需求
Initializer 搭好环境和交接文件
Planner 把需求扩展成产品规格
Builder 每次只实现一个明确功能
Evaluator 像真实用户一样验收
失败就回到 Builder 修复
通过后再进入下一个功能

它解决的不是“模型不会写代码”,而是这些更实际的问题:

  • Agent 想一次做太多,最后留下半成品。
  • 上下文越来越长后,Agent 忘记早期目标。
  • 新一轮 Agent 不知道上一轮做到哪里。
  • 功能没真实跑通,就被标记成完成。
  • Agent 自评过于乐观,明明有 bug 也会说“整体可用”。

Anthropic 两篇文章的核心可以浓缩成一句话:

长任务不能只依赖模型记忆和自觉,必须把目标、进度、验证和评审外部化。


2. 实战案例:个人任务看板 TaskFlow

我们要构建的应用叫 TaskFlow

它不是一个复杂 SaaS,但足够覆盖长运行 Agent 的典型问题:

  • 有多个功能模块。
  • 有 UI 交互。
  • 有状态持久化。
  • 有端到端验收路径。
  • 容易出现“看起来做了,实际没通”的假完成。

最终用户应该能做到:

  1. 创建任务。
  2. 编辑和删除任务。
  3. 在“待办、进行中、已完成”之间切换任务状态。
  4. 给任务设置截止日期。
  5. 搜索任务。
  6. 按状态和日期筛选任务。
  7. 查看总任务数、已完成数、逾期数、完成率。

这个需求如果直接丢给一个 Agent,它很可能会先做一个漂亮界面,然后遗漏持久化、边界校验、筛选联动或统计准确性。

所以我们先搭 Harness。


3. 创建工作区结构

建议先创建这样的目录:

taskflow-agent-harness/
  app/
  harness/
    SPEC.md
    feature_list.json
    progress.md
    sprint_contract.md
    qa_report.md
    prompts/
      initializer.md
      planner.md
      builder.md
      evaluator.md

每个文件的作用如下:

文件 作用
SPEC.md 产品规格,说明要做什么、用户路径是什么
feature_list.json 可验证功能清单,每项都有验收步骤和通过状态
progress.md 长期交接记录,告诉下一轮 Agent 做到哪里
sprint_contract.md 当前 Sprint 的完成约定
qa_report.md Evaluator 的验收报告
prompts/initializer.md 初始化 Agent 提示词
prompts/planner.md 规划 Agent 提示词
prompts/builder.md 开发 Agent 提示词
prompts/evaluator.md 验收 Agent 提示词

这里最重要的是:这些文件不是文档摆设,而是 Agent 的外部记忆。

每轮 Agent 开始前先读它们,每轮结束后更新它们。


4. 第一步:Initializer 先搭现场,不急着开发

Initializer 的任务是搭建长期可接力的工作现场。

它不应该一开始就实现所有功能。它应该先创建项目骨架、功能清单、运行脚本和交接文件。

可以把下面内容保存为 harness/prompts/initializer.md

# Initializer Agent Prompt

你是 Initializer Agent,负责为长时间运行的软件开发任务搭建工作环境。

用户原始需求:
做一个个人任务看板,支持任务创建、状态流转、截止日期、搜索筛选和基础统计。

你的任务:
1. 创建 app/ 目录,并初始化一个最小可运行的前端项目。
2. 创建 harness/SPEC.md,扩展完整产品规格。
3. 创建 harness/feature_list.json,将需求拆成可端到端验证的功能项。
4. 创建 harness/progress.md,记录初始化结果和后续工作规则。
5. 创建 harness/sprint_contract.md 空模板。
6. 创建 harness/qa_report.md 空模板。
7. 初始化 git 仓库并提交初始状态。

约束:
- 不要一次性实现全部功能。
- feature_list.json 中每个功能都必须包含 id、description、steps、passes。
- 所有 passes 初始值必须为 false。
- 后续 Agent 只能在真实验证通过后,把 passes 从 false 改成 true。
- 不要删除 feature_list.json 中的功能项。

Initializer 生成的 feature_list.json 应该像这样:

[
  {
    "id": "task-create",
    "category": "functional",
    "description": "用户可以创建新任务",
    "steps": [
      "打开任务看板页面",
      "点击新建任务按钮",
      "输入标题、描述和截止日期",
      "点击保存",
      "确认任务出现在待办列表",
      "刷新页面后确认任务仍然存在"
    ],
    "passes": false
  },
  {
    "id": "task-status-change",
    "category": "functional",
    "description": "用户可以改变任务状态",
    "steps": [
      "创建一个新任务",
      "将任务从待办移动到进行中",
      "将任务从进行中移动到已完成",
      "刷新页面",
      "确认任务仍然处于已完成状态"
    ],
    "passes": false
  },
  {
    "id": "task-search-filter",
    "category": "functional",
    "description": "用户可以搜索和筛选任务",
    "steps": [
      "创建多个不同标题和状态的任务",
      "输入关键词搜索",
      "确认只显示匹配任务",
      "选择状态筛选",
      "确认搜索和状态筛选可以同时生效"
    ],
    "passes": false
  }
]

注意,功能清单里不要只写“支持任务管理”。要写成真实用户可以执行的步骤。


5. 第二步:Planner 把一句话扩展成产品规格

Planner 的价值是防止 Builder 低估需求。

如果没有 Planner,Agent 很容易直接开写,最后做出一个“有按钮、有卡片、有三列”的浅层 Demo。Planner 要先把产品目标、用户路径、阶段规划和验收边界讲清楚。

保存为 harness/prompts/planner.md

# Planner Agent Prompt

你是 Planner Agent,负责把用户的简短需求扩展成可执行产品规格。

开始前必须阅读:
- harness/SPEC.md
- harness/feature_list.json
- harness/progress.md

你的任务:
1. 检查 SPEC.md 是否完整覆盖用户目标。
2. 将产品拆成 3 到 5 个开发阶段。
3. 每个阶段都要有可验证的用户价值。
4. 补充遗漏的功能清单项,但不要过度设计。
5. 不要规定过细的技术实现,除非它影响产品行为。
6. 更新 progress.md,说明你做了哪些规划变更。

输出要求:
- SPEC.md 中必须包含产品目标、核心用户路径、非目标、开发阶段。
- feature_list.json 中每个功能都必须可以端到端验证。

Planner 产出的阶段规划可以是:

## 开发阶段

### Phase 1:基础任务 CRUD
- 创建任务
- 编辑任务
- 删除任务
- 本地持久化

### Phase 2:看板状态流转
- 待办、进行中、已完成三列
- 任务可在状态之间移动
- 状态刷新后保留

### Phase 3:搜索、筛选和排序
- 按关键词搜索
- 按状态筛选
- 按截止日期排序
- 搜索和筛选可以组合使用

### Phase 4:统计视图
- 总任务数
- 已完成任务数
- 逾期任务数
- 完成率

Planner 不需要把每个 React 组件怎么写都指定出来。太细的技术规格反而会把错误提前固化。

它应该把“做什么”和“做到什么程度算完成”讲清楚。


6. 第三步:Builder 每次只做一个小闭环

Builder 是真正写代码的 Agent。

但它不能随便写。它每一轮都要遵循固定流程:

读交接记录
读功能清单
读产品规格
启动项目
做基础冒烟测试
选择一个未完成项
写 Sprint Contract
实现功能
自测
通过后更新 passes
写 progress
提交 git

保存为 harness/prompts/builder.md

# Builder Agent Prompt

你是 Builder Agent,负责实现 TaskFlow 应用。

开始前必须:
1. 读取 harness/progress.md。
2. 读取 harness/SPEC.md。
3. 读取 harness/feature_list.json。
4. 查看最近 git log。
5. 启动应用,并确认基础页面可以打开。

工作规则:
- 每轮只实现一个功能,或者一个紧密相关的小功能组。
- 开发前必须更新 harness/sprint_contract.md。
- sprint_contract.md 必须写清楚本轮目标、包含范围、不包含范围、完成标准、验证步骤。
- 如果 harness/qa_report.md 显示上一轮失败,本轮只能修复失败项,不能开发新功能。
- 只有真实验证通过后,才能把 feature_list.json 对应 passes 改为 true。
- 每轮结束必须更新 progress.md。
- 每轮结束必须 git commit,提交信息要说明本轮完成了什么。

不要做:
- 不要删除 feature_list.json 的功能项。
- 不要把未测试功能标记为通过。
- 不要在一个 Sprint 中顺手做大量无关功能。
- 不要因为 UI 看起来完成就跳过端到端验证。

一个好的 sprint_contract.md 示例:

# Sprint Contract

## 本轮目标

实现任务创建功能。

## 包含范围

- 新建任务按钮
- 创建任务表单
- 标题、描述、截止日期字段
- 标题必填校验
- 保存后任务出现在待办列
- 刷新页面后任务仍然存在

## 不包含范围

- 编辑任务
- 删除任务
- 拖拽状态流转
- 搜索筛选
- 统计视图

## 完成标准

- 用户可以通过 UI 创建任务。
- 空标题不能保存。
- 保存后页面立即显示新任务。
- 截止日期显示在任务卡片上。
- 刷新后任务仍然存在。

## 验证步骤

1. 打开应用首页。
2. 点击新建任务。
3. 不填写标题直接保存,确认出现校验提示。
4. 填写标题、描述和截止日期。
5. 保存任务。
6. 确认任务出现在待办列。
7. 刷新页面。
8. 确认任务仍然存在。

Sprint Contract 的作用是把“实现任务创建”这种模糊目标,变成一组可检查的行为。


7. 第四步:Evaluator 不写代码,只负责验收

Evaluator 是独立 QA。

它不能因为页面漂亮就放行,也不能被 Builder 的解释说服。它只看实际行为。

保存为 harness/prompts/evaluator.md

# Evaluator Agent Prompt

你是 Evaluator Agent,负责验收 Builder 的工作。

开始前必须阅读:
- harness/SPEC.md
- harness/feature_list.json
- harness/progress.md
- harness/sprint_contract.md

你的任务:
1. 启动应用。
2. 像真实用户一样操作页面。
3. 严格按照 sprint_contract.md 的完成标准逐项验证。
4. 检查是否存在核心路径失败、状态错误、刷新后丢失、UI 不可理解等问题。
5. 输出 harness/qa_report.md。

评审原则:
- 不要因为代码存在就判定功能完成。
- 不要因为 UI 看起来不错就判定功能完成。
- 如果核心用户路径失败,本轮必须失败。
- 如果功能只是 stub、假数据或展示壳,本轮必须失败。
- 反馈必须具体到可修复的问题。

qa_report.md 必须包含:
- 结论:通过或失败
- 验证过的步骤
- 失败项
- 通过项
- 修复建议

一次失败的 QA 报告可能是:

# QA Report

## 结论

失败。

## 验证过的步骤

1. 打开首页。
2. 点击新建任务。
3. 测试空标题保存。
4. 创建包含标题、描述、截止日期的任务。
5. 刷新页面检查数据是否保留。

## 失败项

1. 空标题任务仍然可以保存。
2. 创建任务后刷新页面,任务消失。
3. 截止日期没有显示在任务卡片上。

## 通过项

1. 新建任务按钮可以打开表单。
2. 表单可以输入标题、描述、截止日期。
3. 保存后任务会临时出现在待办列。

## 修复建议

优先修复本地持久化,其次修复表单校验和任务卡片字段展示。

这个报告会直接决定 Builder 下一轮做什么。


8. 第五步:失败后不要开新功能,只修当前问题

这是很多 Agent 任务失败的关键点:一轮没通过,Agent 却继续做下一个功能。

Harness 要明确规定:

如果 QA 失败,下一轮 Builder 只能修复 QA 报告中的失败项。

修复轮的 Builder 提示可以这样写:

你是 Builder Agent。

harness/qa_report.md 显示上一轮没有通过。

本轮任务:
1. 只修复 qa_report.md 中列出的失败项。
2. 不开发新功能。
3. 不扩大范围。
4. 修复后重新按照 sprint_contract.md 自测。
5. 只有全部通过,才更新 feature_list.json 的 passes。
6. 更新 progress.md。
7. git commit。

这样开发循环就变成:

写 Contract
实现功能
QA 验收
失败则修复
复验通过
进入下一个功能

这个闭环比“让 Agent 一直写”稳定得多。


9. 一次完整运行示例

假设我们按上面的 Harness 跑 TaskFlow,合理的轮次如下:

第 0 轮:Initializer
创建项目、规格、功能清单、进度文件、初始提交。

第 1 轮:Planner
补全产品规格,规划 4 个开发阶段。

第 2 轮:Builder
实现任务创建。

第 3 轮:Evaluator
验收任务创建,发现刷新后数据丢失。

第 4 轮:Builder
修复本地持久化和表单校验。

第 5 轮:Evaluator
复验任务创建,通过。

第 6 轮:Builder
实现任务编辑和删除。

第 7 轮:Evaluator
验收编辑删除。

第 8 轮:Builder
实现状态流转。

第 9 轮:Evaluator
验收状态流转和刷新后状态保留。

这个流程看起来慢,但它换来的是稳定。

长任务真正浪费时间的地方,通常不是“多写了几份 Markdown”,而是 Agent 在错误状态上继续堆代码,最后整个项目难以收拾。


10. 关键设计:为什么要用 JSON 做功能清单

Anthropic 的文章里提到,他们实验后更偏向用 JSON 存功能清单。

原因很简单:模型更不容易随手改坏 JSON。

Markdown 对人友好,但对 Agent 来说太容易“顺手重写”。它可能会把未完成项删掉,把验收步骤简化,或者把失败项改成看起来完成。

JSON 更适合做状态文件。

推荐字段:

{
  "id": "task-create",
  "priority": "P0",
  "category": "functional",
  "description": "用户可以创建新任务",
  "steps": [
    "打开任务看板页面",
    "点击新建任务按钮",
    "输入任务信息",
    "点击保存",
    "确认任务出现",
    "刷新后确认任务仍然存在"
  ],
  "passes": false
}

并且要在提示词里强约束:

只能修改 passes 字段来标记完成。
不能删除测试项。
不能简化验收步骤。
不能把没有真实验证的功能标为 true。

这类约束看起来啰嗦,但对长任务很有用。


11. 主观质量也可以被 Harness 化

功能可以测试,但设计质量、产品手感、交互流畅度怎么办?

Anthropic 的第二篇文章给了一个重要方法:不要问“好不好看”,而是拆成可评分标准。

对 TaskFlow,可以给 Evaluator 增加这几个维度:

## 产品与设计评分维度

### 功能完整性
核心用户路径是否真的可用,而不是只有静态展示。

### 信息架构
用户是否能快速理解任务在哪、下一步可以做什么。

### 交互效率
创建、移动、筛选任务是否顺手,是否需要多余步骤。

### 视觉清晰度
状态、优先级、截止日期、逾期信息是否容易辨认。

### 原创性与克制
界面是否避免模板化堆卡片、默认组件感、过度渐变和无意义装饰。

这样 Evaluator 就不会只检查“按钮能不能点”,还会检查“这个应用是否真的像一个可用产品”。

主观质量不能完全自动化,但可以被结构化地改进。


12. 什么时候需要完整多 Agent,什么时候不需要

Harness 不是越复杂越好。

你可以用这个标准判断:

任务类型 推荐 Harness
改一个按钮、修一个小 bug 单 Agent 即可
实现一个页面或一个模块 Builder + feature_list + progress
多模块功能、需要持续开发 Initializer + Planner + Builder
完整应用、质量要求高 Initializer + Planner + Builder + Evaluator
有大量 UI 和端到端交互 必须加入浏览器自动化验收
主观质量很重要 加入评分标准和独立 Evaluator

每个 Harness 组件都是一个假设:

  • 需要 Planner,说明模型容易低估需求。
  • 需要 Sprint,说明模型容易一次做太多。
  • 需要 Evaluator,说明模型自评不可靠。
  • 需要 progress 文件,说明跨会话状态容易丢。
  • 需要 git commit,说明要能恢复到稳定点。

当模型能力提升后,要重新检查这些组件是否仍然必要。

好的 Harness 不是堆复杂度,而是只保留真正承重的结构。


13. 可以直接复用的最小模板

如果你只想快速落地,可以先用这个最小版本:

harness/
  SPEC.md
  feature_list.json
  progress.md
  sprint_contract.md
  qa_report.md

每轮 Builder 固定执行:

1. 读 progress.md
2. 读 SPEC.md
3. 读 feature_list.json
4. 选一个 passes=false 的功能
5. 写 sprint_contract.md
6. 实现
7. 自测
8. 更新 progress.md
9. git commit

每轮 Evaluator 固定执行:

1. 读 sprint_contract.md
2. 启动应用
3. 按真实用户路径操作
4. 写 qa_report.md
5. 通过才允许进入下一个功能

这是最小可用 Harness。

如果任务变复杂,再加入 Planner、多轮 QA、设计评分、自动化测试和更严格的状态文件。


14. 把 Agent 当作团队,而不是聊天窗口

长运行 Agent 的本质,不是一个更长的聊天窗口,而是一个迷你软件团队。

可以这样理解:

Harness 角色或文件 对应真实团队能力
Planner 产品经理 + 架构师
Builder 工程师
Evaluator QA + Code Reviewer
SPEC.md 产品规格
feature_list.json 验收清单
sprint_contract.md Sprint 交付契约
progress.md 交接记录
git commit 可恢复工作点

Agent 不是不能做长任务,而是不能在没有流程的情况下稳定做长任务。

所以 Harness 的核心不是“让 Agent 看起来更复杂”,而是让它:

  • 更难跑偏。
  • 更难假完成。
  • 更容易接着做。
  • 更容易被验收。
  • 更容易从错误中恢复。

最后可以记住这一句:

不要期待 Agent 长期自己保持清醒。用 Harness 把清醒变成流程。


15. Harness 会随模型一起“瘦身”

最后还要补一个很重要的判断:Harness 不是固定形态,它会随着模型能力一起变化。

在 Anthropic 的实验里,Opus 4.5 时代的问题更明显:长上下文下容易出现 context 焦虑,所以需要拆 Sprint,需要 context reset,也需要更强的外部评审来对抗自评偏见。这个阶段的 Harness 会比较厚,因为它要补模型当前不稳定的地方。

到了 Opus 4.6,模型的规划能力和长上下文能力变强,一些原本承重的结构就可以被拆掉。比如文章里提到,Sprint 这个构件在某些任务上可以直接移除,Harness 变得更简单,但质量并没有下降。

这背后的原则是:

先找最简单的方案,需要时才增加复杂度。每个 Harness 部件,都是对“模型当前短板”的一个假设;模型一升级,就要回头拆掉不再承重的部分。

所以不要把 Planner、Builder、Evaluator、Sprint、context reset 当成永远必须存在的标准答案。它们都是工程工具,不是信仰。

更好的做法是定期问自己几个问题:

  • Planner 还在显著提升需求完整度吗?
  • Sprint 拆分还在减少失控,还是已经变成额外开销?
  • Evaluator 还能抓到 Builder 自己抓不到的问题吗?
  • context reset 还必要吗,还是自动 compaction 已经足够?
  • 这套 Harness 的成本,是否仍然匹配它带来的质量收益?

模型越弱,Harness 往往越厚;模型越强,Harness 不一定消失,但会变轻、变窄、变得更有针对性。

最终成熟的 Agent 工程,不是堆出最复杂的多 Agent 系统,而是持续找到当前模型和当前任务之间最小但有效的支撑结构。


参考资料