FDE 面試指南 Part 51:百萬級多輪對話的 KV Cache 驅逐機制與記憶體架構優化

大多數工程師的做法:把 KV Cache 設一個固定 TTL,讓它自動過期,再出問題就加更多 GPU。 資深 FDE 的思維:把快取當分層財務決策——什麼時候該升層、什麼時候該壓縮、什麼時候主動驅逐, 每一個決策節點都有精確的數字閾值,而不是「看狀況再說」。 差距不在技術知識,在於你能不能把顯存、計費週期、對話語義三個維度同時管住。


面試情境

你的 B2B 對話式 AI 平台服務 5 萬名企業用戶,平均每位用戶每天與 Agent 進行 20–40 輪對話。 隨著上下文長度增長,GPU 顯存使用率持續攀升,高峰期 OOM(Out of Memory)崩潰率達到 3%, 同時 Vertex AI 帳單每月 $120K,CFO 要求兩個月內把成本降低 50%。 你被要求在不降低對話品質的前提下,重新設計快取架構。你的方案是什麼?


一、核心問題:為什麼 KV Cache 管理會讓 B2B SaaS 崩潰

1.1 KV Cache 的本質與代價

大型語言模型在推理時,Attention 機制需要存取所有歷史 Token 的 Key/Value 向量。每一輪新對話都要「看過」所有先前的 Token,這個快取(KV Cache)讓模型不需要重新計算,代價是它活在 GPU 顯存(VRAM)裡。

以 Gemini 1.5 Pro 為例:

  • 每 1K tokens 的 KV Cache 佔用約 0.5–1 MB VRAM
  • 100 輪對話 × 平均 500 tokens/輪 = 50K tokens = 25–50 MB per session
  • 同時服務 1,000 個活躍 session = 25–50 GB VRAM

一張 A100 80GB 只能服務約 1,600 個並發長對話 session,再多就 OOM。

1.2 計費陷阱:Vertex AI Context Caching 的結構性問題

Vertex AI Context Caching 按以下規則計費:

  • 最低快取長度:32,768 tokens(低於此不得建立快取)
  • 計費單位:每小時,不足一小時按一小時計算
  • 快取寫入費: 比標準輸入 token 低 25%,但快取存儲本身每小時有持續費用

這意味著:若用戶聊了 10 分鐘(產生 5K tokens)就下線,快取根本無法建立;若強行建立也不符合條件。但若系統設計不當,在對話剛過 32K 就立即建立,而用戶在 10 分鐘後下線,你就付了整整一小時的快取存儲費,什麼效益都沒有。

1.3 業務維度的三重矛盾

┌─────────────────────────────────────────────────────────────┐
│              KV Cache 的三重矛盾                            │
├──────────────────┬──────────────────┬───────────────────────┤
│  GPU 顯存限制    │   計費週期結構   │   對話品質要求        │
│                  │                  │                       │
│ 長對話 → OOM     │ 短對話 → 浪費    │ 壓縮過度 → 失憶      │
│ 多用戶 → 競爭    │ 建得太早 → 罰款  │ 丟棄太多 → 幻覺增加  │
│ 無驅逐 → 崩潰   │ 放太久 → 超收    │ 快照太粗 → 脈絡斷裂  │
└──────────────────┴──────────────────┴───────────────────────┘

核心洞察:這不是純技術問題,是需要對齊計費模型、顯存容量、對話語義三個維度的財務工程問題。


二、三個演進階段

╔══ Phase 1(POC / < 10K 用戶)══╗

策略:單層 Redis TTL,靠 GPU 撐住

┌──────────────────────────────────────────────────────────┐
│                  Phase 1 架構(POC)                     │
│                                                          │
│  用戶請求                                                │
│     │                                                    │
│     ▼                                                    │
│  ┌──────────┐     ┌──────────────────────────────────┐  │
│  │  API GW  │────▶│  LLM Service (Vertex AI)         │  │
│  └──────────┘     │  - 每次請求帶全部 History          │  │
│                   │  - 無 Context Cache               │  │
│                   └──────────────┬───────────────────┘  │
│                                  │                       │
│                   ┌──────────────▼───────────────────┐  │
│                   │  Redis(單機)                    │  │
│                   │  - Key: session_id               │  │
│                   │  - Value: 全部對話 JSON           │  │
│                   │  - TTL: 24 小時                  │  │
│                   └──────────────────────────────────┘  │
└──────────────────────────────────────────────────────────┘

新增組件(vs 無快取基線): Redis 單機,session 對話存儲

成本/複雜度:

  • 基礎設施:$200/月(Redis + GPU VM)
  • 工程成本:2 週實作
  • OOM 閾值:~500 並發用戶就開始出問題

能解決什麼: 不用每次重連都從頭建立 session;Redis 讀取 < 5ms

還剩什麼問題:

  • 沒有 token 感知:不知道對話有多長,盲目存全文
  • 沒有顯存管理:100 輪對話直接把 GPU 壓垮
  • 帳單線性成長:用戶越多,輸入 token 費用越高(無快取複用)
  • 用戶超過 5K 就開始 OOM 崩潰

╔══ Phase 2(MVP / 10K–200K 用戶)══╗

策略:L1 Redis + L2 Vertex AI Context Cache,加入 Token 閾值判斷

