Weave Anthropic harness essay into s16 teaching spine

Ground the progressive chapter in why custom harnesses exist, the three
single-window failure modes, dynamic vs static, tasteful patterns, when
not to use workflows, and sharp neighbors (s06/s13/s15/s17).

Co-authored-by: Xinlu Lai <CrazyBoyM@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-08-12 13:47:06 +00:00
parent e28bec6dd4
commit bab23aabf7
No known key found for this signature in database
3 changed files with 191 additions and 53 deletions

View file

@ -7,6 +7,8 @@ s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](..
> *「ターンごとのチャットは、10 秒ごとにシェフへメールするようなものです。Workflow は厨房が従えるレシピです。」*
>
> **Harness 層**: Orchestration — single-agent loop の上で multi-agent script を実行します。
>
> モデルを信頼し、harness をエンジニアリングする。Workflow は orchestration 層での harness 設計です。
---
@ -14,38 +16,50 @@ s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](..
ふつうの「モデルが指揮者」な会話も同じです。**Workflow** は書かれたレシピです。厨房runtimeがそれに従い、助手subagentが判断し、途中の器はカウンターに置かれます —— グループチャットの中ではありません。
## 問題
## そもそも harness は何のため?
s01 から s15 まで、各ラウンドでモデルが次の tool を選びます。直前の発見で次の道が変わるタスクには向いています。
デフォルトの Claude Code harness は、コーディング型の仕事に強いです。直す、走らせる、エラーを読む、また試す —— すべて同じループの中です。
一方、形が先に分かっている仕事もあります。
ある種の仕事には、その上に**定制の harness** が要ります。深い調査、セキュリティ分析、agent teams、大規模な code review。SDK でその harness を先に手書きしてもよいです。あるいは —— ここが dynamic の発想ですが —— Claude に**このタスク用の harness をその場で書かせ**、走らせ、良いものを保存できます。
- 複数の観点で多くのファイルを review する
- 調査 → 検証 → 統合
- N 個のモジュールを同じやり方で移行する
コースのモットーを一段上げるとこうなります。各ステップの中ではモデルを信頼する。ステップ同士の構造はエンジニアリングで決める。
計画を `messages[]` の中だけで「覚えている」と、三つのことが起きます。orchestration の雑音で context が埋まる、途中で計画がずれる、落ちたら完了済みの作業までやり直す。
## 問題: ひとつの窓、三つの失敗
必要なのは並行性、安定した結果の形、そして再開です。会話履歴だけにそれを預けるのは弱いです。
s01 から s15 まで、モデルは**同じ** context の中で計画と実行をします。直前の発見で次が決まるタスクには向いています。長く、大規模に並行し、硬い構造が要り、あるいは敵対的な検証が要る仕事では脆くなります。
Claude Code の設計者は、その単一ウィンドウで起きやすい三つの失敗に名前を付けています。平たい言葉では:
| 失敗モード | どんな感じか |
|------------|--------------|
| **Agentic laziness途中で切り上げ** | 50 項目の review のうち 35 で「完了」と言う |
| **Self-preferential bias自己びいき** | 自分の発見を自分で採点すると甘くなる —— 狐が鶏小屋を採点する |
| **Goal drift目標の漂流** | もともとの「X には触るな」が多ターンと圧縮のあいだに薄れる |
会話履歴は、並行性・安定した結果の形・再開の三つを同時に預ける場所としても弱いです。多くのファイルを review する、調査してから検証する、N 個のモジュールを同じやり方で移す —— こうした仕事は**形が先に分かっている**ので、なおさらその三つが要ります。
## 一息でいうアイデア
**計画をコードへ移します。** Subagent は相変わらず判断します。script がループ、扇状の分配、マージを持ちます。中間結果は変数にあり、会話には入りません。
**オーケストレーションを「賢さ」から「構造」へ移します。**
Subagent は相変わらず判断します —— それぞれきれいな context と、焦点の定まった仕事で。**script** がループ、扇状の分配、マージを持ちます。中間結果は変数(と journalにあり、会話には入りません。分かれた助手 + script が握る制御フローが、laziness・自己チェックの偏り・drift への対抗策です。
![Workflow Runtime Overview](images/workflow-runtime-overview.svg)
1 回の `Workflow` tool call が、その script 実行を始めます。実行中に lifecycle / progress event が出て、最後に launch 情報・result・task state を含む tool result が返ります。
## ふたつの入口
## ふたつの入口 — dynamic と static
Claude Code は、workflow の始め方について正直です。
Claude Code は同じ厨房への入口を二つ開いています。
| 入口 | 渡すもの | いつ使うか |
|------|----------|------------|
| **Dynamic** | オーケストレーション用の JavaScript`script`、あとから `scriptPath` | モデルが**このタスク用**にレシピを書く |
| **Saved** | `name` + `args` | 良いレシピを例えば `.claude/workflows/` に保存し、名前で再実行する |
厨房は同じです。Dynamic は「今レシピを書く」、Saved は「カード箱から引く」です。
厨房は同じです。Dynamic は「今レシピを書く」、Saved は「カード箱から引く」—— 良い dynamic run の残した、再利用できる残りです。
このレッスンの外にはいとこもあります。**static** harnessあらかじめ書く Agent SDK / `claude -p` の编排です。static はあらゆるエッジケース向けなので、どうしても汎用になります。dynamic は*この*タスク向けの特注です。形が合ったら saved にします。
**このレッスンは Python の teaching runtime です。** 同じアイデアを、1 行ずつ読める形で示します。デモは名前で saved workflow を登録します。概念は Claude Code の script 世界と 1:1 です。「モデルは実行可能コードを渡せない」と Claude Code について主張するのは誤りでした。ここでは単に、完全な JS インタプリタを埋め込まないだけです。
@ -90,6 +104,18 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]]
```
## 味のあるパターン(一覧の投げ売りではない)
パターンはレシピのスタイルだと思ってください。サンプル `review-changes` が頼るのは主に三つです。
| パターン | 平たい意味 | サンプルでは |
|----------|------------|--------------|
| **Fan-out-and-synthesize** | 仕事を分け、きれいな机で進め、あとでまとめる | 4 つの dimension が `pipeline` で audit し、確認リストへ |
| **Adversarial verification** | 別の助手が前の成果をあえて疑う | 各 finding が verify agent を通ってから残る |
| **Generate-and-filter** | 候補を出し、検査を通ったものだけ残す | findings 入り → `isReal` だけ出し |
同じ道具箱には、あとで出会うスタイルもあります。**classify-and-act**(種類で振り分け)、**tournament**(競わせて勝者を選ぶ)、**loop-until-done**(新しいものがなくなるまで回す)。コストに見合う、より明確で安全な結果が取れるときだけ使います。
## 答えを機械が読める形に
助手が散文で返してくると、次の stage は finding と verdict を reliably に対応づけられません。`schema` を渡します。runtime は JSON を求め、検証し、だめなら**1 回だけ**再試行します。それでもだめならその call はエラーになります(下の null 分離を参照)。
@ -142,7 +168,7 @@ resume: A hit → B hit → C 変更 → D は live古い D への silent h
## サンプルを歩く: `review-changes`
4 つの review dimension が同じ 2 段階の道を通ります。
4 つの review dimension が同じ 2 段階の道を通ります —— fan-out、敵対的 verify、filter
```text
correctness ── audit ── verify ──┐
@ -151,8 +177,8 @@ performance ── audit ── verify ──┤
style ── audit ── verify ──┘
```
1. **Review** — 各 dimension の auditor が構造化 findings を返します。
2. **Verify** — 各 finding を敵対的チェッカーへverify stage 内で `parallel`)。
1. **Review** — 各 dimension の auditor が構造化 findings を返します(きれいな机 → 混線が減る)
2. **Verify** — 各 finding を敵対的チェッカーへverify stage 内で `parallel`)。書いた本人が審判を兼ねない。
3. 本物とされたものだけ残し、severity で並べます。
```python
@ -177,6 +203,26 @@ s15 は依然として host loop です。s16 が足すのは一つの tool、`W
main loop が workflow エンジンになるわけではありません。`bash``task` を借りるのと同じく、tool をひとつ借ります。
## 近所: 計画を握っているのは誰か
Workflow は「agent を増やす」ことではありません。**トポロジーを誰が持つか**を変えます。
| 近所 | 計画を握るもの | 中間結果の置き場 | 向いている用途 |
|------|----------------|------------------|----------------|
| [s06 Subagent](../s06_subagent/) | モデル、一度きり | 最終 summary 以外は捨てる | 汚い子タスクを隔離 |
| [s13 Agent Teams](../s13_agent_teams/) | Lead モデルがターンごと + mailbox | 共有タスク / メッセージ | 長時間の同僚、人間らしい協働 |
| [s15 Integrated Harness](../s15_integrated_harness/) | 一つのループ内のモデル | 会話 `messages[]` | 積み上げ型の coding agent |
| **s16 Workflow** | **Script** | **Script 変数 + journal** | 既知 / 大規模な構造化 fan-out + verify |
| [s17 Goal Loop](../s17_goal_loop/) | 停止境界の evaluator | 会話を証拠にする | 「ゴール全体は終わったか?」 |
より安い代替もしばしば勝ちます。skill / prompt を軟らかい計画にする、短い multi-agent チャット、手書きの static SDK orchestrator、あるいは単に大きな一回のモデルターン。単一 context より長く構造を保ちたいときに workflow へ手を伸ばします —— 審査員パネルが聞こえがいいからではありません。
## Workflow を*使わない*とき
Workflow は token と調整コストがかかります。ふつうのコーディングの大半は、5 人の reviewer パネルを**必要としません**。
聞いてください。この仕事は本当にもっと計算と定制 harness が要るか? ふつうの s15 の一ターン(や一つの s06 subagentで足りるなら、そこで止めます。抑制も設計思想の一部です —— 並行と専門化は、そのコストを回収しなければなりません。
## 試してみる
```bash
@ -202,6 +248,6 @@ python s16_workflow_runtime/code.py resume # 同じ runId。prefix はすべ
**s16 = バッチの回し方。s17 = ゴール全体が終わったかどうか。**
[s17 Goal Loop](../s17_goal_loop/) は独立した評価器に聞きます。止めるべきか、もう一ターンか。
[s17 Goal Loop](../s17_goal_loop/) は独立した評価器に聞きます。止めるべきか、もう一ターンか。繰り返せる workflow に硬い完了条件も要るときは、そちらと組み合わせます。
<!-- translation-sync: zh@v11, en@v11, ja@v11 -->
<!-- translation-sync: zh@v12, en@v12, ja@v12 -->

