mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-09-21 21:03:38 +08:00
Cut s16 README mainline to March-style short skeleton
Compress ZH/EN/JA essay into problem → ASCII/figure → minimal code → try it. Move pattern grid, quarantine, primitives card, and overview SVG into details; bump translation-sync to v18. Co-authored-by: Xinlu Lai <CrazyBoyM@users.noreply.github.com>
This commit is contained in:
@@ -4,114 +4,78 @@
|
||||
|
||||
s01 → ... → s14 → [s15](../s15_integrated_harness/) → `s16` → [s17](../s17_goal_loop/)
|
||||
|
||||
> *「ターンごとのチャットは、10 秒ごとにシェフへメールするようなものです。Workflow は厨房が従えるレシピです。」*
|
||||
> Workflow = コードに書いたオーケストレーション。トポロジはスクリプト、一歩の判断はモデル。
|
||||
>
|
||||
> **Harness 層**: Orchestration — single-agent loop の上に multi-agent script を載せます。
|
||||
> **Harness 層**: オーケストレーション — 単一 agent ループの上で多 agent スクリプトを回す。
|
||||
>
|
||||
> モデルを信頼し、harness をエンジニアリングする。Workflow は、その考えを一階上げたものです。
|
||||
> モデルを信じ、harness を設計する。Workflow はその一言を一段上げる。
|
||||
|
||||
---
|
||||
|
||||
友だちとチャットだけで料理しているところを想像してください。「玉ねぎを切って」。待つ。「できた?」。次はフライパン、塩。一品ならそのリズムでも持ちます。二十卓の宴会では持ちません。手順は抜け、同じ言葉が返り、スマホが落ちたら冷たいところからやり直しです。
|
||||
## 問題
|
||||
|
||||
モデルがシェフとクリップボードを兼ねるときも、同じ感触です。計画と実行が一つの会話に押し込まれます。**Workflow** は書かれたレシピです。厨房(小さな runtime)がそれに従い、助手(subagent)が味見と判断をし、仕掛かりの器はカウンターに——変数と journal に——置かれます。グループスレッドの中ではありません。
|
||||
長い仕事では計画と実行が同じ chat に同居する:途中で完了宣言、自分の宿題を甘く採点、圧縮のあと静かな制約が消える。並列・安定した結果形・再開——柔らかい会話メモリでは支えきれない。
|
||||
|
||||
## なぜ、もう一枚の harness が要るのか
|
||||
十秒おきにシェフへ SMS を送るような催促。**Workflow** は厨房がそのまま従えるレシピだ。
|
||||
|
||||
デフォルトの Claude Code harness は、コーディング型の仕事にもう十分強いです。直す、走らせる、エラーを読む、また試す。一つのループ。一つの頭。かなりの手業が出ます。
|
||||
## アイデア
|
||||
|
||||
ただ、ある仕事にはその上に**定制の harness** が要ります。深い調査、セキュリティの洗い出し、agent teams、変更一式を広げて review するような仕事です。SDK で先に手書きしてもよい。あるいは——ここが生きているところですが——Claude に**このタスク用**の harness を書かせ、走らせ、良いものを残せます。
|
||||
ヘルパー(サブ agent)は考える。**スクリプト**がループ・分散・マージを握る。中間結果は変数と journal に置き、会話には入れない。
|
||||
|
||||
コースのモットーを一階上げると、こうなります。各ステップの中ではモデルを信頼する。ステップの並びは、自分で形を決める。
|
||||
|
||||
## 長いチャットが静かにやりがちなこと
|
||||
|
||||
s01 から s15 まで、計画と行動は同じ context window を共有します。次の一手が直前の発見に依るときは心地よいです。仕事が長く、大規模に並行し、硬い構造を求め、あるいは疑り深い第二意見が要ると、脆くなります。
|
||||
|
||||
長いチャットをじっと見ていると、用語を覚える前に癖に出会います。50 項目のうち 35 で勝利宣言をする。自分の宿題を採点させると甘くなる——狐が鶏小屋を採点する。多ターンと圧縮のあいだに、「X には触るな」が薄れていく。
|
||||
|
||||
それが agentic laziness、self-preferential bias、goal drift です。名前より感触が大事です。仕事をする窓が、計画を覚える窓でもある。柔らかい会話メモリは、並行性や安定した結果の形、再開を預けるには弱い場所です。
|
||||
|
||||
## アイデアが落ちる瞬間
|
||||
|
||||
もし計画がコードの中に住んだらどうでしょう。
|
||||
|
||||
助手は相変わらず考えます——きれいな机で。**script** がループと扇状の分配とマージを持ちます。中間結果は変数と journal にあり、会話には入りません。途中で切り上げる癖は艦隊を止めにくくなり、自己採点の甘さは著者ではない第二の助手にぶつかり、drift も掴みにくくなります。
|
||||
|
||||
**Workflow はオーケストレーションを「賢さ」から「構造」へ移します。** モデルは各 `agent()` の中で判断し、地図は script が持ちます。
|
||||
**オーケストレーションを「知性」から「構造」へ移す。**
|
||||
|
||||
```text
|
||||
messages[] ──► Workflow(...) ──► tool_result { launched, result, task }
|
||||
messages[] ──► Workflow(...) ──► tool_result
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ script が │
|
||||
│ topology を持つ│
|
||||
└───────┬───────┘
|
||||
│ agent / parallel / pipeline
|
||||
スクリプトが握る: agent / parallel / pipeline
|
||||
│
|
||||
▼
|
||||
変数 + journal
|
||||
```
|
||||
|
||||
1 回の `Workflow` tool call が、その実行を始めます。進み具合は途中で小さく鳴り、レシピが終わると一つの tool result が戻ります。
|
||||
`Workflow` ツール呼び出しひとつで開始;レシピが終わると結果がひとつ返る。
|
||||
|
||||
<details>
|
||||
<summary>Runtime 概要図(任意)</summary>
|
||||
<summary>Runtime 概要図</summary>
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
## ふたつの入口——そして外のいとこ
|
||||
## ふたつの入口
|
||||
|
||||
Claude Code は入口について率直です。
|
||||
- **Dynamic**: モデルが*この*タスク向けに JS オーケストレーションを書く(`script` / `scriptPath`)。
|
||||
- **Saved**: 良いスクリプトを `.claude/workflows/` に置き、`name` + `args` で再呼び出し。
|
||||
- **Static**(外のいとこ): SDK / `claude -p` で事前に書く——だいたい汎用寄り。
|
||||
|
||||
**Dynamic** — モデルが*この*タスク用の JavaScript オーケストレーションを書く(`script`、あとから `scriptPath`)。問題がまだ熱いうちに裁断する harness。
|
||||

