はじめに
2026年2月ごろ、Claude CodeとChatGPTを会話させて実装を回す、という手組みの遊びをやっていました。 片方が仕様を書き、もう片方が実装して返す。人間は眺めていて、たまに口を挟む。当時のモデルで言うと、Claude側がOpus 4.5から4.6に変わる頃、ChatGPT側はGPT-5.2の頃です。
実験のログは残っていません。Dev.toのコメント欄で英語のやり取りをしていた時期、という粒度の記憶だけあります。いまは同じ構図をプラグインで組めるようになりましたが、当時は全部手作業でした。 手作業というのはつまり、2人を会話させるためだけにWSLでUbuntuを立ててtmuxでペインを並べる、という土木工事込みの手作業です。Windows機なのに。 最早Linuxに帰った方が早いだろとか思ってた。
断っておくと、サブエージェントやエージェントの組み合わせ自体は、当時すでに珍しくありませんでした。マルチエージェントのフレームワークは2023年から乱立していたし、Claude Codeにも2025年7月からサブエージェント機構が入っている。2月の遊びの眼目は、ベンダーの違うモデル同士を組ませるほうでした。こちらは当時、実際にやっている人は海外でも一部だったと思います。いまは当たり前にできる。良い時代です。
半年後の2026年8月。オープンソース化されたCloudflare OSを触っていたら、やっぱりサブエージェント機構が入っていました。面白かったのは機構があること自体ではなく、渡し方の絞り方です。サブに渡されるツールは describeBinding と executeCode の2つだけ(agent.ts:2833)。読む・計算するは渡すが、書く・繋ぐは渡さない。
手組みで辿り着いた結論と、製品の設計が同じ方向を向いていた。答え合わせの気分でした。
で、その8月の検証がこれです。
akari-iku.github.io
Cloudflare OSをVRAM 8GBのゲーミングPCで動かしたら、三目並べ1個に5ラウンドかかった話 | akari.log
ローカルのqwen3に三目並べを作らせたら5ラウンドかかった、という奮闘記なんですが、書き終えてから気付きました。2月と8月は、感度の違う同じ実験だったんですよ。
2月は強いモデル同士。互いの粗を賢さで埋め合うので、受け渡しの不備が見えない。 8月は実装担当が非力なローカル30B。同じ不備が容赦なく表面化する。
というわけでこの記事は、その2回分の実験から出てきた「モデル間の受け渡しで設計しておく6つの面」の話です。ここを決めておくと、実装担当のモデルを差し替えられるようになります。
人間→メインは会話、メイン→サブは仕様書
先に背骨を一本立てておきます。人間からメインへの指示と、メインからサブへの指示は、ジャンルが違う文章です。
なお、ここで言う「サブ」は同一システム内のサブエージェントに限りません。別ベンダーのコーディングエージェントでも、CLIの向こうのローカルモデルでも、仕様を受け取って実装する側をこの記事ではまとめて「サブ」と呼びます。2月のChatGPTも8月のqwen3も、立場としてはこれです。
人間はメインに雑に投げていい。そばにいて「違う、そうじゃない」と言えるから。往復が前提のコミュニケーションです。
メインからサブは逆で、サブは冷えた状態から始まります。会話の文脈も、意図の蓄積もない。しかも前回見たとおり、詰まっても聞きに来られない環境が普通にある。つまり一発で完結する必要がある。会話の書き出しではなく、仕様書です。
ここを取り違えると、メインは人間の真似をしてサブに雑に投げ始めます。人間→メインで上手くいっている渡し方を、そのままコピーするので。 しかもメインは、人間と長く会話しているほど人間の癖を吸います。雑な頼み方、暗黙の前提、「言わなくても分かるでしょ」。ブレイン役が吸収するのは、人間の良いところだけではないんですよ。
じゃあ仕様書きを最上位のモデルに任せれば解決かというと、そうでもありません。Fableクラスに頼むのは全然ありなんですが、書き手のモデルが考える最適と、受け取る側のモデルにとっての最適は別物です。宛先に合わせて書く工程は、書き手がどれだけ賢くても消えません。
そして仕様書には仕様書で、書き手のバグが入ります。前回の検証で、私はqwen3に「gadget というRPCスタブが使える」ことは伝えたのに、クラス名が Gadget 固定という一番肝心な制約を書き忘れて、1ラウンドまるまる空転させました。その時点で私はシステムプロンプトを読み込んでいて、その制約が空気のように当たり前になっていたからです。
自分が知っていることには気付けない。
あの1ラウンドの空転は、モデルの失敗ではなく仕様のバグでした。
設計しておく6つの面
本体です。それぞれに8月の実測を添えます。
1. 仕様の形式
散文よりスケルトンコード。日本語の説明で4ラウンド失敗して、完全なスケルトンを渡した5ラウンド目で通った、というのが実測です。
コードはモデル間の共通語で、モデルを跨いでも解釈が揺れません。散文の仕様は書き手の前提を吸って曖昧になりますが、export class Gadget extends DurableObject は誰が読んでもこの形です。
2. 禁止事項リスト
規約を伝えるだけでは足りません。モデルが持ち込む常識を、能動的に抑制する必要があります。
実測で言うと、「gadget スタブを使え」より「fetchを使うな、CORSヘッダーを足すな」のほうが効きました。正解を教えるより、事前分布の強い誤答を潰すほうが先。
しかも規約はシステムプロンプトに丸ごと書いてあったのに、qwenちゃんは会話履歴にある自分の失敗案(fetch方式)に引きずられ続けました。「書いてある」だけでは本当に足りないんですよね。
3. 受け入れ基準
サブが自己照合できる形で書きます。「動くこと」は基準になりません。
基準がないとどうなるか。真っ白な盤面に✅を3つ並べて「完全に動作します」と宣言されます。実話です。
4. 戻り値の形
報告は file:line のような、検証コストの低い形を指定します。散文で返ってくると、検証にこちらの思考が要る。委譲した意味が薄れていきます。
5. 検証面
自己申告を信じない。テスト・コンソール・スクリーンショットなど、モデルに依存しない外部に検証を置きます。
自己申告の癖はモデルごとに違うので、自己評価に依存した運用はモデルを差し替えるたびに壊れます。外部の検証面は、差し替えても壊れません。
ログを残させる、結果をハンドアウトとして書き起こさせる。セキュリティやインフラが本業の人には「当たり前では?」という話だと思います。自己申告を信じず証跡で裁くのは監査の基本作法なので。その当たり前を、モデル運用にも持ち込むだけです。
6. エスカレーション
詰まったときの合図を最初に決めておきます。「同種のエラーがN回続いたらメインに戻す」のような、外形的に数えられる基準で。
基準を外形的なものにするのは、サブに判定させないためです。そもそも「これは失敗なのか」「さっきと同じ失敗なのか」という切り分け自体が、人間や上位モデルにしかできない判断なので。数えるのはサブ側でいい。裁くのは、戻した先の仕事です。
前回書いたとおり、Cloudflare OSの停止条件には「失敗が繰り返されている」という概念がなく、CORS修正の無限ループは人間のStopボタンでしか止まりませんでした。ハーネスに機構がないなら、受け渡しの契約側で決めておくしかない。
じゃあCloudflare OSの場合、実際どこに書くのか。調べたら、置き場は半分だけありました。
プロンプトで表現できる契約(禁止事項、報告の形式、受け入れ基準)には、Instance Instructionsという公式の注入口があります。管理画面から設定できるデプロイ全体共通の指示文で、システムプロンプトに連結される。コード改変なしでいけます。
一方、ループ政策には口がありません。停止条件は agent.ts にリテラル直書きで、設定にもフックにも出ていない。「同種エラーN回で停止」を本当にやるなら、Apache-2.0のself-hostなのでカーネルに直接パッチです。プロンプト層には口が開いているのに、プロンプトでは解決できない側には口がない。逆だといいのにね、という。
なおこの置き場問題は、qwenだからではありません。席の条件はどのモデルを挿しても同じなので、ChatGPTやClaudeを挿して運用する人にもそのまま付いてきます。
失敗ログはそのモデルの取扱説明書になる
実務で一番効くのは、たぶんこの話です。
qwen3は放っておくとDenoのimportを書き、CSP違反をCORSで解決しようとしました。これは一度観測すれば分かる癖なので、次からは先回りして禁止事項リストに入れられます。
つまり失敗の出方には、そのモデルの事前分布がそのまま出ます。モデルを新しく入れたら、まず小さいタスクで一度失敗させて癖を採取する、という運用が成り立ちます。ベンチマークのスコアより、自分の環境での転び方のほうが仕様書に直結する。
採取できるのはモデルの癖だけではありません。CSPが実際に何を遮断するのか、クラス名がどこまで固定なのか、という環境側の強制の実態も、ドキュメントより失敗のほうが先に教えてくれました。どこまでどんな強制がされているかは、正直やらないと分からなかった。失敗ログは環境の取扱説明書にもなります。
ちなみに、教える側も間違えます。Cloudflare OSのシステムプロンプト内のサンプルコードには、自前定義しているクラスを cloudflare:workers からimportしてしまっているミスがありました(実装側の同等サンプルは正しい)。規約を教える文書のノイズは、弱いモデルほど素直に吸います。
委譲できるかの判定テスト
6つの面を書き切れるかどうか自体が、委譲できるかの判定になります。自問はこれです。
「このプロンプト、小さいモデルでも通るか?」
「新卒でも分かるように書け」「高校生に説明できるか」と昔から言われる、あれと同じ形です。要は渡し先の考慮ができているか。
通らないなら、まだ委譲できる状態ではない。それはたいてい、自分がまだ理解していないということです。仕様を書く行為そのものが設計作業で、そこを飛ばして丸投げすると空転する。前回の5ラウンドは、私がこのテストを受け続けていた記録でもありました。
線引きの軸は3つあります。
- 検証コスト: 結果の検証に、自分でやり直すのと同じ労力がかかるなら出す意味がない
- 統合の要否: 素材集めは出せる。素材同士を繋ぐ部分は出せない(分割すると劣化する)
- 権限の非対称: 読む・計算するは渡す。書く・繋ぐは親が握る
Cloudflare OSのサブエージェントがツールを2つしか持たされていないのは、3つ目の軸そのものです。冒頭の答え合わせがこれでした。
おわりに
6つの面を決めておくと、実装担当は差し替え可能になります。
賢いモデルと人間が仕様を書き、安い(あるいはローカルの)モデルが実装する構成は、経済的にも今の最適解に近いはずです。8月の体制で言えば、設計は課金モデル、実装は電気代。受け渡しさえ設計されていれば、実装側の性能差は越えられない壁ではなくなります。残るのは、設計とハーネスでどこまで支えるか、どの目的にどのモデルを充てるか。モデルの性能問題が、こちら側の設計問題に変わるんですよ。
ボトルネックは受け渡しの仕様品質に集約されます。逆に言えば、そこだけ磨けば全体が良くなる。
どれも基本的なエンジニアリングの話ではあります。ただ、この基本がどれだけ効くかは環境次第で、ハーネスが色々拾ってくれる普段のツールなら、雑でも案外回ってしまう。Cloudflare OSのように規約が独自で、ハーネスが失敗を拾わず、どんなモデルでも挿せる環境では、受け渡しの契約が唯一の安全網になります。
ところで、Gadget開発は独自規約の塊で用語も専用ですが、Cloudflareの思想さえ理解してしまえば実は怖くありません。何をやらせたくて、やらないの線をどこに引いているのかは、規約を暗記しなくても思想から推測がつく。規約は思想の圧縮版なので。 そして、思想を読んで、宛先のモデルが従える形に展開する。これが仕様の翻訳という仕事の中身です。
前回の検証を振り返ると、あれは「qwen=実装者、Claude=仕様の翻訳者、人間=承認者」というミニ開発組織でした。回るかどうかを決めていたのは個人の能力ではなく、インターフェースのほう。 人間のチームと同じですね。