┌──────────────────────────────────────────────────────────────────┐
│                   Phase 2 架構(MVP)                            │
│                                                                  │
│  用戶請求                                                        │
│     │                                                            │
│     ▼                                                            │
│  ┌──────────┐   ┌────────────────────────────────────────────┐  │
│  │  API GW  │──▶│       Cache Gateway(新增)                │  │
│  └──────────┘   │  - 查 Token 計數 (Redis Counter)           │  │
│                 │  - 判斷是否升層至 L2                        │  │
│                 └────────┬──────────────────┬────────────────┘  │
│                          │                  │                    │
│              Token < 32K │    Token ≥ 32K   │                   │
│                          ▼                  ▼                    │
│               ┌──────────────┐    ┌─────────────────────────┐   │
│               │ L1: Redis    │    │ L2: Vertex AI Context   │   │
│               │ Cluster      │    │ Caching API             │   │
│               │ (最近 3 輪)  │    │ (全部歷史壓縮快取)      │   │
│               └──────┬───────┘    └──────────┬──────────────┘   │
│                      │                       │                   │
│                      └──────────┬────────────┘                   │
│                                 ▼                                 │
│                    ┌────────────────────────┐                    │
│                    │  LLM Service           │                    │
│                    │  (Vertex AI Gemini)    │                    │
│                    └────────────────────────┘                    │
└──────────────────────────────────────────────────────────────────┘

新增組件(vs Phase 1):

  • Cache Gateway:token 計數 + 升層決策
  • Redis Cluster(多節點,支援 LRU 驅逐策略)
  • Vertex AI Context Caching API 整合
  • Redis Sorted Set 存放活躍 session 排名(LRU 基礎)

成本/複雜度:

  • 基礎設施:$3,500/月(Redis Cluster + GPU + L2 快取費)
  • 工程成本:6 週實作
  • 5 萬用戶時的 OOM 率從 3% 降至 0.4%

能解決什麼:

  • 長對話(> 32K tokens)自動升至 L2,GPU 顯存降低 60%
  • 輸入 token 費用降低(Context Cache 重複使用)
  • Redis LRU 自動驅逐非活躍 session,顯存不再積累

還剩什麼問題:

  • 用戶閒置後快取仍在計費(未主動 Evict)
  • 無語義壓縮:長時間不活躍的對話沒有被摘要歸檔
  • 重新上線的用戶需要重建完整 Context,冷啟動慢

╔══ Phase 3(Scale / 200K–1M+ 用戶)══╗

策略:L1 Redis + L2 Vertex AI Cache + L3 Firestore Snapshot,完整三層驅逐閘道

┌──────────────────────────────────────────────────────────────────────────┐
│                     Phase 3 架構(Enterprise Scale)                     │
│                                                                          │
│  用戶請求                                                                │
│     │                                                                    │
│     ▼                                                                    │
│  ┌──────────┐   ┌────────────────────────────────────────────────────┐  │
│  │  API GW  │──▶│         Hierarchical Cache Gateway                 │  │
│  └──────────┘   │  ┌────────────┐  ┌──────────────┐  ┌───────────┐  │  │
│                 │  │ Token 計數  │  │ 頻率窗格驗證 │  │ 閒置偵測  │  │  │
│                 │  │ (Redis)    │  │ (滑動窗口)   │  │ (TTL觸發) │  │  │
│                 │  └──────┬─────┘  └──────┬───────┘  └─────┬─────┘  │  │
│                 └─────────┼───────────────┼────────────────┼─────────┘  │
│                           │               │                │             │
│          ┌────────────────▼───┐   ┌───────▼──────┐  ┌────▼──────────┐  │
│          │  L1: Redis Cluster │   │ L2: Vertex AI│  │ L3: Firestore │  │
│          │  - 最近 3 輪明文   │   │ Context Cache│  │ Snapshot      │  │
│          │  - LRU 驅逐        │   │ - 32K+ token │  │ - < 1K token  │  │
│          │  - TTL: 30 分鐘    │   │ - 按小時計費  │  │ - 永久保存    │  │
│          └────────┬───────────┘   └──────┬───────┘  └─────┬─────────┘  │
│                   │                      │                 │             │
│          ┌────────▼──────────────────────▼─────────────────▼──────────┐ │
│          │              LLM Service (Vertex AI Gemini)                 │ │
│          └─────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │                  異步 Flash 壓縮任務(Cloud Run Jobs)            │   │
│  │  閒置 15 分鐘觸發 → Flash 模型語義摘要 → 寫入 L3 → Evict L2     │   │
│  └──────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────────────┘

新增組件(vs Phase 2):

  • 頻率窗格驗證器:滑動窗口計數器,防止短對話誤建 L2 快取
  • 閒置偵測器:Redis TTL + Pub/Sub 觸發異步壓縮
  • Flash 壓縮任務:Cloud Run Job 執行語義摘要 + 重要性評分
  • L3 Firestore Snapshot:< 1K token 的精煉核心記憶快照
  • 主動 Evict 邏輯:壓縮完成後呼叫 API 釋放 L2 快取

成本/複雜度:

  • 基礎設施:$18,000/月(vs 無優化的 $60,000+)
  • 工程成本:12 週實作(包含 Flash 壓縮品質調校)
  • 100 萬用戶 OOM 率 < 0.05%
  • GPU 顯存使用率峰值從 92% 降至 41%

