エージェントに関する議論で、私は同じ考えを何度も目にします。詳細な仕様はもはや旧世界のオーバーヘッドであると。モデルに大まかな目標を与え、探索させ、返ってきたものを修正し、次に進む。効率的に聞こえますが、そのコストは隠されています。
単純なプロンプトは、実装をすぐに開始できるため、安くて魅力的に見えます。すると修正ループが始まります。出力をレビューし、意図を明確にし、変更を依頼し、テストを再実行し、次のギャップを見つけ、そしてまた繰り返します。結果が本当の目標に合致するかどうかを決定する人が依然として必要です。その人がオラクルになります。
もう一方の極端では、完全な正式仕様は明らかに初期コストが高いです。受け入れ基準、契約テスト、または振る舞い駆動開発(BDD)シナリオを書くには、実際の努力が必要です。しかし、下流のコストは異なります。なぜなら、オラクルの多くが実行可能になるからです。テストは毎回同じ条件をチェックします。それは昼食の5分前に疲れたり、急いだり、楽観的になったりしません。
それが実際のトレードオフです。問題は仕様が良いか悪いかではありません。最小総コストがどこにあるかです。ほとんどのエージェント作業では、それは中間のどこかにあります。作業を制約するのに十分な構造、意図を具体化するのに十分な例、そしてレビューが推測にならないようにするのに十分な実行可能なチェックです。
ゼロ仕様はインテリジェントでもリーンでもありません。それは単にコストのかかる「バイブコーディング」です。
ボトルネックは移動したのであって、消えたわけではない
ソフトウェアエンジニアリングは、タイピングやコード生成が主だったわけではありません。それは、何が存在すべきか、何が決して起こってはならないか、どのトレードオフが重要か、そして問題が現実世界に触れたときに「完了」が何を意味するかを決定することでした。
長年にわたり、チームは人間の摩擦を通じて欠落した仕様を発見してきました。レビューアがエッジケースに気づき、QAが誰も説明しなかったパスを見つけ、シニアエンジニアが実際の要件の半分を頭の中に保持し、それを一回の会議ごとに翻訳しました。それらのどれもエレガントではありませんでしたが、曖昧さを明るみに出すことを強制しました。
エージェントはこれを根本的に変えます。実装をはるかに安く、はるかに速くします。それはまた、十分に定義されていないアイデアが、誰もがシステムが何を意味するかに本当に同意する前に、もっともらしいシステムに変わる可能性があることを意味します。
古い世界では、あいまいな要件は人間の遅さに直面しました。エージェントの世界では、あいまいな要件は機械の速度に直面します。
だからこそ、仕様が突然再び重要に感じられるのです。それは常に重要でした。私たちは単に実装コストを粗い強制関数として使い、その結果をプロセスと呼んでいただけです。
実装が安くなるにつれて、より多くの困難が「正しいとは何か」を決定し、それを確実にチェックすることに移行します。
仕様を書くだけでは十分ではない
これが、人々が最も頻繁にスキップする部分だと思います。彼らは、順序が単純であるかのように話します。仕様を書き、次にエージェントに実装させる。欠落しているステップはコストのかかるものです。
仕様自体にレビューが必要です。
注意深く書かれた仕様でさえ、おなじみの方法で失敗する可能性があります。自己矛盾するか、ハッピーパスのみをカバーし、リトライ、レート制限、部分的な失敗について何も有用なことを言わないことがあります。正確に聞こえるが実際には検証できない動作を説明することがあります。そして時には、まったく間違った方法で正確です。それは、あなたが意図したことではなく、書いたことを言います。
エージェントが欠陥のある仕様を忠実に実行すると、障害の診断が難しくなります。実装は一貫しているように見えるかもしれません。提供したチェックに合格することさえあるかもしれません。しかし本当の問題は上流、仕様に存在するため、修正するにはコードと推論を一緒に解きほぐす必要があります。
だからこそ、仕様検証はそれ自体の項目に値すると思います。実装を開始する前に、誰かがいくつかの明白な質問をする必要があります。これは内部的に一貫していますか?このタスクに対して十分に完全ですか?どの部分がテスト可能ですか?まだ人間の判断に依存している部分はどこですか?誰もが暗黙のうちに想定したために欠落している失敗モードはどれですか?
エージェントはここで役立ちますが、「要件を書け」よりも有用なことに使う場合に限ります。そのプロンプトは通常、磨かれた霧を生成します。より良いプロンプトははるかに具体的です:
別のエージェントがこれを安全に実装できる最小の仕様を起草してください。仮定、非目標、受け入れ基準、エッジケース、観察可能な結果、未解決の質問を含めてください。どの主張が自動テストになり、どの主張がまだ人間のレビューを必要とするかをマークしてください。
その後、ドラフトを別のエージェントに渡し、結果を攻撃するように指示します:
矛盾、曖昧な用語、隠れた依存関係、テスト不可能な主張、欠落した失敗モード、および実装が書かれた基準を通過しながらも意図に違反する可能性のある場所を見つけてください。
この単純なワークフローでも、人間の判断に値する仕様に到達するコストを下げます。
エージェントは仕様の必要性を取り除くのではありません。実際に有用な具体性のレベルに達することをより安くするのです。
なぜマルチエージェントシステムにはより強力な契約が必要か
単一のエージェントが小さく境界のあるタスクに取り組む場合、多くの場合、緩い指示から回復できます。ループはタイトで、爆発半径は局所的であり、人間は通常、逸脱したときに軌道に戻すことができます。人間は逸脱自体を簡単に見つけることさえできます。
マルチエージェントシステムは非常に異なる問題です。あるエージェントの出力が別のエージェントの入力になると、解釈のずれが蓄積し始めます。エージェントBは、エージェントAが要件を10%誤解したことを知りません。出力を真実として扱い、続けます。人間が結果を見る頃には、元の間違いは、有能に見える作業のいくつかの層の下に埋もれているかもしれません。
その時点で、仕様はもはや単なるガイダンスではなく、より契約のようなものです。
その契約には、意図の段落以上のものが必要です。スキーマ、不変条件、許可されたあいまいさ、検証ルール、明示的な失敗動作が必要です。多くの場合、契約テスト、型付きインターフェース、機械でチェック可能な引き継ぎフォーマットも必要です。引き継ぎは製品の一部であり、これは人々が望んでいたよりも華やかではありませんが、現実にはるかに近いものです。
ここでBDDと実行可能な受け入れテストの出番です。それらの価値は方法論だけではなく、人間のオラクルの一部を繰り返し可能なものに移すことです。動作が十分に安定して正確に指定できる場合、実行可能な仕様は多くの場合、別のレビューラウンドよりも安価です。
エージェントが作業を他のエージェントに引き継ぎ始めると、その引き継ぎ自体が実際のインターフェースのように指定され、検証される必要があります。
仕様には有効期限を設定すべき
チームがここで犯す別の失敗があります。それは、より多くのテキストが常に安全であるかのように、仕様曲線に押し込み続けるときに現れます。そうではありません。少なくとも現在のモデルではそうではありません。
Chromaのコンテキスト腐敗に関する研究は、問題の最初の部分を明確にします。モデルのパフォーマンスは、単純なタスクでも入力が増えるにつれて信頼性が低下します。コーディングプロジェクトでは、その上に2番目の問題があります。デザインの散文、例、計画、コメント、チケット、古い受け入れ基準をコンテキストに詰め込むほど、どの部分が命令でどの部分が成果物かが不明確になります。
これをセキュリティの意味でのプロンプトインジェクションとは呼びません。誰もモデルを攻撃しようとしていません。それは、自己誘発的な指示の漂流に近いです。コンテキストには、古い設計意図、現在の実装、半分有効な例、3セッション前の生成された計画、そしておそらくもう存在しないクラスをまだ説明している古いソフトウェア設計文書が含まれています。その時点で、モデルは1つの仕様を読んでいるのではなく、競合する真実のソース間で平均を取っています。
それが、過剰仕様が役立つのをやめてモデルを混乱させ始めるときです。エージェントは、段落がアクティブな要件なのか、履歴メモなのか、それともコードがすでに置き換えたものなのかを判断できなくなります。
設計文書は、コードがまだ存在しないため初期には有用です。後には、縮小する必要があります。インターフェース、テスト、不変条件が現実になったら、詳細な構築計画は消え始めるべきです。「コード自体がうまく表現できない部分」を残してください。ビジネスの根拠、非目標、安全制約、外部契約、そして試行錯誤によって再発見されたくない少数の不変条件です。クラスやメソッドがすでに行っていることを単に言い換えた散文は削除してください。
そうしないと、2つの仕様で終わります。人間はレビューでそれについて不満を言うでしょう。エージェントはしばしば両方に従おうとします。
APIはコードを仕様のように振る舞わせることができる
この話にはより楽観的なバージョンもあります。一部のコードベースは他よりも早く「コードが仕様」のポイントに達し、API設計がその大きな理由です。
内部APIが動作を規約、弱い型付きパラメータ、セットアップマジック、汎用エラーの背後に隠している場合、エージェントはコードを仕様として扱うことができません。散在する散文と試行錯誤からルールを再構築する必要があります。それは人間には遅く、モデルにはさらに悪いです。
逆もまた真です。明示的な名前、タスクレベルのメソッド、強い型、読みやすいバリデーション、有用な例、実行可能なエラーを持つAPIは、エージェントに具体的な基盤を与えます。エージェントが表面領域を検査し、メソッドの動作を見て、どの入力が合法かを理解し、推測せずにエラーから回復できる場合、コードはそれ自体でより多くの仕様負荷を運びます。
ここでAIフレンドリーなAPI設計のアイデアが実際に重要になります。明示的な発見可能性が規約に勝ります。メソッドは、エージェントを十数の脆弱なステップに強制するのではなく、実際のタスクと一致するべきです。型とバリデーションは、合法な入力がどのように見えるかを示すべきです。エラーメッセージは、単に失敗を宣言するのではなく、次の修正を指し示すべきです。内省と例は、モデルが既存のコードベースからAPIの形状を学ぶのに役立ちます。パフォーマンスの透明性も重要です。なぜなら、APIが手がかりを与えなければ、エージェントは高価な呼び出しの周りに正しいが恐ろしいループを喜んで書くからです。
これはパブリックSDKだけの問題ではありません。内部サービスの境界、ライブラリクライアント、リポジトリの抽象化、さらには大規模モノレポのヘルパークラスにも適用されます。APIが発見し検査しやすいほど、エージェントはコードを権威ある仕様として扱い、より多くの散文をコンテキストに引きずり込むのを避けやすくなります。私はこれすべてについて以前に詳しく書いています。興味があれば。
どこに投資するか
私が強く信じているのは、単一の適切な仕様の量は存在しないということです。答えは、あなたが行っている作業の種類に依存します。小さく境界のあるタスクの場合、スイートスポットは通常、構造化された意図です。目標、いくつかの例、非目標、明確な受け入れ基準。これで、セットアップをタスク自体より重くすることなく、エージェントを生産的に保つのに十分です。
CRUDフロー、API統合、データ変換などの決定的な作業の場合、最適値は右に移動します。これらのドメインは制約しやすく、テストしやすいです。より多くの仕様は、繰り返しのレビューと手直しを削減するため、すぐに元が取れます。ここでBDD、契約テスト、実行可能な受け入れ基準が最も役立ちます。
アーキテクチャオプション、研究統合、新しい製品アイデアなどの探索的作業の場合、最適値は再び左に移動します。過剰仕様は、エージェントを有用にするまさにその柔軟性を殺す可能性があります。その場合、私は結果よりも境界を指定したいと思います。真でなければならないこと、起こってはならないこと、必要な証拠、そしてまだ人間を必要とする決定。
マルチエージェントパイプラインの場合、最適値は再び右に移動します。エージェント間のすべての境界には契約が必要です。それがなければ、システムを調整しているのではありません。解釈を積み重ねて、それらが相殺されることを期待しているのです。
普遍的な最適値はありません。適切な仕様の量は、作業が探索的か、境界があるか、決定的か、マルチエージェントかによって異なります。
4つのケースすべてに共通するルールは単純です。実装を拡大する前に仕様を検証してください。
アジャイルとXPから生き残るもの
私はエージェントがアジャイルやXPを無意味にするとは思いません。それらは、人々がすでに我慢していた部分から有用な部分を分離しやすくします。
最初の犠牲者は、主に人間の努力を調整するために存在した儀式です。