標籤: LatentAudit

  • LatentAudit:用殘差幾何盯住 RAG 幻覺

    📌 本文重點

    • 光看檢索分數與事後自評難以即時監控幻覺
    • LatentAudit 直接讀殘差流幾何結構估真實度分數
    • 可在 RAG pipeline 中低延遲加入實時 guardrail

    在實務 RAG 專案裡,光靠「檢索品質 + 事後自評/投票」抓幻覺是不夠的
    – 檢索成功 ≠ 回答一定忠於證據(模型還是會自由發揮)
    – 自評 / judge 模型會 吃額外 Token 和延遲,流量大時成本爆炸
    – 多輪對話、串接工具後,哪一步開始幻覺常常完全沒監控

    💡 關鍵: 只靠檢索分數和事後評審,既無法即時阻斷幻覺,又會讓延遲與成本大幅增加。

    LatentAudit 提供另一條路:直接讀取生成模型的 殘差流(residual stream)幾何結構,在推理中測量「模型內部狀態」與檢索證據之間的 馬氏距離,做到:

    • 不需要額外 judge 模型
    • sub-millisecond 延遲、可 16-bit 固定點實作
    • 少量標註就能校準成實用的 真實度分數,在 API 層或 UI 層直接觸發 fallback

    重點說明

    1. 為什麼傳統 RAG 監控做不到「實時 + 便宜」

    實務上的典型做法:

    1. 只看檢索分數:例如 cosine 相似度、BM25 分數
    2. 問題:檢索到對的文獻,但模型回答的細節錯了(over-generalize, mis-attribute)完全抓不到。

    3. 事後自評 / 多模型投票

    4. judge LLM 問「這個回答是否根據檢索到的內容?」
    5. 或讓多個模型生成,再投票 / 聚合。
    6. 問題:

      • 推理路徑變成:檢索 → 回答 → 評審,延遲翻倍以上
      • 成本和吞吐量吃不消,很難在大規模 production 開啟
      • judge 模型本身也會幻覺,還得再校準
    7. log 後離線分析

    8. 用人審 / labeling 分析錯誤 pattern
    9. 問題:無法 實時阻斷 危險輸出(醫療/法律/金融)

    LatentAudit 直接把監控塞進 生成時的 forward pass

    • 白盒讀取中後段 殘差流 activation
    • 與「證據 representation」做幾何對齊度測量
    • 即時計算 距離 → 真實度分數 → 決策(放行 / fallback)

    💡 關鍵: 把監控邏輯塞進 forward pass,能在幾乎零額外延遲下拿到可用的真實度分數。

    2. LatentAudit 的核心做法(殘差幾何 + 馬氏距離)

    架構概念:

    1. 選定幾層殘差流:例如 Llama-3-8B 的 layer 20–30 殘差向量 ( h_l )

    2. 建一個 evidence representation ( e ):

    3. 通常來自:

      • 把所有檢索到的 passages 拼在一起,取 encoder / 第一層 decoder 的 CLS / BOS 向量
      • 或平均檢索 chunks 的 embedding
    4. 在訓練(校準)階段

    5. 收集 (question, evidence, answer) 三元組,並有「忠於證據 / 不忠」標註
    6. 對每個樣本取出中後段殘差流,做 pooling(例如平均或拼接):

      [
      z = P(h_{l_1}, …, h_{l_k})
      ]

    7. 在 latent 空間中估計「忠實」分佈的均值 ( \mu ) 和協方差 ( \Sigma )

    8. 定義馬氏距離規則

    9. 把 residual 表示 ( z ) 投影到 evidence 表示空間,或做簡單線性對齊,最後計算

      [
      d_M(z, e) = (z – W e – b)^T \Sigma^{-1} (z – W e – b)
      ]

    10. 這就是 LatentAudit 的核心:一條二次判別規則(不需要深 judge 模型)

    11. 校準成真實度分數

    12. 用 held-out 集合做 threshold / logistic calibration,得到:

      [
      s_{faith} = \sigma(\alpha \cdot d_M(z,e) + \beta)
      ]

    13. ( s_{faith} ) 越接近 1 表示越「有可能忠於證據」。

    因為只做矩陣乘、向量內積和少量逆協方差運算,
    可以用 16-bit fixed point 實作,延遲在 0.x ms 級別,可進一步配合 Groth16 做可驗證計算(不展開細節)。

    💡 關鍵: 使用 16-bit 固定點與馬氏距離,使得真實度評估可以在 sub-millisecond 延遲下完成。


    如何嵌入既有 RAG pipeline

    你需要:
    可白盒存取的模型(LlamaQwenMistral 等開源或自託管)
    – 在 forward 裡 hook activation,並在生成過程中同步喂入 evidence 表示

    常見 stack:

    • OpenAI compatible API(自託管 vLLM / Ollama 上掛開源模型)
    • 各種向量庫(PGVectorMilvusWeaviateQdrantElastic,…)

    典型 pipeline:

    1. user query → 檢索(向量庫) → 構造 prompt + evidence
    2. 呼叫 自託管模型(非黑盒雲 API)生成
    3. 在生成中,LatentAudit 模塊監控殘差流 → 算馬氏距離 → 輸出真實度分數
    4. API 返回:{ answer, faithfulness_score }
    5. 前端 / Orchestrator 根據 score 做 fallback 策略。

    實作範例

    以下以 vLLM + Llama3 自託管為例,展示核心落地點(偽碼 + Python 範例)。

    1. 在 HF 模型上 hook 殘差層

    from transformers import AutoModelForCausalLM, AutoTokenizer
    import torch
    
    MODEL_NAME = "meta-llama/Meta-Llama-3-8B-Instruct"
    model = AutoModelForCausalLM.from_pretrained(
        MODEL_NAME, torch_dtype=torch.bfloat16, device_map="auto"
    )
    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
    
    TARGET_LAYERS = [20, 24, 28]
    residual_acts = []
    
    
    def make_hook(layer_idx):
        def hook(module, input, output):
            # input[0] 通常是 residual stream
            # 只取最後一個 token 的向量,減少開銷
            h = input[0][:, -1, :].detach().to(torch.float32)
            residual_acts.append((layer_idx, h))
        return hook
    
    
    for idx, blk in enumerate(model.model.layers):
        if idx in TARGET_LAYERS:
            blk.register_forward_hook(make_hook(idx))
    

    2. 建立 evidence representation

    假設你已經從向量庫拿到 top-k passages:

    def build_evidence_rep(passages: list[str]):
        text = "\n".join(passages)[:4096]  # 避免太長
        inputs = tokenizer(text, return_tensors="pt").to(model.device)
        with torch.no_grad():
            out = model.model(**inputs, output_hidden_states=True)
        # 用最後一層 hidden state 的 BOS / 第一 token 表示
        e = out.hidden_states[-1][:, 0, :].detach().to(torch.float32)
        return e  # shape: [1, d]
    

    3. 馬氏距離計算 + 校準

    事前你要離線擬合:
    WbΣ^{-1}αβ(可用 sklearn 或手寫)

    線上部分簡化為:

    # 假設以下參數已離線訓練好並載入
    W = torch.load("wa_projection.pt")         # [d_residual, d_e]
    b = torch.load("wa_bias.pt")              # [d_residual]
    Sigma_inv = torch.load("wa_sigma_inv.pt")  # [d_residual, d_residual]
    alpha, beta = torch.load("wa_logistic.pt")
    
    
    def latent_audit_score(evidence_vec, residual_acts):
        # pooling residual: 取指定層平均
        hs = [h for idx, h in residual_acts if idx in TARGET_LAYERS]
        H = torch.stack(hs, dim=1).mean(dim=1)  # [1, d_residual]
    
        # 對 evidence 做線性對齊
        e_proj = (evidence_vec @ W.T) + b  # [1, d_residual]
    
        diff = (H - e_proj)  # [1, d_residual]
        # 馬氏距離
        d_M = (diff @ Sigma_inv @ diff.transpose(0,1))[0,0]
    
        # logistic 校準成 [0,1]
        score = torch.sigmoid(alpha * d_M + beta).item()
        return score
    

    生成時流程:

    def rag_answer_with_faith(query, passages):
        residual_acts.clear()
    
        evidence_vec = build_evidence_rep(passages)  # [1,d]
    
        prompt = build_rag_prompt(query, passages)  # 你的 RAG prompt 模板
        inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    
        with torch.no_grad():
            out = model.generate(
                **inputs,
                max_new_tokens=256,
                do_sample=False,
            )
    
        answer = tokenizer.decode(out[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
        score = latent_audit_score(evidence_vec, residual_acts)
    
        return {
            "answer": answer,
            "faithfulness_score": score,
        }
    

    這邊只在 一次 forward + generate 裡多做幾個矩陣運算,延遲增量極小;你可以把結果包成 OpenAI 兼容 API 回傳:

    {
      "id": "chatcmpl-...",
      "object": "chat.completion",
      "choices": [
        {
          "message": {
            "role": "assistant",
            "content": "...",
            "faithfulness_score": 0.82
          }
        }
      ]
    }
    

    前端或 Orchestrator 可以直接讀 faithfulness_score 做決策。

    💡 關鍵: 直接在 API 回傳中加入 faithfulness_score,可讓前端與協調層即時採用不同的 fallback 策略。

    4. Fallback 策略示例(醫療 / 法律 / 客服)

    簡單策略:

    THRESHOLD_WARN = 0.7
    THRESHOLD_BLOCK = 0.4
    
    
    def route_by_faithfulness(result):
        s = result["faithfulness_score"]
    
        if s < THRESHOLD_BLOCK:
            # 高風險:重新檢索 + 明確要求引用 evidence,或升級人工
            return {
                "mode": "escalate",
                "message": "本次回答可信度較低,已轉交人工處理。",
            }
        elif s < THRESHOLD_WARN:
            # 中風險:要求模型引用更多 evidence / 提示使用者核對
            return {
                "mode": "warn",
                "message": "以下回答可能不完全可靠,請以實際條文/文獻為準。",
            }
        else:
            # 正常放行
            return {
                "mode": "ok",
                "message": "",
            }
    

    實際場景:

    • 醫療問答mode == "escalate" 時強制顯示「非醫療建議」,並把 case 丟進人工客服隊列
    • 法律諮詢mode == "warn" 模式時要求模型 列出具體條文/條號 並顯示原文片段
    • 客服查詢:低分時先做 重新檢索(不同索引 or 更寬鬆 query) 再生成一次,若仍低分再轉人工

    多模型 / 多輪對話:
    – 對每輪回答都算一個 faithfulness_score,記錄在對話 state
    – 對 工具返回 / 多模型投票輸出 也可以跑 LatentAudit,看哪個候選與 evidence 更對齊,再做投票加權


    建議與注意事項

    1. 必須白盒存取模型

    • 無法在 OpenAI / Anthropic 純雲端黑盒模型上做(拿不到殘差流)
    • 適合:
    • 自託管 Llama / Qwen / Mistral
    • Ollama / vLLM,但要在本地 wrap core HF 模型 做 hook,而不是只用遠端 HTTP

    2. 殘差層選擇與標準化影響很大

    • 中後段層(例如 60–80% depth)通常信號最好
    • 建議在校準時網格搜尋:
    • 選幾組 layer subset + pooling 策略(最後 token / mean / concat)
    • 對每組分別訓練 WΣ^{-1},選 AUROC / AUPRC 最佳
    • 標準化:
    • 建議對 residual 做 per-dimension z-score 或 whitening,有助於 Σ^{-1} 穩定

    3. 校準集的 domain mismatch 是大坑

    • 如果你用 PubMedQA 上的校準結果直接套到法律問答,誤報 / 漏報會很嚴重
    • 建議:
    • 至少針對你的業務 domain 收集 數百到數千個標註樣本
    • type 要包含:
      • 正確且完全有證據支撐
      • 幻覺 / 瞎掰
      • 部分支持(evidence 裡只有一半說法)

    4. 隱私與合規下收集校準資料

    • 若資料有 PHI / PII:
    • 在內網做標註與訓練,不要把 prompt / evidence / answer 傳出公司
    • 可以只存 殘差向量 + 二元標籤,丟棄原文內容,以降低隱私風險
    • 若需要對外可驗證(尤其在金融 / 公共服務):
    • 考慮用論文中的 16-bit fixed-point 實作 + Groth16,在不洩漏權重/activation 的前提下提供「監控邏輯正確執行」的證明

    5. 與現有評估/監控系統的整合

    • LatentAudit 不是 用來取代離線評估(BLEU, Rouge, factuality benchmark),而是:
    • 補上一層 以模型「內在狀態」為基準的實時 guardrail
    • 建議實務策略:
    • 離線:用 benchmark / 人工評估確認 RAG pipeline 基本可靠
    • 線上:啟用 LatentAudit,只作「低分拋錯/告警」,不要一開始就用來做 aggressive block
    • 每隔一段時間(例如每週)抽樣「被 block / warn 的案例」做人工 review,調整 threshold / 校準

    對你的專案的實際好處
    – 在不引入第二個 LLM 的前提下,把幻覺監控塞進現有 RAG 路徑,几乎不加延遲
    – 增加一個 可量化、可調整的真實度分數,方便 API / UI / workflow 做自動化 fallback
    – 線上問題不再只有「出事後看 log」,而是可以 即時標記高風險回答,甚至直接攔截,特別適合醫療、法律、金融、客服等高風險場景。


    🚀 你現在可以做的事

    • 在現有自託管 Llama / Qwen / Mistral 專案中,加上殘差層 hook 並輸出簡單的 faithfulness_score
    • 針對你的業務 domain 收集一批「忠於證據 / 幻覺 / 部分支持」標註樣本,用來擬合 WΣ^{-1} 與校準參數
    • 在 API 回傳中加入 faithfulness_score,並在前端或 Orchestrator 中實作最簡版本的 warn / block / escalate 策略