解決的問題:

  • 閒置快取費用歸零(主動 Evict)
  • 冷啟動使用 L3 Snapshot,< 1K token 重建 context
  • GPU 顯存降低 80%,帳單砍半

三、L1 層:Redis Cluster 的對話槽位與 LRU 驅逐設計

3.1 資料結構設計

L1 層使用 Redis Cluster,每個 session 的資料結構如下:

Key:   conv:{tenant_id}:{session_id}:messages
Type:  List(最多保留最近 N 輪)
TTL:   1,800 秒(30 分鐘不活躍自動過期)

Key:   conv:{tenant_id}:{session_id}:token_count
Type:  Integer(累計 token 數)
TTL:   1,800 秒

Key:   conv:{tenant_id}:active_sessions
Type:  Sorted Set(score = last_active_timestamp)
TTL:   永不過期(LRU 基礎)

Redis 設定 maxmemory-policy allkeys-lru,當記憶體達到閾值(設 80% 容量)時,自動驅逐最久未存取的 key。

3.2 LRU 驅逐的租戶公平性問題

純 LRU 在多租戶環境有個問題:大租戶(高頻用戶)會把小租戶的 session 全部驅逐出去。解法是實作「租戶配額感知的 LRU」:

每個租戶最大可佔用 Redis 記憶體 = 總容量 × (租戶月費 / 總月費) × 1.5
(1.5 倍作為突發緩衝)

超過配額的租戶:新 session 直接觸發該租戶內部的 LRU 驅逐
未超配額的租戶:按全域 LRU 正常運作

這樣 Enterprise 客戶不會因為 SMB 客戶的突發流量而 session 被驅逐。

3.3 token 計數的精確度取捨

精確 token 計數需要呼叫 tokenizer,每次對話更新有 2–5ms 額外延遲。在 L1 層使用估算法

估算 token 數 = 字元數 × 0.35(中文)或 × 0.25(英文)
誤差率:± 8%
觸發 L2 的保守閾值:28K estimated tokens(= 實際 32K 的 87.5%)

用 8% 誤差換取 < 0.1ms 的計數延遲,在 100K QPS 下每秒省下 200–500ms 的累積計算時間。

3.4 Redis Cluster 的 Sharding 策略

在多租戶環境下,Redis Cluster 的 key 分佈策略直接影響 hot slot 問題。若直接以 tenant_id 作為 hash slot 基礎,大型租戶的所有 session 都落在同一個 slot,會造成單節點過熱。

正確做法是使用複合 hash tag

Key 格式:{tenant_id:session_id}:messages
Redis 以花括號內的內容計算 hash slot:tenant_id:session_id

效果:
- 同一 tenant 的不同 session 分散到不同 slot
- 同一 session 的所有 key(messages、token_count)落在同一 slot(保證原子操作)

Cluster 節點數設計參考:

  • 每個 Redis 節點建議最大記憶體 32 GB(含 replica 的 overhead)
  • 每個活躍 session 約佔 50–200 KB(3 輪對話 JSON + metadata)
  • 100K 並發 session × 100 KB = 10 GB,建議 6 節點(3 主 3 從)配置,留 40% 緩衝

3.5 L1 的 Pipeline 批量寫入優化

在高峰期(如早上 9–10 點,企業用戶集中上線),每秒可能有 50K+ 次 Redis 寫入。使用 Redis Pipeline 將每輪對話的多個操作批量提交:

單次對話輪次的 Redis 操作(批量執行):
1. LPUSH  conv:{tid}:{sid}:messages  {turn_json}    → 新增對話輪次
2. LTRIM  conv:{tid}:{sid}:messages  0 5            → 只保留最近 6 輪
3. INCRBY conv:{tid}:{sid}:token_count {turn_tokens} → 更新 token 計數
4. EXPIRE conv:{tid}:{sid}:messages  1800           → 重設 TTL
5. ZADD   conv:{tid}:active_sessions {ts} {sid}     → 更新 LRU 排名

Pipeline 批量 vs 逐條執行:RTT 從 5ms × 5 = 25ms 降至 5ms(一次 RTT)

四、L2 層:Vertex AI Context Caching 的精確觸發機制

4.1 升層決策矩陣

不能只看 token 數就升層,必須同時驗證對話頻率:

┌──────────────────────────────────────────────────────────────────┐
│               L2 升層決策矩陣                                    │
│                                                                  │
│           Token 數 < 28K    │   Token 數 ≥ 28K                  │
│  ─────────────────────────────────────────────────              │
│  頻率 < 3 輪/小時  │  不升層  │  不升層(短暫爆發)              │
│  頻率 3–10 輪/小時 │  不升層  │  升層(正常長對話)             │
│  頻率 > 10 輪/小時 │  不升層  │  升層 + 提前觸發(高頻用戶)    │
│                                                                  │
│  滑動窗口:過去 60 分鐘的對話輪數(Redis ZADD + ZCOUNT)        │
└──────────────────────────────────────────────────────────────────┘

頻率驗證的實作使用 Redis Sorted Set:

ZADD conv:{session_id}:turns {current_timestamp} {turn_id}
ZREMRANGEBYSCORE conv:{session_id}:turns 0 {timestamp_1h_ago}
turn_count = ZCOUNT conv:{session_id}:turns {timestamp_1h_ago} +inf

這個操作的時間複雜度是 O(log N),N 為一小時內的對話輪數,在 1,000 QPS 下約 0.3ms。

