ClaudeClaude Code系列第 10 / 10 篇

让 Claude 连续干几个小时:Anthropic 的两套长任务 harness,和用 claude -p 搭的最小版实测

长任务难在每个新会话都不记得之前做过什么。整理 Anthropic 工程博客的两套 harness:初始化代理加功能清单、进度文件和 git;规划、生成、评审分工。本站用 claude -p 和沙箱搭了最小版实测:结构被严格遵守,但比一个会话做完多花 10 倍,最有用的是独立验收。

发布 · 约 17 分钟读完 · 经人工审核()· 本站的内容怎么来的

本站已实测,测试日期:2026-10-16。

本页目录(7 节)
  1. 长任务为什么会失败
  2. 第一套:初始化代理和编码代理
  3. 第二套:规划、生成、评审
  4. 本站实测:用 claude -p 搭一个最小版
  5. 什么时候值得用
  6. 这次实测没有覆盖到的
  7. 参考

这篇解决一个问题:任务大到一个会话做不完时,怎么让 Claude 一轮接一轮地做下去,而不是做到一半乱了套。

难点在于每个新会话都不记得之前发生过什么。Anthropic 工程博客上有两篇文章专门讲这件事,给了两套做法:

  1. 初始化代理加编码代理(2025 年 11 月):第一轮只打基础,写一份功能清单、一个进度文件、一个启动脚本,建好 git;之后每一轮读这些文件接着做,一轮只做一项,做完提交。
  2. 规划、生成、评审(2026 年 3 月):在前一套的基础上,加一个把一句话需求扩成完整规格的规划代理,再加一个专门挑毛病的评审代理,因为让 Claude 评自己做的东西,它总是说好。

本站按第一套搭了一个最小版,用的是 Claude Code 的 claude -p,不用另写程序;末尾加了第二套里的评审。和“一个会话从头做完”的对照组比了一次:同一份需求、同样的沙箱和权限、同一个模型。

结论先说:

  • 结构管用。 10 轮编码各做一项,没有乱改功能清单,没有提前收工,每一轮都提交并留下记录。
  • 但这个任务一个会话就做得完。 对照组 151 秒、0.33 美元,本站的 25 项验收全过;harness 用了约 20 分钟、3.33 美元,验收也是全过。任务在模型能力范围之内时,harness 主要是开销,这和第二篇文章的结论一致。
  • 最值钱的是独立验收。 两轮找出 9 处需求没写到的边界问题;它也很难满意,修完一轮又挑出两处。

长任务为什么会失败

第一篇文章说,即使有自动压缩,在 Agent SDK 上循环跑 Opus 4.5,只给一句“做一个 claude.ai 的克隆”,也做不出能用的网页应用。失败有两种:

  • 想一口气做完。 做到一半上下文用完了,下一个会话接手的是一个做了一半、没有记录的功能,只能猜前面发生了什么,再花大量时间把应用修回能跑的状态。
  • 过早宣布完成。 做了一部分以后,后来的会话看看周围,觉得进展不少,就说做完了。

第二篇又补了两种:

  • 上下文焦虑。 有的模型觉得上下文快满了,就开始提前收尾。这时压缩不够用,要彻底清空、开一个新会话,靠一份交接文件把状态带过去。文章说 Sonnet 4.5 这个毛病明显,Opus 4.5 基本没有了,所以第二套里把清空上下文这一步去掉了,交给 Agent SDK 的自动压缩。
  • 自评太宽。 让 Claude 评价自己做的东西,它会很有把握地夸,哪怕在人看来质量明显一般。设计这类没有对错标准的任务尤其严重。

第一套:初始化代理和编码代理

两个“代理”其实是同一个 harness、同样的工具,只是第一轮的提示词不同。

**第一轮(初始化代理)**打好四样东西:

文件 作用
feature_list.json 把需求展开成一条条端到端的功能,每条带验证步骤,全部标成 "passes": false。克隆 claude.ai 那次写了 200 多条
claude-progress.txt 进度记录:每一轮做了什么、下一轮做什么
init.sh 启动开发服务器、跑一遍基本测试的脚本,后面每一轮先跑它
第一次 git 提交 后面可以看历史,也可以把改坏的退回去

功能清单用 JSON 而不用 Markdown,原因是模型不太会去乱改、整个重写 JSON 文件。提示词里还用了很重的语气,大意是“删掉或改动功能条目是不可接受的”,编码代理只能改 passes 这一个字段。

