8月10日、Tara Pourhabibが「The Hidden Engineering Behind Successful AI Agents (Part 2): Why Your Agent Needs a Python Co-Pilot」と題した記事を公開した。AIエージェントを「純粋なLLM任せ」から「決定論的なPythonとのハイブリッド構成」に切り替えることで、大規模コード移行における無音の失敗(サイレント障害)を解決した実装経験を詳述した内容だ。なお本記事はシリーズの後編にあたり、前編「The Hidden Engineering Behind Successful AI Agents (Part 1)」ではLLM単体が抱える構造的限界が論じられている。前編と合わせて読むと、本稿の議論がより深く理解できる。
コンテキストウィンドウは嘘をつく
「100万トークンのコンテキストウィンドウがあれば、レガシーコードベース全体を流し込んでエージェントに任せればいい」——この発想は、現在の業界に広く蔓延している。しかし、Tara Pourhabibはそれを「アーキテクチャの罠」と断言する。
Pourhabibが直面したのは、レガシーエンタープライズDBをクラウドベースのデータプラットフォームへ移行するプロジェクトだ。エンタープライズDBの移行では、長年にわたって積み重なった複雑な依存関係が常態化しており、単純なSQLの書き換えで済まないケースが多い。今回もその典型で、60以上の入れ子になったレガシービューが複雑に連鎖しており、中間テーブルやビューの一部はアクセス不能か廃止済み。その欠落した層をバイパスしながら、最終テーブルを再構成する必要があった。
小規模(5〜6ビュー、数百行のSQL)ではLLMは完璧に動作した。依存関係をトレースし、ベンダー固有の関数を変換し、クリーンなSQLを生成した。
問題は、これを本番スケールに乗せたときに起きた。
「サイレント障害」という最悪の失敗モード
単一のターゲットテーブルが5,000行以上の密なコードに依存するケースで、LLMに巨大なワークロードを渡すと——システムはクラッシュしなかった。例外も出ない。レート制限にも引っかからない。出力は一見まともに見える。
しかし、失敗していた。
これが「アテンション希釈(Attention Dilution)」、いわゆる "Lost in the Middle" 問題だ。モデルは最初の10ビューと最後の数ビューは忠実に変換するが、中間部分を無音で省略する。具体的には、UNION句の丸ごと欠落、CTE(Common Table Expression:WITH句で定義する名前付き一時クエリ)ブロックの消失、複雑なロジックのサイレントな単純化——そしてその出力は「完全に妥当に見える」。
[ Input: 50+ Legacy Views ] ──> [ LLM Long-Context Session ] ──> [ Output: 見た目は正常 ]
│
(中間ビューのロジックをサイレントに省略)
構文エラーなら即座に検出できる。しかし財務パイプラインでのJOIN条件の欠落やCTEブロックの消失は、隠れた地雷だ。エンタープライズ規模の移行でこの種のサイレント障害が頻出する背景には、ビュー間の依存関係が深く、全体を一度に把握しようとすると必然的にコンテキストが肥大化するという構造的な問題がある。
プロンプトエンジニアリングでは解決できない
当初のアプローチは、多くのエンジニアが取る道と同じだった:
- 「どのビューもスキップするな」という厳格な指示を追加
- マルチビューのリファクタリング例をfew-shotで提供
- プロンプトチェーン内に明示的なチェックステップを挿入
結果は「限定的な改善」にとどまった。根本原因はプロンプトの質ではなく、ワークロードの過負荷にあったからだ。
LLMに対して「意味的な推論エンジン」「AST(Abstract Syntax Tree:コードの構造を木構造で表現した中間表現)パーサー」「依存関係リゾルバー」「決定論的コードコンパイラ」の役割を同時に担わせていた。これ自体がアーキテクチャ上のアンチパターンである。
解決策:確率的タスクと決定論的タスクを分離する
転換点は、LLMをシステム全体ではなく、大きなソフトウェアアーキテクチャの中の専門コンポーネントとして扱い始めたことだ。
Pourhabibが設計したハイブリッドパイプラインは以下の4ステップで構成される:
+-------------------------------------+
| 1. Python 依存関係パーサー |
| レガシービューを抽出・順序付け・ |
| グルーピング |
+------------------+------------------+
|
v
+-------------------------------------+
| 2. マイクロコンテキスト変換(LLM) |
| 少数のビューを1グループとして |
| 独立したCTEに変換 |
+------------------+------------------+
|
v
+-------------------------------------+
| 3. 決定論的Pythonスティッチャー |
| CTE重複排除、エイリアスリネーム、 |
| 最終スクリプト組み立て |
+------------------+------------------+
|
v
+-------------------------------------+
| 4. バリデーションエンジン(sqlglot等)|
| 構文・AST整合性を検証 |
+-------------------------------------+
ステップ1(Python): 依存グラフを解析し、LLMには関連する少数のビューのみを渡す。コンテキストは極小化され、モデルの注意は一点集中。情報損失は最小またはゼロになる。
ステップ2(LLM): 小さなコンテキストで、LLMは本来得意な「意味的推論」に専念できる。ビュー単位のCTEへの変換という限定された責務だけを担うため、アテンション希釈が起きにくい。
ステップ3(Python): LLMが生成したCTEをPythonが受け取り、名前衝突の解決、最終的なWITH句の付加、ターゲットSELECTの結合をプログラム的に行う。Pythonはコードを1行も忘れない。アテンション疲労もない。 nビューを渡せば、n個のCTEが必ず出力に含まれることが保証される。
ステップ4(バリデーション): sqlglotなどのライブラリを用いてASTレベルで構文整合性を検証する。見た目は正常に見えるサイレント障害を、この段階で機械的に検出する。
AIエージェント設計者への教訓
Pourhabibはこの経験から、3つのルールを提示している:
- 無限コンテキストの罠に注意せよ: モデルが200万トークンを受け取れても、それを100%の精度で推論できるわけではない。密度が高い処理ほど、コンテキストを小さくする。
- 失敗しえないまでに分解せよ: LLMタスクが不安定な失敗を示すなら、各呼び出しが単一のシンプルな責務だけを扱うまで分解する。
- 古典的なソフトウェアエンジニアリングを再評価せよ: モジュール設計、状態管理、ASTパース、決定論的エラー処理——これらはAIアプリケーション開発においても重要性は下がらない。むしろ上がっている。
エージェントのフレームワーク(Agent Developer Kit、LangChain、AutoGen、CrewAI)やモデルのベンチマーク比較に議論が集中しがちだが、最も重要なのは「モデルの周囲にある決定論的な足場」だとPourhabibは指摘する。
詳細はThe Hidden Engineering Behind Successful AI Agents (Part 2): Why Your Agent Needs a Python Co-Pilotを参照していただきたい。