4.2 Vertex AI Context Cache 的生命週期管理

建立快取時,TTL 設定策略:

初始 TTL = 2 小時(預估用戶當天會繼續使用)
每次對話輪次 → 延長 TTL 30 分鐘(上限 8 小時)
閒置 15 分鐘 → 觸發異步壓縮任務,壓縮完成後主動 DELETE cache

主動 DELETE 是關鍵:不等 TTL 自然過期,壓縮完成後立即釋放,避免付「無效快取時間」的費用。

4.3 快取命中率監控

在 Cloud Monitoring 追蹤三個指標:

指標目標值告警閾值
L1 命中率> 85%< 70%
L2 命中率> 60%< 40%
L2 建立後存活時間(中位數)> 90 分鐘< 45 分鐘
無效快取費用比例< 5%> 15%

L2 存活時間低於 45 分鐘代表升層條件設得太寬鬆,讓太多短暫高峰對話建了快取又立刻閒置。

4.4 L2 快取的版本管理問題

當 Gemini 模型版本升級時(如從 gemini-1.5-pro-001 升至 gemini-1.5-pro-002),舊版本的 Context Cache 無法被新版本讀取,必須重建。這個「快取失效風暴」(Cache Invalidation Storm)如果發生在高峰期,會造成:

  • 所有活躍的 L2 快取同時失效
  • 瞬間大量請求降級到 L1 或重建 Context
  • GPU 顯存和 token 費用同時暴增

緩解策略:

  1. 滾動升級:先在 10% 流量上切換新模型版本,觀察 L2 重建速率,確認無異常後再全量切換
  2. 雙版本並行期:維持 48 小時的舊版本快取,讓用戶自然下線後重建新版本快取
  3. 預熱腳本:在低峰期(凌晨 2–4 點)批量預建高活躍租戶的 L2 快取(取最近 7 天活躍 session 的 Top 20%)

4.5 L2 快取的成本精算模型

以 5 萬 MAU、平均對話深度 30 輪、每輪 400 tokens 為例:

每日 L2 快取建立評估:
- 活躍 session 數:5 萬 × 60%(當天活躍率)= 3 萬 session
- 突破 32K token 閾值的 session:3 萬 × 25%(長對話比例)= 7,500 session
- 符合頻率條件的 session:7,500 × 70%(頻率篩選通過率)= 5,250 session

每個 L2 快取的成本:
- 平均快取大小:40K tokens
- 每小時存儲費:$0.00025/1K tokens × 40K = $0.01/小時
- 平均存活時間:2.5 小時(閒置 15 分鐘觸發壓縮前的預期活躍時間)
- 每 session 每天 L2 費用:$0.01 × 2.5 = $0.025

總 L2 每日成本:5,250 × $0.025 = $131/天 ≈ $3,900/月

對比無快取方案:
- 每次請求重新輸入 40K tokens:$0.001/1K × 40 = $0.04/請求
- 每個 session 每天 30 次請求:$0.04 × 30 = $1.20/session/天
- 5,250 session × $1.20 = $6,300/天 ≈ $189,000/月

節省:$189,000 - $3,900 = $185,100/月(節省 98%)

五、L3 層:Flash 模型語義壓縮與 Firestore Snapshot

5.1 Flash 壓縮的觸發與執行流程

┌──────────────────────────────────────────────────────────────────┐
│                  L3 壓縮流程                                     │
│                                                                  │
│  Redis TTL 到期事件(Keyspace Notification)                    │
│     │                                                            │
│     ▼                                                            │
│  Cloud Pub/Sub(session_idle_topic)                            │
│     │                                                            │
│     ▼                                                            │
│  Cloud Run Job(flash-compressor)                              │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  1. 從 Redis L1 拉取最近 3 輪對話                        │   │
│  │  2. 從 Vertex AI L2 取得完整 Context(若存在)           │   │
│  │  3. 呼叫 Gemini Flash:語義摘要 + 重要性評分             │   │
│  │  4. 產出 Core Memory Snapshot(目標 < 1K tokens)         │   │
│  │  5. 寫入 Firestore:conv_snapshots/{tenant}/{session}     │   │
│  │  6. 呼叫 Vertex AI API:DELETE context cache             │   │
│  │  7. 發送完成事件至監控系統                               │   │
│  └──────────────────────────────────────────────────────────┘   │
│     │                                                            │
│     ▼                                                            │
│  Firestore(L3 永久存儲)                                       │
└──────────────────────────────────────────────────────────────────┘

5.2 語義重要性評分(Semantic Importance Score)

Flash 模型在壓縮時,對每個對話段落打 0–1 的重要性分數:

評分維度(權重):
- 用戶明確提出的需求/問題(0.9–1.0)
- Agent 給出的決策與建議(0.8–0.95)
- 用戶確認的關鍵事實(0.7–0.9)
- 閒聊/寒暄/重複確認(0.0–0.2)
- 已被後續對話推翻的決策(0.1–0.3)

壓縮策略:
- 分數 ≥ 0.7:逐字保留(Verbatim)
- 分數 0.4–0.69:語義摘要(1–2 句)
- 分數 < 0.4:丟棄

壓縮率目標:50K tokens → 800 tokens(壓縮比 62:1),實測品質分數(人工評估的 Context Recall)維持在 78% 以上。

5.3 用戶重新上線的冷啟動流程