**之后每一轮(编码代理)**按固定的步骤开头:看工作目录,读进度文件和 git 记录,读功能清单挑优先级最高的未完成项,跑 init.sh 确认应用没坏,然后才开始做新功能。一轮只做一项,做完用 git 提交、写进度。

文章把四种失败和对策列成了一张表,大意如下:

问题 初始化代理做什么 编码代理做什么
过早宣布整个项目完成 按需求写一份结构化的功能清单 每轮开头读清单,只挑一项来做
留下 bug 或没记录的进度 建 git 仓库和进度文件 开头读进度和 git 记录、跑一遍基本测试;结尾提交并写进度
没测好就标成完成 写功能清单 每项都自己验证,仔细测过才标“通过”
每轮都要琢磨怎么跑起来 写 init.sh 开头先读、先跑 init.sh

测试这一条最关键。 文章说,不明确要求的话,Claude 会改完代码、跑跑单元测试或者用 curl 调一下接口,就当做完了,发现不了端到端其实不通。明确要求它用浏览器自动化、像真人用户一样测之后,效果好了很多。他们给的是 Puppeteer 的 MCP 服务器。局限也有:浏览器原生的弹窗它看不到,依赖弹窗的功能 bug 就多。

官方的示例代码在 claude-quickstarts 的 autonomous-coding:用 Agent SDK 写的,两份提示词、沙箱加一个 Bash 命令白名单的 hook,克隆 claude.ai 的规格要 200 条功能,README 提醒每轮要 5 到 15 分钟、做完要好几个小时。

第二套:规划、生成、评审

第二篇的作者先在前端设计上试:没有约束时,Claude 做出来的页面能用,但普通、可预测。他的办法是把“好不好看”变成可以打分的四条标准(整体感、原创性、做工、可用性),让生成和评审分开:生成代理做页面,评审代理用 Playwright 的 MCP 真的打开页面点来点去、截图,再按标准打分写意见,意见回给生成代理改。一次跑 5 到 15 轮,最长 4 个小时。分开之后评审也还是偏宽,但把一个独立的评审调教得挑剔,比让生成代理批评自己容易得多。

然后把这个结构搬到全栈开发上,变成三个代理:

代理 做什么
规划 把一到四句话的需求扩成完整的产品规格。要求它在范围上大胆,只写产品和高层设计,不写实现细节,免得规格里的技术错误一路传下去
生成 按规格一个冲刺一个冲刺地做,每次一项功能,交给评审之前先自查
评审 用 Playwright 像用户一样操作运行中的应用,测界面、接口和数据库;按产品深度、功能、视觉设计、代码质量打分,每项有及格线,一项不及格这一轮就打回

每个冲刺开始前,生成和评审先谈一份“冲刺合同”:这一块做到什么算完成、怎么验证,谈妥了才写代码。两个代理之间靠文件沟通。评审找出的问题很具体,比如“矩形填充只在拖动的起点和终点放了砖块,fillRectangle 函数存在但没有在 mouseUp 时触发”。

花费和效果,文章给了两组数(都是 Anthropic 自己跑的):

做什么 怎么跑 时长 花费
复古游戏编辑器(Opus 4.5) 一个代理直接做 20 分钟 9 美元
同上 完整的三代理 harness 6 小时 200 美元
浏览器里的音乐制作软件(Opus 4.6,简化后的 harness) 规划 4.7 分钟,三轮生成加评审 3 小时 50 分 124.70 美元

贵了 20 多倍,但单代理做的游戏编辑器核心功能是坏的:角色出现在画面上,按键没有反应;三代理那次能真的玩起来。

评审调教起来很费劲。 作者说开箱即用的 Claude 是个差劲的测试员:找到了真问题,又说服自己“问题不大”,照样放行;测得也浅,边界情况不碰。他的办法是读评审的日志,找出它和自己判断不一样的地方,改评审的提示词,来回好几轮。

模型变强以后,harness 要做减法。 换到 Opus 4.6 后,作者一次去掉一个组件看影响:冲刺可以整个去掉,模型自己能连续做两个多小时不乱;规划要留着,没有它生成代理会把范围做小;评审改成最后一次性验收。评审值不值,取决于任务在不在模型自己能可靠做好的范围之内:在范围内,评审是多余的开销;在边缘上,它仍然能抓到真问题。他引用了《Building effective agents》里的一句话作为原则:先找最简单的办法,需要时才加复杂度。harness 里的每个组件,都是在假设模型自己做不到某件事,这些假设要经常拿出来检验。

本站实测:用 claude -p 搭一个最小版

