powered by TechFeed
表示モード
Deep Dive

AIエージェントが「何をしたか」を証明する監査ログの設計 — チャット履歴では足りない理由とツール呼び出しスキーマの全貌

9月2日、Stein Ove Helsetが「AI Agent Audit Trail Schema: What to Log for Tool Calls」と題した記事を公開した。この記事では、AIエージェントがツールを呼び出す際に何をログに残すべきか、監査・コンプライアンス対応に使える具体的なスキーマとその設計思想について詳しく紹介されている。以下に、その内容を紹介する。

9月2日、Stein Ove Helsetが「AI Agent Audit Trail Schema: What to Log for Tool Calls」と題した記事を公開した。この記事では、AIエージェントがツールを呼び出す際に何をログに残すべきか、監査・コンプライアンス対応に使える具体的なスキーマとその設計思想について詳しく紹介されている。以下に、その内容を紹介する。


チャット履歴は監査ログではない

MCPサーバー(Model Context Protocol対応のツール群)と連携したAIエージェントを運用していると、「システムに変更が入ったが、エージェントがやったのか人間がやったのか分からない」という状況に直面する。チャット履歴はユーザーが何を指示したかを示すだけで、「どのツールが呼ばれたか」「どんな引数が渡ったか」「何が返ってきたか」「どれくらい時間がかかったか」は残らない。

記事ではこれを「Webサーバーのアクセスログに相当するもの」と表現している。ツール呼び出し1件につき1レコード、クライアントの外側に保存する構造が必要だという主張だ。


スキーマの全体像

以下が記事で紹介されているログスキーマの実例だ。

{
  "id": "02J8X5K2M3N4E5Q6R7Z4T9C4Q1",
  "timestamp": "2026-08-20T09:12:32.118Z",
  "session_id": "sess_3f2c9c",
  "request_id": "req_2b5f",
  "parent_id": null,
  "actor": {
    "user_id": "hello@codewithstein.com",
    "client": "cursor/3.17.2",
    "model": "claude-opus-5"
  },
  "server": {
    "name": "notion",
    "version": "2.1.0",
    "transport": "streamable-http"
  },
  "tool": {
    "name": "update_page",
    "arguments": { "page_id": "abc123", "title": "My favorite AI models.." },
    "arguments_hash": "sha256:4f1d..."
  },
  "result": {
    "status": "ok",
    "is_error": false,
    "duration_ms": 412,
    "content_size_bytes": 2048,
    "content_hash": "sha256:41db..."
  },
  "auth": {
    "identity": "oauth:notion:user_007",
    "scopes": ["pages:write"]
  },
  "policy": {
    "decision": "allow",
    "rule": "team-editors-can-write"
  }
}

各フィールドの設計意図

IDとタイムスタンプ

idにはULIDまたはUUIDv7を使う。どちらも時刻順にソート可能なため、インシデント発生時に時系列を追いやすい。timestampはミリ秒精度で記録し、複数のツール呼び出しが連鎖した際の順序を明確にする。

セッションとリクエストの連鎖

session_idrequest_idparent_idの3つがセットで機能する。ユーザーの1プロンプトが複数のツール呼び出しを生み、さらにツールが別のツールを呼ぶケースで、この連鎖を後から再構築するために必要だ。OpenTelemetryを既に導入していれば、trace IDとspan IDをそのまま流用できる。この連鎖が欠けると「なぜエージェントがその呼び出しをしたのか」という因果関係が失われる。

actor(呼び出し主)

user_id(人間)、client(使ったツール)、model(判断したモデル)を記録する。インシデント調査で最も重要なのはどのモデルが決定を下したかだと記事は指摘する。chain-of-thought(思考過程)をログに含めるかチームで議論になることもあるが、著者は生の推論を記録するよりも決定の入力と出力を残す方針を推奨している。

tool(引数とハッシュ)

引数はシークレットフィールドをマスクした上で記録する。**arguments_hashを残しておくことで、引数を後から改ざんしていないことを証明できる**。クラウドの監査ログはインフラ操作を捕捉するが、エージェントの内部ステップは含まないことが多く、このフィールドがその隙間を埋める。

result(結果はハッシュで持つ)

レスポンス本文をそのまま保存しない。データが大きく、保護対象の情報を含むケースが多いためだ。statusduration_mssize_bytescontent_hashを残し、本文が必要なら別ストレージに短期保存してIDで参照する設計を推奨している。

authとpolicy

authには使用したIDとスコープを記録する。サービスアカウントなどマシンIDも対象で、プロンプト・ツール・依存ライブラリのどれかが侵害されうるという脅威モデルを前提にしている。

policyフィールドは、ObotのようなMCPゲートウェイを介している場合に、ゲートウェイがどのルールで許可・拒否したかを記録する。拒否されたリクエストのログはプロンプトインジェクション試行のレビューに特に有効だと説明されている。


どこに保存するか

各MCPサーバーの内部にログを書くのは避けた方がよい。サーバーごとにフォーマットが異なり、MCPサーバーがユーザー情報を知る必要もない。

記事が推奨するのは、クライアントとMCPサーバーの間に置くゲートウェイ層での一元ログだ。ゲートウェイはすべての呼び出しを通過点として見ており、ユーザー情報もポリシーも把握しているため、一貫したフォーマットで1レコードずつ書き出せる。ゲートウェイを使わない場合は、組織で既に運用しているLoki・PostgreSQLなどのログシンクで問題ない。


コンプライアンス要件との接続

記事の末尾では保存期間の目安も示されている。ツール呼び出しイベントは最低90日間保存し、HIPAAやPCI-DSSが適用される環境ではさらに長期保存が求められる。SOC 2では改ざん不可能なログが求められるが、1つのゲートウェイ層で書き出す構成の方が保証しやすい。EU AI ActNIST AI RMFのようなフレームワークへの対応においても、コントロールプレーンに監査レコードを集約することがコンプライアンスチームの実際のニーズに合致すると述べている。


詳細はAI Agent Audit Trail Schema: What to Log for Tool Callsを参照していただきたい。