5つのAIエージェントでチェスエンジンを作った——驚いたことはこれだ

Dev.to / 2026/4/5

💬 オピニオンDeveloper Stack & InfrastructureIdeas & Deep AnalysisTools & Practical Usage

要点

  • この記事は、外部のチェスライブラリやインターネット検索を使わずに、5人のAIコーディングエージェントを監督してゼロからチェスエンジンを構築する実験を扱っている。
  • 1人のエージェントがアーキテクチャを設計し、3人のエージェントが主要コンポーネントを並行して実装し、マネージャーエージェントがそれらの作業を調整して振り分けた。
  • 実装では、各エンジニアエージェントがそれぞれ独自のブランチ/ディレクトリで作業できるよう、分離したgit worktreesを使用し、干渉を減らし変更を追跡しやすくした。
  • 著者は、完成したエンジンが実際に動作することを報告しており、最大の驚きは最終的な強さそのものよりも、監督付きのマルチエージェント実行とオーケストレーションに関して得られた学びにあったという。
  • このプロジェクトの目標は、開発中に成果を評価するためのテストスイートを用い、少なくとも50%の確率でStockfishに対して約1200 ELOを上回ることだ。

5つのAIコーディング・エージェントに、ある課題を与えました。ゼロからチェスエンジンを作ることです。1人がアーキテクチャを計画しました。3人が並行してコンポーネントを構築しました。1人が全体を監督しました。

外部のチェスライブラリは使いません。インターネットでの調べ物もしません。エージェント、テストスイート、そして目標だけです。少なくとも50%の確率で、1200 ELOでStockfishに勝つこと。

エンジンは動きます。しかし驚いたのは出力そのものではありませんでした。途中で学んだ「監督型AIエージェント実行」についてのことです。

セットアップ

チームは次のようになっていました:

roles:
  - name: architect
    role_type: architect
    agent: claude
    instances: 1
    talks_to: [manager]

  - name: manager
    role_type: manager
    agent: claude
    instances: 1
    talks_to: [architect, engineer]

  - name: engineer
    role_type: engineer
    agent: claude
    instances: 3
    use_worktrees: true
    talks_to: [manager]

5つのエージェント。1人のアーキテクトが、計画のためにOpusを動かします。3人のエンジニアが、実装のためにSonnetを動かします。1人のマネージャが、彼らの間で作業をルーティングします。各エンジニアには、それぞれ独自のgit worktree(自分専用のブランチ、自分専用のディレクトリ)が与えられ、他とは完全に隔離されます。

タスクボードはMarkdownファイルでした:

## やること
- [ ] ボード表現(ビットボード)を実装する
- [ ] 手の生成(合法手)を実装する
- [ ] 位置評価(駒の価値 + 位置テーブル)を実装する
- [ ] 探索(反復深化付きアルファベータ)を実装する
- [ ] UCIプロトコルのインターフェースを実装する
- [ ] 知られた局面に対する統合テストを書く

## 進行中

## 完了

batty start --attachと入力して、見ていました。

サプライズ1:アーキテクトは、どのエンジニアよりも10倍重要だった

これが最大の学びでした。最初は、実際にコードを書くエンジニア(エージェント)がボトルネックだと思っていました。違いました。

ボトルネックはアーキテクトでした。

良いアーキテクチャ計画があると、エンジニアは独立して作業できます。ボード表現、手の生成、評価は、自然に分離されます。別々のファイルを触り、別々のデータ構造を使い、独立してテストできます。アーキテクトはそれを見て、作業をそれに応じて分解しました。

私は、より弱いアーキテクチャ計画で以前のバージョンを回したことがあります。そのときは、エンジニア同士がずっと互いにブロックし合っていました。評価エージェントは、ボード表現エージェントが先に終える必要がありました。探索エージェントは両方必要でした。3人のエージェントがいても、同時に作業できるのは1人だけ。理論上は並行ですが、実際は逐次でした。

対策は、計画フェーズにより多くの時間(そしてより高価なトークン)を投じることでした。私は、アーキテクトにOpus(最も能力の高いモデル)を使い、明確な指示を出しました:「各エンジニアが、別のエンジニアの出力を待たずにすぐ着手できるように作業を分解せよ。インターフェースは最初に定義せよ。」

アーキテクトは、モジュール境界が明確な計画を出し、共通のtypes.rsファイルに型定義を共有し、各エンジニアがそれに対してコードできるスタブ実装を用意しました。3人のエンジニアは、それぞれ互いに数秒以内に開始できました。

教訓:監督型のAIエージェント実行では、タスク分解の質がすべてを決めます。能力が低めのエンジニアでも、すばらしいアーキテクトがいれば、すばらしいエンジニアを持つ劣ったアーキテクチャを上回ります。