官方示例要写 Python、装 Agent SDK 和浏览器自动化。用 Claude Code 的人其实不用另写程序:claude -p 本身就是一个完整的智能体,每次调用是一个全新的会话,正好对应“每一轮都不记得之前的事”。harness 就是一个 shell 脚本,按顺序调几次 claude -p,每次给不同的提示词。

实测环境
日期 2026-10-16
版本 Claude Code 2.1.300,Ubuntu 24.04
模型 Sonnet 5.5(--model sonnet),两组用同一个
连接方式 通过酷站AI 中转站,不是直连官方
任务 一个命令行记账工具:8 条命令(记账、列表、删除、撤销、月度汇总、预算、导出 CSV、导入 CSV)加错误处理,只用 Python 标准库。需求写在一页 app_spec.md 里
对照组 同一份需求、同样的沙箱和权限,一个 claude -p 会话做完
验收 本站另写的 25 项检查,按需求逐条跑命令,不给被测的会话看

文件

h40-harness/
├── app_spec.md        需求,两组都拿这一份
├── CLAUDE.md          项目约定,两组都有
├── sandbox.json       沙箱设置
├── harness.sh         长任务 harness
├── solo.sh            对照组:一个会话做完
└── prompts/
    ├── initializer.md 第一轮
    ├── coding.md      之后每一轮
    ├── qa.md          独立验收
    ├── fix.md         按验收报告修
    └── solo.md        对照组

两道边界:沙箱和 dontAsk

无人值守地跑,没有人点确认,所以要先把能做的事框住。官方示例用的是沙箱加一个 Bash 命令白名单的 hook;C 编译器那个实验用的是 --dangerously-skip-permissions,但整个跑在容器里(见《智能体该搭成什么结构》)。我们在一台共用的服务器上跑,用的是 Claude Code 自带的 Bash 沙箱:

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false
  }
}

三项的意思:打开沙箱,命令只能写项目目录、不能联网;沙箱起不来就不跑,而不是不带沙箱照跑;不允许命令申请跑到沙箱外面。再加上 --permission-mode dontAsk:文件工具只放行项目目录里的读写,其他要确认的一律直接拒绝,不会停下来等人。沙箱怎么配、挡得住什么,见《Claude Code 沙箱怎么配》。

有一个插曲:写这个脚本时,本站用的 Claude Code 开着 auto 模式。第一版脚本没开沙箱,只靠一份允许清单,里面有 Bash(python3 *),等于能执行任意代码。auto 模式的分类器把它拦了下来,理由是 Create Unsafe Agents:它不允许创建既没有沙箱、又没有逐个审批的智能体循环。加上沙箱以后才放行。

脚本

#!/usr/bin/env bash
# 最小的长任务 harness:每一轮都是一个全新的 claude -p 会话,前后两轮只靠目录里的文件交接。
# 用法:./harness.sh 项目目录 [编码轮数上限]
set -uo pipefail
HERE=$(cd "$(dirname "$0")" && pwd)
PROJECT=$(cd "$1" && pwd)
MAX=${2:-14}
LOGS="$HERE/logs/$(basename "$PROJECT")"
mkdir -p "$LOGS"
cd "$PROJECT"

OPTS=(--settings "$HERE/sandbox.json" --permission-mode dontAsk
      --allowedTools Read Glob Grep "Write(./**)" "Edit(./**)" --model sonnet --max-budget-usd 2 --output-format json)

n=0
session() {  # 参数:提示词的名字。每次都是新会话,不接着上一个。
  n=$((n + 1))
  local log="$LOGS/$(printf %02d $n)-$1.json"
  claude -p "$(cat "$HERE/prompts/$1.md")" "${OPTS[@]}" > "$log"
  jq -r --arg s "$1" '"\($s):\(.num_turns) 轮,\(.duration_ms / 1000 | floor) 秒,\(.total_cost_usd) 美元"' "$log"
}
left() { jq '[.[] | select(.passes == false)] | length' feature_list.json 2>/dev/null || echo "?"; }
passed() { tail -1 qa-report.md 2>/dev/null | grep -q "结论:通过"; }

session initializer
for ((i = 1; i <= MAX; i++)); do
  [ "$(left)" = "0" ] && break
  echo "还剩 $(left) 项"
  session coding
done
session qa
if ! passed; then  # 验收不通过:修一轮,再验收一次
  session fix
  session qa
fi
echo "结束:feature_list.json 里还剩 $(left) 项没通过;$(tail -1 qa-report.md)"