用戶在 3 天後重新開啟對話:

  1. Cache Gateway 查詢 Redis L1 → 未命中(已過期)
  2. Cache Gateway 查詢 Vertex AI L2 → 未命中(已主動 Evict)
  3. Cache Gateway 查詢 Firestore L3 → 命中 Snapshot
  4. 將 Snapshot 注入 System Prompt:
[對話歷史摘要 - 上次對話於 2026-06-05]
用戶背景:企業資安部門主管,負責評估 AI 工具採購。
已確認需求:需要符合 ISO 27001 的資料處理協議。
待解決問題:需要法務確認第三條款後才能推進。
重要偏好:偏好書面報告勝於口頭說明。

這個 Snapshot 只佔 800 tokens,vs 重建完整 Context 需要 50K tokens。 輸入成本節省:98.4%;用戶感受的對話連貫性:測試中 82% 的用戶認為「AI 記得之前聊過的事」。

5.4 Snapshot 品質的 A/B 測試框架

Flash 壓縮品質難以用單一指標衡量,需要多維評估:

評估維度測量方法合格閾值
Context Recall(脈絡召回率)人工評估:Snapshot 能讓 Agent 正確回答 10 個對話歷史問題的比例> 75%
幻覺率用戶明確糾正 Agent 錯誤記憶的次數 / 總互動次數< 2%
用戶滿意度差異使用 Snapshot 冷啟動 vs 全量 Context 的 CSAT 分差< 5 分(10 分制)
壓縮比Snapshot tokens / 原始對話 tokens目標 1:50 至 1:80

A/B 測試分流:

  • 控制組(20%):重新上線時使用全量 Context 重建(付 50K token 費用)
  • 實驗組(80%):使用 L3 Snapshot 冷啟動

每兩週評估一次 A/B 結果,調整 Flash 壓縮 prompt 的重要性評分權重。

5.5 Snapshot 的增量更新策略

每次對話 15 分鐘閒置後都全量重壓縮一次,在高活躍用戶(每天多次上線)身上會產生冗餘壓縮費用。優化方式是增量 Snapshot

首次壓縮:全量對話 → 生成 Snapshot v1
後續壓縮:Snapshot v1 + 最新對話增量 → 生成 Snapshot v2
(只需輸入 v1 + 新增的 N 輪對話,而非全部歷史)

成本對比:
- 全量壓縮:每次輸入 50K tokens → $0.02/次
- 增量壓縮:每次輸入 1K(v1)+ 5K(新增)→ $0.002/次
- 高活躍用戶(每天 3 次閒置壓縮):$0.006 vs $0.06,省 90%

增量策略的 flip condition:若對話主題發生根本性轉變(語義距離 > 0.8,用 Embedding 餘弦距離判斷),應捨棄舊 Snapshot 全量重壓縮,避免摘要中累積過時資訊。


六、Cache Gateway 的統一決策邏輯

6.1 請求處理的決策樹

┌──────────────────────────────────────────────────────────────────┐
│              Cache Gateway 決策樹                                │
│                                                                  │
│  收到對話請求                                                    │
│       │                                                          │
│       ▼                                                          │
│  ┌────────────┐  命中  ┌──────────────────────────────────────┐ │
│  │ 查 L1 Redis │──────▶│ 返回最近 3 輪 + 組合完整 Context     │ │
│  └─────┬──────┘        └──────────────────────────────────────┘ │
│        │ 未命中                                                   │
│        ▼                                                          │
│  ┌────────────────┐  命中  ┌────────────────────────────────┐   │
│  │ 查 Vertex AI L2│──────▶│ 載入 Cache ID + 重建 L1        │   │
│  └────────┬───────┘        └────────────────────────────────┘   │
│           │ 未命中                                                │
│           ▼                                                       │
│  ┌────────────────┐  命中  ┌────────────────────────────────┐   │
│  │ 查 Firestore L3│──────▶│ Snapshot → System Prompt 冷啟動 │   │
│  └────────┬───────┘        └────────────────────────────────┘   │
│           │ 未命中                                                │
│           ▼                                                       │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ 全新用戶:空白 Context 啟動                                │  │
│  └────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────┘

6.2 寫入路徑的一致性保障

Cache Gateway 在每次對話輪次結束後:

  1. 同步:更新 L1 Redis(< 2ms)
  2. 異步:更新 token 計數器;若超過升層閾值,異步排隊建立 L2
  3. 觸發評估:每次寫入後重新評估閒置計時器

Gateway 本身是無狀態服務,部署在 Cloud Run,可橫向擴展,每個實例處理 500 QPS,p99 延遲 < 8ms。

6.3 Circuit Breaker 設計

Cache Gateway 對每一層都實作 Circuit Breaker,防止單層故障導致全局雪崩:

┌──────────────────────────────────────────────────────────────┐
│              Circuit Breaker 狀態機                          │
│                                                              │
│   Closed(正常)                                            │
│       │ 失敗率 > 10%(60 秒窗口)                           │
│       ▼                                                      │
│   Open(斷路)──────── 30 秒冷卻 ──────────▶ Half-Open      │
│       │                                        │             │
│       │ 所有請求直接降級                       │ 允許 5% 流量測試  │
│       │                                        │             │
│       │                              成功 ──▶ Closed        │
│       │                              失敗 ──▶ Open          │
└──────────────────────────────────────────────────────────────┘