View file

@ -7,6 +7,8 @@ s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](..
> *"Chatting turn-by-turn is like texting the chef every ten seconds. A workflow is a recipe the kitchen can follow."*
>
> **Harness layer**: Orchestration — run a multi-agent script above the single-agent loop.
>
> Trust the model; engineer the harness. Workflows are harness engineering at the orchestration layer.
---
@ -14,40 +16,52 @@ Imagine you are cooking with a friend over text. You send “chop the onions,”
That is ordinary model-as-orchestrator chatting. A **workflow** is the written recipe: the kitchen (runtime) follows it, helpers (subagents) do judgment, and intermediate bowls sit on the counter — not in the group chat.
## The problem
## Why a harness at all?
From s01 through s15, the model picks the next tool each round. That shines when the path depends on what you just discovered.
The default Claude Code harness is excellent at coding-shaped work: edit, run, read the error, try again — all in one loop.
Some jobs already know their shape:
Some jobs need a **custom harness on top**: deep research, security analysis, agent teams, large code review. You could hand-write that harness once in an SDK. Or — and this is the dynamic idea — Claude can **write a harness for this task on the fly**, run it, and optionally save the good ones.
- review many files on several dimensions
- research, then verify, then merge
- migrate N modules the same way
Course motto, one layer up: trust the model inside each step; engineer the structure around the steps.
If the model keeps “remembering” the plan inside `messages[]`, three things go wrong: context fills with orchestration noise, the plan drifts mid-run, and a crash means redoing finished work.
## The problem: one window, three ways to fail
You want parallelism, stable result shapes, and a way to resume. Chat history is a weak place to store all three.
From s01 through s15, the model plans and executes in the **same** context. Great when the next move depends on what you just found. Weak when the job is long, massively parallel, rigidly structured, or adversarial.
Claude Codes designers name three failure modes that show up in that single window. In plain language:
| Failure mode | What it feels like |
|--------------|--------------------|
| **Agentic laziness** | Stops halfway through a fifty-item review and says “done” after thirty-five |
| **Self-preferential bias** | Likes its own findings when asked to check itself — the fox grading the henhouse |
| **Goal drift** | The original “dont touch X” fades across many turns and compressions |
Chat history is also a weak place to store parallelism, stable result shapes, and resume. You need those for review-many-files, research-then-verify, migrate-N-modules — jobs whose **shape** is already known.
## The idea in one breath
**Move the plan into code.** Subagents still think. The script owns loops, fan-out, and merge. Intermediate results live in variables, not in the conversation.
**Move orchestration from intelligence to structure.**
Subagents still think — each in a clean context with a focused job. The **script** owns loops, fan-out, and merge. Intermediate results live in variables (and a journal), not in the conversation. Separate helpers + script-owned control flow is how you fight laziness, self-checking bias, and drift.
![Workflow Runtime Overview](images/workflow-runtime-overview.svg)
One `Workflow` tool call starts that scripted run. Lifecycle and progress events fire while it works; one tool result comes back with launch info, the result, and task state.
## Two doors into a workflow
## Two doors — and dynamic vs static
Claude Code is honest about how a workflow starts:
Claude Code opens two doors into the same kitchen:
| Door | What you pass | When |
|------|----------------|------|
| **Dynamic** | A JavaScript orchestration script (`script`, or later `scriptPath`) | The model writes a recipe for *this* task |
| **Saved** | `name` + `args` | A good recipe lives under e.g. `.claude/workflows/` and you rerun it |
Same kitchen either way. Dynamic is “write the recipe now.” Saved is “pull the card from the box.
Same kitchen. Dynamic is “write the recipe now.” Saved is “pull the card from the box” — the reusable residue of a good dynamic run.
**This lesson is a Python teaching runtime.** It shows the same ideas so you can read every line. Our demo registers a saved workflow by name; the concepts map 1:1 to Claude Codes script world. We do **not** claim “the model cannot submit executable code” — that was wrong for Claude Code. We simply skip embedding a full JS interpreter here.
There is also a cousin outside this lesson: **static** harnesses (Agent SDK / `claude -p` orchestrations you write ahead of time). Static ones must work for every edge case, so they stay generic. Dynamic ones are tailor-made for *this* task; save them when the cut fits well.
**This lesson is a Python teaching runtime.** Same ideas, every line readable. Our demo registers a saved workflow by name; concepts map 1:1 to Claude Codes script world. We do **not** claim “the model cannot submit executable code” — that was wrong for Claude Code. We simply skip embedding a full JS interpreter here.
```python
# Teaching adapter: saved door (name + args).
@ -90,6 +104,18 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]]
```
## Patterns with taste (not a laundry list)
Think of patterns as recipe styles. Our sample `review-changes` leans on three:
| Pattern | Plain meaning | In the sample |
|---------|---------------|---------------|
| **Fan-out-and-synthesize** | Split the work, give each piece a clean desk, then merge | Four dimensions audit in a `pipeline`, then one confirmed list |
| **Adversarial verification** | A second helper tries to knock the first ones work down | Each finding faces a verify agent before it counts |
| **Generate-and-filter** | Produce candidates, keep only what survives a test | Findings in → only `isReal` out |
Same toolbox, other styles you will meet later: **classify-and-act** (route by type), **tournament** (compete, then pick a winner), **loop-until-done** (keep going until nothing new appears). Use a pattern only when its cost earns a clearer or safer result.
## Make answers machine-readable
If a helper returns a poem, the next stage cannot reliably zip findings to verdicts. Pass a `schema`: the runtime asks for JSON, validates it, and retries **once**. Fail again and that call errors (see null-isolation below).
@ -142,7 +168,7 @@ resume: A hit → B hit → C changed → D runs live (no silent hit on old D)
## Walk the sample: `review-changes`
Four review dimensions walk the same two-stage path:
Four review dimensions walk the same two-stage path — fan-out, then adversarial verify, then filter:
```text
correctness ── audit ── verify ──┐
@ -151,8 +177,8 @@ performance ── audit ── verify ──┤
style ── audit ── verify ──┘
```
1. **Review** — each dimensions auditor returns structured findings.
2. **Verify** — each finding gets an adversarial checker (`parallel` inside the verify stage).
1. **Review** — each dimensions auditor returns structured findings (clean desks → less cross-contamination).
2. **Verify** — each finding gets an adversarial checker (`parallel` inside the verify stage) so the author is not also the judge.
3. Keep only findings marked real; sort by severity.
```python
@ -177,6 +203,26 @@ s15 is still the host loop. s16 adds one tool: `Workflow`. The model (or you) as
The main loop does not become a workflow engine. It borrows one tool, the way it borrows `bash` or `task`.
## Neighbors: who holds the plan?
Workflows are not “more agents.” They change **who owns the topology**.
| Neighbor | Who holds the plan | Where intermediate results live | Best for |
|----------|--------------------|---------------------------------|----------|
| [s06 Subagent](../s06_subagent/) | Model, one-shot | Discarded except final summary | Isolate one dirty subtask |
| [s13 Agent Teams](../s13_agent_teams/) | Lead model turn-by-turn + mailbox | Shared tasks / messages | Long-running peers, human-like collaboration |
| [s15 Integrated Harness](../s15_integrated_harness/) | Model in one loop | Conversation `messages[]` | Cumulative coding agent |
| **s16 Workflow** | **Script** | **Script variables + journal** | Known / large structured fan-out + verify |
| [s17 Goal Loop](../s17_goal_loop/) | Evaluator at the stop boundary | Conversation as evidence | “Is the whole goal done?” |
Cheaper alternatives still win often: a skill or prompt as a soft plan, a short multi-agent chat, a hand-written static SDK orchestrator, or simply one bigger model turn. Reach for a workflow when structure must outlast a single context — not because panels sound impressive.
## When *not* to use a workflow
Workflows cost tokens and coordination. Most ordinary coding does **not** need a panel of five reviewers.
Ask: does this job really need more compute and a custom harness? If a normal s15 turn (or one s06 subagent) is enough, stop there. Restraint is part of the design thought — parallelism and specialization have to earn their keep.
## Try it
```bash
@ -202,6 +248,6 @@ What to watch for:
**s16 = how a batch runs. s17 = whether the whole goal is done.**
[s17 Goal Loop](../s17_goal_loop/) asks an independent evaluator: should we stop, or take another turn?
[s17 Goal Loop](../s17_goal_loop/) asks an independent evaluator: should we stop, or take another turn? Pair them when a repeatable workflow also needs a hard completion check.
<!-- translation-sync: zh@v11, en@v11, ja@v11 -->
<!-- translation-sync: zh@v12, en@v12, ja@v12 -->

View file

@ -7,6 +7,8 @@ s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](..
> *“一轮轮聊天像每隔十秒给厨师发一条短信。Workflow 是厨房能照着做的菜谱。”*
>
> **Harness 层**: 编排 — 在单 agent 循环之上,跑一套多 agent 脚本。
>
> 信任模型,工程化 harness。Workflow 就是编排层上的 harness 工程。
---
@ -14,40 +16,52 @@ s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](..
普通“模型当总指挥”的对话就是这样。**Workflow** 是写好的菜谱厨房runtime按谱做帮手子 agent负责判断中间结果放在台面上的碗里 —— 不塞进群聊记录。
## 问题在哪
## 为什么需要 harness
从 s01 到 s15每一轮都由模型决定下一步调用什么工具。当“下一步取决于刚才发现了什么”时这很合适
默认的 Claude Code harness 很擅长“写代码那种形状”的工作:改、跑、看报错、再试 —— 都在同一个循环里
有些任务的形状事先就知道:
有些活需要**叠一层定制 harness**深度调研、安全分析、agent teams、大规模 code review。你可以事先用 SDK 手写那层 harness也可以 —— 这就是动态的想法 —— 让 Claude **为这次任务现场写一个 harness**,跑完,好用的再存下来。
- 按多个维度审查很多文件
- 先调研,再验证,再合并
- 用同一种方式迁移 N 个模块
课程的口号往上提一层:每一步里信任模型;步骤之间的结构,靠工程来定。
如果模型只能把计划“记”在 `messages[]` 里,会发生三件事:编排噪音占满上下文、中途计划漂移、崩了就得把做完的活重做一遍。
## 问题:一个窗口,三种走偏
你需要并行、稳定的结果形状,以及能续跑。把这三样只寄存在对话历史里,太脆弱。
从 s01 到 s15模型在**同一个**上下文里既规划又执行。当“下一步取决于刚才发现了什么”时,这很合适。当任务又长、又要大规模并行、又要求死板结构、或需要对抗验证时,就会变脆。
Claude Code 的设计者给单窗口里常见的三种失败起了名字。用大白话说:
| 失败模式 | 感觉起来像什么 |
|----------|----------------|
| **Agentic laziness偷懒收工** | 五十项审查做到三十五,就说“做完了” |
| **Self-preferential bias自我偏爱** | 让它检查自己的结论时,总觉得自己更对 —— 狐狸给鸡窝打分 |
| **Goal drift目标漂移** | 原来的“别动 X”在多轮对话和压缩之后渐渐淡掉 |
对话历史也很难同时扛住并行、稳定的结果形状、以及续跑。审查很多文件、先调研再验证、按同一方式迁移 N 个模块 —— 这些活的**形状**事先就知道,更需要那三样。
## 一句话说清想法
**把计划写进代码。** 子 agent 仍然负责判断;脚本负责循环、分发和合并。中间结果存在变量里,不进对话。
**把编排从“靠聪明”挪到“靠结构”。**
子 agent 仍然负责判断 —— 各自干净的上下文、专注的目标。**脚本**负责循环、分发和合并。中间结果存在变量(和 journal不进对话。分开的帮手 + 脚本掌握的控制流,就是对抗偷懒、自我检查偏差和漂移的办法。
![Workflow Runtime 总览](images/workflow-runtime-overview.svg)
一次 `Workflow` 工具调用启动这次脚本运行。运行中会发出生命周期和进度事件;最后一条工具结果带回启动信息、结果和任务状态。
## 两扇门
## 两扇门 — 以及动态 vs 静态
Claude Code 对“工作流怎么启动”是诚实的
Claude Code 用两扇门走进同一间厨房
| 门 | 你传什么 | 什么时候用 |
|----|----------|------------|
| **动态Dynamic** | 一段编排用的 JavaScript`script`,或之后的 `scriptPath` | 模型为**这次任务**现写菜谱 |
| **已保存Saved** | `name` + `args` | 好用的菜谱放进例如 `.claude/workflows/`,按名字再跑 |
同一间厨房。动态是“现在写菜谱”,已保存是“从卡片盒里抽一张”
同一间厨房。动态是“现在写菜谱”;已保存是“从卡片盒里抽一张”—— 一次漂亮动态运行留下来的可复用残渣
**本课是一个 Python 教学运行时。** 用同样的想法,但每行你都能读懂。演示按名字注册一个已保存的 workflow概念和 Claude Code 的脚本世界一一对应。我们**不会**再说“模型不能提交可执行代码”——那是对 Claude Code 的误述。这里只是不嵌入完整的 JS 解释器。
本课之外还有表亲:**静态** harness事先写好的 Agent SDK / `claude -p` 编排)。静态的要覆盖所有边角,所以往往更泛用。动态的是为*这次*任务量身定做;合身了再存成 saved。
**本课是一个 Python 教学运行时。** 同样的想法,每行你都能读懂。演示按名字注册一个已保存的 workflow概念和 Claude Code 的脚本世界一一对应。我们**不会**再说“模型不能提交可执行代码”——那是对 Claude Code 的误述。这里只是不嵌入完整的 JS 解释器。
```python
# 教学适配器已保存这扇门name + args
@ -90,6 +104,18 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]]
```
## 有品味的模式(不是清单倾销)
把模式想成菜谱风格。示例 `review-changes` 主要用了三种:
| 模式 | 大白话 | 在示例里 |
|------|--------|----------|
| **Fan-out-and-synthesize分发再汇总** | 拆开干,每人一张干净桌子,再合并 | 四个维度在 `pipeline` 里审计,最后合成确认列表 |
| **Adversarial verification对抗验证** | 第二个帮手专门来挑刺 | 每条 finding 先过 verify agent 才作数 |
| **Generate-and-filter生成再过滤** | 先产出候选,只留通过检验的 | findings 进来 → 只留 `isReal` |
同一工具箱里还有别的风格,以后会遇到:**classify-and-act**(按类型分流)、**tournament**(比武再选冠军)、**loop-until-done**(直到没有新发现再停)。只有当额外成本能换来更清楚或更稳妥的结果时,才上模式。
## 让答案机器能读
如果帮手回来写散文,下一阶段就很难把 finding 和 verdict 一一对应。传入 `schema`:运行时要求 JSON、做校验不对就**重试一次**。再不对,这次调用报错(见下面的空值隔离)。
@ -142,7 +168,7 @@ journal: [A ✓] [B ✓] [C ✓] [D ✓]
## 跟着示例走:`review-changes`
四个审查维度走同一条两阶段路径:
四个审查维度走同一条两阶段路径 —— 先分发,再对抗验证,再过滤
```text
correctness ── 审计 ── 验证 ──┐
@ -151,8 +177,8 @@ performance ── 审计 ── 验证 ──┤
style ── 审计 ── 验证 ──┘
```
1. **Review** — 每个维度的审计员返回结构化 findings。
2. **Verify** — 每条 finding 交给对抗性检查(在 verify 阶段里用 `parallel`)。
1. **Review** — 每个维度的审计员返回结构化 findings(干净桌子 → 少串味)
2. **Verify** — 每条 finding 交给对抗性检查(在 verify 阶段里用 `parallel`,作者不当裁判
3. 只保留被标成真实的问题,再按严重程度排序。
```python
@ -177,6 +203,26 @@ s15 仍是宿主循环。s16 只多一个工具:`Workflow`。模型(或你
主循环不会变成 workflow 引擎。它只是多借一把工具,就像借 `bash``task` 一样。
## 邻居们:谁握着计划?
Workflow 不是“多派几个 agent”。它改的是**谁拥有拓扑结构**。
| 邻居 | 谁握着计划 | 中间结果住哪 | 最适合 |
|------|------------|--------------|--------|
| [s06 子 Agent](../s06_subagent/) | 模型,一次性 | 除最终摘要外丢掉 | 隔离一个脏的子任务 |
| [s13 Agent Teams](../s13_agent_teams/) | Lead 模型逐轮 + 邮箱 | 共享任务 / 消息 | 长跑同伴、偏人类协作 |
| [s15 Agent Harness 集成](../s15_integrated_harness/) | 模型在一个循环里 | 对话 `messages[]` | 累积型 coding agent |
| **s16 Workflow** | **脚本** | **脚本变量 + journal** | 已知 / 大规模结构化分发 + 验证 |
| [s17 Goal Loop](../s17_goal_loop/) | 停止边界上的判断器 | 对话当证据 | “整个目标做完了吗?” |
更便宜的替代方案经常就够用skill / prompt 当软计划、一小段多 agent 闲聊、手写静态 SDK 编排,或者干脆更大的单轮模型调用。当结构必须比单个上下文活得更久时,再伸手去拿 workflow —— 不是因为“专家团”听起来很酷。
## 什么时候*别*用 workflow
Workflow 要花 token也有协调成本。大多数普通写代码的活**不需要**五人评审团。
问问自己:这件事真的需要更多算力和定制 harness 吗?如果普通的 s15 一轮(或一个 s06 子 agent就够就停在那儿。克制也是设计思想的一部分 —— 并行和分工必须赚回自己的成本。
## 试一下
```bash
@ -202,6 +248,6 @@ python s16_workflow_runtime/code.py resume # 同一个 runId前缀应全部
**s16 = 一批活怎么跑。s17 = 整个目标算不算做完。**
[s17 Goal Loop](../s17_goal_loop/) 会问一个独立判断器:该停,还是再来一轮?
[s17 Goal Loop](../s17_goal_loop/) 会问一个独立判断器:该停,还是再来一轮?可重复的 workflow 若还需要硬性完成条件,可以和它配对。
<!-- translation-sync: zh@v11, en@v11, ja@v11 -->
<!-- translation-sync: zh@v12, en@v12, ja@v12 -->