几个设计:每一轮都不带 --continue,是真正的新会话;--max-budget-usd 2 给每一轮设花费上限;--output-format json 让每一轮的轮数、耗时、花费都记进日志;循环靠 jq 数功能清单里还剩几项,全部通过就停,最多 14 轮。

提示词

初始化的提示词让它做五件事:读需求,写 feature_list.json(拆成 8 到 12 项能在命令行里验证的功能,每项带验证步骤,全部 "passes": false),写一条命令跑完全部测试的 init.sh,搭项目骨架,提交一次并写 claude-progress.txt。并且说明这一轮不实现功能,清单以后只能改 passes。

之后每一轮用的是这一份,照着官方那份的结构缩写的:

你在接着做一个长任务。这是一个全新的会话,你不记得之前做过什么。

第一步,摸清现状:读 claude-progress.txt;看 git log --oneline -10;读 feature_list.json,
数一数还有几项没通过;跑 ./init.sh,确认已经通过的功能没有坏。坏了先修,修好之前不做新功能。

第二步,只挑一项:feature_list.json 里排在最前面、passes 还是 false 的那一项。这一轮只做这一项。

第三步,实现并验证:写代码、写测试,然后按这一项的 steps 真的在命令行里跑一遍,像用户那样用,
看输出对不对。只跑单元测试不算验证。

第四步,收尾:确认无误后,把这一项的 passes 改成 true(只能改这个字段);git commit,写清楚做了什么;
在 claude-progress.txt 末尾追加这一轮的记录:做了哪一项、发现了什么问题、现在通过了几项、
下一轮该做什么。不要留下没提交的改动。

验收的提示词借的是第二套的思路:“你是验收的人,不是写代码的人……默认它有问题,除非你亲手验证过没有”,要求按需求逐条在命令行里用,重点试边界情况,把结果写进 qa-report.md,最后一行写“结论:通过”或“不通过”,不许改代码。修的那一轮读报告、按复现命令逐条修。

第一次跑失败了,教训在 CLAUDE.md 里

第一次跑,初始化那一轮就出了问题:它想用一条 Bash 命令、靠 heredoc 一次写好所有文件。这条命令被 dontAsk 拒绝了,它改用 Write 工具把文件写完,但没跑测试、也没提交。第一轮编码更糟:同样的长命令被拒以后,它停下来写了一段话请人“放开 Bash 权限”,然后就结束了。无人值守的时候,没有人会回答它。

我们停掉重来,在 CLAUDE.md 里加了几条,两组都一样:

- 这是无人值守的运行,没有人会回答你的问题。某条命令被拒绝时,换一种做法,不要停下来等人。
- 写文件、改文件用 Write 和 Edit 工具,不要在 Bash 里用 `cat >`、heredoc 写文件,这类命令会被拒绝。
- Bash 只用来跑测试、运行程序、看文件和用 git。一条命令只做一件事,不要把很多步骤串成一长条。
- 只用 Python 标准库,测试用 `python3 -m unittest`。
- 命令在沙箱里运行:提交时按文件名 `git add 文件1 文件2`,不要用 `git add -A` 或 `git add .`,沙箱里的占位文件会让它们失败。
- 临时文件放在项目目录里,不要写到项目外面。

最后一条之前那条,是沙箱那篇实测过的坑:Linux 上开了沙箱,git add -A 会被沙箱放的占位文件卡住。git 仓库也是我们在沙箱外面先建好的,因为沙箱里 .git/config 是只读的。

改完以后两组都没再卡住。所有会话里被拒绝的 Bash 命令一共三类,都是沙箱里也要走正常审批、dontAsk 下就被直接拒绝的:

被拒的命令 特点
用 heredoc 往文件里写一大段代码 一条命令里写好几个文件
mkdir -p run_tmp && cd run_tmp && export PYTHONPATH=.. && python3 -m ledger … 用 export 改环境变量,还串了很多步
python3 -m ledger --file tmp/bad.json list; echo "exit=$?" 带 $? 这类展开

官方文档的说法是,变量写在命令前面(比如 FOO=bar npm test)这类会改变实际运行什么的命令,即使在沙箱里也不自动放行。被拒之后,两组都换了一种写法接着做。

结果

harness 跑了 14 个会话:初始化 1 个,编码 10 个(初始化拆出了 10 项功能,正好一轮一项),验收 2 个,修复 1 个。