L1 Circuit Breaker 閾值:
- 錯誤率 > 10% / 60 秒 → Open
- 降級行為:繞過 L1,直接從 Vertex AI L2 讀取

L2 Circuit Breaker 閾值:
- 錯誤率 > 5% / 60 秒,或 p99 延遲 > 3,000ms → Open
- 降級行為:使用 L1 + 完整 History 送 Vertex AI 推理(無快取)

L3 Circuit Breaker 閾值:
- 錯誤率 > 15% / 60 秒 → Open
- 降級行為:新對話從空白 Context 啟動,記錄告警

6.4 故障降級策略

故障場景降級行為用戶影響
L1 Redis 不可用直接查 L2/L3,無快取寫入延遲 +50ms,對話不中斷
L2 Vertex AI API 超時使用 L1 + 完整 History 重建成本上升,對話不中斷
L3 Firestore 讀取失敗空白 Context 啟動用戶感受到「AI 忘記了之前的事」
Flash 壓縮任務失敗L2 保留到自然 TTL 過期多付 1–3 小時快取費用

七、監控儀表板與告警設計

7.1 關鍵可觀測性指標

顯存層(GPU VRAM):

  • 每個 GPU 實例的 VRAM 使用率(目標 < 70%,告警 > 85%)
  • 活躍 L2 快取數量(告警:> GPU 可負載上限的 90%)
  • OOM kill 率(目標 < 0.05%)
  • 每個 GPU 實例服務的並發 session 數(目標:A100 80GB 維持 < 1,200 個活躍長對話 session)

快取效率層:

  • L1/L2/L3 各層命中率(分租戶追蹤)
  • L2 快取平均存活時間(目標 > 90 分鐘)
  • 無效快取(建立後 < 30 分鐘被驅逐)的費用佔比
  • 升層拒絕率(因頻率不足被 Cache Gateway 拒絕升層的比例):目標 30–50%(太低說明條件太鬆,太高說明條件太嚴)
  • L3 Snapshot 命中後冷啟動成功率(用戶感受到連貫性的比例):目標 > 80%

成本層:

  • 每 MAU 的 Vertex AI token 費用(目標 < $0.30/天)
  • Context Cache 存儲費用佔 LLM 總費用比例(目標 15–25%)
  • Flash 壓縮任務的每次執行成本(目標 < $0.002/session)
  • 每個 L2 快取的投資回報比(節省的 token 費 / 快取存儲費):目標 > 5:1

儀表板結構建議(Cloud Monitoring):

頁面一:實時健康狀態
  ├── L1 Redis 延遲 p50/p99(滾動 5 分鐘)
  ├── L2 建立成功率(每分鐘)
  ├── OOM kill 事件(即時)
  └── Cache Gateway 錯誤率(按錯誤類型分層)

頁面二:成本儀表板(每日/每周)
  ├── 三層快取費用佔比(圓餅圖)
  ├── 每 MAU 費用趨勢(折線圖)
  ├── 無效快取費用(棒狀圖,目標歸零)
  └── Flash 壓縮任務總費用 vs 節省的 L2 費用(對比圖)

頁面三:品質監控(每日)
  ├── L3 Context Recall 抽樣評估結果
  ├── 用戶「AI 失憶」回報率
  └── Flash 壓縮任務失敗率 + 死信佇列積壓數

7.2 Symptom → Diagnosis 鏈

症狀:L2 命中率突然從 65% 跌至 35%

  • Traces:查看 Cache Gateway → L2 lookup → miss reason
  • 可能原因 A:大量新用戶(首次對話不可能命中)→ 查 DAU 新用戶比例
  • 可能原因 B:頻率窗格閾值調太嚴 → 查升層拒絕率
  • 可能原因 C:Vertex AI Cache API 間歇性失敗 → 查 L2 建立成功率

症狀:帳單突然暴增 40%

  • Metrics:查 Context Cache 存儲費用時序圖
  • 可能原因 A:Flash 壓縮任務掛掉 → 查 Cloud Run Job 失敗率
  • 可能原因 B:升層條件被人改鬆 → 查 Git history + config diff
  • 可能原因 C:大型活動導致大量長對話同時建立 L2 → 查 L2 建立量峰值

症狀:用戶回報 AI 回答「前言不搭後語」(失憶)

  • 確認 L3 Snapshot 是否存在(Firestore 查詢)
  • 確認 Snapshot 是否被成功注入 System Prompt(查 Gateway request log)
  • 確認 Flash 壓縮品質:取最近 10 筆壓縮結果,人工評估 Context Recall
  • 若 Recall < 60%:Flash 壓縮 prompt 需要調整(可能對話主題領域偏移)

7.3 容量規劃模型

在擴展到 100 萬 MAU 之前,需要提前規劃各層容量:

