設定

語言

為什麼您的 Semantic Cache 會回傳錯誤的答案

T
TokenLab
·2026年3月5日·約 8 分鐘閱讀·更新 2026年7月14日·1649 次瀏覽
#語義緩存#嵌入#LLM 基礎設施#生產環境調試
為什麼您的 Semantic Cache 會回傳錯誤的答案

有使用者回報,我們的翻譯外掛程式對每個請求都回傳相同的快取結果,無論輸入內容為何。我們進行調查後發現了更嚴重的問題:我們平台上 95% 的語義快取命中 (cache hits) 都是誤報 (false positives)。199 個不同的翻譯請求中,有 198 個請求主體各不相同,卻全都被回傳了同一個快取回應。

如果您關心長效 Agent 狀態與生產環境的請求處理,這篇文章與 AI Agent 為何總是遺忘記憶單一 API Key 聊天機器人指南,以及 AI API 速率限制指南 非常適合搭配閱讀。

重點摘要

  • 平台上 95% 的語義快取命中屬於誤報,198 個獨特的請求全被回傳了同一個快取回應。
  • 根本原因是結構化輸入。固定的模板文字在 Embedding 向量中佔據主導地位,導致變動的內容幾乎無法改變餘弦相似度 (cosine similarity)。
  • 提高相似度門檻無法解決此問題,因為正確與錯誤命中的分佈會重疊。近期關於語義快取可靠性的研究證實了相同的模式。
  • 解決方案分為兩層:在 Embedding 前提取有意義的內容,然後使用快速的 FNV-1a 指紋雜湊 (fingerprint hash) 來驗證每次命中。這將誤報率從約 95% 降低至 5% 以下。
  • 模型選擇會影響曝險程度。無論由哪個模型完成請求,冗長的系統提示詞 (system prompts) 和 JSON 封裝輸入都會加劇此問題;若您正在決定哪些模型適合用於快取流量,請查看 TokenLab 的 模型目錄(觀察日期:2026-07-07)以獲取當前模型選項。

錯誤報告

報告內容很簡單:「我停用了語義快取,但每次翻譯還是回傳一樣的結果。」

三個請求 ID、三個不同的翻譯片段,卻有著相同的快取回應。請求主體的大小從 1,564 到 8,676 位元組不等,但快取回應 ID 卻全都是:chatcmpl-DG6J03nhdvcF7Ek0C8rJkjh7lN9pF

最初懷疑是使用者的快取設定未生效。結果發現這是另一個資料來源同步的 Bug(管理面板寫入一個資料表,API Gateway 卻讀取另一個)。修復該問題只解決了一半。即使快取功能正常運作,語義快取仍會匹配到本不該匹配的請求。

生產環境資料

我們從 ClickHouse 提取了 24 小時的快取命中資料。數據非常糟糕。

模型 總請求數 快取命中數 獨特請求數 獨特回應數 命中率
DeepSeek V4 Flash 200 199 198 1 99.5%
glm-4.6-thinking 100 38 13 1 38%
gpt-5-nano 31 29 28 2 93.5%
gpt-oss-120b 18 17 17 1 94.4%
qwen3-vl-flash 17 16 16 1 94.1%

198 個獨特的翻譯請求,全回傳同一個快取回應。那不是快取,那是一個回傳常數的故障函式。

每個受影響的模型都有兩個共同特徵:所有請求來自同一個使用者,且都使用了固定的系統提示詞模板,僅變更使用者內容。由於模型陣容經常變動,關於平台上可用模型的最新清單,請以 TokenLab 的 模型目錄(觀察日期:2026-07-07)為準。

如何在您的系統中偵測此問題

您不需要我們的日誌也能判斷是否有同樣的問題。最快的指標是「每個模型的回應多樣性」。如果一個模型有很高的快取命中率,但幾乎沒有獨特的回應,代表您正用同一個答案回應許多不同的問題。

以下是我們使用的 ClickHouse 風格查詢(已通用化):

SELECT
  model,
  count() AS total_hits,
  uniqExact(substring(response_body, 1, 200)) AS unique_responses,
  round(uniqExact(substring(response_body, 1, 200)) / count(), 3) AS diversity_ratio
FROM request_logs
WHERE cache_hit = true
GROUP BY model
ORDER BY total_hits DESC;