|
||||
|
||||
**Saved** — 良い script がすでに `.claude/workflows/` のような場所にある。`name` + `args` で呼び出す。残すに値した run が、再利用できるカードになったものです。
|
||||
*左: 固定パイプライン → 汎用レポート。右: あなたのコード向けに裁断 → 具体的な提案。*
|
||||
|
||||
外にはいとこもあります。**static** harness を Agent SDK や `claude -p` で先に書くやり方です。あらゆるエッジケースに耐える必要があるので、どうしても汎用になります。dynamic はこの布のための裁断です。形が合ったら保存します。
|
||||
|
||||

|
||||
|
||||
*同じ問い、ふたつの harness。左: 固定の検索→検証→要約 → 汎用レポート。右: billing コードを読み、分岐し、devil's advocate を呼ぶ → 具体的な推奨。*
|
||||
|
||||
**この章は Python の teaching runtime です。** 同じアイデアを、1 行ずつ読める形で示します。デモは名前で一つの saved workflow を登録します。概念は Claude Code の script 世界と 1:1 です。「モデルは実行可能コードを渡せない」などと言いません——それは Claude Code については初めから正しくありませんでした。ここでは JS インタプリタを埋め込まないだけです。
|
||||
本章は **Python のティーチング runtime**(JS VM なし)。概念は Claude Code に揃え、デモは Saved 入口。製品ではモデルが実行可能スクリプトを出せる——ここでは JS インタプリタを埋め込まないだけ。
|
||||
|
||||
```python
|
||||
# teaching sketch — saved の入口(完全な Claude Code schema ではない)
|
||||
# teaching sketch — 完全な schema ではない
|
||||
Workflow({ "name": "review-changes", "args": { "changes": "..." } })
|
||||
|
||||
# Claude Code は他にも受け付ける: script | scriptPath | resumeFromRunId
|
||||
# Claude Code はさらに: script | scriptPath | resumeFromRunId
|
||||
```
|
||||
|
||||
## スクリプトが話す三つの動詞
|
||||
|
||||
学校のバザー。どのテーブルも 混ぜる → 焼く → 箱詰め。助手が味見をし、レシピが順番を決めます。
|
||||
## 三つの動詞
|
||||
|
||||
```text
|
||||
agent 助手ひとり、仕事ひとつ
|
||||
pipeline 各ケーキが自分で stage を歩く (既定 — barrier なし)
|
||||
parallel すべてのトレイが戻るまで待つ (barrier — 控えめに)
|
||||
agent ヘルパー一人、仕事ひとつ(schema で JSON 検証可)
|
||||
pipeline item ごとに段階を進む(既定 — 障壁なし)
|
||||
parallel 全部揃ってから次へ(障壁 — 控えめに)
|
||||
```
|
||||
|
||||
`agent(prompt, opts?)` は助手ひとりに頼みます。`schema` があれば検証済み JSON が返り——次の段が受け取れるソケットになり——最初が雑なら一回だけやり直せます。
|
||||
失敗しても艦隊は続く: `parallel` はそのスロットが `null`;`pipeline` は**その item** と後段を落とす。マージ前にフィルタ。
|
||||
|
||||
`pipeline` はケーキ A が箱詰めのあいだに、ケーキ B がまだ混ぜていてもよい形です。`parallel` は次の段が本当に全部の結果を要すときだけ——トレイ全部を味見してから採点表を書く、といった場面です。
|
||||
|
||||
```python
|
||||
# teaching sketch — 形だけ(実行可能な sample は code.py)
|
||||
results = await ctx.pipeline(DIMENSIONS, audit, verify)
|
||||
confirmed = [f for r in results if r for f in r["confirmed"]]
|
||||
```
|
||||
|
||||
助手が失敗しても艦隊は優しくいられます。`parallel` の失敗はそのスロットで `null`、`pipeline` の失敗は**その item** を落として残りの stage を飛ばします。マージの前に絞ります。
|
||||
|
||||
厨房が止まったら? disk 上の journal が*呼び出し順*で各 call を覚えます。resume は**最長の未変更プレフィックス**を再生し、最初の変更から先は live。本物の JS runtime は `Date.now()` / `Math.random()` を禁じてノートを揃えます。この Python デモはそのサンドボックスまではやりません——それでも script は決定的に書いてください。
|
||||
再開: journal は呼び出し順に記録;**最長の未変更プレフィックス**を再生し、最初の変更以降は実走。本物の JS runtime は `Date.now()` / `Math.random()` を禁じる。このデモは完全サンドボックスしない——それでも決定的に書く。
|
||||
|
||||
```text
|
||||
journal [A] [B] [C] [D]
|
||||
resume hit hit ✂ live ← プレフィックスは C で切れる
|
||||
journal [A] [B] [C] [D]
|
||||
resume hit hit ✂ live
|
||||
```
|
||||
|
||||
<details>
|
||||
@@ -119,157 +83,104 @@ confirmed = [f for r in results if r for f in r["confirmed"]]
|
||||
|
||||

