AIに考えさせる。でも、計算と更新まで任せきらない。
Googleの「Agent Bake-Off」総括は、5つの実践則の一つを見出しでこう表現しました。LLMは推論し、決定論的なコードが実行する。金融取引の計算をAIに担わせたチームでは、大きな検証エラーを招いたと報告しています。
今回は、自然言語を理解するAIと、毎回同じ結果を返す従来コードをどう分業させるか。構造化出力を「安全装置」と誤解しないための設計を整理します。
LLMが得意な仕事、コードが得意な仕事
LLMは入力の揺れを吸収するのが得意です。「来月から毎月3万円を積み立てたい」のような文章から、金額・開始月・意図を読み取れます。一方、複利計算、在庫更新、送金、権限判定のように、同じ入力には同じ結果が必要な処理は従来コードの担当です。
- LLM:意図抽出、分類、候補作成、例外の説明
- スキーマ:受け渡す項目・型・許容値の固定
- コード:計算、検証、認可、データ更新
Googleの公式記事では、金融取引の変数を厳格なJSONスキーマで受け取り、検証後にPython関数やSQLへ渡す構成を推奨しています。AIを電卓にするのではなく、電卓へ正しい引数を渡す通訳にする設計です。
構造化出力は「正しい意味」を保証しない
Gemini APIの公式ドキュメントでは、JSON Schemaに従う構造化出力を、データ抽出・分類・ツール入力に使えると説明しています。PythonではPydantic、JavaScriptではZodからスキーマを定義できます。ただしJSON Schemaの全機能に対応するわけではなく、大きすぎる、または深くネストしたスキーマは拒否される場合があります。
ただし、ここが重要です。Google自身が「出力は構文的に正しいJSONでも、値はアプリケーション側で必ず検証する」と明記しています。形が正しくても、中身が正しいとは限りません。
たとえば仮に、次のJSONは型としては正常です。
{
"amount_yen": 30000,
"months": 12,
"annual_rate": 15.0
}
しかし、年利15%がユーザーの入力なのか、AIが補った値なのかは別問題です。スキーマが検査できるのは、定義した項目・型・列挙値・上限などの範囲です。根拠のない数値まで消してはくれません。
本番では4つの境界を置く
- 抽出境界:LLMは入力から変数だけを抽出する。推測値には出典や信頼度を付ける
- 型境界:JSON Schemaで必須項目、型、列挙値、上限・下限を絞る
- 業務境界:コードで「残高以内か」「承認権限があるか」「締切前か」を再検証する
- 副作用境界:確認前は計算・見積もりまで。DB更新や送信は承認後の別処理にする
特に3番目が肝です。型検証を通過したからといって、業務上正しいとは限りません。金額が整数でも、利用上限を超えていれば拒否する必要があります。
車載開発にたとえると
この考え方は、AIシステムに限らず制御系の設計にも通じます。
LLMはドライバーの曖昧な要望を読み取るHMIに近く、決定論的コードはECUの制御ロジックに近い存在です。「少し暖かくして」を温度目標へ変換するのはAI向きですが、アクチュエータの上限監視やフェイルセーフまで確率的モデルへ預けるべきではありません。
自然言語の柔軟性は入口で使い、実行経路は型・ルール・承認で狭める。この分離が、便利さを落とさずに事故の範囲を小さくします。
実践チェックリスト
- LLMの出力を、そのまま計算結果や更新値として使っていないか
- 構造化出力をPydanticやZodなどで再検証しているか
- 型検証とは別に、金額上限・権限・状態遷移を確認しているか
- 欠損値をAIが勝手に補わず、確認へ戻せるか
- 読み取り・計算と、送信・更新の副作用を分離しているか
まとめ
- LLMは意図を読み、決定論的コードが計算・検証・実行する
- JSON Schemaは形を保証するが、値の意味までは保証しない
- 型検証、業務ルール、承認を別々の境界として設計する
- AIは「答えを出す装置」より「正しい処理へつなぐ通訳」として使う
賢いモデルほど多くを任せたくなります。しかし本番品質を決めるのは、AIに何をさせるかだけではなく、どこから先を普通のコードへ戻すかです。