健康的快取其 diversity_ratio 應接近 1.0,代表大多數命中會針對不同輸入回傳不同的回應。比率接近 0 則代表許多請求都收斂到了少數幾個快取答案上。對於輸入多樣性高的模型,若比率低於 0.5 左右,就值得調查。

如果您沒有記錄回應主體,也可以使用更簡單的代理指標:比較「獨特請求主體數量」與「從快取回傳的獨特回應數量」。當 198 個獨特請求對應到 1 個回應時,快取匹配的不是語義,而是樣板文字 (boilerplate)。

另一個徵兆是使用者對於結構化工作負載的抱怨。翻譯外掛、摘要工具、表單填寫工具以及 JSON 輸入/輸出工具通常是嫌疑對象,因為它們將變動內容包裹在固定的模板中。

為什麼 Embedding 在結構化輸入上會失敗

翻譯外掛發送的請求如下:

System: "Act as a translation API. Output a single raw JSON object only.
         Input: {"targetLanguage":"<lang>","title":"...","segments":[...]}"

User:   {"targetLanguage":"zh","title":"Product Page",
         "description":"Translate product descriptions",
         "tone":"formal",
         "segments":[{"text":"actual varying content here"}]}

系統提示詞在所有請求中都是一樣的。使用者訊息是一個 JSON 物件,其中 targetLanguagetitledescriptiontone 都是固定的,只有 segments[].text 會變動。

當我們的語義快取提取文字進行 Embedding 時,它會串接系統提示詞和使用者訊息。固定模板約佔文字的 80%。Embedding 模型 (all-mpnet-base-v2, 768 維度) 將其壓縮成一個向量,其中模板結構佔據主導地位,實際的翻譯內容幾乎無法影響向量結果。

結果:"translate 'Hello world'" 與 "translate 'The quarterly financial report shows a 15% increase in revenue'" 之間的餘弦相似度超過了 0.95。我們的門檻是 0.95,因此每個翻譯請求都會匹配到第一個快取項目。

深入挖掘日誌後,我們發現了三種導致失敗的情況:

翻譯外掛是最嚴重的違規者。固定的 JSON 鍵值淹沒了實際的翻譯片段。DeepSeek V4 Flash 和 gpt-5-nano 都遇到了這個問題。

上下文摘要助手則有另一種形式的同樣問題。它的系統提示詞太長,導致 5KB 到 47KB 的使用者內容在 Embedding 中幾乎無法被識別。這就是為什麼 glm-4.6-thinking 會對每場對話回傳相同的摘要。

第三種模式較為隱蔽。對於 gpt-oss-120b 和 qwen3-vl-flash,每個請求的前 500 個字元完全相同。變動內容在後面,但 Embedding 已經被共享的前綴所主導。

研究結果怎麼說

這並非新問題,近期論文已對此進行了量化。

加州大學柏克萊分校的 vCache 專案發現,正確與錯誤的快取命中相似度分佈有很大程度的重疊,這意味著沒有固定的門檻能明確區分真實匹配與結構相似的誤報。該發現與我們在生產環境中觀察到的完全一致:翻譯外掛的誤報集中在 0.95 以上,這正好也是合法改寫匹配 (paraphrase matches) 的範圍。

其他關於語義快取可靠性的研究也得出了類似結論:原始 Embedding 相似度是快取正確性的必要條件,但非充分條件。任何僅依賴此指標的生產系統,在處理結構化、模板密集的流量時,都應預期會有顯著的誤報率。

雙層修復方案

第一層是內容提取。在 Embedding 之前,剔除固定的系統提示詞和模板架構,僅對變動的負載 (payload) 進行 Embedding:即實際的 segments[].text 內容,而非周圍的 JSON 鍵值與樣板文字。僅此一項就能顯著提高 Embedding 向量中的信噪比。

第二層是指紋驗證。即使有更好的提取方式,近乎重複的內容仍可能產生高相似度分數。在提供快取命中前,對傳入請求與快取項目的提取內容計算快速雜湊(我們使用 FNV-1a)。如果雜湊完全匹配,則使用快取;如果不匹配,則進入正常的模型完成流程,或者對於高價值流量,路由至廉價的驗證呼叫,以評分語義而非位元組。

錯誤的做法是完全跳過驗證,僅信任原始餘弦相似度。表中的每一種方法都比這更好。從適合您查詢類型的最廉價方法開始,只有在測量到真實的改寫遺漏時,才考慮升級方案。

