5つの修正:AIエージェントが私の本番データベースについて知らなかったこと

Dev.to / 2026/4/8

💬 オピニオンDeveloper Stack & InfrastructureIdeas & Deep Analysis

要点

  • AIエージェントが、Django+Aurora MySQLの本番環境を分析して、適切なトランザクション分離レベルを提案した。並行性のパターンをうまく対応づけ、コードベース内で分離設定が欠けていることも特定した。
  • しかし調査は、構造的な失敗によって何度も行き詰まった。エージェントは、クラスタ全体のCloudWatchメトリクスを“著者のアプリケーションだけ”を反映したもののように扱い、その結果、共有Auroraクラスタ上の他テナントに属する結論を導いてしまった。
  • 著者はエージェントを5回中断して修正した。誤りのうち3回は、より広範な/システム全体のデータスコープを、アプリケーション固有の根拠と取り違えるという同じパターンに従っていた。
  • この記事は「より良いプロンプトを書け」というだけが教訓ではない、と主張する。観測(オブザーバビリティ)のシグナルから推論する際に、AIエージェントがデータの出所(プロベナンス)、スコープ、そしてマルチテナントにおける分離制約を理解する必要があることを強調している。

なぜ「より良いプロンプトを書く」ことは誤った教訓なのか

AIエージェントは、たった今でCloudWatchの過去30日分のメトリクスを取得し、正しく解析して、テーブルを作り、見つけた内容に基づいて推奨を全面的に組み替えていました。
私が入力したのは4語だけでした。「それは共有クラスターデータです」。
デッドロック数、接続のピーク、日次のパターン——すべて実データベースクラスタからの本物の数値です。私たちが下そうとしていた判断にとってはまったく無意味でした。私たちのアプリケーションは、そのクラスタを他のサービスと共有しています。エージェントはデータを完璧に処理し、他人の負荷から結論を導き出しました。
データは完璧でした。結論が他人のものでした。このギャップには、見ておく価値のある構造があります。

セットアップ

Aurora MySQL上のマルチテナントDjangoアプリケーション。ユーザー数は少ない。大量処理のためのバックグラウンドワーカー。プライマリ-レプリカ構成。どこにもトランザクション分離レベルは設定されていません——MySQLのデフォルトであるREPEATABLE READが、異議なくそのまま動作している状態です。バックグラウンドタスクで時折発生するデッドロック、レプリカでの古い読み取り。
私はAIエージェントにコードベースを渡し、適切な分離レベルを選ぶための計画を考えさせました。「『READ COMMITTEDに切り替えろ』」ではなく、「何を選ぶべきかを証拠とともに決めろ」

エージェントがうまくやったこと

数分でコードベース全体を調べ、並行アクセスの6つのカテゴリのパターンをマッピングし、4つすべてのMySQL分離レベルをそれぞれ評価しました。その結果、どこにも分離レベルは設定されていないことが分かりました——Djangoの設定にも、ミドルウェアにも、init_commandにもありません。大量書き込みのサイクルを行っている特定のバックグラウンドタスク、トランザクション境界が欠けているビュー、削除してから再作成するサービスで、レースコンディションに構造的に脆弱である部分を特定しました。
これは私なら、一日かけてメソッドを探して読み進める必要があったはずです。エージェントは、セッション開始時点では存在していなかった並行性の地図を作って出してきました。
そして、次に間違い始めました。

3つの修正、同じ形

調査の過程で、私はエージェントを5回中断しました。そのうち3回は、同じ構造的なパターンを明らかにしています。残り2回は種類が異なります——それについては後で説明します。
「それは共有クラスターデータです。」 CloudWatchには、30日間で何百もの接続ピークと、散発的なデッドロックが示されていました。エージェントはこれらの数値から慎重な分析を組み立てましたが、それらの数値は私たちのアプリケーションではなくAuroraクラスタ全体に属するものだったのです。ユーザー数は少なく、バックグラウンドワーカーも少数で、それらの接続の一部に過ぎません。デッドロックは、同じクラスタ上の他テナントのものだけで説明できてしまいます。
より良いプロンプトなら防げたのか?もちろんです。「Auroraクラスタは共有されている。CloudWatchのメトリクスはクラスタ全体のものだ。」——これは事前に知っていました。プロンプト可能です。
しかし私は、エージェントがそれを見つけることを期待していました。ユーザー数も、ワーカー数も、CLAUDE.mdも、エージェントは持っていました。少なくとも、その接続ピークが本当に自分たちのものなのかを疑うだけの十分なシグナルがありました。エージェントは何も疑わず、数値を自分たちのものとして処理し、そのまま進めてしまったのです。
「本番だけを見ましたか?それともステージングや開発も混ざっていましたか?」 エージェントはSigNozに問い合わせてデータベースのメトリクスを取得しました——何百万もの読み取り、数万の書き込み、レイテンシのパーセンタイルはきれいに整っています。SigNozには環境ごとに分かれたサービスエントリがあり、エージェントはそれがどれを集計しているのかを検証していませんでした。CLAUDE.md、プロジェクトのドキュメント——名前空間の分離はそこに明確にありました。
「遅いキューのワーカーはどうですか?」 エージェントはメインAPIサービスとプライマリのバックグラウンドワーカーについて、エラーデータを引き出しました。遅いキューのワーカーは完全に見落としていました。つまり、最も重い大量処理を扱っている——デッドロックが実際に表面化する可能性が高い、まさにそのワークロードです。私はルーティングを設計したので、どのキューに何が流れるかは分かっています。エージェントは目につくサービス名を問い合わせただけで止まってしまいました。
そのパターン。 毎回、エージェントは方向性の手がかりを持っていました。コードベース、プロジェクトのセットアップ、そしてCLAUDE.mdが調査のスコープを示しています。共有クラスタ、環境境界、キューのルーティングはいずれも、エージェントが見ることのできた素材から推測可能でした。
公平な反論:「つまり文脈はあったのにエージェントが見落とした。これはツールの問題だ。」そうです、悪くない反論です——より良いエージェントなら、ここも改善されるでしょう。
ただし、実際に何が起きているかに注目してください。エージェントは、観測(オブザーバビリティ)データを自己記述的なものとして扱い、観測データはそれを生成するインフラストラクチャのトポロジーを継承します——問い合わせ結果には自己からは告げない構造です。CloudWatchは、どの接続がどのテナントに属するかをラベル付けしません。SigNozは、環境をまたいだ集計を警告しません。データはただ到着し、権威あるように見えるままです。
総合的な文脈空間には、クラスタの構成、環境命名規則、サービスルーティング、監視設定、過去のインシデントに関するチームの履歴などが含まれます。難しいのは、その文脈を供給することではありません。難しいのは、推論の「ちょうどその瞬間」に、どの要素が当てはまるかを見抜くこと——それは、文脈マスクをかぶった判断の問題です。
より良いエージェントのプロトコルなら、このギャップの一部は埋められます。観測データを取り込む前の検証ステップ、環境境界のチェック、ワーカーの列挙などです。敵対的ループや自己修正プロンプト——「このデータから結論を導く前に、そのスコープを検証せよ」——なら、おそらく3つすべてを見つけられたでしょう。ですが、それをチェックリストとして書く誰かが必要で、そのチェックリストを書けるのは、エージェントがどこで迷走するかをすでに知っているエンジニアです。つまり判断をプロセスに事前エンコードするのです。人間の操縦は消えません。もっと早いパイプライン段階へ移動するだけです。
この反論が成り立つのは、この3つに限られます。次の2つは、完全にそれを退けます。

