デモは成功した。
部長の質問にも答えた。参照元も表示された。用意したケースは、三つともきれいに通った。
本番投入前のレビューで聞かれた。
「これ、答えられない質問が来たらどうなるんですか」
誰も見たことがなかった。失敗するところを。
うお、成功デモどこいった。いや、成功デモしかなかった。
成功率を確認していた
PoCでは、まず動くところを見せたくなる。
検索できる。回答できる。出典も付く。toolも呼べる。ここまで揃えば、少なくとも実装としては前へ進んでいる。
入力も自然と整う。
- 必要な資料が存在する質問
- 想定したドメインの質問
- 答えの形が分かっている質問
- 開発者が正解を判断できる質問
この条件では、Agentはよく動く。デモも盛り上がる。
問題は、その成功が本番で必要な能力の半分しか見ていなかったことだった。
本番で先に来たのは、答えられない質問だった
本番の入力は、PoCの入力ほど親切ではない。
資料が足りない。対象外の案件が混ざる。文書同士が矛盾している。質問そのものが曖昧なこともある。
それでもシステムが「何か答える」ように作られていると、LLMはそれらしい文章を返す。
エラーにはならない。画面も赤くならない。
だから厄介だった。
たとえば内部状態が、実際にはこうだったとする。
{
"evidence_found": false,
"conflict_detected": true,
"missing_facts": ["対象条件", "適用時期"]
}
最終出力だけを作らせれば、この状態からでも文章は出る。
PoCで見ていたのは、回答が出るかどうかだった。本番で必要だったのは、回答を出してはいけない状態から、正しく戻れるかだった。
failure policyは例外処理ではなかった
最初は、失敗時の処理を後から足せると思っていた。
検索が空ならメッセージを出す。toolが落ちたら再試行する。モデルがタイムアウトしたらエラー画面へ送る。
それだけでは足りない。
RAG / AI Agentの失敗は、HTTP 500のように分かりやすく落ちるとは限らないからだ。
- 材料が足りないのに答えられてしまう
- 関連文書はあるが、対象条件が違う
- tool callは成功したが、原質問から離れている
- 回答は自然だが、誰も責任を持てない判断を含んでいる
動いている。だから失敗に見えない。
必要だったのは、成功経路の外側にエラー処理を置くことではなかった。状態ごとに、続行・追加取得・人間へ戻す・答えないをworkflow側で選べることだった。
input
↓
retrieve
↓
stateを更新
├─ 材料が揃った → render
├─ 追加取得できる → retrieveへ戻る
├─ 人の確認が必要 → escalate
└─ 対象外 / 判断不能 → abstain
ここで重要なのは、分岐の名前を増やすことではない。
「毎回回答まで進む」という一本線を、完成形だと思わないことだった。
成功デモをやめる必要はない
デモで成功経路を見せること自体は悪くない。最初から失敗ばかり見せても、何を作ったのか伝わらない。
ただ、成功したケースだけで本番性を評価すると、システムが一番危ないところを見ないまま進む。
少なくとも一度は、意図的に材料を抜く。矛盾した資料を入れる。対象外の質問を投げる。toolを失敗させる。
そのとき、モデルがどれだけ賢く取り繕うかではなく、workflowがどこへ戻すかを見る。
成功率を上げていたはずなのに、いつの間にか失敗を隠す能力を育てていた。
普通にダメ。
本番で問われるのは、答えた回数だけではない
PoCでは「答えられた」が成果になりやすい。
本番では、答えない方がよかったケースも同じくらい重要になる。
必要だったのは、さらに強いモデルではなかった。失敗を失敗として観測し、次の行き先を決めるruntimeだった。
この失敗を含め、本番投入前に確認したいPrincipal / Artifact / Boundary / Runtime / State / Observabilityの観点を、チェックリスト本にまとめています。