這兩層結合後,我們在受影響流量中的誤報率從約 95% 降至 5% 以下。

何時不該使用語義快取

快取並非免費的工程,有些工作負載根本不值得快取。

  • 高基數 (high-cardinality)、低重複率的流量。如果幾乎每個請求都是獨特的(例如一次性的創意生成),命中率太低,無法抵銷 Embedding 的開銷。您支付了所有內容的 Embedding 成本,卻很少從中獲益。
  • 必須保持新鮮的輸出。任何對時間敏感、即時資料、個人化結果或包含「今天」字眼的內容,即使技術上匹配正確,也可能從快取中回傳過時的答案。答案一小時前是對的,現在卻錯了。
  • 嚴格正確性的領域。對於醫療、法律或金融答案,單次誤報的代價可能高於節省的成本。若在此類領域使用快取,驗證層是強制性的,且可能需要 LLM 等級的檢查才可接受。
  • 模型呼叫本身就很便宜的小型提示詞。Embedding、相似度搜尋和驗證都有其成本。如果底層完成任務只需廉價模型上的幾百個 Token,快取的成本可能高於節省的費用。

快取在重複性高、模板密集且昂貴的完成任務中表現出色,而這恰恰是誤報最容易出現的工作負載。這種矛盾正是驗證層重要的原因。如果您的目標主要是成本控制,將快取與廉價模型路由搭配使用也是值得的。定價比較最佳 AI 程式設計模型指南涵蓋了 Token 節省的來源,而 TokenLab 的 模型目錄(觀察日期:2026-07-07)顯示了當前選項,包括 DeepSeek V4 Flash 和 Gemini 3.5 Flash 等低成本路由選擇。在承諾路由計畫前,請先確認連結目錄中的當前定價。

為什麼不直接提高門檻?

我們的門檻已經是 0.95 了。提高門檻沒有幫助。問題在於,無論實際內容為何,結構相似的輸入產生的相似度分數都會高於 0.95。

vCache 的資料證實了這一點:正確與錯誤命中的相似度分佈重疊嚴重,沒有單一的截止點能將它們分開。將門檻推至 0.99,您會扼殺合法的改寫匹配,而結構完全相同的請求(如我們的翻譯 JSON 負載)無論內容為何,仍會集中在 0.99 以上。門檻不是槓桿,輸入表示法才是。這就是為什麼第一層(內容提取)和第二層(指紋驗證)有效,而提高門檻無效的原因:它們改變了被比較的對象,而不是比較嚴格程度。

如果您正在建置或維護語義快取,請將門檻視為粗略的過濾器,而非正確性的保證。將其與內容提取搭配,使 Embedding 能真正代表請求的變動部分,然後增加廉價的驗證步驟,確保 Embedding 的近乎匹配永遠不會在生產環境中悄悄變成錯誤答案。

在連接快取驗證層之前,請先使用 TokenLab 的 模型目錄 來比較前沿模型、程式設計模型與低成本路由模型的當前定價與基準測試。無論您的完成端點背後是哪個模型,提取加指紋的方法才是真正解決誤報的關鍵。

常見問題

提高相似度門檻能解決語義快取誤報嗎? 不能。來自 vCache 及相關研究顯示,正確與錯誤的命中分佈在整個門檻範圍內都有重疊,因此提高截止點會阻擋合法的匹配,卻無法可靠地過濾掉結構相似但語義不同的請求。

驗證語義快取命中率最便宜的方法是什麼? 對提取出的有意義內容進行指紋雜湊(FNV-1a 或類似演算法)的延遲不到一毫秒,且計算成本為零。它無法捕捉改寫,但能消除此處描述的精確誤報,而這正是結構化工作負載中大部分損害的來源。

此問題取決於哪個模型執行完成任務嗎? 不取決。誤報問題存在於 Embedding 與匹配層,而非完成模型。任何語義快取背後的模型,無論是 DeepSeek V4 Flash、glm-4.6-thinking 還是更新的模型,如果快取將固定模板文字與變動內容一起 Embedding,都會受到同樣的影響。在決定哪些模型要透過快取管線路由時,請查看 TokenLab 的 模型目錄(觀察日期:2026-07-07)以獲取當前模型可用性。

來源

價格觀測於 2026-07-07

分享:

相關模型

公開模型最近更新

用本文涉及的模型開始構建

比較價格、測試路由,把文章研究直接變成可執行的 API 呼叫。