本番運用 — Logging Safety / Drift / Cost / Rollback で RAG を運用する
2026-05-24 改訂: 本シリーズは Ollama + Qwen3 で完全ローカル再現できる構成に作り直しました。題材は架空企業「ナギサ・パートナーズ」(中堅 SIer、自社 SaaS「Mirage」を運用) の社内 wiki です。本記事は運用 runbook なので測定値の chart はありませんが、コスト節ではローカル経路 (API コスト 0 円) とクラウド経路の両方を併記します。
Part 1 で素朴な RAG、Part 2 で hybrid+filter、Part 3 で reranker + Citations、Part 4 で 30 件 golden set × RAGAs 4 指標。ここまでが offline の話でした。本記事 (Part 5、シリーズ完結) では online に持ち込んだ瞬間に立ち上がる別の課題群 — logging の設計、PII の取扱い、embedding drift、古い文書の退役 (freshness)、コスト構造、ロールバック — を扱います。

最初に強い警告を 1 つ置きます。個人情報を含むコーパスで default のまま retrieved chunks をログに出すと、それは即座に PII データレイクになります。Part 4 までの「動かす」「測る」と、Part 5 の「運用する」の間には、設計レベルの溝があります。本記事はその溝を埋める runbook です。
Offline で良かったものが Online で壊れる場所
Part 4 の最後で offline と online の対比表を出しました。改めて、online で 何が新しく壊れるか を観察します。
| 壊れる場所 | Offline では | Online で起きること |
|---|---|---|
| Logging | 30 件の固定 query | 実 user query (PII / 機微情報含む) が大量に流れ込む |
| 評価 | golden set 5pp 改善で勝ち | A/B で 0.5pp の delta を信頼する必要 |
| Retrieval | 固定 corpus | 文書改訂・新規追加で embedding drift が常に進行 |
| Generation | 同じ judge | コスト構造 (embed / rerank / LLM tokens) を 常時 監視 |
| 障害 | sandbox で再現 | rollback 計画と postmortem が必須 |
ここからは各観点を順に runbook 化します。
Logging の設計 — 何を、どこに、どれだけ保持するか
最初の判断は 「何を記録するか」 ではなく 「何を記録しないか」 です。
記録対象の 4 層
| 層 | 例 | 機微度 | retention の標準 |
|---|---|---|---|
| Request | query, user_id (匿名化), timestamp | 中 | 90 日 |
| Retrieval | retrieved chunk_ids, scores | 低 | 90 日 |
| Generation | answer text, model, tokens | 中 | 30 日 |
| Evaluation | RAGAs スコア, user feedback | 低 | 1 年 |
retrieved chunk の本文を保存しない のがポイントです。chunk_id だけ残せば、後から corpus を pin-point して再構築できます。本文をそのまま保存すると 検索結果がそのまま PII データセット になります1。
OpenTelemetry semantic convention に乗せる
LLM 関連の telemetry には OpenTelemetry の gen_ai.* semantic convention2 が定着しつつあります。
from opentelemetry import trace
tracer = trace.get_tracer("rag-pipeline")
with tracer.start_as_current_span("rag.query") as span: span.set_attribute("gen_ai.system", "anthropic") span.set_attribute("gen_ai.request.model", "claude-opus-4-7") span.set_attribute("rag.retrieved.chunk_ids", ",".join(chunk_ids)) # chunk 本文ではなく id span.set_attribute("gen_ai.usage.input_tokens", usage.input_tokens) span.set_attribute("gen_ai.usage.output_tokens", usage.output_tokens)Datadog / Grafana / OneUptime いずれの可視化 backend も OTel convention を解釈するので、dashboard を作り直さずに backend を入れ替えられます3。
Logging Safety — PII redaction を default に置く
ここからが本記事で最も強調したい節です。「個人情報を含むコーパスで default のまま retrieved chunks をログに出すと、それは即座に PII データレイクになる」。これを防ぐ設計を 3 箇所 で多重化します4。
ナギサ corpus は教育用に無害化してありますが、現実の社内 wiki を想像してください。本シリーズの corpus でも、顧客 PJ 名 (Lumen / Tide / Marisol — 実在企業なら NDA 対象)、障害 post-mortem の担当者名、ボードゲーム同好会の参加者 initials のような 機微情報が業務文書に普通に混ざります。retrieved chunk 本文をそのままログに流せば、「障害対応フロー」を引いただけで担当者名と顧客名がログに焼き付きます。
3 箇所で redact する
| 箇所 | 強み | 弱み |
|---|---|---|
| Ingest (embedding 前) | 最も強い保証、永続的 | corpus 再生成が必要、失われた情報は復元不可 |
| Retrieval (取得後 / ログ書き込み前) | 柔軟、ホット pass で介入可 | hot-path 遅延 (数 ms) が乗る |
| Output (UI 表示 / API 返却前) | 最終安全網 | retrieved chunk 本文がすでに上流ログに出ていれば手遅れ |
production では 3 箇所すべて に同じ regex / named entity 検出器を入れて多重化するのが標準です。1 箇所だけだと「redact 漏れの hop」が必ず生まれます。
検出粒度 — regex で取れるもの、取れないもの
regex で確実に取れるもの:
- email (
\S+@\S+\.\S+) - 電話番号 (国別)
- クレジットカード (Luhn check 併用)
- API key 風 token (
sk-,xoxb-などの prefix) - IP アドレス
regex では取れず NER (named entity recognition) が要るもの:
- 人名 (姓名独立も含む)
- 住所
- 組織名 (機微案件名)
- 病名
軽量実装は presidio5 や pyap などのライブラリ。本シリーズの companion repo src/rag/pii_redactor.py は regex 6 種類 に絞った教育実装で、production では presidio に置き換えてください。
Opt-in sampling と retention
「全 query を保存」は legal/compliance リスクが大きすぎます。default で sampling rate 0.01 (1%) にし、debug 中だけ 1.0 に上げる運用が標準です:
import random
SAMPLE_RATE = float(os.getenv("RAG_LOG_SAMPLE_RATE", "0.01"))
if random.random() < SAMPLE_RATE: logger.info("rag.query", extra={ "query": redact(query), "retrieved_chunk_ids": chunk_ids, "answer_summary": redact(answer[:200]), # 全文ではなく冒頭のみ })retention は 30 日 default、tenant 設定で 7 日まで短縮可、というのが GDPR / APPI の運用幅です6。
知っておくべき法的制約 (極要約)
- GDPR: EU 居住者の data subject 削除要求に 30 日以内 で応じる義務6。logger 側で query → user_id の逆引きが必須 (匿名化済みでも要紐付け)
- APPI (日本): 利用目的の事前明示と保管期間制限。AI 学習目的を別枠で同意取得する潮流7
- 米国 state laws (CCPA / CPRA): opt-out 権の即時反映。logger に削除フラグ伝播の経路が必要
詳細は法務と必ず合議してください。本記事は 「最小限の構造的安全」 を示すだけです。
Embedding Drift — 何がいつ壊れるか
corpus と query 分布が時間で変わると embedding が徐々にズレます。3 種類の drift があります8。
Drift の 3 型
| 型 | 原因 | 検出シグナル |
|---|---|---|
| Corpus drift | 文書の追加・改訂・削除 | retrieved chunk の age 分布変化 / hit rate 急落 |
| Query drift | user の興味・語彙変化 | top query embedding の cluster 中心移動 |
| Model drift | embedding model のバージョン更新 | 同じ chunk で異なる embedding (基本は再 index で対応) |
検出の最小実装
import numpy as np
# 過去 7 日と直近 1 日の query embedding 分布の cosine 距離def drift_score(recent_embeds: np.ndarray, baseline_embeds: np.ndarray) -> float: recent_center = recent_embeds.mean(axis=0) baseline_center = baseline_embeds.mean(axis=0) return 1.0 - float( np.dot(recent_center, baseline_center) / (np.linalg.norm(recent_center) * np.linalg.norm(baseline_center) + 1e-9) )
# alert 閾値if drift_score(recent, baseline) > 0.05: notify("query drift detected — corpus 改訂 or 評価 set 更新を検討")5pp の cosine 距離変化は経験上 「golden set を見直すべきタイミング」 の signal です。
Re-index のタイミング
| トリガー | 頻度 |
|---|---|
| 文書改訂率 > 10% | 即時 |
| embedding model major version up | 即時 (互換性ゼロ) |
| cold data (90 日以上アクセスなし) の再 embed | 四半期 |
| 全件再 embed | 半年〜年 |
Cold data の四半期再 embed は storage cost と冷えた retrieval 品質のバランス点 として広く採用されています9。
古い「現行扱い」文書の退役 — Part 2 からの宿題
Part 2 で status filter を入れ、明示的に archive された旧版 (mirage-architecture-v2-archive など) を top-5 から追い出しました。けれどそこで宿題を 1 つ残しました。「status=active のままだが、内容が古びていく文書」 です。現行 mirage-architecture-v3.md も、いつか v4 が出れば「active だが古い前提を語る文書」になります。誰も status を archived に書き換えなければ、filter は素通りさせます。
これは static な metadata filter では解けず、運用の仕組み で退役させる必要があります:
| 仕組み | 内容 |
|---|---|
| owner + 定期確認 | 各 doc に owner (部署 / チーム) を持たせ、半年ごとに「まだ現行か」を確認するワークフロー。確認が切れた doc は status を stale に降格 |
| updated_at の鮮度スコア | retrieval スコアに freshness = exp(-age / τ) を掛け、古い doc を相対的に沈める (hard filter ではなく soft penalty) |
| 参照グラフ | 「v3 が出たら v2 を自動 archive」のように、後継 doc の出現をトリガに前任を退役させる (corpus に 関連: リンクがあれば辿れる) |
ナギサ corpus は各 doc に owner (例: プロダクト本部 / SRE 室) と 関連: リンクを持たせてあるので、この 3 つを乗せる素地があります。Part 2 の _extract_metadata で拾った updated_at / owner が、ここで効いてきます。「明示 archive は Part 2 で即除外、内容劣化は Part 5 で運用退役」という二段構えが、ドキュメンテーション劣化への完全な打ち手です。
コスト構造の分解 — どこに金が消えているか
「LLM が高い」とよく言いますが、production RAG では費用は 4 箇所 に分散しています。
| 費目 | 単価感 (2026-05) | 月コスト試算 (10k query/day) |
|---|---|---|
| Embedding (query) | $0.02 / 1M tokens | 〜数千円 |
| Embedding (corpus 再構築) | 同上 × 文書総 token | 数万円 (年 4 回想定) |
| Vector DB (managed) | $0.10 / GB / 月 | 数千〜数万円 |
| Reranker (cross-encoder local) | CPU/GPU 償却 | 数千円 |
| LLM generation | $3-15 / 1M output tokens | 数万〜数十万円 |
LLM generation が dominant ですが、hidden cost が 2 つあります:
- Corpus 再 embedding: 文書 100k 件 × 1k tokens で 100M tokens = $2. 半年に 1 度なら年 $4 だが、毎週やると年 $200
- Vector DB egress: managed DB の network 課金は traffic 量で別建て
ローカル経路 (Ollama) のコスト: 本シリーズの再現に使った
qwen3-embedding:0.6b+qwen3:8b経路は API コストが 0 円 です。費用は電気代と、何より 自分の時間 に乗ります。embedding と単発生成は数秒ですが、Part 4 の RAGAs 一括評価 (30 件 × 3 pipeline) は Apple Silicon で 1 時間強かかります。「無料」と「高速」は別物で、ローカル LLM は 金銭コストを計算時間に付け替えている だけ、という理解が運用判断には重要です。本番のスループットが要るなら、generation だけクラウド API に出して embedding/rerank はローカル、のような hybrid 構成が現実解になります。
直接効くコスト最適化 (Part 1-3 でやったこと)
| 打ち手 | 効くコスト | 効果 |
|---|---|---|
| Part 2 hybrid (BM25 で fallback) | LLM input tokens | retrieved の精度 ↑ で k を絞れる |
| Part 3 cross-encoder rerank | LLM input tokens | top-20 → top-3 で input -85% |
| Prompt caching (Anthropic) 10 | LLM input tokens | 同一 corpus で input 90% off |
| Part 4 evaluation (offline) | judge LLM tokens | 全 query では走らせない |
Anthropic prompt caching は Part 3 の Citations API と 併用可能 で10、社内ナレッジボットのように コーパス + system prompt がほぼ固定 な構成では大きく効きます。
インシデント対応とロールバック
「LLM が壊れた」と「データが壊れた」は責任分界点が違います。
Fault model の 4 分類
| 分類 | 例 | rollback 単位 |
|---|---|---|
| Model regression | 新モデルが回答品質低下 | model version pin |
| Index corruption | re-embed 途中で部分破損 | index snapshot 切替 |
| Prompt regression | system prompt 変更で hallucinate 増 | prompt version pin |
| Corpus poisoning | 悪意ある doc 混入 | corpus diff revert |
Rollback のための前提
- Index は version 管理する (timestamp 付きで複数 snapshot 保持、N=3 が標準)
- Prompt と model は version 文字列で pin する (
v=2026-05-15のような明示的 tag) - Corpus 改訂は git で diff 可能にする (companion repo の corpus/ 構造を参考)
Incident playbook (5 ステップ)
- 検知: dashboard alert (RAGAs スコア降下 / latency 上昇 / cost 急増)
- 隔離: traffic を baseline pipeline に戻す (canary 5% で導入していれば即座)
- 計測: golden set の re-run で regression 範囲を特定
- 修復: 該当 component を rollback または hotfix
- postmortem: blameless で golden set に該当ケースを追加 (Part 4 の golden を厚くする)
5 番目が最重要です。インシデントが起きるたびに golden が太り、同じ事故は二度と起きません。
シリーズ総括 — 次の入口
5 部にわたって 「動く RAG」から「使える RAG」へ の橋を架けてきました。最後に、本シリーズが意図的にスコープ外にした 3 つの方向を、次の入口として置きます。
Fine-tuning — domain-specific reranker / embedding
Part 3 で off-the-shelf cross-encoder の domain mismatch を観察しました。法務 / 医療 / 専門 jargon が密な領域では sentence-transformers の fine-tuning パイプラインで domain-specific reranker を作る価値があります11。golden set が 30 → 500 件に育った段階で検討するタイミングです。
Multimodal RAG — 画像 / 表 / 音声を含むコーパス
PDF の図表、議事録の音声、技術ドキュメントの diagram — 「テキストだけの corpus」は実世界の半分以下です。Anthropic Claude や GPT-4o の vision 入力を combine する multimodal RAG が 2026 以降の標準になりつつあります12。
Agentic RAG — query 自体を LLM に分解させる
「複数 doc を統合して比較」「時系列で集約」のような複雑な query は、1 度の retrieve + generate では解けません。LLM 自身に 「どの retrieve を、どの順序で投げるか」 を計画させる agentic な構造が登場しています13。本シリーズの Part 2 で導入した hybrid retrieval + Part 3 の Citations API + Part 4 の評価ループは、agentic な系の 基盤 として機能します。
5 部完結です。Part 1 で 100 行 RAG を動かしたところから、Part 5 で本番運用 runbook を組むところまで来ました。「使える RAG」は遠くなさそうで、本気でやると 5 部かかります。けれど 5 部分の積み上げが終われば、PoC で止まらないシステムが作れます。
シリーズ全体: 今更聞けない RAG の作り方、評価の仕方
companion repo: zawazawa5809/rag-fundamentals-companion — part-05 tag で本記事の examples/ops/run.py / src/rag/pii_redactor.py / src/rag/logger.py / tests/ を再現できます。
参考文献
Footnotes
RAG Pipeline Security Best Practices for 2026: Protecting Sensitive Data — retrieved chunks ログのリスクと 3 箇所 redact 戦略 ↩
OpenTelemetry semantic conventions for GenAI —
gen_ai.*attribute 標準 ↩How to Implement RAG Pipeline Tracing with OpenTelemetry — backend 中立な OTel pipeline 設計 ↩
Safe Observability: A Framework for Automated PII Redaction from LLM Prompts in OpenTelemetry Pipelines — 3 箇所多重化の根拠 ↩
Microsoft Presidio — 産業実装の PII detection / anonymization SDK (regex + NER + custom recognizer) ↩
GDPR Article 17 — Right to erasure — 削除要求への 30 日以内対応の根拠条文 ↩ ↩2
個人情報保護委員会 — 改正 APPI 解釈通知 — AI 学習目的の同意取得に関する 2024 改正解釈 ↩
Drift Detection in Production RAG Systems — 3 型 drift と alert 閾値の実務観 ↩
Cold-data re-embedding cadence in production RAG — 四半期再 embed の cost / quality バランス ↩
Prompt Caching - Anthropic API Docs — Citations API との併用と input token 90% 削減 ↩ ↩2
Fine-tuning Cross-Encoders for Reranking — sentence-transformers — domain-specific reranker の学習レシピ ↩
Multimodal RAG with Anthropic Claude — 画像入力を含む RAG パターン ↩
Agentic RAG: A Survey — 2025 サーベイ。multi-hop / query decomposition / tool-use RAG の体系化 ↩