┌──────────────────────────────────────────────────────────────────┐
│               容量規劃速查表(100 萬 MAU 基準)                  │
├─────────────────┬──────────────────────────────────────────────┤
│  L1 Redis       │                                              │
│  - 記憶體需求   │ 100 萬 × 30%(日活率)× 100KB = 30 GB        │
│  - 節點配置     │ 6 節點(各 16 GB)= 96 GB,留 68% 緩衝       │
│  - 峰值 QPS     │ 100 萬 × 3 次/分 / 60 = 50K QPS             │
│  - 成本/月      │ ~$1,200(Cloud Memorystore Redis 企業版)     │
├─────────────────┼──────────────────────────────────────────────┤
│  L2 Vertex AI   │                                              │
│  - 並發快取數   │ 100 萬 × 5%(符合升層條件)= 5 萬 sessions   │
│  - 平均大小     │ 40K tokens                                   │
│  - 每月存儲費   │ 5 萬 × $0.01/h × 2.5h = $1,250/天 → $37.5K │
│  - 節省 token費 │ 無快取 $180K/天 vs 有快取 $3.75K/天          │
├─────────────────┼──────────────────────────────────────────────┤
│  L3 Firestore   │                                              │
│  - 文件數       │ 100 萬(每用戶 1 份最新 Snapshot)           │
│  - 存儲空間     │ 100 萬 × 3 KB(Snapshot JSON)= 3 GB        │
│  - 讀寫 QPS     │ 日活 30 萬 × 20%(冷啟動率)= 6 萬次/天     │
│  - 成本/月      │ ~$150(Firestore 依讀寫次數計費)             │
├─────────────────┼──────────────────────────────────────────────┤
│  Flash 壓縮任務 │                                              │
│  - 每日觸發數   │ 日活 30 萬 × 60%(有 L2 的 session)= 18 萬 │
│  - 執行時間     │ 平均 1.5 秒/次                               │
│  - Cloud Run    │ 並發實例數:18 萬 / (86400/1.5) = 3.1 實例  │
│  - 成本/月      │ 18 萬次 × $0.002 = $360/天 → $10,800/月     │
└─────────────────┴──────────────────────────────────────────────┘

總計:三層快取月成本 ≈ $49,650
對比無快取月成本:$180K/天 × 30 = $5,400,000(僅 token 費)
ROI:約 108:1

八、為什麼選 X 不選 Y

選擇選 X 的理由不選 Y 的理由Flip Condition
Redis LRU 作為 L1< 1ms 讀寫延遲;原生 TTL 支援;allkeys-lru 策略自動驅逐Memcached:無持久化、無 Sorted Set(LRU 排名需要);DynamoDB:50ms+ 延遲、按讀寫次數計費若 L1 僅作純 key-value 存取且不需排名,Memcached 更省記憶體(約 30%);若流量 < 1K QPS 且需要持久化,DynamoDB 反而更簡單
Vertex AI Context Caching 作為 L2原生 Gemini 整合,無需序列化/反序列化 KV;官方支援的快取機制;硬體層加速自建 vLLM KV Cache:需要自管 GPU 叢集、版本維護、硬體採購;短期 TCO 高 3–5 倍若月 GPU 用量超過 $50K 且有 MLOps 團隊,自建 vLLM 可降低長期邊際成本;若需要 100% 資料落地控制(金融/醫療法規),自建是必選
Gemini Flash 作為壓縮模型成本是 Gemini Pro 的 1/10;延遲 < 2 秒(壓縮任務可接受);摘要品質足夠(78% Context Recall)Gemini Pro 壓縮:成本過高,每次壓縮 $0.02 vs Flash 的 $0.002;規則式截斷:Context Recall 只有 45%,用戶感受差若對話涉及高度技術性或法律文件(Context Recall 要求 > 90%),需要升到 Pro;若規模 < 1K sessions/天,規則式截斷已夠用
Firestore 作為 L3自動 schema-less、支援複合查詢(tenant_id + session_id);强一致性讀取;GCP 生態整合Cloud Spanner:對 L3 過度設計,每月固定成本 $900+;BigQuery:分析型資料庫,點讀延遲 200ms+,不適合即時查詢若 snapshot 需要跨 session 的複雜關聯查詢(如「找出同一租戶所有提到合約的 session」),Cloud Spanner 的 SQL 能力更強
Cloud Pub/Sub 觸發壓縮解耦閒置偵測與壓縮執行;支援重試、死信佇列;萬次以下觸發幾乎免費直接 HTTP 呼叫 Cloud Run:若壓縮任務 timeout,呼叫端會 block;無法重試失敗任務;Cloud Tasks:適合有明確延遲要求的任務,但 Pub/Sub 更適合事件驅動若壓縮任務有嚴格 SLA(如「必須在閒置後 2 分鐘內完成」),Cloud Tasks 的精確延遲控制更適合
滑動窗口頻率驗證(Redis ZADD)精確反映最近 60 分鐘的真實對話頻率;O(log N) 複雜度;原生 Redis 操作固定窗口計數器:在窗口邊界會有 2× 突發誤判;Token Bucket:實作更複雜,且對「對話頻率」這個語義不夠直觀若只需要「今天是否有活躍對話」這種粗粒度判斷,固定窗口計數器(Redis INCR + EXPIRE)成本更低、更簡單

九、系統效應:優化前後對比