|
||||
|
||||
*公式カード: `agent`、そして `parallel`(barrier)と `pipeline`(streaming stages)。Claude Code には `model` / `isolation` / `agentType` もあります。teaching runtime は表面を小さく保ちます。*
|
||||
*`agent`;`parallel`(障壁)vs `pipeline`(ストリーミング段階)。Claude Code には `model` / `isolation` / `agentType` もある;ティーチング面は小さめ。*
|
||||
|
||||
静かな動詞: `phase`、`log`、入れ子の `workflow`(1 段)、`args`、`budget`。
|
||||
静かな動詞: `phase`、`log`、ネスト一段 `workflow`、`args`、`budget`。
|
||||
|
||||
</details>
|
||||
|
||||
## レシピが書けるようになったら——パターンの道具箱
|
||||
## ふたつの形 + ひとつの sample
|
||||
|
||||
動詞は小麦粉と火加減です。人が何度も発明し直すのは、少数の*形*——道具箱であり、必点メニューではありません。
|
||||
|
||||

|
||||
|
||||
*公式の六パターン格子。トポロジーは script が持ち、このレッスンでは `agent` / `parallel` / `pipeline` / journal で各形を話します。*
|
||||
|
||||
このあとのサンプルのために、いちばん大事な三つを先に感じてください——名前はあとからでよいです。
|
||||
|
||||
**Fanout-And-Synthesize** — 五十ファイルは一つの疲れた context に入りません。分け、多く走らせ、barrier でまとめます。
|
||||
まずふたつ(六パターン全体は下の折りたたみ):
|
||||
|
||||
```text
|
||||
task ──► ● ● ● ● ══barrier══► synthesize
|
||||
Fanout task ──► ● ● ● ● ══barrier══► synthesize
|
||||
Adversarial worker ──► verifier×N → 残るものだけ残す
|
||||
```
|
||||
|
||||
**Adversarial Verification** — 狐が鶏小屋を採点してはいけません。worker が出し、独立した verifier が突き、立っているものだけ残します。
|
||||
|
||||
```text
|
||||
worker ──► verifier
|
||||
├──► verifier
|
||||
└──► verifier → まだ立つものだけ
|
||||
```
|
||||
|
||||
**Generate-And-Filter** — 欲しいのは選択肢であり、最初に賢く聞こえた案ではありません。多くの generator、そのあと rubric(と dedupe)。
|
||||
|
||||
同じ道具箱には **Classify-And-Act**(専門家へ振り分け)、**Tournament**(ペア審判で勝者)、**Loop Until Done**(「新しい発見?」が yes のあいだ spawn、硬い `budget` 付き)もあります。コストが明瞭さや安全を買うときだけ、スタイルを借ります。
|
||||
|
||||
<details>
|
||||
<summary>各パターンをこのレッスンのプリミティブへ写す</summary>
|
||||
|
||||
| パターン | プリミティブの素描 | 使わないとき |
|
||||
|----------|--------------------|--------------|
|
||||
| Classify-And-Act | `agent` → 分岐 → `agent` | 全部が同じ扱いでよい |
|
||||
| Fanout-And-Synthesize | `pipeline` / `parallel` → 統合 | 一通しでもう足りる |
|
||||
| Adversarial Verification | 生産 → `parallel(verify)` → filter | 間違えても安い |
|
||||
| Generate-And-Filter | `parallel(gens)` → filter | 良い答えの空間がもともと狭い |
|
||||
| Tournament | pairwise 審判 `agent` | 鋭い rubric が一通しで決める |
|
||||
| Loop Until Done | `while` + 停止 + `budget` | 仕事量が分かっている |
|
||||
|
||||
```python
|
||||
# teaching sketch — 分類してから動く
|
||||
kind = await ctx.agent("この ticket を分類", schema=KIND)
|
||||
if kind["type"] == "billing":
|
||||
return await ctx.agent("billing を処理…")
|
||||
```
|
||||
|
||||
組み合わせはふつうです。深い調査はしばしば fanout → filter → verify → synthesize と重ねます。
|
||||
|
||||
</details>
|
||||
|
||||
### 信頼できない入力に workflow が出会うとき
|
||||
|
||||
サポートチケットやユーザーフィードバックは信頼できません。それらを*読む* agent に、PR を開ける鍵まで持たせたくありません。エアロックを残します。reader は read-only のまま、構造化 summary だけを渡し、trusted な actor は summary にだけ作用する——生本文には触れない。
|
||||
|
||||
```text
|
||||
backlog (untrusted)
|
||||
│
|
||||
▼
|
||||
┌─ QUARANTINE (read-only) ─┐
|
||||
│ readers → dedupe → summary │
|
||||
└────────────┬───────────────┘
|
||||
▼
|
||||
┌─ TRUSTED (high privilege) ─┐
|
||||
│ actor → fix / escalate │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>公式 quarantine 図</summary>
|
||||
|
||||

|
||||
|
||||
*Reader は quarantine で分類と dedupe をし、高権限ツールは trusted 側に住みます。バックログが眠らないなら `/loop` と組んでもよいです。*
|
||||
|
||||
</details>
|
||||
|
||||
## `review-changes` を歩く — ひとつの composition
|
||||
|
||||
サンプルは「一つのパターン」ではありません。**Fanout-And-Synthesize** の中に **Adversarial Verification** が入り、終わりで軽く filter がかかる——`isReal` の finding だけが残ります。
|
||||
sample `review-changes` = **Fanout** の中に **Adversarial**: 次元ごとに `pipeline(audit, verify)`、`verify` 内で `parallel` 検証、`isReal` だけ残す。
|
||||
|
||||
```text
|
||||
correctness ── audit ── verify ──┐
|
||||
security ── audit ── verify ──┤── confirmed
|
||||
performance ── audit ── verify ──┤
|
||||
style ── audit ── verify ──┘
|
||||
fanout ▲ synthesize
|
||||
└── 各 finding の懐疑的 verify
|
||||
```
|
||||
|
||||
`pipeline(DIMENSIONS, audit, verify)` が各 dimension に机を渡します。`verify` 内の verifier の `parallel` が敵対の和音です。リスト filter が synthesize。`phase` が Review → Verify を印し、journal が各 `agent()` を覚えるので、止まっても audit をやり直さない。
|
||||
|
||||
三つの癖が席を失う感触があります。艦隊は二つの dimension で止められず、著者は審判ではなく、トポロジーは途中で漂いません。
|
||||
|
||||
```python
|
||||
# code.py より — 実行可能な sample(短縮)
|
||||
# code.py から(抜粋)
|
||||
async def sample_workflow(ctx, args):
|
||||
ctx.phase("Review")
|
||||
results = await ctx.pipeline(DIMENSIONS, audit, verify)
|
||||
confirmed = [f for r in results if r for f in r["confirmed"]]
|
||||
ctx.log(f"{len(confirmed)} 件の実在する問題を確認")
|
||||
return {"confirmed": confirmed}
|
||||
```
|
||||
|
||||
艦隊は早止めできず、作者は審判にならず、トポロジは chat の毎ターンで書き換わらない。
|
||||
|
||||
<details>
|
||||
<summary>s15 に掛けて(置き換えない)</summary>
|
||||
<summary>六パターン格子 + プリミティブ対応</summary>
|
||||
|
||||
s15 は依然として host loop です。s16 が足すのは `Workflow` tool だけです。あなた(またはモデル)が saved の名前を頼み、adapter が script を走らせます。
|
||||

|
||||
|
||||
本番では背景+通知で置けます。teaching CLI は `demo` / `resume` を前景に置き、phase と cache hit を追いやすくしています。アイデアは同じで、簡略化は明示します。
|
||||
| パターン | プリミティブ速写 | 使わないとき |
|
||||
|----------|------------------|--------------|
|
||||
| Classify-And-Act | `agent` → 分岐 → `agent` | 全部同じ扱いでよい |
|
||||
| Fanout-And-Synthesize | `pipeline` / `parallel` → マージ | 一回で収まる |
|
||||
| Adversarial Verification | 生成 → `parallel(verify)` → フィルタ | 間違っても安い |
|
||||
| Generate-And-Filter | `parallel(gens)` → フィルタ | 答え空間がもともと狭い |
|
||||
| Tournament | 一対一の審判 `agent` | 明確な尺度で一発選定可 |
|
||||
| Loop Until Done | `while` + 停止 + `budget` | 仕事量が既知 |
|
||||
|
||||
```python
|
||||
# teaching sketch
|
||||
kind = await ctx.agent("このチケットを分類", schema=KIND)
|
||||
if kind["type"] == "billing":
|
||||
return await ctx.agent("請求を処理…")
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## 宝石を回す: 計画を握っているのは誰か
|
||||
<details>
|
||||
<summary>信頼できない入力: quarantine</summary>
|
||||
|
||||
役に立つ問いは「agent は何人か?」ではなく、**トポロジーを誰が持つか**、仕掛かりの器はどこに置かれるか、です。
|
||||
チケットを*読む* agent が PR を開く鍵まで持つべきではない。reader は読み取りのみ → 構造化サマリ;trusted actor はサマリだけ見て動く。
|
||||
|
||||
| 近所 | 計画を握るもの | 中間結果の置き場 | 向いている用途 |
|
||||
|------|----------------|------------------|----------------|
|
||||
| [s06 Subagent](../s06_subagent/) | モデル、一度きり | ほとんど捨てる | 汚い子タスクの隔離 |
|
||||
| [s13 Agent Teams](../s13_agent_teams/) | Lead + mailbox | 共有タスク / メッセージ | 長時間の同僚 |
|
||||
| [s15 Integrated Harness](../s15_integrated_harness/) | 一つのループ内のモデル | `messages[]` | 積み上げ型 coding agent |
|
||||
| **s16 Workflow** | **Script** | **変数 + journal** | 構造化した fan-out + verify |
|
||||
| [s17 Goal Loop](../s17_goal_loop/) | 停止時の evaluator | 会話を証拠に | 「ゴール全体は終わったか?」 |
|
||||
```text
|
||||
backlog(非信頼)→ [quarantine: readers → 重複除去 → summary] → [trusted: actor]
|
||||
```
|
||||
|
||||
より安い道もしばしば勝ちます。skill を軟らかい計画にする、短い multi-agent の会話、手書きの static orchestrator、あるいは大きな一回のモデルターン。構造が単一の context より長く生きねばならないときに、workflow へ手を伸ばします。
|
||||

