验证模式与模型分层:让对的模型做对的事
同样的任务质量,账单从每月4200美元降到1600美元——没有换模型,只是换了"谁干哪件事"
本文导航
- 验证模式:Diamond里的对抗性把关
- 模型分层的第一性原理:判断力密度
- 三层模型分工:Opus决策、Sonnet执行、Haiku路由
- CLAUDE_CODE_SUBAGENT_MODEL与配置实战
- 成本优化数据:一份真实账单的拆解
- 小结
- 下节预告
- 互动区
验证模式:Diamond里的对抗性把关
上一节的Diamond里其实埋了个伏笔:最后那个"合并审查"节点,本质上就是Verifier(验证者)。这一节把它正式请出来,讲清楚验证模式怎么设计。
第36节讲拓扑模式的时候我说过Verifier的核心是对抗性——验证者不能是生成者的"自己人"。在Claude Code的Dynamic Workflows里落实这三条原则:
- 独立上下文。Verifier用独立的
agent()调用,不共享生成者的对话历史,只看最终产物。这天然满足节点隔离。 - 角色对立。生成者的prompt是"实现它",Verifier的prompt是"推翻它"。
- 模型更强。裁决者的判断力要高于被裁决者,这条下一节细说。
在Diamond上加Verifier有三个可选位置,我画出来:
- 验证点1(生成前):审查需求拆解和接口契约。最便宜的验证位置——契约错了,后面全部返工。
- 验证点2(生成后、合并前):各层自检。可以下放给生成Agent自己做(self-check),成本低但对抗性弱。
- 验证点3(合并后):全局对抗审查。最强的Verifier放这里,因为层间冲突只有拼起来才暴露。
我的经验是验证点1和3必做,2可选。一个常见的反模式是只做验证点3,结果Verifier发现契约错误,整个Diamond白跑一遍——验证点1一行代码就能省下这次全额返工。
验证节点的prompt模板我固定用这个格式,对抗性直接写进指令里:
constverdict=awaitagent(`你是独立评审员,与生成方零关联。你的任务是找出问题,而不是认可成果。 对以下产物逐项审查,输出 JSON:{"verdict":"pass|reject","defects":[{"where":"...","why":"...","severity":"high|mid|low"}]} 没有问题才允许 verdict=pass。产物:${artifact}`,{model:"opus",role:"adversarial-reviewer",output:"json",tools:["Read"]},// 只给读权限,防止Verifier"顺手改代码");注意最后一个细节:Verifier的工具集要收窄。只给Read不给Edit/Bash,验证者只能"挑毛病"不能"动手改",否则它会跳过验证直接改产物,对抗性就废了。
模型分层的第一性原理:判断力密度
为什么Opus/Sonnet/Haiku要分工?不是因为"贵的就该干重要的活"这种废话。我的框架是一个词:判断力密度。
不同任务对"每token推理深度"的要求差异巨大:
- 写一段CRUD代码:模式匹配为主,判断力密度低,Sonnet绰绰有余。
- 决定系统该不该有缓存层:涉及权衡和预测,判断力密度高,必须Opus。
- 从一段文本里提取5个字段:几乎不需要推理,判断力密度极低,Haiku就够。
用高判断力密度的模型干低密度任务,是拿茅台炒菜——钱花在了模型的推理能力上,而那部分能力根本没被用到。反过来,用低密度模型干高密度任务,是拿92号汽油跑F1——省了钱,质量崩了。
所以分层的正确问题不是"哪件事重要",而是"哪件事需要每token推理深度"。按这个标准,我把典型图节点分成三档:
| 节点类型 | 判断力密度 | 推荐模型 | 典型节点 |
|---|---|---|---|
| 决策/裁决/架构 | 高 | Opus | 需求拆解、契约设计、仲裁、对抗审查 |
| 执行/生成/转换 | 中 | Sonnet | 写代码、写文档、格式转换、数据分析 |
| 路由/提取/分类 | 低 | Haiku | 意图识别、字段抽取、结果分类、摘要 |
再补一刀:同一个节点在不同阶段密度也不同。比如"代码生成"整体是中密度,但如果生成的代码里有个算法选型的决策点,就该先用Opus出方案、再用Sonnet落实现。这就是"决策与执行分离",本质上是把一个混合密度节点拆成两个纯密度节点。
三层模型分工:Opus决策、Sonnet执行、Haiku路由
把上一节的Diamond按这个框架重排一遍,得到完整的模型分层版编排脚本:
// workflows/layer-gen-tiered.js —— 带完整模型分层的 Diamondexportdefaultasyncfunctionrun(ctx){// 【决策层 Opus】需求拆解:错则全盘返工,值得用最强模型constplan=awaitagent(`拆解需求为三层并定义接口契约,输出 JSON:${ctx.input}`,{model:"opus",role:"architect",output:"json"});// 【路由层 Haiku】快速判断各层复杂度,决定是否需要升级模型constcomplexity=awaitagent(`判断以下三个模块各自的实现复杂度(simple|complex),输出 JSON: {"data":"...","service":"...","api":"..."} 契约:${JSON.stringify(plan)}`,{model:"haiku",role:"router",output:"json"},);// 【执行层 Sonnet/Haiku 动态分派】简单层降级,复杂层保级constpick=(level)=>(level==="complex"?"sonnet":"haiku");constlayers=awaitparallel([agent(`实现数据层:${plan.data_api}`,{model:pick(complexity.data),role:"data-engineer",output:"file"}),agent(`实现服务层:${plan.service_api}`,{model:pick(complexity.service),role:"backend-engineer",output:"file"}),agent(`实现接口层:${plan.http_api}`,{model:pick(complexity.api),role:"api-engineer",output:"file"}),]);// 【裁决层 Opus】全局对抗审查 + 仲裁constvalid=layers.filter(Boolean);constreview=awaitagent(`你是独立架构评审员,任务是挑刺。审查三层代码接口一致性,输出 JSON: {"verdict":"pass|reject","defects":[...]} 代码:${valid.join("\n=====\n")}`,{model:"opus",role:"adversarial-reviewer",output:"json"},);return{plan,complexity,review};}控制台输出:
$ claude workflow run workflows/layer-gen-tiered.js --input "实现一个带缓存的用户查询服务" [architect] 拆解完成(opus,输入1240 tok / 输出890 tok) [router] 复杂度判定:data=simple service=complex api=simple(haiku,耗时2.1s) [workflow] 动态分派:data→haiku service→sonnet api→haiku [data-engineer] 完成(haiku,54行,11.3s) [backend-engineer] 完成(sonnet,96行,28.7s) [api-engineer] 完成(haiku,41行,9.8s) [adversarial-reviewer] verdict=pass,defects 1 项(low) [workflow] 执行完成,总耗时 51.4s === 本次调用统计 === 模型调用 6 次:opus×2 sonnet×1 haiku×3 估算成本:$0.19(未分层基线 $0.42,节省 54.8%)看到了吗,路由节点(Haiku,2.1秒)花的那点小钱,直接把两个执行节点的成本砍半。这就是"用便宜模型决定贵模型干什么活"的杠杆效应。
CLAUDE_CODE_SUBAGENT_MODEL与配置实战
说说落地配置。Claude Code里子Agent的默认模型由环境变量CLAUDE_CODE_SUBAGENT_MODEL控制,命令行和编排脚本里逐节点的model选项优先级更高。优先级链是:
节点级 model 选项 > CLAUDE_CODE_SUBAGENT_MODEL > 主会话模型我的标准配置(写进项目的.claude/settings.json和CI环境变量):
# .envrc 或 CI 环境变量# 子Agent默认用 Sonnet:执行类节点占大头,性价比最优exportCLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-4-5# 成本熔断:单次 workflow 调用预算上限(美元),防止失控循环烧钱exportCLAUDE_CODE_WORKFLOW_BUDGET_USD=2.0# 并发上限:避免 fan-out 过宽触发限流exportCLAUDE_CODE_MAX_PARALLEL=4踩过的坑说两个。第一,别把CLAUDE_CODE_SUBAGENT_MODEL设成opus。我见过有团队图省事全量上opus,结果一个中等复杂度的workflow跑出两位数美元,而质量提升肉眼看不出来。默认模型应该是Sonnet,opus只在节点级显式指定。
第二,并发上限别裸奔。parallel里挂10个Agent看起来很爽,实际会撞API限流,失败位变多,filter(Boolean)之后剩一半结果,反而拖慢整体。我的经验是并发4是个甜点位,超过8收益递减、失败率上升。
另外提一句跨框架的一致性:如果你在Python侧也调Claude API做混合编排,同样的分层原则适用——我习惯用pydantic定义每个节点的输出Schema做运行时校验,路由节点解析失败直接降级到Sonnet重试,防止Haiku的JSON抽风把脏数据流进下游。
成本优化数据:一份真实账单的拆解
光说不练假把式。这是我参与的一个真实项目:一个每天跑200次的PR审查+重构建议workflow,改造前全量Sonnet(决策节点也是Sonnet),改造后按三层分层。一个月(22个工作日)的数据:
| 指标 | 改造前(全Sonnet) | 改造后(三层分层) | 变化 |
|---|---|---|---|
| 月调用次数 | 26,400 | 27,200(多了路由调用) | +3% |
| 月成本 | $4,210 | $1,603 | -62% |
| 平均单次耗时 | 74s | 61s(便宜模型更快) | -18% |
| 审查问题召回率 | 91% | 93%(裁决换Opus) | +2pp |
| 误报率 | 12% | 7%(对抗审查更严) | -5pp |
两个反直觉的点:
- 调用次数变多了,成本反而降了62%。多出来的路由调用用Haiku,成本忽略不计,但让60%的执行节点降级成了Haiku。
- 质量不降反升。因为分层把省下的预算投给了Verifier——裁决节点从Sonnet升级到Opus。所以模型分层不是单纯省钱,是预算再分配:把钱从低密度节点挪到高密度节点。
从"长度与耗时"的关系看也有收获:Haiku的执行节点平均输出token数和Sonnet差不多,但耗时只有Sonnet的40%——生成类任务里模型速度差异比token成本差异更影响总时长。这也是为什么分层后端到端延迟降了18%。
小结
这一节把Diamond的智力配置做对了:
- 验证模式三原则:独立上下文、角色对抗、裁决者更强;Verifier工具集要收窄到只读。
- 验证点1(契约)和3(全局)必做,验证点2可选——在最早的位置拦截错误最省钱。
- 模型分层的第一性原理是判断力密度,不是任务重要性:Opus管决策裁决、Sonnet管执行生成、Haiku管路由提取。
- 路由节点是杠杆:花Haiku的2秒钟,决定哪些执行节点可以降级,实测成本降62%、质量还微升。
下节预告
说到Claude Code里的图应用,有一个绕不开的"镇宅之宝"——/deep-research。它是Anthropic官方内置的深度研究系统,是目前公开可见的最完整的Graph工程落地之一。下一节我把它的五个阶段(Scope → Parallel Search → Fetch → Adversarial Verify → Synthesize)逐层拆开,看它的图拓扑、状态管理和并行策略是怎么设计的。这节含金量极高,建议先收藏。
互动区
你们给Verifier的prompt是怎么写的?有没有遇到过"验证者太宽容,什么都给pass"的问题?我怀疑对抗性prompt的质量比模型选择影响更大,想收集一批案例验证这个猜想。
如果觉得本文对你有帮助,欢迎点赞、收藏、关注三连!
本系列持续更新中,关注不迷路~