医療とAIの、これまでとこれから。

AIの書き込みを後から追えるようにする — before/after/reason の監査ログ設計

AIに書き込み権限を渡すなら、監査ログはあとから足す機能ではなく前提条件になる。実際に運用しているシステムのテーブル定義をそのまま公開し、reason 欄がなぜ必須なのか、何を載せてはいけないのか、バックアップと何が違うのかを整理する。

AIの書き込みに対する監査ログとは

AIの書き込みに対する監査ログとは、変更の前後の値だけでなく「AIが述べた変更理由」を、追記専用で残す記録である。

人間のオペレータの操作ログと決定的に違うのは、あとから当人に聞けないことだ。人間なら「なぜこれを消したのか」を本人に確認できる。AI にはそれができない。同じモデルに同じ質問をしても、それは当時の判断の再現ではなく新しい生成である。当時の理由は、その時に書き残さなければ永久に失われる。

だから設計としては、before / after に加えて reason を必須項目として扱う。以下は実際に運用しているシステムの実装である。

テーブル定義をそのまま出す

このシステムでは、AI による変更は例外なく1行が残る。実テーブルの列はこうなっている。

何を入れるか
idTEXT主キー(UUID)
project_idTEXTどの案件の変更か(複数案件を1基盤で回す将来構成のための外部キー。現在は単一)
actorTEXThuman:<id> / agent:<name> / system
actionTEXTcontent.publish / experiment.adopt など動詞
entity_type / entity_idTEXT何に対する変更か
before_json / after_jsonTEXT変更前後の値(JSON)
reasonTEXTAIが述べた変更理由
experiment_id / resultTEXT実験に紐づく変更かどうか
created_atINTEGER記録時刻(UNIX秒)

索引は2つだけ置いている。(entity_type, entity_id, created_at DESC)(actor, created_at DESC) である。この2本は、事故のときに実際に投げる質問がこの2種類に集約されるからだ。「この記事に何が起きたか」「このエージェントが何をしたか」。前者は影響範囲の特定に、後者は暴走したエージェントの停止判断に使う。監査ログの索引は「あとで分析するため」ではなく、「事故対応で最初に打つクエリ」から決めるとよい。

書き込み関数は追記しかしない。UPDATE も DELETE も用意していない。更新できる監査ログは監査ログではないからで、これは性能や容量の話より先に決めるべき性質である。

reason 欄が実際に効く場面

before / after は「何が起きたか」しか示さない。ロールバックの判断に必要なのは、たいていそこではない。

差分だけを見て「これは戻すべき変更か」を判断できる場面は、そう多くない。値が変わったこと自体は正しい変更でも起きるからだ。判断を分けるのは、その変更が何を意図していたかである。「A/B の勝ち筋が出たので採用した」と「参照していた指標が欠測していたので暫定値で埋めた」は、after が同じでも扱いがまったく違う。

そこで、書き込みを行う AI に「なぜそうしたか」を自分の言葉で書かせる欄を必須にしている。運用してみて分かったのは、この欄の副作用のほうが大きいということだ。理由を書けない変更は、たいてい根拠が薄い。 reason が空欄になりがちな経路は、権限設計を見直したほうがいい箇所である。

載せてはいけないものを先に決める

監査ログは「全部記録する」が正しく見えるが、そのまま実装すると個人情報の複製装置になる。

このシステムでは、問い合わせフォームから届いた連絡先を after に載せないと決めてある。リードのレコード自体は保存するが、監査ログ側には残さない。監査ログは長期に残り、追記専用で消せず、権限の異なる複数の経路から読まれる。削除できない場所に個人情報を入れると、あとから取り消せない。

同じ理由で、APIキーなどの秘密情報も載せない。監査ログに残すべきは「誰が・いつ・何を・なぜ変えたか」であって、値そのものが必ず要るわけではない。機微なフィールドは、値ではなく「変更があった事実」だけを残す設計にできる。

医療・美容医療の領域でこの設計をそのまま使う場合、ここは特に慎重に扱う必要がある。監査のために残した記録が、本来アクセス制御されるべき情報の抜け道になりうるからだ。

監査ログとバックアップは別物である

「データベースの復元機能があるから監査ログは要らない」という整理は成り立たない。両者は目的が違う。

Cloudflare の D1 は公式ドキュメントの説明ではこうである。

D1 is Cloudflare's managed, serverless database with SQLite's SQL semantics, built-in disaster recovery, and Worker and HTTP API access.

同ドキュメントは復元機能(Time Travel)について、直近30日以内の任意の時点へ復元できると説明している。

バックアップ / 復元監査ログ
目的状態を戻す何が起きたかを説明する
粒度データベース全体1変更ごと
意図の記録無いreason に残る
保持期限がある追記して残す

復元は「壊れた状態から戻す」ための手段で、どの時点に戻すべきかは教えてくれない。その判断材料が監査ログである。逆に監査ログはデータを戻せない。片方だけでは事故対応が完結しない。

付け忘れないための置き場所

監査ログの一番の失敗は、設計の欠陥ではなく付け忘れである。新しい書き込み経路を足したときに、そこだけログが無い。

このシステムでは、書き込みが必ず通るリポジトリ層の関数に権限チェックを置き、監査ログもその同じ経路に寄せている。AI がデータベースへ直接アクセスすることを禁じているので、権限チェックを通った書き込みは監査も通る。「必ず通る場所」を1か所に決めて、そこに全部載せるのが、規律で守るより確実である。

チェックリストとしては次の3つで足りる。

  1. 書き込み経路は1か所に集約されているか(迂回路が無いか)
  2. その経路で reason が必須になっているか
  3. 個人情報・秘密情報が before / after に入らないことがテストで固定されているか

FAQ

Q. 監査ログは全部の書き込みに必要ですか。 AI が実行する書き込みには必要です。人間なら事後に意図を確認できますが、AI には確認先がありません。

Q. reason は何字くらい書かせるべきですか。 長さより粒度です。「更新した」ではなく「何を根拠にそう判断したか」が1文で読めれば足ります。

Q. ログが増えすぎませんか。 1変更1行なので、AI の書き込み頻度が現実的な範囲なら問題になりません。肥大するのは before / after に大きな本文を丸ごと入れた場合です。

Q. バックアップがあれば監査ログは不要では。 不要になりません。復元は状態を戻しますが、どこへ戻すべきかの判断材料は監査ログにしかありません。

まとめ

AI に書き込ませる設計で先に用意すべきなのは、賢さではなく説明可能性である。

自律的に動く AI を業務に入れるとき、この記録があるかどうかが「試せる」と「試せない」の境目になります。設計と実装のご相談を承っています。

出典

  1. Cloudflare Docs(公式ドキュメントのソース)— D1 overview(参照 2026-08-09)