RAGに溜めた誤った教訓を、あとから撤回する仕組みを作った — 相棒を毎ターン歪める汚染を自動で消す
はじめに
個人で、複数のシステムを横断して作業するAIエージェントに、共有の記憶(RAG=過去の判断・失敗・教訓をベクトル検索で呼び出す仕組み)を持たせている。これがあると、エージェントは「毎回初対面の他人」ではなく「私を知る相棒」として動く。前提はこの二つの記事へ譲る。
AI に5回訂正された夜 — 個人 RAG を5年付き合える相棒にする設計思想
AIに毎ターン「今、思い出すべきこと」を差し込む — 個人RAGの活性化層
この共有記憶には、前にひとつ落とし穴を見つけて塞いだことがある。別プロジェクトの決定が、共有記憶を経由してもう片方の設計書に混入する、という話だ。
別プロジェクトの決定の混入を検出して分離した — 複数システムを横断するAIとRAGの落とし穴
今回は、そこから一歩進む。混入を「検出して分離する」だけでなく、一度書いてしまった誤った教訓を、あとから取り消す仕組みを作った。先に立場をはっきりさせておく。RAG本体(記録を溜めるDB)は受け身の保管庫で、自分から何かを取り消したりはしない。取り消しを実行するのは、私がその周りに組んだ運用の仕組み(日次バッチ)の方だ。「RAGが賢く自浄する」話ではなく、「保管庫に撤回の運用を後付けした」話として読んでほしい。
誤った教訓は、毎ターン相棒を歪める
この記憶には、重要なものに「優先度:高」の印を付ける仕組みがある。印の付いた記録は、毎回の対話の冒頭で「今これを思い出せ」と自動で差し込まれる(この差し込みが活性化層だ。詳細は上のリンク先へ)。強力だが、裏を返すと危うい。根本原因がまだ確定していないのに、断定口調の教訓を「優先度:高」で書いてしまうと、その誤りが毎ターン差し込まれ続ける。
実際にやってしまった。あるツールの不具合について、原因を突き止めきる前に「診断確定:原因はこれだ」と書いた。後日、それは誤りだと分かった。だが印の付いた誤った教訓は、その間ずっと相棒の目の前に差し込まれ、判断の土台を静かに歪めていた。バックアップが「壊れない」ための備えなら、これは記憶が「汚れない」ための問題だ。
訂正ノートを足しても、なぜ効かないのか
素朴には「訂正を追記すればいい」と思う。ところが、これがほとんど効かない。追記型の記憶では、あとから訂正を足しても、元の誤った記録は消えずにそのまま残る。検索は意味の近いものを引くので、同じ話題では誤りと訂正の両方が引かれ、印の付いた誤りは相変わらず毎ターン差し込まれる。訂正は「上書き」ではなく「並置」にしかならない。
ある話題について相棒が記憶を引く
│
├─▶ 誤った教訓(優先度:高)──▶ 毎ターン差し込まれる ──┐
│ │ 判断を歪め続ける
└─▶ あとから足した訂正ノート ──▶ 一緒に引かれるだけ ───┘
↑
「並んだ」だけで、誤りは消えていない
人間の記憶なら、忘却や上書きで古い誤りは薄れていく。追記だけのログには、その「消える」機構が無い。RAGは「書けばよい」のではなく、「誤りを取り消せる」ところまで含めて、はじめて信頼できる——これがこの記事の背骨だ。
作った仕組み ― 行頭に一行、あとは日次バッチが消す
そこで、明示的に「これを撤回する」と宣言できる仕組みを後付けした。誤りに気づいたら、訂正エントリの行頭に、消したい誤りを一意に指せる語句を添えてこう書く。
RETRACTS: <消したい誤った教訓を一意に指すフレーズ>
毎日走る日次バッチの後段に、記録全体を走査してこのマーカーを拾い、一致する記録をDBから自動で削除する処理を足した(バックアップの自動化と同じ日次バッチに同居させた。バッチ全体の設計は対の記事Aに書いた)。実行するのはこの運用スクリプトであって、DBが自分で判断するわけではない。流れはこうなる。
誤りに気づく
│
▼
訂正エントリの行頭に RETRACTS: <一意フレーズ> を書く
│
▼
日次バッチ(毎日・ローカルPC)
│
├─▶ 記録全体を走査してマーカーを拾う
│ │
│ ├─ 一致した ──▶ その記録を両方の記録先から削除(生ノートと厳選知恵)
│ └─ 一致0件 ──▶ 何もしない(冪等)
▼
誤った教訓が、活性化層への差し込みごと消える
「気づいた時点で一行書いておけば、あとは自動で消える」。訂正を並べるのではなく、元を断つ。
暴発させないための安全設計
自動でDBのレコードを消す仕組みは、作り方を誤ると危険だ。撤回のつもりで無関係な記録まで巻き込めば、それはそれで記憶の破壊になる。だから安全側の作り込みに一番手をかけた。
- 既定は削除しない(dry-run=実際には消さず「消す対象」を表示するだけ)。実削除はバッチの本番実行のときだけに限定する。手で確かめるときは何も消えない。
- 短すぎるフレーズは無視する(一定の文字数未満は対象外)。ありふれた短い語で撤回すると、無関係な記録まで一致して巻き込むためだ。
- 撤回宣言そのものは消さない(
RETRACTS:を含む記録=撤回エントリ自身は対象から除外)。さもないと撤回文が自分を消してしまう。行頭にあるRETRACTS:だけをマーカーとみなし、文章の途中でこの語に触れただけのものはマーカー扱いしない。 - 消す前にバックアップが在る。日次バッチは前段でDBのスナップショットを取っているので、撤回の前の状態がつねに残る。
- 何度流しても同じ結果になる(冪等=一致0件なら何もしない)。
正常系(マーカーがある)だけでなく、境界と敵対的な入力(短すぎる語・撤回文の中に出てくる RETRACTS: の言及・散文中に紛れた同じ語)を通して、意図しない一致で暴発しないことを確かめてから本番に載せた。
平常時(マーカー0件)に実際こう出る。既定は消さず「消す対象」を並べるだけで、--apply は日次バッチだけが付ける(内部パス・スクリプト名は伏せている)。
$ retraction --dry-run
[retraction] scanning data/ ...
[retraction] RETRACTS markers found: 0
[retraction] would delete: 0 records
(no changes; --apply is added only by the daily batch)
自動化は保険 ― 気づいたその場で消す規律と二層で
もう一つ大事にしたのは、自動化を万能にしないことだ。撤回マーカーは「取りこぼしの保険」であって、第一線ではない。誤った教訓に気づいたその瞬間に、まずその場でDBから消し、元のノートも直す。これを第一の規律に置き、マーカーによる日次の自動撤回を第二の網とした。
第一線:気づいたその場で削除+ソース修正(即時・確実)
│ 取りこぼしたら
▼
第二の網:RETRACTS: マーカー → 日次バッチが自動撤回(保険)
一つの手段に賭けないのは、バックアップを三層で持ったのと同じ考え方だ。即時対応は確実だが人が気づけたときしか働かない。自動撤回は網羅的だが一日一度だ。両方あって、はじめて漏れが小さくなる。
いま割り切っていること
この仕組みは、まだ意図して素朴に留めてある。撤回できるのはDB側の記録で、大元のMarkdownからの物理的な抹消(tombstone=墓標を立てて無効化する処理)までは自動化していない。ファイルの自動編集は壊れやすく、副作用が読みにくいからだ。毎ターン差し込まれて判断を歪める実害はDB側にあるので、まずそこを確実に断つことを優先した。一致した大元のファイルはログに残るので、必要なら手で消せる。
「矛盾していそうな教訓を、AIに自動で見つけさせて消す」という、もう一段賢い方向もある。だがそれは確率的で、正しい記憶まで誤って消しかねない。まず確実な明示マーカーを土台に据える——賢さより確実さを先に置いた、という判断だ。
追記するだけの記憶に、「取り消し」を後付けする
やったことは、突き詰めれば一つだ。追記しかできなかった記憶に、「これは無かったことにする」という操作を後から与えた。 溜めるだけの知識ベースは、時間が経つほど誤りが澱のように溜まり、しかも印の付いた誤りは毎日それを蒸し返す。忘れられない記憶は、賢くなるどころか歪んでいく。撤回を運用に組み込んで、はじめて記憶は「増える」だけでなく「正される」ものになった。
これは個人RAGに限った話ではないはずだ。ログでも、設計ドキュメントでも、追記だけで育つ知識ベースには、どこかに「撤回・置き換え」を一等地で扱う仕組みが要る。記憶を「壊れない」ようにした話は、対になる次の記事に書いた。
AWS S3 + restic で相棒の脳を暗号化オフサイトバックアップ — 記憶を”平文のままクラウドに上げず”に遠隔退避する
情報量に飲まれない学習設計 — RAG/LLMチューニングを”深く3つ”に絞り、測るまでを1単位にする
そして、これらを健全なまま保ち続けるための毎週の点検の仕組みは、この記事に書いた。