サプライズ2:テストのゲートが、見落としていたものを拾った

各エンジニアのブランチは、マージ前に必ずcargo testを通過しなければなりませんでした。例外なしです。エージェントが「完了」と言う——その後、監督者がテストを実行します。終了コード0は「完了」を意味します。それ以外なら「やり直し」です。

テストのゲートが、コードレビューでは気づかなかったものは次のとおりです:

手の生成における1オフ(off-by-one)。 エンジニア2がポーンの手を実装しました。コードは正しく見えました——きれいで、よく構造化されていて、エンパッサンと昇格の扱いも適切でした。ですが、テストスイートにはPerft test suiteの既知の局面が含まれていました。そこでは合法手の正確な数が分かっています。エンジニア2の実装は、20手あるべき局面で19手を生成していました。ルークを取った後のキャスリング権における、エッジケースの欠落です。ロジックが正しく読めるため、コードレビューを通過してしまう種類のバグです。

テストのゲートがそれを捕捉しました。エージェントは失敗出力を受け取り、どの局面が、何手分ずれて失敗したのかを正確に把握し、リトライで修正しました。

評価スコアにおける型の不一致。 エンジニア3は、センチポーンのスコアを使って位置評価を実装しました。探索モジュールは、別のスケール範囲のスコアを想定していました。両モジュールはそれぞれ独立にコンパイルされました。どちらもユニットテストは通りました。しかし統合テスト——既知の局面に対してエンジン全体を走らせる——では、生成された手は合法ではあるものの、戦略的にひどいものでした。エンジンは間違ったスケールを最大化していました。

テストのゲートがなければ、これはそのままマージされていたでしょう。「なぜエンジンが理由なくクイーンを生贄にするのか」を1時間デバッグして、スコアのスケーリング問題を見つけることになっていたはずです。

教訓:テストゲートは単にバグを見つけるだけではありません。単体では正しく見えるが、統合の境界で壊れる種類のバグも見つけます。こここそがマルチエージェントシステムが失敗するまさにその場所です——各エージェントの作業は局所的には正しいのに、全体としては壊れているのです。

サプライズ3:5つのエージェントが最適点だった

私は3つの構成を試しました:

構成 エージェント数 結果
ペア 1アーキテクト + 1エンジニア 動くが逐次。約45分。
チーム 1アーキテクト + 3エンジニア + 1マネージャ 並行実行。約18分。
スクワッド 1アーキテクト + 5エンジニア + 1マネージャ マージの複雑さが増えて得を相殺。約22分。

1人から3人のエンジニアに増やしたのは、明確な勝ちでした。各エンジニアは別々のモジュールに取り組みました。worktreeの隔離によってファイル競合が防がれたためマージはきれいに進み、またアーキテクトの分解によってモジュール同士が独立したまま保たれました。

3人から5人のエンジニアに増やすと、実際には作業が遅くなりました。

なぜでしょう?理由は2つです:

マージの直列化。 Battyはファイルロックを使って、マージをブランチごとに順番に(逐次的に)行います。3人のエンジニアがほぼ同時期に作業を終えると、マージ待ち行列は短時間だけ発生しますが、解決は素早く進みます。5人になると、待ち行列が詰まっていきます。各マージのたびに、対象ブランチ側でテスト実行が走り、さらに後続のマージが、マージが行われる間にコードベースが変わってしまっているため、前のマージと衝突することもあります。

タスクの粒度。 チェスエンジンには、だいたい5〜6個の自然なモジュールがあります。3人のエンジニアなら、それぞれがまとまった量の仕事を担当できます。5人になると、モジュールをもっと小さい部品に分割することになり、結合がより密になります。エンジニア4はUCIプロトコルを実装する必要がありますが、それは探索モジュール(エンジニア3)と、ボード表現(エンジニア1)に依存します。3つのエージェントで成り立っていた独立性は、5人では崩れてしまいます。

教訓:エージェントが多ければ常に良いわけではありません。最適なチーム規模は、「本当に独立したタスク」がどれだけあるかに依存します。エージェントに仕事を与えるために人工的な境界を作らなければならないなら、やり過ぎです。

Surprise 4: Token Costs Weren't What I Expected

素朴な前提:5人のエージェント=コストが5倍。実際はそれより近くて2倍程度でした。

理由は次のとおりです:

スコープ付きのコンテキスト。 各エンジニアは、自分のモジュールに関係するファイルだけを読み込みました。エンジニア1(ボード表現)は評価コードを見ることはありません。エンジニア3(評価)はUCIプロトコルを見ることはありません。厳格な.claudeignoreファイルにより、各エージェントのコンテキストはフルの約80Kプロジェクトコンテキストではなく、約25Kトークンに抑えられました。