对照组:一个会话 harness
会话数 1 14
耗时 151 秒 约 20 分钟(其中初始化加编码 12.5 分钟)
花费 0.33 美元 3.33 美元(其中初始化加编码 2.30 美元)
本站的 25 项验收 25/25 25/25
需求没写到的 9 个边界情况 处理好 5 个 处理好 6 个(经过一轮验收和修复)
测试 19 个,210 行 67 个,927 行
代码 402 行 330 行
git 提交 1 次 14 次

花费是 Claude Code 按官方价的估算,不是中转站实际扣的金额。编码的每一轮 19 到 27 轮对话、46 到 102 秒、0.18 到 0.29 美元,差别不大。

几处值得看:

  • 结构被严格遵守。 10 轮编码各做一项,没有人想一口气做完,也没有人提前宣布完成;功能清单 10 次修改都只改了 passes 字段;每一轮都先跑测试、最后提交,进度文件写了 124 行。第一套要解决的几种失败,这次一种都没出现。
  • 但这个任务一个会话就做得完。 Sonnet 5.5 一个会话两分半钟做完,本站的 25 项检查全过。它还如实说了哪些只在测试里验证过、没有在命令行手动跑。对这么大的任务,harness 花了 10 倍的钱,换来的是更多的测试和一条一项一提交的记录。
  • 最有用的是独立验收。 第一轮验收用了 96 轮对话,逐条在命令行里试,找出 7 处需求没写到的问题:分类可以是空字符串;金额写成阿拉伯-印度数字“٣”会被当成 3 收下;list --category "" 会列出全部;导入时多出来的列被悄悄截掉;数据文件的目录不存在、或者 --file 指向一个目录时,直接抛出 Python 的报错堆栈。修复那一轮把 7 处都修了,并补了测试。
  • 单个会话反而写得更周全。 拿两轮验收的复现命令去试对照组,列数检查、目录不存在、--file 指向目录、数据文件结构不对这 4 种情况,对照组一开始就处理好了;harness 按功能一项项做出来的代码,这几处原本都没处理,是靠验收补上的。每一轮只看得到自己那一项,顾不上全局。
  • 验收很难满意。 修完以后第二轮验收又挖出 2 处:预算的分类可以为空,引号没闭合的 CSV 行被当成正常数据导入。结论还是“不通过”。我们的脚本只修一轮,到此为止。这两处对照组同样没处理。不给验收定一条及格线,它会一直挑下去。

第二篇文章的作者说开箱即用的 Claude 是个太宽容的测试员;我们的验收提示词一上来就要求“默认它有问题”,结果是另一头:严,严到需求以外的问题也判不通过。两头都说明,评审的严格程度主要由提示词决定,要按你的需求去校准。

什么时候值得用

把两篇文章和这次实测放在一起,本站的看法:

你的情况 怎么做
任务一个会话做得完 不用 harness,让它一次做完
做完想多一层保险 另开一个会话专门验收,提示词写明“你不是写代码的人”,要求在命令行或浏览器里真的用一遍。这次一轮验收 0.4 美元左右,找出了自评发现不了的问题。“一个会话做完再加一轮验收”这个组合本站没有单独测,是根据上面的结果给的建议
任务大到一个会话做不完、要跑几个小时,或者要求每一步都有记录 用第一套:功能清单用 JSON、一轮只做一项、每轮先跑测试再提交、写进度文件
用了独立验收 事先说清楚及格线:需求没写的问题算不算失败。要么写进需求,要么告诉它记下来但不算失败
无人值守地跑 先定边界:沙箱加 dontAsk,或者整个跑在容器、虚拟机里;在 CLAUDE.md 里写明没有人会回答,命令被拒就换做法
换了更强的模型 照原文的原则,一次去掉一个组件,看它还是不是必需的

和本站其他文章的关系:要它朝一个目标连续做下去,Claude Code 有内置的 /goal 和 /loop,见《Harness 工程和 Loop 工程是什么》;要几个会话同时干,见《代理团队实战》和《动态工作流》;把 claude -p 接进脚本的基础用法,见《把 Claude Code 接进脚本和 CI》。

这次实测没有覆盖到的

  • 任务太小,没有测到 harness 真正要解决的问题。 一个会话就做完了,没有碰到上下文用完、要好几个会话接力的情况。
  • 没有规划代理。 需求是本站写好的,没有测“一句话扩成完整规格”这一步。
  • 没有浏览器自动化。 做的是命令行工具,验证靠在命令行里跑。
  • 两组各跑一次。 模型每次的表现不一样,不能当成稳定的结论。
  • 第一次失败的那一轮没有算进花费。 两个会话约 0.4 美元,加上中途停掉的几个会话。

参考

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章