第 25 章
从需求到 Agent:Harness 设计清单
先画控制面,再选框架。
读完前面 24 章,很容易产生一个错觉:下一个 Agent 应该从“选框架”开始。
不是。先写一页纸:目标、成功标准、循环、工具、权限、状态、评测、上线。写不出来,说明你还没想清楚,换什么框架都一样。
这一章不是“方法论”,是一张可以照着填的 Harness 设计清单。
25.1 先决定“要不要 Agent”
按顺序问:
任务能写死吗?
├─ 能 → Workflow / 脚本 / 规则引擎
└─ 不能 → 需要动态决策吗?
├─ 不需要 → 普通函数 + 重试
└─ 需要 → 需要嵌入产品/多租户/自定义工具吗?
├─ 需要 → Claude Agent SDK
└─ 不需要 → 先用 SDK 跑通,再考虑裸 API几个判断:
- 固定审批流(报销、入职)→ Workflow;不要让模型决定下一步。
- 代码修复、资料调研、客服对话→ Agent;步骤不固定,需要看情况。
- 需要接公司内部工具、多租户、审计→ SDK;Harness 的权限/会话/工具面能省很多。
- 要改循环、用非 Claude 模型、极致低时延→ 裸 API 或其他框架;SDK 的循环是闭源的。
“用 Agent”不是身份,是成本。能用 Workflow 解决的,不要用 Agent。
25.2 Harness 六问,不是 SDK 功能清单
设计一个 Agent,先填这六行:
| 六问 | 设计问题 | 默认答案 |
|---|---|---|
| 看见什么 | 常驻/按需/禁止的上下文分别是什么? | 短规则 + 检索;不塞全仓库/全文 |
| 能做什么 | 读/写/执行/搜索,各需要什么? | 只读优先;写/执行最小化 |
| 允许做什么 | 路径/命令/网络/租户,谁判? | 代码判;写走审批;危险命令 deny |
| 什么时候停 | 成功标准、轮数、预算、人工接管 | 代码验证 + max_turns/budget |
| 失败怎么办 | 重试/恢复/降级/回滚 | 幂等 + 状态机 + resume |
| 做完留下什么 | patch/报告/流水/审计/成本 | 每次 run 留产物 |
这六行比“用哪个模型/框架”重要。第 16 章的控制矩阵,就是这六问的 SDK 版本。
Harness 的控制强度,从弱到强大概是:
提示词 < 工具面 < 权限/审批 < 沙箱 < 持久化状态/审计只在提示词里写“不要删库”,是最弱的;把 Bash 关进沙箱、危险命令 deny、写操作审批,才是控制。
25.3 一页画布
把下面这份 YAML 填完,再写代码:
goal: "一句话:给谁解决什么问题"
success: "机器能判的成功标准(测试/diff/字段/引用)"
loop: "几步?每步输入/输出?谁决定下一步?"
tools:
read: ["..."] # 只读、免审批
write: ["..."] # 写、必须审批
compute: ["..."] # 本地计算/查询
context:
always: ["system prompt", "CLAUDE.md 短规则"]
on_demand: ["README", "docs", "检索"]
never: [".env", "密钥", "其他租户数据"]
permissions:
mode: "default / dontAsk / acceptEdits / ..."
approval: "谁批、超时多久、拒绝理由"
sandbox: "Bash 在哪跑、网络开不开"
state:
session: "ClaudeSDKClient / resume"
notes: "progress.md / features.json"
checkpoint: "enable_file_checkpointing"
eval:
tasks: "5-20 个固定任务"
grader: "测试/字段/引用/人工抽查"
metrics: ["success", "turns", "cost", "latency"]
deploy:
tenants: "单租户 / 多租户"
quota: "每租户预算/限流"
monitoring: "审批拒绝率、PII、错误率"落到 SDK,骨架是:
options = ClaudeAgentOptions(
cwd=str(ROOT),
setting_sources=["project"],
system_prompt={
"type": "preset",
"preset": "claude_code",
"append": WORKFLOW,
},
tools=["Read", "Glob", "Grep", "Edit", "Bash"],
allowed_tools=["Read", "Glob", "Grep"], # 写/跑走审批
permission_mode="default",
can_use_tool=approve_write,
hooks={"Stop": [HookMatcher(hooks=[require_tests])]},
max_turns=12,
max_budget_usd=0.3,
)这不是模板,是骨架:WORKFLOW、approve_write、require_tests 要按画布填。
25.4 生产就绪:从 demo 到上线
demo 能跑,不代表能上线。至少过这九项:
- 状态机:run 有
queued/running/verifying/succeeded/failed,转移原子;两个 worker 不能领同一个 run。 - 隔离:一 run 一个 workspace/容器;失败可丢弃;不共享
HOME/配置。 - 权限:写/执行走
can_use_tool;路径 jail;危险命令 deny;沙箱 fail-closed。 - 审批:持久化、超时默认拒绝、理由回填;不是内存弹窗。
- 幂等:写操作带
request_id;重试不重复副作用。 - 恢复:
resume前验证世界;会话/文件/审批可续接。 - 审计/脱敏:工具调用、审批、结果;PII 在进上下文前替换。
- 预算/限流:每 run/每租户;
max_budget_usd留余量。 - 评测/监控:固定任务集、确定性评分、trace、成本/时延/失败率。
如果只能先做三件:状态机、权限、Verifier。这三件决定“会不会重复执行、会不会闯祸、做完算不算完成”。
25.5 五天最小计划
不要一上来写“完美 Agent”。按五天走:
Day 1:任务集 + 裸循环。 选 3 个真实任务,写清成功标准;用最小循环跑一遍。先看它怎么失败。
Day 2:工具 + 权限。
只加任务需要的工具;读/写分开;写操作走审批;跑一次攻击用例(改测试/读 .env/危险命令)。
Day 3:上下文 + 评测。
加 CLAUDE.md/Skill/检索;写评分器;跑 N 次,记录 turns/cost/latency。第 17 章的 run_eval.py 可以直接用。
Day 4:SDK 化。 把循环/工具/权限/会话换成 SDK;不要一次换全部,先换循环,再换工具,再换权限。每换一层跑一次评测。
Day 5:上线/监控。 加预算、限流、审计、脱敏、告警;用小流量灰度;准备回滚。
五天不是“保证上线”,是“保证每一层都有证据”。生产就绪的九项,通常不止五天。
25.6 三个项目的取舍
coding agent:Harness 的重点是“工作区 + 权限 + 验证”。一 run 一个 worktree;写白名单;Stop + Verifier。没有 Verifier,模型说完成就完成。
research agent:Harness 的重点是“来源 + 上下文预算 + 引用验证”。提纲先于搜索;来源表/claim 表可追溯;摘要省上下文但会丢信息。
support agent:Harness 的重点是“权限 + 幂等 + 脱敏 + 恢复”。写操作审批;退款幂等;PII 在工具边界替换;进程重启后审批/会话还在。
三个项目的共同点:成功标准都是代码判的,不是模型自称的。
25.7 反模式
- 先写完美提示词:提示词是最后调的,不是第一件事;
- 一上来 30 个工具:工具越多,选择越难、schema 越贵;
- 没有评测:只凭一次运行判断好坏;
- 没有权限:能跑
Bash就敢跑rm -rf; - 把所有东西塞进上下文:长文档、日志、历史,每轮都付钱;
- 用 Agent 做确定性流程:能用
if/else的,不要用模型; - 把“审批”做成弹窗:没有规则、超时、审计的弹窗,只是打扰人;
- 把“resume”当重试:它可能重复未完成的工具调用。
25.8 迁移清单
从 Claude Code 迁到 SDK:
- 把
.claude/的规则/Skill 显式加载(setting_sources); - 把常用命令写成工具或 Skill;
- 把权限/审批从“人工确认”换成
can_use_tool+ 规则; - 保留
CLAUDE.md,但只放短规则。
从 tiny 迁到 SDK:
- 循环/工具/权限/会话分别替换,不要一次重写;
- 每换一层,跑同一套评测;
- 记录“换之前/换之后”的 turns/cost/success。
从 demo 迁到生产:
- 加状态机、隔离、超时、重试、预算、限流;
- 加审计、脱敏、租户隔离;
- 加监控和回滚;
- 把“模型自称完成”换成“代码验证”。
25.9 结语
这本书从“200 行循环把测试改了”开始,到“三个业务 Agent + 一页 Harness 设计清单”结束。
如果只带走一句话:
Agent 的能力,取决于模型外面那套程序;那套程序,取决于你有没有想清楚“看见什么、能做什么、允许做什么、什么时候停、失败怎么办、做完留下什么”。
先写一页画布,再写第一行代码。
本章说明 这一章没有新代码;它是一张设计清单。附录 A 把六问和 SDK 旋钮做成了总表,方便你回头查。