2種類の別種

早すぎる収束。 エージェントの最初の計画はREPEATABLE READREAD COMMITTEDを比較し、切り替えを推奨しました。MySQLには4つの分離レベルがあります。その計画はREAD UNCOMMITTEDやに触れておらず、接続単位かトランザクション単位かといった戦略の違いも考慮していません。Aurora固有の機能も見ていませんでした。探る前に最適化してしまっています。これらの穴はすべて同じ重みではありません——実際に致命傷になるのはトランザクション単位の戦略です——しかし重要なのは、エージェントが絞り込む前に意思決定の空間をそもそもマッピングしていないことです。おそらく、REPEATABLE READ vs. READ COMMITTEDの二択がMySQLのドキュメントやStack Overflowを支配しているため、学習データがそこへ流れ込んでいるからでしょう。強い初期の証拠が収束を引き起こし、意思決定空間への意識は、指示追従ではなく判断のスキルです。
敵対的な査読(ピアレビュー)。 エージェントがREAD COMMITTEDを推奨した後、私は別途準備していた文書を投入しました。これは、そこに「主張としては成立するが議論がある」という事実確認です。OracleのMySQLパフォーマンスアーキテクトであるDimitri Kravtchukは、READ COMMITTEDがステートメントごとのReadViewのオーバーヘッドを生み、その結果、大規模環境でtrx_sysミューテックスの競合が発生すると示しています——短いトランザクションでは最大でパフォーマンスが2倍程度悪化します。まだ到達していない結論に対する反論を、どんなプロンプトでも先読みしてロードできません。ここで働いたのは、人間が敵対的な査読者として行動していた、ということです。軌道修正ではなく、目的地にかかるストレステストをしたのです。

なぜこれは一般化するのか

分離レベルが「乗り物」でした。このパターンはどこにでも当てはまります。コードベースがシステムの不完全な地図になっている場所——キャパシティ計画、移行戦略、インシデント対応などです。エージェントが、見えているものは分析できるが、暗黙の前提に重みづけできない状況ならどこでも。
文脈を与え、エージェントにそれを適切な推論の瞬間に適用させることは別の問題であり、後者にはシステム全体を頭の中に保持する必要があります。これはまさに、エージェントが活用することで置き換えるべきではなく、活かすべき種類の知識です。

実際に起きたこと

返却形式: {"translated": "翻訳されたHTML"}

エージェントは、堅実なアーキテクチャ意思決定記録、チーム向けのレポート、並行性アーキテクチャ文書、見つけたギャップに対する数件の課題、そして実装を含むPRを出荷した。init_command 経由で READ COMMITTED を指定し、本当にスナップショット分離を必要とする2つの操作についてはエスケープハッチを用意している。何日ものシニアエンジニアリング作業が、数時間に圧縮された。
しかし最終的な推奨は正しかった。なぜなら、そのシステム――インフラ、観測(オブザーバビリティ)の設定、ワークロードのルーティング、外部の文献――を理解している人が、分析が少しでも逸れたたびに、何度も分析を正しい方向へリダイレクトし続けたからだ。
部屋の中で、トポロジーを握っているのは誰ですか?
それがインフラに適用された メンタルモデル問題だ。エージェントはパワーマルチプライヤーだ――しかし、掛け算をするには何かを掛け算する対象が必要だ。
誤った推論は、十分以上であるはずの文脈があったにもかかわらず、メンタルモデルの影を落とした。つまり、ビジネスルール、運用(オペレーション)の構造、そしてインフラの制約はすべて、同じ多次元の生き物の投影であり、その生き物はあなたを永遠に食い尽くすことも、守り続けることもできる。