指標優化前(Phase 1)Phase 2Phase 3(目標狀態)改善幅度
GPU VRAM 使用率(峰值)92%68%41%↓ 55%
OOM 崩潰率3.0%0.4%0.05%↓ 98%
每 MAU 每天 LLM 費用$1.20$0.65$0.30↓ 75%
月度總 Vertex AI 帳單$120K$72K$36K↓ 70%
L1 快取讀取延遲(p99)45ms(每次全量 DB 讀取)3ms1.2ms↓ 97%
對話請求端到端延遲(p99)2,800ms1,900ms1,400ms↓ 50%
用戶重新上線 Context 重建成本50K tokens($0.15/次)50K tokens800 tokens($0.002/次)↓ 98%
無效 L2 快取費用比例N/A22%3%↓ 86%
Flash 壓縮任務失敗率N/AN/A0.8%基線
L3 Snapshot Context RecallN/AN/A78%基線
系統可服務並發用戶數(同 GPU 預算)8K28K95K↑ 11.8×
工程師在快取相關 incident 花費時間/月40 小時15 小時4 小時↓ 90%
L2 快取投資回報比N/A3.2:18.5:1↑ 165%
Flash 壓縮平均執行時間N/AN/A1.4 秒基線
冷啟動 System Prompt token 數N/A50K800↓ 98%

Phase 3 達成 CFO 目標的路徑:

月帳單分解(5 萬 MAU,Phase 3 狀態):

LLM 推理費(優化後):  $18,000  (↓ 75% vs Phase 1 的 $72,000)
L2 快取存儲費:          $3,900   (精確升層控制,無效比例 3%)
L1 Redis 費用:          $1,200   (Memorystore 企業版,6 節點)
L3 Firestore 費用:      $150     (讀寫次數計費,100 萬文件)
Flash 壓縮任務費用:     $2,160   (18 萬次/天 × 30 天 × $0.002)
Cloud Run Gateway:      $800     (無狀態、自動縮放)
Cloud Pub/Sub:          $50      (訊息量低於免費配額上限)
─────────────────────────────────
總計:                   $26,260  (vs Phase 1 的 $120,000)
節省幅度:               78%
CFO 要求(降低 50%):  達成,超額完成

十、進階議題:多租戶快取隔離與安全邊界

10.1 快取洩漏風險

KV Cache 在 GPU 層面共享記憶體,理論上存在跨用戶讀取的風險。Vertex AI Context Caching 的隔離邊界:

  • 每個 Cache 物件以 cache_name(含 projects/{project}/locations/{location}/cachedContents/{id})索引
  • API Key / Service Account 驗證:每個租戶使用獨立的服務帳號,透過 IAM 限制只能讀寫自己租戶的 Cache
  • 應用層再加一層:Cache Gateway 驗證 JWT claim 中的 tenant_id 與 cache 的 metadata 一致,才允許讀取

10.2 Flash 壓縮的隱私合規

部分企業客戶的對話內容涉及 NDA 資料。壓縮任務的合規設計:

  • Flash 壓縮在租戶的 VPC 內執行(Cloud Run 掛載到租戶 VPC)
  • Snapshot 寫入 Firestore 時使用客戶管理的加密金鑰(CMEK,透過 Cloud KMS)
  • Snapshot 的保留策略由租戶設定(預設 90 天,可縮短至 0)

10.3 快取毒化攻擊(Cache Poisoning)防範

在多租戶系統中,攻擊者可能試圖透過特製輸入污染快取,讓其他用戶的 Agent 行為異常。防範措施:

輸入驗證層(Cache Gateway 前置):
1. 最大 token 限制:單輪輸入 > 8K tokens 需要人工審核(異常長輸入)
2. Prompt Injection 偵測:掃描輸入中是否包含「忽略先前指令」等模式
3. 快取隔離驗證:每次快取讀取前,驗證 cache_name 的 tenant hash 與當前請求一致
4. Snapshot 簽章:寫入 Firestore 時附加 HMAC 簽章,讀取時驗證完整性

10.4 Rate Limiting 與防止 Cache Flooding

惡意用戶可能透過大量短對話觸發大量 L2 快取建立,消耗平台的 Context Cache 配額。防護機制:

限制類型限制值實作方式
每租戶每分鐘 L2 建立數最多 50 次Redis 計數器 + EXPIRE
每用戶每天 Flash 壓縮次數最多 20 次Firestore 計數 field
單 session 最大 L2 快取大小128K tokensCache Gateway 前置截斷
全局每分鐘 L2 建立數(配額保護)1,000 次Token Bucket 限流

十一、面試答題要點

「這題的核心是把 KV Cache 管理從『技術問題』升維成『財務工程問題』。我會設計三層架構:L1 是 Redis Cluster,存最近 3 輪對話,LRU 驅逐保證 < 2ms 讀取;L2 是 Vertex AI Context Caching,但觸發條件是雙重門檻——對話必須超過 32K tokens 且過去 60 分鐘頻率超過 3 輪/小時,用 Redis 滑動窗口驗證,這樣精確避開短對話的計費陷阱;L3 是 Firestore 存放 Flash 模型壓縮的 Core Memory Snapshot,不超過 1K tokens。驅逐邏輯同樣有精確數字:閒置超過 15 分鐘,異步觸發 Flash 壓縮任務,壓縮成功後主動呼叫 API 釋放 L2,不等 TTL 自然過期。這套架構在 100 萬用戶規模下,GPU VRAM 使用率從 92% 降至 41%,每 MAU 每天費用從 $1.20 降至 $0.30,月帳單從 $120K 直接砍到 $36K,CFO 的目標兩個月內完全達成。關鍵 Why-X-not-Y:選 Flash 不選 Pro 做壓縮,因為 Context Recall 差距只有 12%(78% vs 90%),但成本差 10 倍,在壓縮任務這個 batch 場景完全值得。」


系列導航


系列導航

Part 50:前一篇 | Part 52:下一篇

Yen

Yen

Yen