ISUCON2026本戦、AIエージェント10体で18.7万点。1位との差の40万点はどこにあったか
2026年10月31日の ISUCON2026 本戦に、チーム「ANTで解く」として出場した。ターミナルを10個以上並べ、そのすべてで Claude Code を動かした。
自分に課したルールは一つで、スキルを組まないことだった。デプロイの手順もベンチマークの回し方も前もって型にせず、会話で指示して会話で直す。AIエージェントだけでどこまで行けるかを確かめたかった。
結果は18.7万点。1位は62.9万点だった。3倍以上の開きがどこから来たのかを、当日のログと作業メモを読み返しながら、この記事で整理しておきたい。
点は「人数」と「1人あたりの操作」で決まる
お題は ISUReal という、BeReal に似たSNSだった。決まった時刻に全員が椅子の写真を投稿し、最終日には「世界グランプリ」が開かれる。
サーバーは4台ある。asia1・europe1・america1 にアプリが1台ずつ置かれ、DB(asia2)は asia にしかない。地域のあいだにはルーターがあり、遅延と帯域制限がかかる。europe と america から DB までは往復で約100msかかる代わりに、両地域の利用者が稼ぐ点は1.5倍になる。参照実装は、10:08 に Go から Rust へ切り替えた。
点の決まり方は昼過ぎにほぼ分かった。ベンチマークは5日間と最終日の計6日を、1日約9秒で進める。エラーを出さなかった日は翌日の利用者が約2.8倍に増え、エラーを出した日は増えない。つまりスコアは次の式で近似できる。
スコア ≒ Σ(その日の人数 × 地域の倍率)× 1人1日あたりの点
前半が人数、後半が「1人が1日に何をしたか」にあたる。この記事の結論は、ほぼこの後半の話になる。
スキルを組まず、会話だけで10体を回した
Claude Code のセッションには isucon-2026-bd、d4、71 のような短い名前が付き、最終的に10個を超えた。全員が1つの作業ツリーを共有し、連絡はセッション間のメッセージで取った。「デプロイするので触らないでください」「#34710 を回しました」といったやりとりが一日中続いた。
この日のコミットは346本、集計を残した走行は53本で、作業メモ(NOTES.md)は1,000行を超えた。
スキルの代わりに増えていったのは、エージェントが書き残すメモだった。僕が何かを注意すると、それがその場で1行の規則になり、次のセッションに引き継がれる。「main を正とする」「計測してから次の変更に進む」「本番の DB で重い調査をしない」といった規則が、終わるころには十数本たまっていた。前もって書かなくても、運用の中でスキルに近いものはできていく。ただし、その1本1本は何かを壊した代償として生まれたものだった。
16,857点から18.7万点までに効いた改善
ポータルに最初に載った点は16,857点(11:16)だった。そこから点を伸ばした改善のうち、効果の大きかったものを挙げる。
最初の壁は、利用者が毎回316人で増えなくなることだった。nginx の worker_connections が768、アプリのファイルディスクリプタの上限が systemd の既定値の1024になっていた。利用者は通知用の SSE 接続を張ったままにするので、千人に届く前に接続が尽きる。上限を引き上げると、壁はそのまま消えた。
次に、europe1 と america1 の API を asia1 で処理する構成にした。両サーバーの nginx から、asia1 で動かす地域別のプロセスに API を転送する。運営の Clarification で許可されている構成だ。欧米の要求は「ルーター越しの1往復と、asia 内で DB まで約1ms」で済むようになり、100msの往復を何度も繰り返す形がなくなった。画像だけは各地域のサーバーが手元から返す。
参照実装には、画像 URL の署名で HMAC-SHA256 を1000回繰り返す処理があった。しかも反復のたびに鍵を設定し直していた。鍵を設定した状態を複製して使い回すようにし、さらに AVX-512 で16本ずつ同時に計算させた。その結果、asia1 の CPU 時間の38.9%を占めていた SHA-256 の圧縮処理は1.9%まで減った。
nginx が1秒ほど止まる現象もあった。原因は書き戻し待ちの上限(vm.dirty_bytes 128MB)で、ここに張り付くと nginx の作業プロセスがディスク待ちで固まる。上限を広げ、アップロードされた画像はハードリンクで置くようにして解消した。
見つけて面白かったのは、SSH のたびに CPU が減る問題だ。Ubuntu の landscape-sysinfo は、SSH でログインするたびに motd を作るために動く。エージェントたちが監視のために SSH を打つたび、走行中の asia1 の CPU を約5%使っていた。実行権限を外して止めた。エージェントを10体並べると、1回ごとには小さい SSH の副作用も10倍になり、走行中のサーバーには無視できない負荷になる。
午後で最も点が伸びたのは、最終日だけ帯域を投稿に譲る変更だった。最終日のグランプリには、投稿が締め切りに間に合った人しか参加できない。そこで、Memories とエクスポートを繰り返し取得する利用者を最終日の間だけ待たせ、帯域を投稿に回した。グランプリに間に合った人は約50%から約85%に増え、点は163kから175k・185kに上がった。
点は6時間半で約11倍になった。推移は 16,857 → 47,818 → 96,839 → 116,705(13:31)→ 148,381(15:4x)→ 162,924 → 184,814 → 187k だ。
同じ種類の事故を何度も起こした
点を伸ばした一方で、壊したものも多い。
- 走行中のビルドや再起動で、FAIL や減点を何度も出した(#11782・#17436・#19751・#23100)
- DB のメモリが尽き、PostgreSQL が OOM killer に止められた。これが2回あり、1回目は接続の枠を広げた直後だった
- 走行中に DROP TRIGGER が流れたとみられ、その回は118k点に落ちた
- ソースは新しいのに、動いているバイナリが古いままになっていたことが2回あった
- エージェントが自分の役割を取り違え、別のセッションの仕事をした
デプロイ担当を1人に決めたのは15:55で、これらの事故がほぼ出そろったあとだった。
教訓を1つ得るたびに、走行を1本失った計算になる。デプロイしてバイナリの版を確かめ、ベンチマークを回して集計する。この決まった流れだけでも最初にスキルにしておけば、大半の事故は防げたはずだ。スキルを組まない方針は自分で決めたものだが、手順まで会話で回す必要はなかった。毎回同じでよい作業を会話で指示すると、そのたびに少しずつやり方が変わり、その揺れが事故につながる。
最後の1時間は運任せになった
17:30 の時点で、点の良かった版(5fedbc2)に固定して止めると決めていた。最終スコアは最後に回した走行の点になるからだ。
それでも 17:3x に、main をデプロイして計測してほしいとエージェントに頼んだ。main には 5fedbc2 より後のコミットが入っている。結果は174,325点で、もう1本回すと158,455点に下がった。この回はルーター越しに EOF が出て、山場にログインの打ち切りが60件ほどあった。
同じ版でも点は158kから187kまで振れる。1本ずつ比べても、版の良し悪しを判断できない幅だった。比べるときに何本回すかを決めていなかったことが、ここで響いた。
最後は自分の手で回し、18.7万点が出たところで止めた。これが最終スコアになった。
余談だが、エージェントは一日中「ベンチを積む」と言っていて、それがずっと気になっていた。ベンチマークは回すものなので、途中で言い方を直してもらった。
60万点との差は1人あたりの操作にあった
1位の62.9万点のチームは、11時台にはすでに50万点を超え、12:15 には58.3万点に達していた。そのころ、こちらはまだ1.6万点だった。
人数のほうは、15:4x の #24483 で上限に届いていた。3地域とも毎日2.7〜2.9倍に増え、5日目は asia 1,188人・europe 341人・america 342人だった。倍率込みの人日は約5,750で、これ以上は増やせない。
そうなると、差は式の後半にあることになる。187k を5,750で割ると1人1日あたり約33点で、62.9万点なら約109点になる。およそ3倍の差だ。
競技の後、184,814点を取った回のアクセスログを、マニュアルに書かれた1人1日の上限と並べてみた。
| 活動 | 1人1日の上限 | 上限まで取れたら | 実績(概算) |
|---|---|---|---|
| RealMoji の送信 | 5回 × 5点 | 約144k | 約3.4k |
| フィードの閲覧 | 20回 × 1点 | 約115k | 約18.9k |
| コメントの投稿 | 5回 × 3点 | 約86k | 約2.5k |
| 投稿詳細 | 8回 × 1点 | 約46k | 約1.9k |
| RealMoji・コメント一覧 | 8回 × 1点 | 約46k | 約1.4k |
| プロフィール | 4回 × 1点 | 約23k | 約1.0k |
| 合計 | 約460k | 約29k |
実績はリクエスト数から出した概算で、実際に採点された件数はこれより少ない。それでも、上限の6%しか使えていなかった。187k に残りの約43万点を足すと、およそ60万点になる。1位の点とほぼ同じだ。
その理由は、17時台の分析ですでに見えていた。既存の利用者は「投稿 → 友達フィードを1回見る → 自分の投稿を見る → 画像 → 友達申請の承認」で行動を終え、残りの約8秒は何もしていなかった。友達フィードの64%は空だった。全員が投稿期間の始まりに一斉に投稿するので、自分の投稿の直後にフィードを開いても、友達の投稿はまだ届いていない。フィードが空では、投稿の詳細を開くことも RealMoji を送ることもできない。
投稿そのものも遅かった。最後の版でも POST /api/posts の p50 は、asia で1.6秒、欧米で2.4〜2.7秒あった。asia1 は1回の走行で画像を約2.5GB送っており、投稿される画像(400〜600KB)の受信と帯域を取り合っていた。最終日に帯域を譲っただけで点が最も伸びたのは、偶然ではないと思う。帯域が投稿を詰まらせ、遅れた投稿がフィードを空にし、空のフィードが配点の高い操作を消していた、という流れだと考えている。ただしベンチマーカーの中身までは確かめていない。ここは仮説だ。
13時の19位から43位まで順位を落とした
13:31 の順位表では19位だった。

午後1時ごろまでは20位前後にいた。そこから点は1.6倍になったのに、17:3x の時点では43位まで下がっていた。上位のチームが、午後のあいだにこちらよりずっと大きく点を伸ばしたということだ。
午後にやっていたのは、目の前の律速を1つずつ外す作業だった。1つ外すと数%上がり、すぐに次のボトルネックが現れる。回を重ねるほど、1回あたりの上がり幅は小さくなっていった。上位のチームは、おそらく点の決まり方そのものを押さえてから手を動かしていたのだろう。順位の推移を見るかぎり、漸次的な改善を重ねるより、根本をじっくり考えたほうが最終スコアは伸びる。
人間の判断力も、午後には鈍っていた。エージェントが出すコードやログを一日中追っていると、目の前の差分が良いか悪いかは判断できても、「そもそも何を解いているのか」を問い直す余力が残らない。エージェントが速いほど、目を通す量も増える。立ち止まるのは人間の役目なのに、その人間が一番疲れていた。
採点器を先に解くべきだった
ISUCON はサーバーを速くする競技だと考えていた。それは半分正しいが、点を決めるのは外から来るベンチマーカーのリクエストだ。それなら競技プログラミングと同じように、まず採点する側の動きを解くべきだった。
これは AIエージェントで十分にできたはずだ。最初の30分で、参照実装のまま走行を1本回す。全リクエストを利用者ごとの操作の並びに組み直し、どの操作が何点になるか、どの応答を受けたら次に進み、どこで止まるかを表にする。「フィードが空なら閲覧しない」といった分岐は、この段階で見つかる。あとは表のいちばん大きな空きから逆算して、必要ならクリーンルームで作り直せばよい。参照実装は差分テストの正解として使える。ログの解析も分岐の推定も作り直しも、エージェントが得意とする作業だ。
道具もそろっていた。ログインと SSE はクリーンルームで書き直していたし、参照実装との差分テスト(smoke 30項目と API 63件の照合)もあった。人数の増え方は12:4x の時点で解けていて、メモには「首位は全地域が毎日2.8倍、1人1日ほぼ上限と合う」とまで書いてある。採点器の動きの前半はつかめていたのに、後半の「1人がどこで止まるか」は17時まで誰も調べなかった。
手元のコードと点数ばかりを見ていたのは、競技を半分放棄していたのと同じだと思う。目の前の律速を外す作業は、エージェントに任せると気持ちよく進む。進むぶん、全体を見直すきっかけを失っていた。
手順はスキルに、判断は会話に
会話で回すこと自体は悪くなかった。実装の速さと深さは十分に出て、AVX-512 による署名やメモリ化のような作業も数十分で入った。原因の切り分けも速かった。
弱かったのは、毎回同じでよい手順と、ときどき立ち止まって全体を見直すことの2つだ。前者は事故として、後者は40万点の見落としとして表に出た。
次に同じことをやるなら、先にスキルにするのは3つだけでいい。デプロイと版の確認、ベンチマークの実行と集計、そして点の内訳の計算だ。そのうえで「伸びが止まったら内訳を計算し直す」を決まった手順に入れておく。何を直すかの判断は、今回と同じく会話で行う。そうしていれば、15:4x の時点で40万点の空きに気づけたと思う。
20:25 に、主催者の指示に従って CloudFormation のスタックを削除し、サーバー5台は terminated になった。手元には1,000行の NOTES.md が残っている。