腾讯エンジニア:AI コーディング時代、人間は判断役へ移行
本文の状態
日本語全文を表示中
詳細モードで約79分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Tencent Engineering
腾讯エンジニアリングチームは、AI がコード生成を完全に担う環境において人間の役割が「実装」から「判断」へ移行し、AI のエラーは確率ではなく規模に依存する事実を報告した。
AI深層分析を開く2026年8月27日 21:49
AI深層分析
キーポイント
人間の役割の転換:実装から判断へ
コード生成が AI に委譲された場合、人間の仕事量は減らず、代わりに設計文書の選定や失敗の定義など「判断」に集中する必要がある。
AI エラーの本質は規模の問題
モデルの精度が高まっても、コード量と反復回数の増加に伴い絶対的なエラー数は増大し、人間のレビュー能力とのギャップが拡大する。
失敗の可視化は AI の弱点
AI は機能実装には優れるが、「失敗を名付ける」「状態を区別する」といった価値観に基づく判断や可視化において頻繁にミスをする。
提示詞からインフラへの依存シフト
複雑な制約を提示詞で管理する限界を超え、フレームワークやランタイムレベルでの強制力が必要となる。
提示詞の限界とフレームワークによる根本解決
提示詞の最適化には边际收益が尽きるため、モックの自動復元やトレース分析など、エラーそのものを排除する仕組みをフレームワーク層に実装する必要がある。
重要な引用
コード让给 AI 之后,人退到判断上,把取事实的活交给机器
不管什么技术栈,AI 产出都需要大量保障工作,因为出错的绝对数量不由单次准确率决定,由累积量决定
AI 交付功能的能力,明显强于它交付'让失败可见'这种纪律的能力
提示詞层面你只能"叮嘱",框架层面你可以"取消这个错误的存在"
編集コメントを表示
編集コメント
この記事は、AI コーディングが単なるツール導入ではなく、開発プロセスそのものの再定義を迫る転換点であることを示唆している。特に「失敗の可視化」や「価値観に基づく判断」といった人間の領域を明確に定義した点は、実務における AI 活用戦略を考える上で極めて示唆に富む。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
オリジナル:テックメディア編集部
2026年8月27日 17時38分 北京
コード作成をAIに任せた後、人間は判断の領域へと退き、事実確認という作業を機械に委ねる。
著者:黄迅(PUBG Mobile バックエンド担当)
百万行の Lua コード、独自フレームワーク、そして AI モデルはほとんど使ったことがない——コード作成を AI に委ねた今、人間の役割は「判断」へとシフトし、「事実の収集」という作業は機械に任せる。
まえがき:AI はすでにエンドツーエンドでの納品が可能になった
この四半期、私たちはコーディングエージェントを支える内部プラットフォームを構築しました。7 つのサービス、3 か月の開発期間、1,800 回以上のコミット、そして 16 万行のプロダクションコード、11 万行のテストコード、8 万行超のフロントエンドコード——これらすべてに人間が書いた一行もありません。設計ドキュメントに至るまで、すべて AI が執筆しました。
このプラットフォームは対照実験(コントロールグループ)として機能します。汎用的な技術スタックを採用し、新規プロジェクトで歴史的重負荷を排除した、AI にとって最も環境の整ったケースです。ここではまず、「コード作成を完全に AI に任せる」というシナリオを実証しました。つまり、業務コードにおける AI のエンドツーエンド納品は、もはや遠い未来の話ではないのです。
では、人間は何をしたのか?答えは「大量の意思決定」です。
(一)人間の労働量は減っていない。単に「執筆」から「決断」へとシフトしただけだ
私は当初、AI がコード作成を全権掌握すれば人間が楽になると考えていました。しかし現実は全く異なります。毎日読むべきものは以前と変わっていません。ただし、「コードを読む」ことが「仕様書・結論・根拠を読む」ことに置き換わっただけです。決断すべき事項も減っていません。「この部分をどう書くか」という判断から、「この道筋を進むべきか」「この失敗は問題として扱うべきか」という判断へとシフトしただけのことです。
現在、リポジトリには 70 篇を超える設計ドキュメントが保存されています。これらすべて AI が執筆しましたが、それぞれの採用・不採用の決定は人間が行いました。しかし、実際の成果はこの数よりも遥かに多い——膨大な量の仕様書(spec)を私が削除しました。削除してもプロジェクトは正常に稼働し、損失は一切ありませんでした。
残されたドキュメントの一部は、すでに実装が完了したコードを AI に読み込ませ、そこから逆算して再執筆させたものです。「コードに合わせてドキュメントが変わる」のではなく、「ドキュメントに合わせてコードが変わる」という旧来のアプローチとは一線を画しています。ここには明確な区別が必要です。
着手前に合意形成のために作成された仕様書は、一度使えば捨てて構いません。一方、事後に蓄積される設計説明は残す必要があります。なぜなら、それは次回の担当者にとっての「メンタルモデル(心的モデル)」を構築するためのものだからです。見た目は似ていても、その寿命は全く異なります。
この事実は、私が前稿で十分に考え抜けなかった一つの問いに対する回答でもあります。SDD(システム設計ドキュメント)が流行する中で、多くの人が仕様書自体を中核資産と捉えています。しかしもし文書こそが核心なら、私が削除したものが核心であり、プロジェクトは破綻しているはずです——実際には破綻していません。また、中核業務が AI に委譲されたのだから人間の労働量は減るはずだ——これも現実ではありません。
この二つの矛盾は、核心となるものは「spec という媒体」そのものではないことを示しています。真に重要なのは、文書を作成する過程で強制的に考えさせられる事柄です。仕様書の価値は、着手前に問題を明確に定義させる点にあります。一度明確になれば、文書自体は不要になります。
AI に委ねられず、代替もできない唯一のステップ——それは「考えること」そのものです。ブレインストーミングこそが、人間にとっての真の価値です。
(二)AI のエラーは確率の問題ではなく、規模の問題である
「Go と TypeScript を組み合わせた最も親和性の高い環境」——新プロジェクトでツールエコシステムも整っているにもかかわらず、3 ヶ月間で事故リストは確実に蓄積されました。
資産登録が中間状態で 4 回停止し、いずれも空のコミットを提出した際でした。カバレッジダッシュボードでは「収集失敗」と「データなし」が同じ表示に混同され、リトライキュー内のゾンビタスクが全体のスケジューリングをロックしました。また、要件抽出機能のリリース初夜には 4,000 件以上のタスクが溜まり込みました。
これらの事故を通じて、私は漠然としていた直感を明確に理解できました。どんな技術スタックであっても、AI が生成したコードには大量のバックアップ作業が必要です。なぜなら、発生するエラーの絶対数は「1 回あたりの精度」ではなく「累積量」によって決まるからです。反復回数が十分多く、生成されるコードが長ければ長いほど、わずかなエラー率でも現実的な事故に蓄積されます。一方、人間のレビュー能力は、その成長スピードに合わせて向上していません。
したがって、「モデルが強くなるほど、ハーン(検証環境)を薄くすればよい」という考え方は思い込みです。モデルが強くなれば生成量と速度は増えますが、人間側の処理上限は変わりません。その結果、ギャップはさらに拡大するのです。
(三)AI が特に犯しやすいエラーの一種
これらの事故の中で、特筆すべきカテゴリがあります。それは機能しないことではなく、「失敗が見えない」ことです。
AI は完全な状態マシンを記述できますが、初期段階で「マージ失敗」という状態を漏らしました。その結果、失敗に名前が付けられず、「マージ中」の状態から抜け出せなくなります。カバレッジダッシュボードも同様で、「収集失敗」と「実際にカバレッジがない(0%)」を同じ 0% として表示してしまいます。リトライキューについても、ゾンビタスクがスケジューリングをロックする原因を作りました。
AI は機能を納品する能力は高いですが、「失敗を可視化する」という規律を維持する能力はまだ劣ります。前者は単なる「要件」ですが、後者は「価値観」です。後ほど詳しく述べますが、AI の学習プロセスは試験対策のようなものであり、現時点では価値そのものを理解できていないのです。
ここが人間の判断が不可欠な理由です。これらの事故において人間が行ったのは、「この失敗には名前が必要だ」「2 つの 0% は区別すべきだ」という判断でした。これらはどこにも要件として記載されていません。
(四)3 つの発見が指し示す共通項
機械は事実を提供し、人間は判断を下す。
これは即戦力となる「ものさし」です。「今行っている作業は、事実か、それとも判断か?」と自問します。事実であれば機械に任せて、人間が確認したり AI の声明を鵜呑みにしたりする必要はありません。判断が必要な場合は人間に残し、仕組みに丸投げしてはいけません。
これら 3 つの発見はすべて、対照実験(コントロールグループ)から得られたものです。私たちが実際に毎日作業を行うのはもう一方の環境です:100 万行の Lua コード、独自フレームワーク、市販モデルではほとんど見たことがない技術、そして重層的な負債。対照実験でさえこのようにバックアップが必要なのに、こちらの環境ではより一層必要となるでしょう。
以下に述べる 5 つの事項は、まさにその現場で得られた教訓であり、これらは段階的に連なるチェーンとなっています:AI の側が耐えなければなりません。プロンプトで対応しきれない部分はフレームワークへ、フレームワークでも対応できない部分はさらに下層の runtime へと委ねます。成果の良し悪しは「数値化」して計測する必要があります。機械が耐え、数値も出た上で初めて、「人間はどこまで退くべきか」が決まります。最後に、これらの判断基準を日常運用されるフローに変換します。
各ステップで実際に行っていることは一つです。「AI の声明を信じる」状態から「事実を信じる」状態へと、特定の工程を移行させることです。
全文の構成概要
- 項目:私たちが以前信じていたこと / 後に改めた考え方
- 一、プロンプトの限界はインフラ:AI は覚えておくべきだ / プロンプトに注意点を積み重ねるとモデルが鈍化する。制約をフレームワークへ沈めることで、モデルは厚く強くなる
- 二、オーケストレーションの限界は runtime:公式メカニズムで十分、Skill で補完可能 / メカニズムが欠落して補えない場合、runtime は監査・介入が可能でなければならない
- 三、スコアは信頼できない、問題は問題集にある:評価システムを構築するだけでよい / 判断基準は実行可能でなければならず、工程規模の大きさが信頼性を保証するわけではない
- 四、人間は意思決定点へ退く:人間が逐行レビューすればカバーできる / 機械にしか取得できない事実があり、AI はそれを回避できない
- 五、判断基準をフロー化する:1 回のセッションで完結し、AI の自己実行レポートを信じる / 大ループの中に小ループを重ねる多重チェック。各ループ間では事実のみが伝達される
上記の 5 つは本文の核心であり、それぞれが一つの物語です。以下、この順序で詳しく解説します。
第一部分:プロンプトの限界はインフラ
#### 本部分のポイント
- プロンプトの限界:注意点を積み重ねるほどモデルの注意力が散漫になり、メインタスクのパフォーマンスが低下する。
- 制約をフレームワークへ沈める:宣言型モックによる自動復元や、Trace のタイムアウト分析パッケージなど。これらはフレームワークによって「エラーそのものの存在を消し去る」ことで、AI の注意力をメインタスクに戻す役割を果たします。
エラー出力のチャンネル自体が、そのままプロンプトインジェクションの経路でもあります——最も効果的なプロンプトとは、適切なタイミングでのフィードバックです。しかし、間違った方向へ導くフィードバックは、何もない状態よりも悪いです。
基準を下げること:事実として確定した事象に対してのみハードな制限をかけ、代理指標については最多でも警告にとどめるべきです。信号は外部から取得し、誤検知が起きれば、かえってコードの質を低下させる圧力になります。
まずは AI 側の耐性について見てみましょう。ここでは、垂直領域のエージェントを開発するチームなら必ず直面する現象について解説します。それは「プロンプトによる収益性の限界」です。
AI 時代には、数行のプロンプトでそれらしいデモを構築できます。しかし、本番環境で使えるレベルまで深掘りしようとすると、最終的にたどり着く先は同じ——インフラストラクチャです。
テスト用エージェントの事例を見てみましょう。まず背景を説明します。プロジェクトの技術スタックが特殊なため、私たちは独自にエンドツーエンドのテストフレームワークを開発しました。AI に任せる前に、すでに数ヶ月間社内で使用され、成熟した状態になってから AI へ引き渡されました。テストエージェントのプロンプトとフロー編成もまた、数ヶ月かけて磨き上げられていました——しかし、すぐにボトルネックに直面します。プロンプトをどう調整しても、初期に見られたような劇的な効果は得られなくなりました。
当時の私の第一反応は、引き続きプロンプトの改善でした。言葉遣いをより厳しくし、ルールを細かくし、例を追加する。この方向性は長く壁にぶつかり続けました。手元にあるすべてのテストセッションを分析ツール「tracesift」で展開して分析した結果、残りの課題がプロンプトやフローのレベルでは解決できないことが明確になりました。具体例を二つ挙げます。
(一)事例 1:モックの復元
テストの古典的なパターンは setup/teardown です。開始前にモックを設定し、終了後に復元します。プロンプトで「setup と teardown は必ずペアで実行する」と繰り返し強調しても、AI は約半数の確率で teardown を見逃してしまいます。その結果、テストケース同士が互いに汚染され、検証プロセス全体が制御不能な状態になります。
一般的なアプローチは lint フックを追加することですが、この問題はルールベースの lint では検出が難しく、AI も回避する可能性があります。そこで発想を転換し、フレームワークレベルで解決することを考えました。自動 GC のように、宣言的なモック設定と自動復元機能をフレームワークに追加しました。モックを設定すれば、テスト終了時にフレームワークが自動的に復元します。これにより、AI がここでミスを犯すことはほぼなくなりました。
テスト作成では同時に考慮すべき点が多すぎます。このタスクは AI にとって実は非常に重荷です。フレームワークを使って特定の種類のエラーを排除することは、AI の注意力を本来の主要なタスクに戻すことに等しいのです。
(二)事例 2:トレースリンク分析
AI がテスト実行で最も頻繁に直面する問題が「リンクタイムアウト」です。この種の課題では大量のコードを読み込み、呼び出しチェーンを追跡する必要があります。すでに負担の大きいテスト実行タスクに、高度な分析をさらに追加すると、AI は非常に長い時間を要し、文脈オーバーロードや注意力散漫を起こす確率も高まり、根本的な解決に至らないことが多々あります。
私はフレームワーク内のトレース実装を再構築しました。リンクタイムアウトが発生した際、正確な原因と分析パッケージを自動的に返すようにしました。
単なるタイムアウトエラーでは「応答が来なかった」という事実しか伝えられません。そこで、タイムアウト発生時にフレームワークは各サービスのキューやレート制限登録表に対して逆方向にプローブを実行し、検出された状況に応じてタイムアウトを分類します。「まだキュー待ち中」「キューから出たがビジネスコード側で応答がない」「配信層でレート制限により破棄された」「応答は届いたが処理担当者がいない」——各カテゴリには現象の説明だけでなく、次のアクションが明記されています。例えば「前置きリクエストのレート制限クォータを使い切っていないか確認する」といった指示と、どの設定フィールドを確認すべきかも具体的に示されます。分析パッケージにはさらに「コード実行パス」というセクションも含まれます。フレームワークはビジネスソースコードを開き、そのリンクで最後に実行された数行をそのままエラーメッセージに貼り付け、最終行には矢印を表示します。AI はどこで止まっているかを推測する必要がなく、どの行で停止しているかを直接確認できます。
この設計には、別途言及する価値のある副産物があります。エラー出力のチャンネル自体が、プロンプトインジェクションの経路となるのです。これを通じて AI が必要な情報を正確なタイミングで返すことができます——まさに AI が行き詰まった瞬間に情報が届くのです。
最も優れたプロンプトとは、適切なフィードバックです。
しかし、この経路は逆効果になることもあります。フレームワークにはかつて、AI がプロトコルテーブルに登録されていないプロトコル名を待っている際に「そのプロトコル名が見つかりません」と警告する機能がありました。しかし、後にこれを削除しました。理由はドキュメントに記載されています——プロトコルテーブルは実際のトラフィックに基づいて生成されるため、マイナーなプロトコルはそもそも網羅されておらず、ログイン期間中のプロトコルに至ってはテーブルに存在しません。そのためこの警告の信号対雑音比が極めて悪く、AI を誤った方向へ誘導してしまいます。注入する情報は多いほど良いわけではありません。間違った方向へのフィードバックは、何もない状態よりも悪いです。
(三)二つの事例に共通すること
解決策はエージェント層ではなく、その下にあるフレームワーク層にあります。プロンプトの段階では「注意を促す」ことしかできませんが、フレームワークのレベルであれば「このエラー自体が存在しないようにする」ことが可能です。
最も直接的な証拠は、ある規則が消えたことです。自動復元機能上线 之前,我们靠人肉纪律维持秩序:会改脏环境的那批用例必须排到最后跑,跑完还得重启服务。等自动还原和静态闸门都到位,交接文档里写下的是——这条纪律"自此作废"。不是 AI 变听话了,是这类错误不再可能发生,纪律没有了存在的理由。
(四)注意点加不下去了
テストエージェントのスキル名は ut-tester です。SKILL.md は四百行を超え、坑穴回避、テンプレート、注意点が十数枚のドキュメントにわたって記載されています。2 月から 6 月にかけて毎月追加されていましたが、7 月以降はほぼ停止しました。完成したからではなく、「これ以上追加できない」からです。注意点が多すぎると、モデルが同時に記憶すべき情報が増え、注意力が散漫になり、テスト記述という本来のタスクの質が逆に低下します。
これが「ハーンネス(枠組み)が厚くなればなるほど、エージェントは賢くなくなる」という現象が成立する理由です。開発プロセスにはこうした制約が溢れています。スキル、SOP、手順説明など、モデルに指示された通りに行動させる必要があります。モデルには、その分野で安定した事実や能力の境界線が必要です。書かなければモデルは知りません。しかし、それには上限があります。いくら厚くしても、厚くなるのはモデルの作業記憶だけです。
特にパッチ適用のようなケースでは、注意点を追加してはいけません。モデルが一度間違えたら、「次からは必ずこの道筋をたどれ」というルールを追加したくなります。「mock ss は禁止し、正しい書き方は一つだけだ」といった指示も書きました。しかし、実装から八日後にリポジトリ内の 529 の既存単体テストを確認すると、その規則は「記述された時点ですでに事実と矛盾していた」ことが判明しました。長く使ったから壊れたのではなく、有限のルールで無限の問題を覆い尽くそうとした時点で失敗していました。
同じ時期、力点は ut フレームワークに移されました。6 月のフレームワーク側のコミット数はスキルの約四倍に達し、7 月と 8 月もカバレッジ製品の追加や、トレースフックのより深い階層への統合、隔離実行のためのプロトコル補完が続けられました。ut-tester の最後の実際の改修タイトルは「UT フレームワークの最近の変更点への対応」でした。mock の自動復元やタイムアウト分析パッケージなどは、もともとスキルに書かれていた注意点をモデルの頭から取り除く作業です。一つずつ取り除くことで、本来のタスクがクリアになります。
つまり、「厚さ」には二つの種類があります。混同してはいけません。プロンプトに書く場合、厚くなればなるほどモデルは賢くなくなります。一方、フレームワークに組み込む場合、厚くなればなるほどモデルの手間が減り、本来のタスクのパフォーマンスが向上します。検証は三番目のステップで、成果物が出た後に行われます。提出されたテストが本当にバグを捉えられるか、レポートに嘘がないかを核査することです。これは後の評価や验收 の問題であり、開発プロセスにおける SOP ではありません。
本格的なエージェント構築の最終段階は、すべてインフラ基盤の整備に帰着します。AI 時代においても基礎知識が古くなることはありません。むしろ、フレームワーク設計、コンパイラ原理、プロトコルスタックといった硬い技術こそが、あなたのエージェントが深水区を脱出できるかどうかを決定する要素なのです。
(五)それともすべてを下層に沉めるべきか?
制約型の注意点を無制限に積み上げるべきではありませんが、だからといって全てを即座に下層に沉めるべきだということでもありません。判断基準は、私たち自身のフックファイルの中にあります。同じインターセプター内の二つのルールで、扱いが全く異なります。
一つ目は「protocols ディレクトリの読み込み禁止」です。判別基準はパスのプレフィックス比較です。対象パスがそのディレクトリ内にあるかどうか、あるかないかだけです。これは今もハードなインターセプトとして機能しており、AI がこれにぶつかることは避けられません。
二つ目は「.lua ファイルを編集する前に必ずコーディング規約を読むこと」です。これも当初はハードなインターセプトでしたが、判別基準はセッション履歴の走査で、AI がその二つの規範ファイルを読んだかどうかを確認していました。しかし、上线 两周后降成了警告。因为这个判据不是事实,是代理指标:读过不等于遵守,没扫到也不等于没读过。它自己还翻过一次车,代码注释里留着结论——主会话累积了所有历史 Read,会把"已读"这个状态污染给之后的每一个子 agent。
判別基準が確実な事実であれば、ハードなゲートとして機能します。一方、代理指標である場合は、せいぜい警告にとどめるべきです。これは序論で述べた「その尺」と同じものです。使い方が異なるだけです。そこでは「機械に任せるか人間に残すか」を分けていましたが、ここでは「仕組みにするかプロンプトに残すか」を分けているのです。
この基準に従うと、さらに二つの点について言及する価値があります。
まず、評価対象となるコードの信号は外部から取得可能でなければなりません。AI に自己申告させることはできません。
先日あるプラットフォームで行ったテストの一環で、非常に厄介な失敗事例に直面しました。スクリプトは正常終了し、レポートファイルも生成されたにもかかわらず、カバレッジが「0/0 行」と表示され、即座に不合格と判定されました。これは、AI が被験関数の内部ロジックをそのままコピーしてローカル変数で再計算し、アサーションを通すという、極めて巧妙な偽のテストを防ぐための措置です。アサーションはすべて通りますが、カバレッジはゼロであり、回帰テストとしての価値はありません。
こうしたエラーはプロンプトだけで防ぐことはできません。AI 自身も「自分は正しく実行した」と判断してしまうからです。真に問題を見抜けるのは、「被験関数の行が一度も実行されていない」という外部からの事実だけです。
次に、誤検知(False Positive)の代償は想像以上に大きいという点です。
私たちが開発した Lua によるテスト静的解析ツール「ut-lint」には、誤検知を起こしやすいと承知の上で、あえてブロック機能を実装していないルールが二つあります。代わりに、コードレビュー担当者のプロンプトにおいて、「lint の結果は必ずソースコードを再確認し、採用するか誤りとして却下するか、その理由を明記する」ことを義務付けています。
なぜなら、誤検知の実際の代償を私たちは既に経験しているからです。あるルールを改善した際、目的は非常に明確でした。「lint を通すためにヘルパー関数を無理やり分割してインライン化するのをやめること」。しかし、誤検知が起きると、その結果は単なる警告の浪費にとどまりません。人間と AI がチェックを通過するために、かえってコード品質を下げるような書き方を強要されることになるのです。
最後に、少し曲折があった取り組みについて補足します。
ut-lint は当初、レビュー担当者のプロンプトに記述されたルールとして存在し、「レビュー前に必ず実行せよ」という指示でした。これはあくまで制約層の話で、モデルが記憶して実行する仕組みでした。これをより深くシステムに組み込もうと、最初の案は「SubagentStop」フックの実装でした。サブエージェントの終了直後に自動的に lint を実行し、結果をコンテキストに戻すというものです。
しかし、この案は頓挫しました。Claude Code や codebuddy のフックプロトコルでは、「SubagentStop」が「ブロックして理由を提示する」ことしかサポートしておらず、コンテキストへの内容注入は不可能だったからです。私たちが求めたのは「提案」でしたが、プロトコルが許すのは「ブロック」だけでした。
そこで方向転換し、lint のトリガーをテスト実行スクリプト自体に組み込むことにしました。テストを実行すれば自動的に lint も走る仕組みです。これによりエージェントフレームワークからの依存を断ち切り、CI 環境全体も恩恵を受けることができます。この実装はまだ完了していませんが、フック経由の手法よりも根本的な解決策と言えます。同じルールでも、「モデルに実行を促す」から「テストを実行する環境で自動的に実行される」へと進化しました。
この一連の経緯は、より深刻な問題を浮き彫りにしています。「機能を下層へ実装できるかどうか」は、私たちが主導権を握っているかどうかに依存するのではなく、その下に存在するプラットフォームが API を提供しているかどうかにかかっています。
第二部分:编排的尽头是运行时(第二部分:オーケストレーションの果てに待ち受けるのはランタイム)
本節のポイント
- 「workflow-engine」を導入したことで安定性は確保されましたが、トークン消費量、ユーザー体験、メインエージェントの遊休化という三つの課題が顕在化しています。
- 二つの「Agent Teams」実験の結果:完全なワークフローは脆すぎて普及に至りませんでしたが、「テストプロセスに特化した /module-test」は安定して稼働し、数百回の失敗セッションを経て「agent-teams skill」として確立されました。
- 「skill」の導入によりメカニズムの不備を緩和することはできますが、根本的な欠陥を解消できるわけではありません。三つのブラックボックス事故が示す通り、エージェントループのあらゆる环节は監査可能かつ介入可能でなければなりません。
- オーケストレーションの問題を追及すると、最終的に「ランタイムにおける主権」の問題に行き着きます。真の選択課題とは「どの製品を選ぶか」ではなく、「主権の境界線をどこに引くか」です。
フレームワーク層で解決できる問題は既に片付きました。残る課題は、解決不可能なものか、あるいは ut-lint の例のように基盤側の制約によって足かせを掛けられているものです。オーケストレーションの進め方、コンテキストの圧縮方法、ツールパラメータの結合場所——これらは果たしてどのレイヤーで決定すべきなのでしょうか。
(一)workflow-engine が抱える三つの課題
前回のまとめにおいて、私たちのマルチエージェントオーケストレーションは「workflow-engine」に集約されました。メインエージェントを状態機械として設計し、固定されたフローに従ってサブエージェントを起動する仕組みです。当時の結論は、「真にコストがかかるのはトークンではなく、制御不能な状態である」というものでした。そのため、安定性を最優先しました。
一四半期が経過し、確かに安定性は確保されましたが、以下の三つの課題が浮き彫りになってきました。
1. トークン消費の増大
サブエージェントは毎回クリーンなコンテキストからスタートするため、同一のコードを繰り返し探索することになります。特に複数回のループ処理において顕著で、レビューが三回返却されれば、実行者(implementer)は関連コードを三回読み直すことになります。
2. ユーザー体験の低下
オーケストレーションロジックが複雑になりすぎ、習得ハードルが高くなっています。また、サブエージェントが作業を進める過程が見えにくく、ユーザーには制御感が欠如しています。
3. メインエージェントの遊休化
メインエージェントは秩序維持のみを担当しており、最も価値のある機能である「ユーザーとの直接対話」が活用されていない状態です。
今四半期、私たちはかつて閉ざした門を再び開けました。
「制御不能になるコストがトークンより高い」という判断自体は誤りではありませんでした。しかし、「安定」だけを追求するだけではもはや不十分だと気づいたからです。
そこで二つのアプローチを並行して進めています。
一つ目は、最も対話の密度が高い「要件定義」と「アーキテクチャ設計」のフェーズを主エージェントが直接担当し、サブエージェントは前回のセッションから継続(resume)させることで、新規生成(spawn)を避けるというものです。このアプローチには三つのメリットがあります。
第一に、対話頻度の高い工程において、ユーザー体験を単一エージェント並みに向上させられる点です。第二に、主エージェントがタスクを配分する際により多くの有効な文脈を含められる点です。第三に、サブエージェントは前回の記憶を引き継いで作業を進めるため、ゼロから探索する必要がない点です。
この道筋はリスクが低く、すでに現在の /dev 流程に組み込まれています。
二つ目は、Claude Code に固有の「エージェントチーム(agent teams)」を活用するアプローチです。これは本質的に、メンバーが常駐し、相互に直接メッセージを送り合い、タスクボードを共有するネットワーク型の多エージェント通信モデルです。
常駐型であるため複数回のループ処理に適しており、ネットワーク構造によってオーケストレーションの柔軟性を最大化できます。理論上のみを見れば、これは前述の三つの課題に対する最良の解決策と言えるでしょう。
しかし、この二つ目のアプローチはリスクが高いものです。今日に至るまで、エージェントチームに関する公式ドキュメント以外に公開された実践例はなく、公式側もこれを「実験的機能」として位置づけ続けています。この険しい道を私が開拓します。
(二)第一の実験:開発プロセス全体をチームに移行する
5 月末、私は非常に大胆なアプローチで第一回目の実験を行いました(experiments/2026-05-29-team-driven-dev)。その核心は以下の通りです。
/dev コマンドと workflow-engine の状態機械(state machine)を廃止し、代わりに二つのスキルを直列化して接続します。第一のスキルは「brainstorming」で、主エージェントが対話形式で設計を行い、arch.md と plan.md を生成します。第二のスキルは「team-execution」で、チーム主導で実行を行います。
プロダクト駆動型の状態管理には state.json を使いません。arch.md が存在しない場合は最初からやり直し、plan.md が存在する場合はそこから直接実行を開始します。中断からの復旧も状態機械に依存せず、ディスク上のプロダクトを検索することで実現します。
チームには七つの役割を割り当てます:planner(計画)、implementer(実装)、reviewer(レビュー・複数インスタンス可)、test-planner(テスト計画)、test-engineer(テストエンジニア)、explorer(探索者)、guardian(監視役)です。
レビューの循環は、主エージェントを経由せず、実行者とコードレビュアーが直接メッセージを送り合うピアツーピア接続で構成されます。
また、guardian は非同期で常駐し、「ユーザーの発言と主エージェントの理解が一致しているか」だけを監視する傍観者として機能します。これにより、長文の対話において要件が誤解されるのを防ぎます。
設計図上では非常に美しく見えますが、実際に動かしてみると、コミット履歴にはパッチの羅列しか残っていませんでした。陥った課題は四つのカテゴリーに分類でき、浅いものから深い順に解説します。
第一の課題:モデルがこの仕組みを認識していないこと。
Anthropic はエージェントチームの動作原理をモデル自体に組み込んで訓練していません。すべての振る舞いはプロンプトによってその場で教える必要があります。そのため以下のような問題が発生しました。
主エージェントが要件を受け取ると、いきなり対話を始めてしまい、先にチームを構築することを忘れます。このため、スキル内に「STEP 0 は強制前置きであり、スキップ不可」というルールを追加せざるを得ませんでした。
ワークフローディレクトリの命名規則が kebab-case、CamelCase、中国語の間で揺れ動きました。このため、プレースホルダーを固定値として snake_case に書き換える対応を行いました。
guardian が「tracesift ツールを使ってログを読み取る」という指示を受けると、内蔵ツールリストから tracesift を探し始めますが、見つからないと諦めてフォールバック処理へ移行してしまいます。このため、「tracesift は shell コマンドであり、Bash で呼び出すもの」という指示に修正しました。
これら一つひとつの対応は、失敗したセッションから得られた教訓をプロンプトに反映させた結果です。
- 中断活锁(Interrupt Livelock)——最も深刻な問題の一つ
実運用を約 2.5 時間行い、その後の振り返りにおいて、プランナーが「なぜかアイドル状態」に陥り、plan.md を生成できないという事象が発生しました。tracesift でセッション記録を解析した結果、根本原因が判明しました。
主エージェントは約 1 分ごとにプランナーを催促しますが、プランナーの単一ラウンドでの準備(メソッド論のスキル再読込み、arch.md の読み込み、中断された検証の実行)には 1 分以上かかります。このため、各回の催促が進行中のツール呼び出しを中断させ、そのラウンドは破棄されます。結果として、出力されるトークン数は次第に減少し、580 トークン → 278 トークン → 最後にはわずか 1 トークンという状況になりました。
プランナーはセッション記録の中で「私のスキル読み込みと検証クエリがメッセージによって中断された」と記述しています。さらに深刻なのは、主エージェントがこの状況を「チームが再開後に無効になった」と誤判断し、チームを再構築して再び催促を繰り返した点です。このようにして活鎖(ループ)は自己増殖しました。
今回の振り返りから得られた 3 つの鉄則は、その後スキルに組み込まれました:
- 動作中のエージェントを直接催促しないこと
- 明示的な DONE または BLOCKED シグナルのみを信頼すること
- アイドル状態は正常な状態である(これを「PROTOCOL-A」と呼ぶ)こと
また、プランナーのような役割はタスクとして扱い、一度に生成して自己完結させるように変更しました。さらに、テストの断言はアーキテクチャドキュメントの受入基準から事前に凍結し、実装完了後にプレースホルダーを埋める形式とすることで、実装のズレがテストを汚染するのを防止しています。
- メンバーのライフサイクルの不確実性
プロセス内のメンバーは主プロセスの終了とともに消滅します。セッションが再接続された際、生体状態の情報はすべて失われますが、主エージェントはまだ存在しないメンバーに対してメッセージを送信し続けています。
対策は一つだけです。すべての判断をディスク上の成果物に基づいて行うことです。接続が切れた場合は、ディスク上の arch.md や test-plan.md を用いてメンバーを無損失で再構築し、常駐して常に生存していることを前提にしないようにします。
第四の壁:仕組み自体が直感に反する点です。
実際には、非協力的なメンバーを強制的に排除することはできません。強制終了ツールは taskId を要求しますが、spawn 時に取得できるのは agentId で、両者は互換性がありません。メンバーがシャットダウンに応じない場合、チーム解散の呼び出しは常に失敗します。唯一の解決策は、手動で ~/.claude/teams/ ディレクトリ内の config.json を編集し、該当メンバーを削除することです。
一度タスクに所属メンバーが割り当てられると、メンバー間でのタスクの奪い合い(タスクスチール)機能は無効化されます。これが原因でシステムがフリーズすると、そのタスクを引き継ぐ者がいなくなり、処理が停止したままになります。これらの事実は公式ドキュメントには記載されておらず、すべてソースコードの精査と実機でのトラブルシューティングを通じて得られた知見です。
一連のフロー全体を本番環境で運用するに至らなかったのは、技術的に不可能だったからではありません。システムがあまりに脆く、他のメンバーに任せる自信が持てなかったからです。しかし、この実験は貴重な資産を残しました。それが「agent-teams skill」です。これは数百回の失敗したセッションから生み出された運用ノウハウの集約です。
その内容は、前述のトラブルポイントを体系的に整理したものです。具体的には、メンバーの状態をどう読み解くか(idleReason の三態)、エラー発生時に failureReason に基づいてどのように分岐させるかといった指針が含まれています。例えば、レート制限がかかった場合は同じメンバーに対してバックオフして再試行し、決して相手を変えません。認証が失効した場合は即座に処理を停止し、別の担当者を呼び出します。
また、「フリーズ」の判定基準は状態記号ではなく「タイムアウト内にメッセージがないこと」と定義しています。さらに、メッセージの嵐や中断による活鎖(デッドロック)を防ぐための通信ルールも明文化されています。
これらのルールの共通点はすべて「宣言を信じず、事実を信じる」という点にあります。状態記号を信用するのではなく、タイムアウト内に実際のメッセージがあるかどうかを確認します。生きているメンバーを信頼するのではなく、ディスク上に残された成果物を根拠とします。
(三)第二の試み:戦場を狭め、テストフローに限定して Team を活用する
全体フローが不安定なため、運用範囲を縮小しました。チーム機能はテストフローのみで使用し、通信方式とプロセスを厳格に制限します。これが現在の /module-test の仕組みです。
主エージェント(Main Agent)が自ら仕様書(spec)を作成します。この仕様書は「答え付きの引き継ぎ資料」であり、プロトコルのアンカーポイント、読み戻し方法、検証項目のマトリックスなどすべてコードレベルで確認済みで、空白を許しません。
チームにはテストエンジニアとレビュアーという二人のメンバーのみが所属します。テストエンジニアは計画策定、コーディング、テスト実行を担当し、レビュアーは独立した審査を行います。両者は双方向で直接連携して相互審査を行い、主エージェントは仲介や代行審査を行いません。主エージェントは「agent-teams skill」に基づいて進捗を監視し、エラー発生時のセーフティネットとして機能します。3 回の試行で収束しない場合は、ユーザーへエスカレーションします。
仕様の検証項目マトリックスは審査の権威ある基準であり、早期に凍結する。テストで赤色判定が出た場合でも、対応する仕様検証項目が満たされていないなら、それはコードの不具合として扱う。緑化のために断言を緩めることは絶対に許されない。
この編成を数十回にわたる多様なタスクで試しましたが、agent-teams のスキルと test-generator スキルを活用することで、プロセスは比較的安定して完了します。また、agent teams が持つ最大の利点——いつでも任意の agent と直接対話し、あらゆる工程を自由に介入できること——も維持できています。これは workflow-engine には提供できない、確かなコントロール感です。
しかし、編成層面には解決が難しい欠点があります。レビューアーが常駐しているため、再審査時に前回の自分の意見に引きずられがちで、直前の問題ばかりに目が行き、全体を網羅的に審査しきれないのです。これを根本から解決するには、毎回の评审ごとに新しい agent を spawn する必要があります。评审時間とトークン消費のバランスを考慮した結果、私たちは欠点があることを承知の上で、常駐レビューアーを残すという妥協を選びました。
2 つの実験を通じて、私の結論は以下の通りです。agent teams の方向性は正しい(ネットワーク状の通信、常駐メンバー、自由な介入)ものの、現在の実装には欠陥があります。モデルがこのメカニズムを学習していないこと、ツールのプロンプトや行動が LLM に不親切であること、そしてその上に構築された編成ロジックは、いかに記述しても脆いのです。スキルはメカニズムの不完全さを緩和できますが、欠陥そのものを解消することはできません。
では、この「欠陥」はどこにあるのでしょうか?それは、ランタイムに対する主権を私たちが持っていないことにあります。口約束だけでは説得力がないので、以下に3 つの実際の事故事例を示します。
(四)三つのブラックボックス事故
第一の事故は、Claude Code のテレメトリ問題です。claude code は隠れた手段で利用者が中国から来たかどうかを検出し、該当するとプロンプトやツール呼び出し内で毒を注入します。詳細はここでは割愛しますが、これは「生産プロセスをブラックボックスな CLI 上に構築する」という信頼の基盤を揺るがすものです。
第二の事故は、CLI で長い中国語ファイルを作成した際の UTF-8 の破損です。CLI を使って中国語技術文書をバッチ生成した際、37 件の出力のうち 36 件が破損し、合計 370 箇所に U+FFFD が発生しました。根本原因は、CLI がツール呼び出しのパラメータを結合する際に、マルチバイト文字をバイト単位で切断してしまったことにあります(第四部での検証時にも別の角度からこの問題に直面します)。このコードはブラックボックスの中にあるため、私が修正することはできません。
第三の事故は、圧縮バグによる 11 時間のアイドル状態です(完全な振り返りはチームブログ『一個 agent 空轉 11 小時的復盤』をご覧ください)。読み取り専用の探索タスクが 11 時間、6556 回のツール呼び出し、1.23 億の input token を消費して何の結果も得られませんでした。4 つの要因が重なった結果です:max_turns の制限が無効化されていたこと;圧縮しきい値が 100K に固定されており、モデルの 200K ウィンドウの半分しか使われていなかったこと;圧縮サマリーで「生成摘要」という指示をユーザーリクエストと誤認したため、回復に最も重要な「現在の進捗」と「待機事項」のセクションがタイトルだけになってしまうことが頻発したこと。その結果、毎回の圧縮後に agent は記憶喪失となり、同じキーワードセットから Grep をやり直しました。203 回の圧縮は、つまり 203 回の最初からのやり直しです。
(五)合流:自前の agent runtime の構築
この二つの流れがここで交わります。編成実験の結果、メカニズムには欠陥があり、スキルで補うことはできないため、根本から runtime を改める必要があることが証明されました。三つの事故は、agent loop の各环节——コンテキストの圧縮方法、ツールパラメータの結合方法、制限の実行方法、テレメトリの送信内容など——すべてが監査可能かつ介入可能でなければならないことを示しています。claude code や codebuddy はオープンソースではないため、開発者はプロンプトや hook を通じて外部から手を伸ばすしかなく、問題発生時にはセッション記録を逆解析して原因特定を行う必要があります。垂直分野のシーンにおいて、このようなカスタマイズ能力はあまりに弱すぎます。
自前の agent runtime を構築する必要性があります。
ではコストはどうでしょうか?また同じものを再発明することになるのでしょうか?選択肢を並べてみましょう:
trpc-agent-go などのフレームワークから書き下ろす場合:これはまさに「輪子の再発明」です。agent loop、ツールプロトコル、コンテキスト管理など、すべてを自前で実装する必要があります。
trpc-agent-go を薄くラップする場合:必然的に他のチームが同じことをしているはずです——正直なところ、私の第一反応もこれでした(笑)。
claude/codebuddy の agent SDK に基づく場合:底層は依然としてブラックボックスであり、三つの事故のいずれも回避できません。
codex CLI / SDK はオープンソースでカスタマイズ可能ですが、規模が大きく理解コストも高いという課題があります。また、そのオープンソース化は外見ほど徹底しているわけでもなく、これについては後ほど詳しく説明します。
pi agent は MIT ライセンスのオープンソースプロジェクトで、「最小限のエージェント・ハーネス」を自称しています。システムプロンプトは 1000 トークン未満に抑えられており、サブエージェントやプランモードといった機能はあえてコアに組み込まれていません。必要な場合は TypeScript で拡張を作成し、ツール、コマンド、イベント、そして TUI(ターミナルユーザーインターフェース)全体にアクセスしてパッケージ化・配布することも可能です。このプロジェクトのトップページに掲げられた売り文句の一つが、まさに我々の課題に直結しています。「最小限のシステムプロンプト」と「拡張性」を組み合わせることで、コンテキストエンジニアリングを実践し、ウィンドウ内に何を含め、どう管理するかを自分で制御できるのです。その境界線も明確です:変更可能なのは事前に用意された拡張ポイントのみで、エージェントループ自体はコア内のコードであり、プラグインではありません。
DeepSeek Harness は、本稿執筆時に v0.1 の開発者プレビューとしてオープンソース化されました。MIT ライセンスのもと、「すべてがプラグイン」という理念を採用しています。モデル、ツール、スキル、セッション、サンドボックス、ストレージ、ループ、スケジューリング、UI まで、あらゆる要素がプラグインです。基盤となる Cordis メタフレームワークは、プラグインのロード・アンロードと依存関係の管理のみを担当します。ソースコードを変更しなくても、エージェントループ自体を含む任意の機能を置き換えることが可能です。
codex については、もう一つより隐蔽された問題を指摘しておく必要があります:オープンソース化=主権の確保ではありません。新版ではマルチエージェント通信において、サブエージェントのタスクペイロードが暗号化されており、その復号は OpenAI のサーバー側でのみ可能となっています。親エージェントと子エージェント双方が OpenAI に接続していなければ通信できず、子エージェントを他社のモデルに置き換えると暗号文が通過しません。ローカル環境でデバッグしても、実際のタスクテキストを確認することはできません。サードパーティが互換性のある Responses API サービスを提供しようとしても、この復号の壁は越えられません。表面上はマルチプロバイダーに対応しているようですが、核心となるプロトコルは特定のサービスに固定されています。言い方を変えれば、これは「偽のオープンソース」です。リポジトリは公開されていても、プロトコルはロックされており、主権は他者に握られています。
codex の事例は、選定における真の問題を浮き彫りにしました:重要なのは「どの製品を選ぶか」ではなく、「主権の境界線をどこに引くか」という点です。具体的には、プラグイン化がどのレベルまで及ぶかが問われます。過去に起きた 3 つの事故が、この境界線の測り方を示しています。求められる可換性は、それぞれより深いレベルを指し示しています。
- ツールパラメータの結合方法:UTF-8 データをバイト単位で切断するような処理は、自分でコードを握り直せる必要があります。これは最も外側の層であり、多くの基盤が対応可能です。
- コンテキストへの注入内容とテレメトリデータ:モデルが認識するすべての情報は、その出所を追跡可能であるべきです。これが監査の最低ラインです。
- コンテキストの圧縮方法:圧縮戦略は、閾値やサマリーテンプレートの詳細を推測して調整するのではなく、丸ごと交換できる必要があります。これはエージェントループ内部に実装されているため、最も深いレベルの問題です。
11 時間に及ぶ空回りの事故を振り返ると、その根本原因は「生成されたサマリー」をユーザーの要求と誤認し、復旧に不可欠な 2 つのセクションがタイトルだけになってしまったことにあります。これはセッション記録を遡って解析することで判明した事実です。もしすべての注入に追跡可能性があれば、このような調査は考古学的な発掘から始める必要はありません。
この「尺」で測ると、pi agent と DeepSeek Harness の違いは新旧の問題ではなく、「境界線をどこに引くか」の違いとなります。pi はループと圧縮戦略をコア内に残していますが、DSH(DeepSeek Harness)はこれらもプラグイン化し、メタフレームワークはロード・アンロードのみを担当します。監査の要件についても DSH は対応可能です:モデルが認識するすべての情報は、システムプロンプト、思考連鎖、ツール呼び出しとその結果、サブエージェントのスケジューリング、そして各回のコンテキスト注入を含め、append-only(追加専用)のセッションログに記録されます。出所ごとに遡って確認でき、復元、分岐、再生も同じイベントストリームを共有します。
アーキテクチャ上では DSH の方がより徹底していますが、選定はアーキテクチャだけで決まるものではありません。私自身の経験における証拠の強さには大きな差があります。pi については数ヶ月追随し、実際に試した経験もあります(ただし結果はまだ微々たるものですが)。一方、DSH については現在、公式ブログ記事 1 篇のみを手にしています。「すべてがプラグイン」という主張は現時点では DSH 側の発表に過ぎず、私が実際に検証していません。
ここで本文で示した「尺」の出番です:声明と事実は区別する必要があります。順序の問題ではなく、事実ベースでの判断が求められます。
「PI Agent」の先行戦略は、数ヶ月にわたる接触と基盤構築に基づき、拡張のハードルが低く、その自己定位の核心は文脈管理にあります。これはまさに我々の痛みに直結する課題です。
特定領域への拡大は、プロンプトの修正やツールの追加から始め、コアの境界にぶつかるまで記録し続けます。記録された一つ一つの事象が、次のステップにおける要件リストとなります。
「DeepSeek Harness」の追従については、「すべてをプラグイン化する」という設計思想に基づけば、より堅牢な基盤になると期待できます。ループ構造自体も置き換え可能です。しかし、「期待できる」という言葉は、自らの手で検証するものであり、他者の主張を鵜呑みにしてはいけません。現在、コアとなるプラグインや基本インターフェースは急速に迭代(進化)しています。この段階で生産プロセス全体を賭けることは、本番環境をテスト台として使うことと同義です。
守るべき原則は明確です。メタフレームワークは荷役と積卸しのみを担当し、機能はすべて交換可能なプラグインとして実装します。道筋も明確です。最小限の Harness から始め、壁にぶつかったらその部分だけを置き換えればよく、最初からフレームワーク全体の複雑さを背負う必要はありません。真の特定領域への拡大はまだスケジュールに組み込まれていません。これは工期の問題であり、やるべきかどうかという問題ではありません。具体的な進め方は、次回の記事で解説します。
編成(オーケストレーション)の問題を根幹まで追及すると、それはランタイムの主権の問題に行き着きます。この認識は独断ではなく、二つの実験と三件の事故、そして一度のソースコード監査という代償によって得られたものです。
第三部:スコアは信頼できない、問題は問題集にある
本部分のポイント
十七万行に及ぶ評価プラットフォームから残されたのは、たった二つのスコアだけです。十六回の実験で、現在も使用されている一つの戦略が変更されました。違いは工数の規模ではなく、判断基準を実行可能かどうかにかかっています。
業界調査の結論は容赦ありません。論文で裏付けられた手法はすべて機能しますが、唯一自社開発した「空いた穴を埋める」アプローチだけが崩壊しました。
V2 では主要指標を「変異キラー率(Mutation Kill Rate)」に設定しました。「隠れたものを見つけられたか」ではなく、「作成したテストが実際にどの程度のバグを検出できるか」を問います。
評価の核心作業はプラットフォーム構築ではなく、問題集の構築です。スクリプト化可能な工程は、わざわざインフラとして整備する価値はありません。
評価はエージェントの改善に役立ちますが、コスト負担はビジネスチームには難しいものです。導入前に目的を明確にし、その上で導入の有無を決めるべきです。
前二部で AI 側は健闘しました。テスト用エージェントが機能し、編成の問題もランタイムまで追跡できました。次に問われるのは、AI が生成したテストに実際にバグを検出する能力があるかどうか、そしてそれを定量化できるかという点です。この第三部ではその答えを提示します。
評価を行うべきだという意見は誰しもが持ちますが、どのように行うかを語る者は少なく、コスト計算まで行う者はさらに稀です。ここでは二つの導出過程を紹介します。一つは壁にぶつかったケース、もう一つは成功したケースです。両者の投入コストには数桁の差がありましたが、教訓が示す場所は同じでした。
(一)まず、壁にぶつかったケースについて
最初に明確にしておくべきことは、この取り組み自体の判断は正しかったということです。当時、エージェントの能力は確かに向上していましたが、どの程度向上したのか、どこに弱みがあるのかは感覚頼りでした。度量衡がなければ改善も不可能であり、これは当時のチーム内での共通認識でした。私もその一人です。方向性は間違っていませんでした。間違っていたのは、その形態です。
今年三月末から七月半ばにかけて、私たちはコーディング用エージェントのために非常に重厚な評価システムを構築しました。107 日間にわたり、評価ディレクトリには十七万行が追加されました(うち三万行以上は問題集に含まれる参考実装です)。完成したシステムは極めて充実しており、隔離された作業領域の作成からトレースのアップロードに至るまでの六段階パイプライン、四層の加重スコアリング、React と FastAPI を組み合わせた Web プラットフォーム(ログイン認証機能も完備)、トレース確認のために Langfuse とその依存関係である PostgreSQL、ClickHouse、MinIO、Redis を含む六つのコンテナを独自にデプロイし、実行完了後は自動的に WeChat Work に通知を送信します。また、総合スコアが 90 点未満の場合は七種類の根本原因帰属分析がトリガーされます。
問題集は二十五の実際のニーズから構成されています。各問題に対する「正解」は人間が作成した百分制の採点表で、判定基準は自然言語です。例えば、「あるリクエストを同期からの直接返却から、非同期フィルタリング後の返却に変更した場合」といったケースで、完全に満たされれば 12 点、部分的に満たされれば半分(6 点)が与えられます。誰が採点を行うのでしょうか?LLM が項目ごとに判定を行います。
結果は惨憺たるものでした。コードベース内で検証可能な完全な実行記録はたった二回だけでした。一日空けての実行で、得点はそれぞれ 69.9(D)と 51.9(F)。両方とも同じ状況でした。四層のスコアリングのうち一層が完全にスキップされ、レポート末尾には「帰属要約の生成に失敗」と記載されていました。二十日後、これら二つのログは「冗長データの整理」の名目で削除されました。
振り返ると、問題点は四カ所にありました。前三つは技術的な要因ですが、第四つは技術以外の要因です。
第一、評価基準が実行不可能である。
「なぜこれが正しいと言えるのか」という根拠を示すことができないのです。当初は人間が作成した参考実装を正解とし、ファイルや関数のカバレッジを逐行比較していました。しかし、エージェントが同じ要件を満たす別の合理的なアーキテクチャで実装した場合でも、「重大な逸脱」と判定されてしまうという問題がありました。
その後、チェックリストによる項目ごとの採点方式に変更しましたが、主要指標は結局 LLM の意味判断に依存することになりました。後のメソドロジー監査でこの経緯が明確になりました。4 つの層からなる評価のうち、最も確実性が高いとされていた「凍結された単体テストの実行」这一层では、25 問中 22 問がそもそも存在しませんでした。これが欠落したことで、確実な判定基準の占める割合は 65% から 40% に低下し、LLM による採点の影響力は 60% にまで高まりました。つまり、主要指標の実質的な裁量権は、Cohen's Kappa が 0.10 から 0.21 という統計学的に「ほとんど一致がない」とされる範囲にある裁判官に委ねられてしまったことになります。
振り返れば、答えは既に同じコードベースの中に書かれていました。そのドキュメントでは、「要件やアーキテクチャに関するドキュメントへの採点を行わない理由」を説明しています。「LLM の採点誤差が信号よりも大きいため」という判断は、当時としては正しかったのです。ただ、それがコードの評価にも同様に当てはまるとは誰も考えませんでした。
第二、評価者自体にバグが存在する。
あるデータ実行記録では、チェックリストの抽出フォーマットエラーにより得点が 0 点となりましたが、フォーマットを修正した同一ログを再評価すると 98 点という結果が出ました。同じ成果物でありながら、前後で 98 点もの差が生じています。この段階でのスコアは、もはや信号として機能するレベルには達していませんでした。
第三、パイプラインの維持自体がフルタイムの仕事である。
そのシステムに残された運用ドキュメントは、ほぼすべて自らの事故について記述されています。「ログパイプのデッドロックによりタスクが永遠に『実行中』と表示される」「バックグラウンドプロセスが SIGTTIN を受け取って 23 分間フリーズする」「子プロセスがゾンビ化する」「エンドツーエンド単体テストがフリーズする」「サブエージェントがプラグインを読み込めない」などです。これらに「AI がコードを書く能力」という要素は一つも含まれていません。
誰かが手を抜いたわけではありません。跨プロセス、跨コンテナ、さらに別のエージェントを駆使して動作させるパイプラインを安定稼働させること自体が、極めて困難なエンジニアリング課題なのです。ただ、その難しさは評価目標とは無関係の場所にあるだけでした。
第四、試験問題が受験生に追いつかない。
107 日間で、評価ディレクトリは 3 回移転し、採点方式も 3 度変更されました(単体テスト実行 → 参考実装との比較 → チェックリストによる採点)。一方で、評価対象となる開発プロセス自体も変化しています。評価側が古いフローに基づいて出題している間に、評価対象の命令はすでに別の命令にマージされてしまっていたのです。
プラットフォームが重くなるほど、被評価对象への追従速度は遅くなります。しかし、この分野で最も急速に変化する変数はまさにエージェントのイテレーション速度なのです。
ある細かな記憶が鮮明に残っています。評価コードを独立したリポジトリとして切り出した日、そのプラットフォームの使い方解説ページはまだ更新され続けていましたし、設計ドキュメントの状態欄には「実装済み、継続的改善中」と表示されていました。当時、誰もこの作業を止めるべきだと考えませんでした。私自身も例外ではありませんでした。
同じ時期に、コスト対効果が極端に低い別の実験も行われました。「知識ベースをどのようにしてエージェントが検索すべきか」への回答を得るため、A/B テストを実施しました。8 問の課題に対し、2 つの検索手法それぞれを実行し、合計 16 回の試行を一日で完了させました。その成果物は会話記録と分析レポートのみです。
結論は即座に一つのコミットとして実装されました。「エージェントがまずルーティングドキュメントを読み込んでからジャンプする」という従来の手順を廃止し、「知識ベースを直接 grep 検索」に変更したのです。これにより、探索ステップ数は 12 ステップから 2 ステップへと劇的に減少しました。この変更は現在も本番環境で稼働しています。
17 万行のプラットフォームが導き出した二つのスコアは、最終的に何らかの変更にもつながりませんでした。一方、わずか 16 回の試行を行った小規模実験は、現在も使用されている戦略を修正しました。その差は工程規模の違いではなく、「評価基準が実行可能か」「結論が一つのコミットとして実装できるか」にあります。
なお、別途記録に残すべき重要な事柄があります。
このプロジェクトの全体構想自体は非常に早くから完成していました。3 月末にまとめた方針整理には、「pass@k」と「pass^k」の評価指標、課題セットを「能力評価用」と「回帰テスト用」の二つに分ける仕組み、編集の振動を検出する手法(同一ファイルの同一箇所が 2 回以上変更された場合)、仕様書やアーキテクチャドキュメントに照らして実際の改修範囲が逸脱していないかを確認する「越界改修検知」、そしてアクセスしたファイルのうち実際に改修が必要なファイルの割合を示す「ファイル命中率」など、すべてを実装直前まで具体化されていました。その方針からわずか 4 日後には最初のコードが書き込まれました。
しかし、6 月に行われた方法論の監査では、「pass@k」の評価項目は依然として「改善待ち」となっており、再実行さえ行われていませんでした。これは誰も取り組みたくないからではなく、当時、パイプラインの維持管理だけで手一杯だったからです。プラットフォームが重くなるほど、その内部に新しい方針を投入することは困難になります。
一つの事柄を明確に理解するには思考が一度で十分ですが、それを 17 万行にも及ぶシステムに落とし込むのは全く別の話です。序文から膨大な仕様書ドキュメントを削除した件も、ここでの状況と本質は同じです。真に価値があるのは「考え抜くこと」であり、それを担う媒体(ドキュメントやプラットフォーム)ではありません。
この教訓を経て、テストラインの評価においては以下のルールを徹底しました。「プラットフォーム側のコードは一切書かない」。評価対象となるのは課題セット、設定ファイル、スクリプト、および実行記録のみです。以下に、その導出プロセスを示します。
2. テストラインの第 1 版と、行き詰まった数字
評価の対象は明確です。「AI が生成したテストが実際に機能するか」です。
第 1 版(V1)では、以下の二つの評価軌道を用意しました。
- ゲート漏斗: Meta の「TestGen-LLM」の手法に倣い、AI が生成したテストが複数の厳格なハードルを通過できるかを確認します。具体的には、リンターエラーがないこと、実行可能であること、連続 3 回実行で安定していること、カバレッジ基準を満たすことです。
- 空穴埋め: テスト資産から意図的にいくつかの項目を削除し、エージェントにその欠落箇所の再発見(カバレッジ監査)を行わせます。どれだけの項目が復元されたかが「再現率」としてスコアになります。
評価開始当初から以下のルールを設けました。
- 試験問題と正解は独立したリポジトリに保存し、評価対象のエージェントの実行環境からはアクセス不可とします(試験問題を教科書と一緒に置かない)。
- プラグインのバージョン、ビジネスコードのバージョン、テストフレームワークのバージョン、およびモデル自体をすべて単一の設定ファイルで固定します。
- 主要な指標はすべて「実行結果」に基づいて客観的に判定します。AI が AI を評価する方式は採用しません。
この方針により、評価サイクルが回りました。「実行 → スコア確認 → スキル(能力)の特定箇所の修正 → 再実行」。しかし、ある一つの数字がすべての進行を止めてしまいました。あるモジュールにおける監査再現率が 100% から 40% に急落したのです。スキルを二回にわたって修正しても、スコアは全く改善しませんでした。
スキルの修正で解決しない場合、スコア自体に問題がある可能性を検討する必要があります。評価器の内部構造を精査した結果、以下の二つの重大な問題が判明しました。
第一に、評価器が測定すべきものを誤って計測していました。
評価はファイル単位で行われます。削除された項目が「元のファイル」に戻されなければ、復元したとはみなされません。しかし、セッション記録には明確に記されています。「その項目はエージェントによって発見されたが、同じモジュール内の別のファイルに書き込まれた」という事実です。評価器はこの挙動を「未発見」と判定しました。
つまり、40% という数字は「カバレッジの漏れを発見できるか」ではなく、「正解とのファイル分割が一致しているか」を測っているに過ぎません。スキルの修正ではこの問題は解決できず、根本原因は評価器側にあるのです。
第二に、単回の実行結果がノイズに翻弄されていました。
同一のテストセットにおいて、あるモジュールのスコアが 40 ポイント低下する一方で、別のモジュールでは 20 ポイント上昇するなど、変動方向が互いに矛盾していました。各モジュールから削除した項目はわずか 5 つであり、再現率は 20% 刻みで変動します。±1 件のランダムな揺らぎと、真の回帰現象を区別することが不可能でした。
以前採用していた「単一箇所の回帰 → スキルの特定修正」という反復プロセスの半分は、実はノイズを追いかけていたに過ぎなかったのです。
この教訓には非常に高いコストがかかりました。評価システム自体もソフトウェアであり、バグを抱える可能性があるからです。そして、誤った評価信号は「信号がない」状態よりも危険です。それは、実在しない問題へとあなたの改善プロセスを誘導してしまうからです。
これは同じ失敗の二度目です。前回の事例では重厚なプラットフォームが「スコアリング器のフォーマット解析」に陥り、今回は「ファイル粒度」の問題でつまずきました。前回の記事でカバレッジについて述べたのと同じことが、今度は評価システム自体に対して言えます。
3. 問題意識を持って調査し、V1 の死因を解明する
数字が信頼できなくなった今、単に数値を修正するのではなく、基礎から学び直す必要があります。私たちは業界動向に関する一連の調査を行いました。SWE-Bench シリーズにおけるタスク構築と汚染防止策、Meta の TestGen-LLM におけるゲート設計、TestGenEval による変異スコアの算出方法、SWT-Bench における「Fail-to-Pass」の実装など、論文やベンチマークを 50 本以上精査しました。
そして、業界の基準を用いて自社のアプローチを検証した結果、結論は容赦ないものでした。
4 つの核心手法のうち、3 つはトップカンファレンスの論文によって裏付けられており、確固たるものです。唯一自社開発で業界に競合がない「空欄を埋める」アプローチこそが、崩壊した部分です。
その崩壊は当然の結果でした。調査の中で見つかった構造的妥当性に関する研究によれば、ある実験では人工的に注入されたバグの 100% をテストツールが検出しましたが、実際のバグは一つも発見されませんでした。人為的な欠陥は、現実の欠陥よりも発見しやすいのです。「私が意図的に削除したものを推測できるか」という空欄埋めタスクは本質的に合成タスクであり、再現率を全量レポートで水増しすることも可能で、ペナルティもありません。この方法論は、両方の側面で成り立ちません。
そこで導き出されたのが、第二版(V2)の設計思想です。一言で言えば、「判断基準は実行結果でなければならない。合成リストであってはならない」です。「私が隠したものを発見できたか」ではなく、「あなたが書いたテストが実際にどの程度のバグを検出できるか」を問うことにしました。
その後、Anthropic が発表したエージェント評価に関する論文(Demystifying evals for AI agents)では、判定器を「コードベース」「モデルベース」「人手」の 3 つに分類し、コードベースアプローチの利点として「客観性」「再現性」「デバッグの容易さ」を挙げています。私たちが最初に掲げた「AI 同士の採点に頼らず、確定的な判定を行う」という原則は、まさにこの結論と一致しています。
(四)V2:「バグを検出できるか」を実行事実へと昇華させる
V2 の主指標は「変異体殺傷率」です。これは冒頭で提示した問いに対する直接的な答えとなります。
AI が生成したテストが通過すべき 5 つの関門があります。「出力があること」「Lint エラーがないこと」「実行可能であること」「3 回連続で安定して実行されること」、そして「どれだけの変異体を殺傷できるか」です。最初の 4 つは Meta の TestGen-LLM パターンを踏襲していますが、最後の 1 つこそが真の選別基準となります。なぜカバレッジ率を使わないのか?TestGenEval の実測データによると、GPT-4o が生成したテストのカバレッジ率は 35.2% に対し、変異体スコアはわずか 18.8% です。断言のないテストでカバレッジ率を水増しすることは容易ですが、変異体を殺傷するには真の断言が必要です。
変異体とは、意図的に業務コードに埋め込まれた単一のバグです。比較演算子の反転、AND/OR の入れ替え、「or 0」のようなデフォルト値の削除、状態書き込みをコメントアウトすることなどが含まれます。テストが変異後のコードで失敗すれば「殺傷成功」、通常通り通過すれば「断言がそのポイントを捉えきれていない」と判断します。算出プロセスの後半 4 つは、私たちのコードレビューチェックリストから直接採用したものです。これはプロジェクトにおける実際のバグの分類学であり、これに基づいて問題を作成し、埋め込むことで、現実の事故に似た欠陥を再現できます。
しかし、「何を」「どこに」埋め込むかが、この評価体系で最も手間がかかる部分です。「どの関数を選ぶか」は、つまり「どのような能力を試すか」を決めることになります。
V1 では 10 の関数を「見た目」に基づいて選定しました。行数や if 文の数、モジュールの分散度などに加え、「既存のテストケースがたまたま用意されている関数」という制約にも縛られていました。その結果、3 つの問題が生じました。
第一に、純粋な計算処理関数への偏りです。これは LLM が最も得意とする分野であり、成績が虚しく高くなってしまいます。
第二に、既存のテストケースはすべて AI 生成のものであり、人間が作成した正解が存在しないため、「人間の書いたテストとの比較」という意味自体が成立しません。
第三に、コードの活発度を考慮していない点です。ある関数がリファクタリングされた際、それに紐付いた 12 の変異体が一度にすべて失敗してしまいます。
V2 では選定基準を 3 つの層に変更しました。
まず「シナリオ」で業務代表性を定義します(報酬付与、タスク管理、キャンペーン、アチーブメント、ランキング、チャットの 6 大カテゴリ)。
次に「プロトタイプ」で失效モードのカバレッジを確保します(バリデーションゲート、リソース決済、タイムウィンドウ、状態マシン、互換性デフォルト値、反復集約の 6 種。これもレビューチェックリストから採用)。
最後に「4 つの軸」で難易度を調整します(分岐複雑度、依存関係構築コスト、副作用の有無、関数の可視性)です。
さらに 6 つのハードルを設け、それぞれに教訓の由来を明記しました。具体的には、「関数本体は 15〜80 行(短すぎると変異空間が不足し、長すぎると単体テストのコストが制御不能になる)」「分岐密度は 3 以上」「依存関係はモック可能であること」「変異可能な箇所が少なくとも 6 つあること」です。並列処理とパフォーマンスの 2 つの次元については明確に除外しました。これらは単体テストでは評価できないためです。
(五)問題作成という連鎖において、人間と機械はそれぞれのどこに位置するか
この問題セットを構築する過程こそが、私が経験した中で最もクリーンな人机分業でした。その全体の流れは以下の通りです。
「人による提案」から始まる一連のプロセスは、6 つの Sonnet サブエージェントが業務コードから素材を抽出することから始まります。まず、各シナリオごとに知識ベースのファイルマップを読み込んで範囲を特定し、次に実際のコードを検証して、厳しい基準に照らして逐一回答します。その結果、34 件の候補が提出されます。
その後、人間が最終的に決定を下します。シナリオ、プロトタイプ、モックの重み付けという 3 つの軸でバランスを取りながら、34 件の中から 16 件を選定し、除外された理由についてはすべて記録を残します。
次に、スクリプトを用いて変異体を作成します。演算子のローテーション割り当てに基づき、あらゆる種類の失敗モードが均等な機会を得られるように調整されます。
そして、3 段階の検証プロセスに入ります。まず Sonnet が一次審査を行い、明らかに同等なものを除外します。次に、テスト実行による検証で生死を決定し、人間は両者の判断に不一致がある場合のみ再確認を行います。
最終的に deepseek-v4-pro に解答させます。同じ問題に対して 3 回回答させ、その平均値を採用します。
このチェーンには、役割分担が最も明確に表れている 3 つの箇所があります。
第一に、「なぜ検索にスクリプトを使わないのか」です。関数名が check_ で始まるものは単なる転送である一方、update_ で始まるものは実際の検証を行うケースがあるからです。ルールマッチングだけでは「この関数が能力を問うているか」という判断はできません。そのため、このステップはエージェントに任せる必要があります。しかし、直後に人間がそのエージェントが取得した事実の再確認を行います。例えば、「このファイルは過去 1 年間で 48 回変更された」とエージェントが報告した場合でも、実際の候補関数では 1 年に 1 回未満の変更しか起きていないことがあります。これはファイルレベルでの報告であり、関数レベルではありません。これは前述の「AI は機能の提供には問題がないが、提供する『事実』そのものがしばしば歪む」という現象の再発です。したがって、最終審査の前には必ず関数レベルでの検証を追加する必要があります。
第二に、「何が真のバグなのか」を定義できるのは人間だけです。変異体を作成する際、最大の敵は「等価変異」、つまりコードを変更しても動作が変わらない偽のバグです。これが分母に含まれると、永遠に排除できず、すべての受験者を不当に処罰することになります。真の難しさはそれを識別することではなく、定義することにあります。最終的に私たちは以下の 2 つの方針を定めました。
- ログの違いは観測可能とは見なさない(そうすると「ログ出力の断言」のようなテストが生まれ、それが目指す能力の検証にはならないため)。
- 殺せるかどうかは自然な構成によるものとする(入力パラメータやデフォルトフィールドの不足は構成可能だが、環境定数を無効な型にモックしたり、意味的に不自然な値を渡して初めて動作が崩れる場合は等価と判断する)。
これらは純粋な価値判断であり、スクリプトが代わりに決断することはできません。機械は、人間が決断した後にその指示に従って実行するだけです。
第三に、「検証者自身も間違いを犯すため、役割分担の順序を逆転させてはいけない」からです。LLM による一次審査では、以下の 3 つの場所で失敗した事例がありました。
- and/or の入れ替えによりショート回路保護が失效した場合、実行時にエラーが発生しても観測可能と誤判定するケース(3 件)。
- 多分岐条件において、1 つの分岐のみを分析している場合。
- 最も興味深いのは、同一行に同じ記号が 2 つある場合、その判断理由が隣接する別の記号を指していたという事例です。結論は偶然一致していましたが、これも「悪い記録」として残す必要があります。そのため、審査プロンプトには「列番号に基づいて変異点を特定すること」を硬性規定として組み込みました。
参照テスト自体にもバグがありました。ある全量検証では 8 つの変異体が殺されませんでした。そのうち 5 つは参照テストの記述ミスによるものでした(pcall クロージャ内で宣言されたローカル変数を、クロージャ外で読み取ると常に nil となり、断言値が偶然にも期待値と一致すると「仮に合格」と判定され、同種の変異体がすべて漏れていました)。これを修正した後、すべてを殺すことができました。残りの 3 つは本当に等価なものでしたが、これらは構文レベルでは全く区別がつきませんでした。
このように、3 段階の検証順序を逆転させてはいけない理由はここにあります。LLM による審査は計算リソースの節約が目的であり、実行による検証こそが生死を決定するからです。最終的に 184 個の変異体が裁決され、そのうち 172 個が「殺せる」として問題に採用され、12 個が等価として除外されました。すべての判定には LLM の一次評価と人間の再確認という 2 段階の記録が残されており、最終的な決定は人間側の判断を優先します。
試験開始前にもう一つ重要なステップがあります。deepseek-v4-pro を用いて 16 問それぞれを実行し、問題の識別度を調整することです。殺害率は 12% から 100% の範囲に広がり、マクロ平均は 61% でした。これは「難しすぎず、簡単すぎない」適切なレベルであり、これをもって試験開始を許可します。
(六)データ実行の規律と、自らの評価に対する評価
正式なデータ実行では、16 問をそれぞれ 3 回ずつ実行し、合計 48 回のランで約 19 時間の計算リソースを使用しました。統計的な規律は業界標準に従います。
- 単一の結果ではなく平均値のみを参照する。
- Anthropic の実測データに基づく約 6 パーセントポイントのインフラノイズを考慮し、差が 3 パーセントポイント未満の場合は方向性のある結論を出さない。3 から 6 パーセントポイントの間は「おそらく有意」として扱う。6 パーセントポイントを超えて初めて、スキル改善のための根拠とする。
この規律は、V1 の教訓によって強制的に導入されたものです。そのため、ランナー(実行ツール)にも組み込まれており、デフォルトでは 3 回実行します。単回のみの実行モードは、空の実行の場合に限られます。
この手法の信頼性を示す細部があります。統計エージェントが実際にテストを実行したかどうかを確認する際、私たちはその文章内の自己言及を信じるのではなく、セッション記録に残されたツール呼び出しのみを根拠とします。
同じ厳格なルールは自社の内部にも適用されています。命令設定の声明では「Task ツール」を除外すると明記されているにもかかわらず、実際のツールリストにはそれが含まれたままです。声明と現実が一致していないという事実は、まさに自社の内部で起きていることです。
関連記事
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み