
問い合わせ対応へRAG型AIエージェントを入れるとき、評価すべきなのは回答を返したかではなく、案件を定義した完了状態まで進められたかです。
「注文した商品がまだ届かない」
この問い合わせに対して、RAGが配送ポリシーを検索し、「通常は発送後3〜5日で届きます」と回答したとします。参照した文書も正しく、文章にも不自然なところはありません。
それでも、顧客の問題は解決していません。知りたいのは一般的な配送日数ではなく、自分の注文が今どこにあり、遅延が起きているなら次に何をすればよいかだからです。
問い合わせ対応へRAG型AIエージェントを入れるとき、回答精度だけを評価すると、この違いを見落としやすくなります。本番で必要なのは、正しい文章を返すことではなく、案件を定義した完了状態まで進めることです。
問い合わせの完了条件を先に決める
配送状況の問い合わせを完了させるには、少なくとも注文を特定し、配送情報を取得し、その状態を顧客へ説明する必要があります。配送会社から例外ステータスが返された場合は、再配送や調査依頼の手続きが必要になるかもしれません。
したがって、完了状態は「回答を送信した」ではなく、業務側の状態として定義した方が扱いやすくなります。通常配送であれば現在地と到着見込みを案内済みであること、遅延であれば原因と次回更新時刻を案内済みであること、紛失や住所不備の疑いがあれば担当部署への調査依頼が作成されていること、本人確認ができなければ注文情報を開示せずに有人対応へ移管されていることが完了条件になります。
この定義がないと、AIは何らかの文章を返した時点で成功と判定されます。評価指標も回答率へ偏り、顧客が同じ内容で再度問い合わせたことや、回答後に人が処理を続けたことが見えなくなります。
第一段階は「回答する」
回答段階では、RAGで配送ポリシーやFAQを検索し、根拠のある説明を生成します。一般的な配送日数、配送対象地域、追跡番号の確認方法など、顧客固有のデータを必要としない質問は、この段階だけで完了できます。
ただし、検索結果が正しいことと、最終回答が正しいことは別です。検索上位に現行ポリシーと旧ポリシーが同時に含まれていれば、LLMが両者を混ぜて回答することがあります。適切なチャンクを取得していても、適用地域や注文日を無視して一般化する可能性もあります。
そのため、RAGの評価は検索と生成を分けます。検索では必要な文書が取得できたか、権限上参照してよい文書だけが含まれているか、改定日や適用範囲を取得できたかを確認します。生成では取得した根拠と回答が対応しているか、不明な内容を補っていないか、顧客固有の事実と一般ルールを混同していないかを確認します。
検索スコアだけを回答の確信度として利用するのも危険です。類似度が高い文書であっても、その顧客に適用できるとは限らないためです。
第二段階は「実行する」
顧客固有の配送状況を答えるには、注文番号の取得、本人確認、注文システムの参照、配送会社APIの呼び出しが必要です。ここからAIエージェントは文章生成ではなく、業務処理へ入ります。
この段階で最初に分けたいのが、参照権限と更新権限です。注文状況の照会と配送先の変更を、同じツールと同じ認可範囲で扱うべきではありません。参照系ツールは必要な項目だけを返し、更新系ツールは別の認可、入力検証、確認手順を持たせます。返金や再発送のように影響の大きい操作は、AIが実行するのではなく、承認待ちの案件を作るところまでに制限する選択もあります。
Tool Callingでは、正常応答より失敗時の設計が難しくなります。タイムアウトした呼び出しを再試行した結果、同じ調査依頼や再発送が二重登録される可能性があるためです。更新系ツールには冪等キーを付け、AI側の会話IDではなく業務側の案件IDと結びつける必要があります。
第三段階は「人へ引き継ぐ」
有人転送は、AIが失敗した後の例外処理ではありません。最初から予定された状態遷移の一つです。
注文が見つからない、本人確認に失敗した、配送会社から想定外の状態が返った、顧客が補償を求めている。このような案件でAIが会話を続けるほど、もっともらしい推測や不要な聞き返しが増えます。
重要なのは転送ボタンではなく、誰が案件の所有者になるかを切り替えることです。人へ移管した後もAIが同じ案件を処理すると、二重回答や二重実行が起こります。
引き継ぎ時には、会話全文だけでなく、顧客の目的、確認済みの情報、参照したナレッジ、実行したツール、取得結果、失敗理由、人が判断すべき点を構造化して渡します。担当者が最初から注文番号を聞き直すなら、チャネルは切り替わっていても業務は引き継がれていません。
判断ロジックをLLMだけに持たせない
回答、実行、有人転送の分岐をすべて自然言語のプロンプトへ書くと、変更履歴を追いにくく、同じ状態でも結果が揺れることがあります。本人確認、操作権限、業務システムの応答、処理の可逆性に関する条件は、アプリケーション側のルールとして持たせた方が管理しやすくなります。
def next_action(state):
if state.identity_required and not state.identity_verified:
return "ASK_FOR_VERIFICATION"
if state.tool_error and state.retry_count >= 1:
return "HANDOFF"
if state.delivery_status in ["lost", "address_error", "unknown"]:
return "HANDOFF"
if state.requested_action in ["refund", "reship", "change_address"]:
return "REQUEST_HUMAN_APPROVAL"
if state.order_found and state.delivery_status == "in_transit":
return "ANSWER_WITH_TRACKING_DATA"
if state.rag_evidence_is_sufficient:
return "ANSWER_FROM_KNOWLEDGE"
return "HANDOFF"
puts 'code block'
これは実装例というより、LLMへ任せる判断と、業務ルールで固定する判断を分離するための形です。
多輪対話の状態はメッセージ履歴とは別に持つ
問い合わせが一往復で終わらない場合、メッセージ履歴だけで状態を復元しようとすると、確認済みの注文番号や本人確認結果が失われたり、古い情報を現在の状態として扱ったりします。会話とは別に、案件の状態を明示的に保存します。
{
"case_id": "case_xxx",
"intent": "delivery_status",
"order_id": "masked",
"identity_verified": true,
"retrieval": {
"document_ids": ["shipping_policy_v4"],
"scores": [0.82]
},
"tool_calls": [{
"name": "get_delivery_status",
"result": "exception",
"error_code": "ADDRESS_ERROR"
}],
"current_owner": "human_queue_logistics",
"handoff_reason": "business_exception",
"unresolved_item": "配送先住所の確認"
}
puts 'code block'
保存する項目は目的から逆算し、不要な個人情報を残さないことも必要です。会話ログを丸ごと保存すれば調査できるとは限らず、必要な判断情報が埋もれることがあります。
ログで「なぜその結果になったか」を追えるようにする
最低限追いたいのは、入力された意図と抽出項目、検索した文書と検索スコア、生成時に使用した根拠、選択したツールと引数、ツールの応答、再試行回数、最終的な分岐、有人転送理由です。モデルやプロンプト、ナレッジのバージョンも残しておくと、同じ質問への回答が変わった際に原因を追いやすくなります。
一方、ログの量を増やすこと自体が目的になると、個人情報の保存範囲が広がり、調査にも時間がかかります。誤回答の原因を調べるログ、業務処理の監査に使うログ、運用指標を集計するログは、利用目的と閲覧権限を分けた方がよいでしょう。
AIが止まれることも機能である
問い合わせ対応では、AIが処理できる範囲を増やすことと同じくらい、処理を続けてはいけない状態を定義することが大切です。RAGで答えられるか、ツールを呼べるかという技術上の可否だけでなく、誤った場合に取り消せるか、顧客への影響を確認できるか、人の承認が必要かを判断条件へ含めます。
Udeskに関わるAIカスタマーサービスの設計でも、回答、業務実行、有人対応を一つの案件状態としてどう接続するかは継続して向き合っている論点です。皆さんなら、AIエージェントにどの範囲まで更新権限を持たせ、どの条件を越えたらモデルの判断に関係なく人へ切り替えますか。