セッションのリセット。 各タスクの後、エージェントには新しいセッションが与えられました。前のタスクからの会話履歴が蓄積されないためです。クリーンなコンテキスト=完了(completion)あたりのトークン数が少なくなります。

モデルのミキシング。 アーキテクトはOpusで実行しました(Sonnetよりトークンあたり約15倍高価)。エンジニアたちはSonnetで実行しました。エンジニアがトークンを消費する作業の80%を担うため、Opusで全てを実行するよりもブレンド後のコストは大幅に低くなりました。

コスト要素 トークン数 コスト
アーキテクト(Opus) ~40K ~$1.20
エンジニア1(Sonnet) ~60K ~$0.36
エンジニア2(Sonnet) ~55K ~$0.33
エンジニア3(Sonnet) ~65K ~$0.39
マネージャー(Sonnet) ~15K ~$0.09
合計 ~235K ~$2.37

同じ作業を1人のエージェントが逐次的に行う場合、Opus上で約180Kトークン(~$5.40)使うことになります。これは、フルのコンテキストを完了までずっと保持する必要があるためです。マルチエージェント方式は、どちらも速く、しかも安価でした。

教訓:マルチエージェントの実行は、単なるスピード最適化ではなく、コスト最適化戦略です。スコープ付きタスク+モデルのミキシング+セッションリセットが、予想以上にコストを削減します。

What the Engine Looks Like

結果はこちら:chess_test。監督のもとでAIエージェントが全てを構築したRust製のチェスエンジンです。

このままの強さでStockfishに勝つことはありません。ですが、1200 ELOのStockfish相手には一貫して勝てます。アーキテクチャはきれいです。ボード表現、手の生成、評価、探索、UCIプロトコルのそれぞれに別モジュールがあります。各モジュールには独自のテストスイートがあります。

面白いのはエンジンそのものではありません。より注目すべきは開発プロセスです。worktreeの隔離、テストゲーティング、階層的なタスクディスパッチを伴う監督付きAIエージェントの実行によって、単一の長いエージェントセッションから通常私が得るものよりも、よりモジュール化され、より良くテストされたコードベースが生まれました。

1人のエージェントが全部やる場合、手抜きをしがちです。共有される可変状態。暗黙の依存関係。通るけれどもエッジケースをカバーしていないテストです。複数のエージェントが隔離された状態で、強い境界のもとで作業すると、エージェントが互いのファイルに文字通りアクセスできないため、コードはモジュール化を強いられます。

How to Try This

同様の実験を試したいなら:

cargo install batty-cli
cd your-project
batty init --template team  # architect + 3 engineers + manager

.batty/team_config/team.yamlを編集して、エージェント、役割、テストコマンドを設定します。kanbanボードにタスクを追加します。batty start --attachを実行し、隣り合うtmuxのペインでエージェントが作業する様子を見てください。

デモ動画では、アーキテクトの計画、エンジニアたちの並行実装、テストゲートによるバグ検知、ブランチのマージまで、チェスエンジンのビルドが最初から最後まで示されています。

出典: github.com/battysh/batty

The Takeaway

監督付きのAIエージェント実行は、エージェントを速くすることが目的ではありません。出力を信頼できるものにすることが目的です。

5人のエージェントでチェスエンジンを作ることで、私は次を学びました:

  1. アーキテクトに投資する。 タスク分解の質は、エージェント数よりも重要です。計画に最適なモデルを使ってください。
  2. テストゲートは譲れない。 エージェントは、自信ありげで筋の通った、しかし壊れたコードを生成します。終了コード0は、あなたが採用する中で最も安価な(=コストが低い)レビュワーです。
  3. エージェントを増やしても必ずしも良くならない。 チーム規模は、「自然に独立したタスク」の数に合わせます。人工的な分割を作らなければならなくなる境界で止めてください。
  4. マルチエージェントはコスト面での戦略。 スコープ付きコンテキスト+モデルのミキシング+セッションリセットにより、1人の高価なエージェントが全てを逐次的に行うよりも、より速く、かつ安くできます。

エージェントはコード品質そのものでは私を驚かせませんでした。驚かせたのは、監督レイヤー――タスク分解、隔離、テストゲーティング――が結果をどれほど決定づけたか、という点でした。

コードは勝手に書かれました。アーキテクチャはそうではありません。

1つのプロジェクトに対して、これまでに動かしたエージェント数は最大でいくつですか?調整が崩れたのはどこでしょう?他のコードベースでも5エージェントの上限が成り立つのか、それともこの種のプロジェクトに固有なのか、気になります。