一つの契約、すべてのモデル:AIコーディングエージェントの運用基準
本記事では、AIコーディングエージェントの行動規範(ドクトリン)を能力から分離し、標準化する方法を紹介する。著者は「運用基準」という文書を作成し、フロンティアモデルの行動パターンを低性能モデルに移植することで、品質のギャップを縮小した。主な要素には、結果を先に示す、完了の証拠を示す、深層的な分析、早期停止の防止、シンプルかつ効果的な手法、すべての発見の開示が含まれる。この基準は起動時のシステムプロンプトとセッション内ルールの二重チャネルで適用され、安全な完了ゲートと階層的設定も備える。
2026年7月13日 · 14分読了
私は最近行ったエンジニアリング作業を共有したいと思います。それは、AIコーディングエージェントとの連携方法に対する私の考え方を変えました。最初は、「SonnetとOpusをフロンティアモデルのように振る舞わせることはできるか?」という素朴な疑問から始まりました。最終的には、その疑問に値する以上に有用な結果にたどり着きました。
短く言えば、小さなモデルを大きなモデルと同等に能力を持たせることはできません。それは重み(weights)によるもので、プロンプトで重みを動かすことはできません。しかし、能力だけが優れたエージェントのターンと平凡なターンを分ける要因ではありません。もう半分は「ドクトリン」、つまりエージェントがどのようにコミュニケーションし、いつ停止し、作業をどう証明し、決定前にどれだけ深く分析するかです。そしてドクトリンは完全に移植可能です。一度書き留め、システムプロンプトレイヤーとして適用すれば、高価なモデルも安価なモデルも、同じ契約に従って動作し始めます。
この投稿はその論旨と設計図です。すべては自身のスタックに適応可能です。再利用可能なパターンがどこにあるか、私の具体例が単なる例示であるかを指摘します。
問題の正直な説明
私はかなり大規模なコードベースを運用しています。ブロックチェーンベースの金融プロトコル、20以上のバックエンドマイクロサービス、いくつかのNext.jsフロントエンド、スマートコントラクト、Kubernetesクラスターです。作業のほとんどをClaude Codeと専門化されたサブエージェントの一群で行っています。どんな日でも、アーキテクチャエージェントは最も高性能なモデルで、実装エージェントは中級モデルで、高速リサーチエージェントは小型モデルで動作します。三つの異なる知能、一つのコードベース、一つの基準。
摩擦は決して安価なモデルが愚かであることではありませんでした。それは安価なモデルが異なる振る舞いをすることでした。テストを実行せずにタスクを「完了」と宣言する。最終メッセージを答えではなく実装詳細の壁で始める。影響範囲を追跡せずに一回のgrepから変更を行う。途中で停止し、自分で解決できる疑問を投げかける。高価なモデルはこれらをデフォルトで正しく行い、安価なモデルは指示される必要がありました。
長い間、私はこれを安価なモデルを使うための避けられないコストとして扱っていました。それは間違った枠組みでした。私が望んでいた振る舞いは知能ではありませんでした。それらは行動でした。そして行動は指定可能です。
核となる考え:ドクトリンは能力ではない
この区別が全体の論旨ですので、正確に述べます。
能力はモデルが理解できることです。難しい推論、新しい合成、大きな問題を頭の中で保持する能力。それは重みに存在します。プロンプトで追加できません。「GPT-3.5をGPT-5と同じくらい賢くするシステムプロンプト」を売る人は、何も売っていません。
ドクトリンはモデルが持つ能力の周りでどのように振る舞うかです。コミュニケーション契約、完了と呼ぶ基準、変更をコミットする前にエンドツーエンドで追跡する規律、まだできる仕事があるのに停止しないルール。それらは知能ではありません。全てテキストで指定可能です。そして重要なことに、能力のあるモデルがすでにこれらを行っているのは、それらに向けて訓練されたからであり、同じ振る舞いを能力の低いモデルに指示することで、基礎となる知能のギャップは残るものの、目に見える品質のギャップの大部分を埋めることができます。
したがって、目標は「小さなモデルを賢くする」ことではなく、「すべてのモデルに、その階層に関わらず、一つの運用契約を守らせる」ことです。結果でリードし、すべての完了主張を証拠で裏付け、決定前に追跡し、早期停止しない中級モデルのターンは、外部から観測可能なあらゆる尺度でフロンティア標準のターンです。本当に大きなモデルに手を伸ばすのは、タスクの正確性の上限が追加の能力を要求する場合であり、基本的な専門的行動のためではありません。それは標準化できます。
標準を書き留める
これらすべての中心にある成果物は、私が「運用基準」と呼ぶ単一の文書です。約12のセクションからなり、「雰囲気」ではなく「強制可能な行動」として契約をエンコードします。主要な柱:
結果でリードする。最終メッセージは読者にとって作業の最初の一目です。答えで始め、それを裏付けます。読みやすさは簡潔さに勝ります。読者の次の行動を変えない詳細を削ることで短くし、断片や矢印連鎖に圧縮してはいけません。読者が必要とするすべてはその最後のメッセージにあります。
成果物で完了を証明する。「動作するはず」「良さそう」は禁止。すべての「完了/修正/合格」の主張には、コミットハッシュ、テスト出力、終了コード、またはファイルリストを添付します。オーケストレーターは完了主張を信頼する前に、自分で受け入れコマンドを再実行します。エージェントの言葉をそのまま受け入れません。
決定は深さ優先で行い、直感に頼らない。決定前に、変更が触れるすべての層を追跡します:スキーマ、データアクセス、ドメイン、アプリケーション、API契約、すべてのフロントエンド、非同期パイプライン、チェーン、マイグレーション、テスト。型チェックが通っても、ランタイムや契約の波及について何も証明しません。
早期停止しない。リクエストに従う可逆的なアクションについては、続行します。ターンを終える前に、最後の段落を読み直します。それが計画、質問、または「次にXをする」という約束なら、今その作業を行います。タスクが完了したか、ユーザーに本当にブロックされている場合のみ停止します。
最もシンプルでうまくいくことをする。リクエストされていない機能、リファクタリング、抽象化は行わない。不可能な状態に対する防御的バリデーションは行わず、重要なパス(資金やユーザー向け表示など)では型付きエラーでフェイルクローズする。
すべての正直な発見を上限なく開示する。きれいに見せるために長いテールの注意事項を削らない。「約二つの発見」を常に報告する報告書は、定義上、開示不足です。
ここで強調したいのは、私はこれらの断片を好みで発明したわけではないということです。モデルをこの行動に導く正確な表現は、モデルベンダー自身の公開された移行およびプロンプトガイドから取られています。フロンティアモデルはデフォルトでこれらの行動を示します。ベンダーは、そうでないモデルにそれらを植え付ける正確な表現を文書化しています。私はその表現を引き出し、契約にまとめました。この基盤が、単に読みやすいだけでなく実際に機能する理由です。自分自身のものを構築する際には、ブログ記事の意見(これを含む)からではなく、プロバイダーのガイダンスからスニペットを取得してください。
二つのチャネルで、スキップできないようにする
誰もロードしない標準は飾りです。私は二つの方法で適用し、誰かがオプトインを忘れても存在するようにします。
起動時:システムプロンプトファイルとして追加。薄いラッパースクリプトが、完全なドクトリンをシステムプロンプトに含めてエージェントを起動し、それがフォークするすべてのサブエージェントに継承されます。
セッション内:常時ロードされるルールとして。フレームワークは、交渉の余地のないコアをインラインで含み、完全なドクトリンを指す小さなルールファイルを自動ロードします。そのため、普通に開始されたセッションでも契約に従って動作します。
セッション内の小さなルールは意図的に小さくしています。完全なドクトリンは起動層にあり、常時ロードされるコンテキスト予算の外側に位置します。これにより、恒久的なコストを低く抑えつつ、コアが存在することを保証します。
私を謙虚にした教訓:ハーネスが実際にロードするものを検証する
これが私が最も感謝している発見です。なぜなら、それはシステム全体を静かにプラセボにする種類のものだからです。
私は20の美しく書かれたサブエージェントのロール定義を持っていました。それらは数ヶ月間存在していました。設定で参照されていました。私はそれらがディスパッチされていると信じていました。実際に実行中のエージェントの利用可能なサブエージェントタイプのリストを調べたところ、どれも存在しませんでした。ランタイムはビルトインの汎用エージェントのみを示していました。
ロールファイルは、エージェントフレームワークがエージェント定義として解析しない独自のメタデータ形式を使用していました。それらは事実上、ドキュメントでした。私のオーケストレーションは常に汎用エージェントにフォールバックし、ロールコンテキストをプロンプトに貼り付けることで補っていました。それは十分に機能していたため、宣言された専門家が実際には存在しないことに気づきませんでした。
修正は機械的でした。すべてのロールファイルをフレームワークの実際のネイティブ形式に標準化し、有効なフロントマター、名前、説明、ツール許可リスト、モデル階層を含めて、フレームワークがそれぞれを第一級のディスパッチ可能なエージェントとして発見できるようにしました。20すべてに対して一貫して行う決定論的スクリプトを書き、すべてのファイルが解析されることを検証し、ランタイムに対してエージェントが表示されることを確認しました。
移転可能な教訓はバグよりも大きい:ハーネスの真実は、設定が主張するものではなく、ランタイムが実際にロードするものです。宣言されたエージェント、配線されたフック、スコープ付きルール:ランタイムが確認するまではどれも現実ではありません。「設定にある」を仮説として扱い、ランタイム自身のロードしたものの報告だけがそれを閉じる唯一の証拠です。私は今、発見をテストに合格するのと同じ方法で検証します。つまり、意図ではなく出力を見ます。
安全な強制:セッションを詰まらせない完了ゲート
プロンプト内のドクトリンはガイダンスです。時にはメカニズムが必要です。私が構築した最も強力なものは完了ゲートです。これはエージェントが終了しようとするときに起動し、ターンが実際に終わる前に「完了」の主張を実際の証拠に対して再チェックすることを強制します。
完了をブロックできるフックは実際に危険です。なぜなら、単純なバージョンは無限ループを作成するからです。フックが停止をブロックし、モデルが続行し、もう一度停止しようとし、フックが再びブロックする...永久に。悪いゲートはあなたをいらいらさせるだけでなく、セッションを詰まらせます。したがって、ここでのエンジニアリングはほぼ安全性に関するものであり、三つの不変条件は直接借用する価値があります:
デフォルトで非アクティブ。ゲートは環境フラグがオンにならない限り何もしません。配線はされていますがオフで出荷され、既存のワークフローを驚かせることがありません。長い自律実行(早期完了が真のリスクとなる場合)のために有効にします。
ループセーフ。フレームワークはストップフックに、このターンですでに起動したかどうかを伝えます。ゲートはそのフラグを読み取り、二回目のブロックを拒否します。最大でも一度介入し、その後ターンを終了させます。この単一のチェックが、有用なゲートと無限ループの違いです。
フェイルオープン。例外、不正な入力、予期しない事態:ゲートはクリーンに終了し、停止を続行させます。ゲートのバグはノーオペレーションにダウングレードされ、セッションがスタックすることはありません。すべてのターンのクリティカルパスにあるツールでは、フェイルオープンはオプションではありません。
配線する前に、これら三つのプロパティすべてをシェルからテストしました。フラグが設定されていないときは非アクティブ、有効なときは正確に一度ブロック、既に起動したフラグの下では再ブロックしない、ガベージ入力でもクリーンに終了する。敵対的にテストしていない安全機構は責任であり、保護策ではありません。
階層的設定:グローバルドクトリン、ローカル専門家
標準が一プロジェクトで機能した後、明らかな疑問は、「それは私が働くすべての場所に適用されるのか、それともここだけか?」というものでした。スコープを正しく設定することは、細部ではなく、実際のアーキテクチャ上の決定であることがわかりました。
エージェントフレームワークには通常、少なくとも二つの設定階層があります。プロジェクト階層(そのプロジェクト内でのみロード)とユーザー階層(すべてのセッションでグローバルにロード)です。間違いはすべてを一つの階層に詰め込むことです。正しい動きは範囲で分割することです:
ドクトリンは普遍的であるため、ユーザー階層に属します。運用基準はあらゆるコードベースに適用可能であり、行動はプロジェクト固有ではありません。私はユーザーレベルに配置し、マシン上のすべてのセッションが、どのディレクトリにあっても契約に従って実行されるようにしました。メインリポジトリのバージョン管理されたコピーにグローバルコピーをリンクすることで単一の真実源を維持し、ドリフトを防止しました。
専門家エージェントはドメイン固有であるため、プロジェクト階層に残ります。私の20のエージェントは、このプロトコルのサービス、チェーン、名前空間を知っています。それらをグローバルにすると、無関係なプロジェクトでプロトコル固有のエージェントが表面化し、それらはせいぜいノイズ、最悪は積極的に誤ったものになります。
(コスト管理のため原文は途中で切れています)