0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIエージェントが間違えたとき、ログに何を残すべきか。問い合わせAIのObservability設計

0
Posted at

「配送先を会社の住所へ変更してください」
顧客には未発送の注文が二件ありました。問い合わせAIは「変更しました」と返したものの、翌日確認すると、対象ではない注文の住所だけが更新されていました。
ユーザー入力と最終回答しか残っていなければ、原因候補は広がるばかりです。変更対象の解釈を誤ったのか。古い配送ルールを参照したのか。モデルの判断は妥当でもTool Callの引数を組み立てる処理でIDが入れ替わったのか。APIは失敗を返したのに、AIが成功として扱ったのか。
本番の問い合わせAIで必要なObservabilityは、会話を保存することではありません。「どの版の仕組みが、どの根拠で、どの操作を選び、業務側で何が起きたか」を一件単位で再構成できることです。
image.png

問い合わせ一件を、一つのTraceとして扱う

最初に決めたいのは、会話IDとは別のtrace_idです。チャットが複数ターンにまたがり、検索や業務APIが非同期で動き、人へ調査を依頼しても、同じ案件の出来事をtrace_idで関連付けます。各処理にはevent_idとparent_event_idを持たせると、並列検索や再試行を含む順序も復元できます。
イベントの粒度は「LLMを一回呼んだ」だけでは足りません。少なくともIntent、Retrieved Context、Model Decision、Tool Call、Tool Result、Final Answerを別イベントにします。人が案件を引き取った場合は、その理由と引き渡した時点も残します。そうすれば、検索は正しかったのに判断で対象注文を取り違えた、といった切り分けが可能になります。

最小構成のイベントSchema

実装方式に依存しない最小例を、次のようなイベント形式にしています。値そのものを無制限に保存するのではなく、調査に必要な参照と要約を残す前提です。

title.rb
{
  "trace_id": "inq_01J...",
  "event_id": "evt_006",
  "parent_event_id": "evt_005",
  "stage": "tool_result",
  "observed_at": "2026-09-01T09:31:42.184Z",
  "intent": {"name": "change_shipping_address", "entity_count": 2},
  "knowledge": {"document_id": "shipping_policy", "version": "v12"},
  "decision": {"action": "update_order", "reason_code": "USER_CONFIRMED"},
  "tool": {
    "name": "update_shipping_address",
    "argument_fingerprint": "sha256:...",
    "idempotency_key": "inq_01J...:address:1"
  },
  "result": {"status": "rejected", "code": "ORDER_ID_MISMATCH"},
  "model_version": "model_2026_08",
  "prompt_version": "support_agent_v27",
  "latency_ms": 418
}
puts 'code block.'

trace_idと親子関係は、原因までの経路を組み立てるために使います。model_version、prompt_version、knowledge.versionは、同じ入力を再現した際に結果が変わる理由を探す手がかりです。ナレッジ本文を丸ごとコピーするより、文書ID、版、取得順位、利用した範囲を結び付けた方が、更新後も当時の状態を追いやすくなります。
decisionには、モデルの非公開な思考過程を保存するのではなく、選択した行動、対象エンティティ、確認済み条件、ポリシー上のreason_codeを構造化して残します。必要なのは思考の全文ではなく、「なぜこの操作が許可された扱いになったか」をシステムの言葉で説明できる材料です。
Tool Callではツール名だけでなく、対象ID、重要な引数のマスク済み要約、引数全体のfingerprint、idempotency_keyを残します。Tool ResultもHTTP 200だけで成功にせず、業務上の結果コード、更新対象、更新前後のバージョンを記録します。今回の障害なら、AIの回答より先にORDER_ID_MISMATCHへ到達できます。

ログ量より、失敗を分類できるか

大量のプロンプトとレスポンスを保存しても、調査の入口がなければ運用では使えません。intent_conflict、stale_context、policy_denied、tool_timeout、business_rejected、handoff_requiredのように、発生箇所と性質をreason_codeで揃えると、同じ障害が何件起きているかを集計し、そのまま再現テストへ戻せます。
一方で、会話には氏名、住所、注文情報が含まれます。全文ログ、デバッグ用Trace、監査証跡は保存目的、閲覧権限、保持期間を分けるべきです。通常の調査はマスク済みイベントで行い、原文を開く操作自体も監査対象にする。Observabilityを理由に個人情報を増やし過ぎる設計は、本末転倒です。

本番ログを、次の改善へ戻す

障害対応が終わったら、該当Traceを匿名化し、期待するIntent、許可する操作、想定する結果コードを付けて回帰テストへ追加します。ログは事後説明のためだけでなく、同じ失敗を次のリリースで止めるための入力です。原因がナレッジ、モデル、オーケストレーション、業務APIのどこにあったかで、修正担当も変わります。
Udeskに関わるAIカスタマーサービスの実運用でも、回答だけでなく、検索、判断、業務処理、人への引き渡しを一つのTraceとして追えるかは継続的な論点です。皆さんはAIエージェントのログをどこまで残しますか。障害再現に必要な情報と、保存すべきでない情報の境界をどう決めていますか。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?