|
||||
|
||||
## 棚に戻しておくとき
|
||||
*高権限ツールは trusted 側。バックログが眠らないなら `/loop` と組む。*
|
||||
|
||||
Workflow は token と調整のコストを使います。ふつうのコーディングの大半は、五人の reviewer を必要としません。
|
||||
</details>
|
||||
|
||||
この仕事が本当にもっと計算と定制 harness を欲しがっているか、聞いてください。ふつうの s15 の一ターン——あるいは一つの誠実な s06 subagent——で足りるなら、そこで止めます。抑制も設計思想の一部です。
|
||||
<details>
|
||||
<summary>s15 への掛け方</summary>
|
||||
|
||||
s15 がホストループのまま;s16 は `Workflow` ツールを足すだけ。製品ではバックグラウンド可;ティーチング CLI は前景の `demo` / `resume` で段階とキャッシュを見せる。
|
||||
|
||||
</details>
|
||||
|
||||
## 隣人と、使わないとき
|
||||
|
||||
計画を握るのは誰か。s06 一回委譲、s13 メール箱の仲間、s15 単一ループ、**s16 スクリプト + journal**、s17 は「全体ゴールは終わったか」。
|
||||
|
||||
普通のコーディングなら s15 一回、または正直な s06 で十分なことが多い。Workflow は token と調整コスト——構造が単一コンテキストより長生きすべきときだけ。
|
||||
|
||||
## 試してみる
|
||||
|
||||
```bash
|
||||
python s16_workflow_runtime/code.py # s15 host + Workflow(real API)
|
||||
python s16_workflow_runtime/code.py demo # 固定 fixture。phase を見る
|
||||
python s16_workflow_runtime/code.py resume # 同じ runId。cache hit を期待
|
||||
python s16_workflow_runtime/code.py # s15 ホスト + Workflow(本番 API)
|
||||
python s16_workflow_runtime/code.py demo # 固定データ;段階を見る
|
||||
python s16_workflow_runtime/code.py resume # 同じ runId;キャッシュ命中を期待
|
||||
```
|
||||
|
||||
Review が Verify に道を譲るのを見てください。完全な resume では agent が `cached` になり、`agents=0 tokens=0` と出るはずです——ノートが「温め直しは要らない」と言っている感じです。
|
||||
完全再開では `agents=0 tokens=0` になるはず。
|
||||
|
||||
## 次へ
|
||||
|
||||
s16 はバッチの回し方です。[s17 Goal Loop](../s17_goal_loop/) は戸口で別の問いをします。止めるべきか、もう一ターンか。
|
||||
s16 はバッチの回し方。[s17 Goal Loop](../s17_goal_loop/) は聞く:止めるか、もう一周か。
|
||||
|
||||
<!-- translation-sync: zh@v17, en@v17, ja@v17 -->
|
||||
<!-- translation-sync: zh@v18, en@v18, ja@v18 -->
|
||||
|
||||
Reference in New Issue
Block a user