同一個 Agent,Demo 時跑得很好。
上了生產後成本是預估的 8 倍、偶爾 15 秒、有時候對話記憶消失。
「能 Demo」和「可以讓 1,000 個用戶每天用」之間的距離,
就是生產化工程的價值。
面試情境
面試官:「你幫客戶做了一個 3 週的 RAG + Agent POC,Demo 很成功。客戶的 CTO 說:太好了,下個月上線。你說:先等一下,我們需要做幾件事。你會說什麼?」
一、POC 和 Production 的假設差距
POC 的隱性假設:
假設 1:只有你在用(實際:100 個並發)
假設 2:測試資料乾淨(實際:用戶會貼整份合約進來)
假設 3:成本不計較(實際:月底看帳單)
假設 4:出錯了就 debug(實際:1 小時內要給客戶答覆)
假設 5:你挑了最好的 Demo 例子(實際:Murphy's Law)
五個 POC 到 Production 的差距:
差距 1:Token Budget → 成本是預估的 8 倍
差距 2:延遲 SLA → Cold Start 讓 P95 超過 SLA
差距 3:Session State → 重啟後對話記憶消失
差距 4:錯誤處理 → 外部 API Timeout 讓 Agent crash
差距 5:Rollback → Prompt 改錯了沒辦法快速回頭
以下逐一拆解每個差距的成因和設計。
二、差距 1:Token Budget 失控
失控路徑:
POC 測試:平均 2,000 input tokens,成本可接受。
↓
Production 現實:
情況 A:用戶貼了整份合約
input_tokens = 20,000(是預估的 10 倍)
情況 B:Multi-turn 對話 history 累積
第 1 輪:2,000 tokens
第 5 輪:2,000 + (4輪 × 800) = 5,200 tokens
第 15 輪:2,000 + (14輪 × 800) = 13,200 tokens
情況 C:ReAct loop 多跑幾輪
正常:2 輪 Tool Call = 2,000 × 2 = 4,000 tokens
異常:6 輪 Tool Call(遇到困難問題)= 2,000 × 6 = 12,000 tokens
Token Budget 設計:
┌─────────────────────────────────────────────────────────────┐
│ 總 Budget:8,000 tokens(可配置) │
│ │
│ ├── System Prompt(固定):-1,200 tokens │
│ │ (如果 > 1,000 tokens,考慮 Context Caching) │
│ │ │
│ ├── User Query:-actual tokens(優先保留) │
│ │ │
│ ├── Conversation History(最多 30% 剩餘 budget) │
│ │ 超過部分:從最舊的輪次開始截斷 │
│ │ 如果整體 > 10 輪:先壓縮成 Summary │
│ │ │
│ └── Retrieved Context(剩餘 budget) │
│ 按相關性排序,直到 budget 用完 │
└─────────────────────────────────────────────────────────────┘
成本效益:
無 Budget 管理:預估 $0.015/query,實際 $0.12/query(8倍)
有 Budget 管理:$0.015-0.025/query(可預測,可定價)
三、差距 2:延遲 SLA
SLA 失效路徑:
POC 測試:10 個問題,平均 3 秒。「還可以。」
↓
Production 問題:
問題 A:Cloud Run Cold Start
Auto-Scale Scale-Out 後,新實例啟動需要 8-12 秒
第一個打到新實例的用戶:等了 12 秒
問題 B:外部 API Spike
SAP API 在月結日前壓力大,P99 從 200ms 變成 8 秒
整個 Agent 的 P99 跟著變成 11 秒
問題 C:Token 超長的請求
LLM 推論時間和 input_tokens 正相關
20,000 input tokens 的請求比 2,000 的慢 5 倍
SLA 設計:
┌──────────────────────────────────────────────────────────────┐
│ 延遲 SLA 設計 │
│ │
│ 目標:P50 < 2s P95 < 5s P99 < 10s │
│ │
│ Cold Start 解法: │
│ Cloud Run min-instances = 2(高峰期可調高) │
│ 代價:持續計費,即使沒有流量($10-30/月) │
│ 判斷:P95 SLA 要求 < 5s → min-instances 是必要成本 │
│ │
│ Tool Timeout 設計: │
│ 每個 Tool 呼叫設定 timeout(SAP=5s, Oracle=3s, External=8s)│
│ Timeout 後 → Graceful Fallback,不讓整個 Agent 卡住 │
│ │
│ Streaming 回應(改善感知延遲): │
│ 實際延遲:8 秒(完整回答) │
│ 感知延遲:1 秒看到第一個字,用戶知道系統在回應 │
│ 適合:長回答(法律分析、報告生成) │
└──────────────────────────────────────────────────────────────┘
四、差距 3:Session State 消失
消失路徑:
POC:Conversation History 存在 Python dict(記憶體)。
重啟就清空,測試時沒注意。
↓
Production 問題:
問題 A:Cloud Run Scale-Down
閒置 15 分鐘後實例被回收
→ 記憶體清空 → 用戶下次請求找不到對話歷史
問題 B:多實例
Cloud Run Scale-Out 到 3 個實例
用戶的第 1 個請求打到 Instance A(History 在 A)
用戶的第 2 個請求打到 Instance B(History 不在 B)
→ 對話斷掉,Agent 不記得前面說了什麼
Session State 持久化方案對比:
方案 延遲 成本 複雜度 適合場景
──────────────────────────────────────────────────────────────
Firestore 10-50ms 低 低 ADK 原生整合,推薦預設
(ADK 內建) 大多數企業 Agent
──────────────────────────────────────────────────────────────
Cloud < 5ms 中 中 高頻讀寫,
Memorystore 對 Session 延遲敏感
(Redis)
──────────────────────────────────────────────────────────────
記憶體(dict) < 1ms 零 零 只用於 Dev/POC,
不用於 Production
──────────────────────────────────────────────────────────────
Session State 的設計原則:
├── TTL(Session 過期時間):24 小時(不能永久存)
├── 大小上限:每個 Session 最多 100KB(防止無限增長)
└── PII:不存原始 PII(用 anonymized_id 代替 user_id)
五、差距 5:Rollback 機制設計
失效路徑:
新版 Prompt 讓系統開始給出奇怪的答案。
沒有 Rollback 機制:需要改代碼 → 跑 CI → 重新部署 → 30-60 分鐘
30-60 分鐘內,所有用戶都在受影響。
Rollback 三層設計:
┌──────────────────────────────────────────────────────────────┐
│ Layer 1:Prompt 版本控制(1 分鐘內 Rollback) │
│ │
│ PROMPT_REGISTRY = { │
│ "v2": "你是法務助理...", ← 當前 stable │
│ "v3": "你是嚴謹的法律審查員...",← 剛上的新版 │
│ } │
│ │
│ ACTIVE_PROMPT = os.getenv("ACTIVE_PROMPT", "v2") │
│ │
│ Rollback:只需要改環境變數 → 重啟 Cloud Run,不需要改代碼 │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Layer 2:模型版本釘選(防止 Google 更新破壞你的 Prompt) │
│ │
│ ❌ 不要用:model = "gemini-2.0-flash" │
│ (Google 更新這個 model,你的行為悄悄改變) │
│ │
│ ✅ 要用:model = "gemini-2.0-flash-001"(具體版本號) │
│ │
│ 升級流程: │
│ 新版本發布 → Staging 環境切換 → 跑 Eval Pipeline → 通過 │
│ → 更新環境變數 → Canary 部署 → 全量 │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Layer 3:Canary 部署(Traffic Splitting) │
│ │
│ 不做全量切換,先 Canary: │
│ │
│ Day 1:v3(新版)10% + v2(穩定版)90% │
│ Day 2:v3 25% + v2 75%(如果指標正常) │
│ Day 3:v3 100%(全量) │
│ │
│ 監控 Canary 的指標(每小時看一次): │
│ ├── Error Rate:新版有沒有增加錯誤? │
│ ├── P95 Latency:新版有沒有變慢? │
│ └── Shadow Eval Faithfulness:品質有沒有退化? │
│ │
│ 任何指標異常 → 立刻把 Canary 流量改回 0%(5 秒內完成) │
│ │
│ gcloud run services update-traffic agent \ │
│ --to-revisions=STABLE=100 │
└──────────────────────────────────────────────────────────────┘
六、生產化 Go-Live 清單
五個差距對應的 Go-Live 檢查項目:
差距 檢查項目 完成時間
──────────────────────────────────────────────────────────────
Token Budget □ 每個 LLM 呼叫有 Token 上限 2 天
□ Conversation History 有截斷策略
□ Cost Alert 已設定(月費 > $X → 通知)
──────────────────────────────────────────────────────────────
延遲 SLA □ P50/P95/P99 SLA 已定義(不只平均值)2 天
□ min-instances > 0(消除 Cold Start)
□ 每個 Tool 有 timeout 設定
──────────────────────────────────────────────────────────────
Session State □ Session State 不存在記憶體 1 天
□ 已遷移到 Firestore 或 Redis
□ Session TTL 已設定
──────────────────────────────────────────────────────────────
錯誤處理 □ 所有 Tool 有 Graceful Fallback 2 天
□ 全域 Exception Handler(不暴露 stack trace)
□ 結構化錯誤訊息(Agent 能理解,用戶看到友好訊息)
──────────────────────────────────────────────────────────────
Rollback □ Prompt 版本控制(環境變數切換) 1 天
□ 模型版本已釘選(具體版本號)
□ Canary 部署流程已建立
──────────────────────────────────────────────────────────────
可觀測性 □ Cloud Trace 已整合(見 Part 35) 2 天
(前提) □ Error Rate / 延遲 Alert 已設定
──────────────────────────────────────────────────────────────
總計:8 個工作天,一個工程師可以完成。
如果超過 5 個項目未完成 → 建議先 Internal Pilot(50 個內部用戶),
不要直接開放給全部用戶。
七、系統效應:生產化設計對系統的量化影響
維度 有生產化設計 沒有生產化設計
──────────────────────────────────────────────────────────────────
Token 成本 可預測($0.02-0.025/req) 暴跌(最差 $0.12/req,8 倍)
──────────────────────────────────────────────────────────────────
P95 延遲 < 5s(有 min-instances) 8-12s(Cold Start)
< 8s(有 Tool Timeout) 可能無限等待(無 Timeout)
──────────────────────────────────────────────────────────────────
Session 穩定 用戶感知到的連續對話 每 15 分鐘對話重置
(Scale-Down 不影響) (記憶體被回收)
──────────────────────────────────────────────────────────────────
Rollback 時間 < 5 分鐘(環境變數切換) 30-60 分鐘(改代碼重部署)
生產問題影響窗口最小化
──────────────────────────────────────────────────────────────────
上線信心 有清單可以核對 靠感覺,不知道還漏了什麼
──────────────────────────────────────────────────────────────────
生產化工程成本 vs 收益:
成本:8 個工作天(一個工程師)
收益:
├── 防止帳單爆炸(Token Budget)
├── SLA 達標(Cold Start 消除)
├── 用戶體驗穩定(Session 不消失)
└── 出問題可以 5 分鐘內修好(Rollback)
任何一個未處理的差距,在用戶規模放大後都會變成嚴重事故。
生產化工程不是「優化」,是「基本門檻」。
八、面試答題要點
「這道題考的是:知道 POC 和 Production 之間有哪些具體差距,以及如何系統性地填補它們——而不只是說『還需要測試』。
五個差距:Token Budget 失控(需要截斷策略和 Cost Alert);延遲 SLA 差距(需要 min-instances 和 Tool Timeout);Session State 消失(需要 Firestore 持久化);錯誤處理不完整(需要 Graceful Fallback 和全域 Exception Handler);Rollback 機制缺席(需要 Prompt 版本控制、模型版本釘選、Canary 部署)。
和客戶 CTO 的溝通方式:不說「還沒準備好」,說「下個月上線可以,但建議先做 2 週 Internal Pilot,同時並行處理這 5 件事,8 個工作天可以完成。Pilot 讓我們在真實流量下驗證,把影響範圍控制在 50 個內部用戶,而不是第一天就開放給所有用戶出問題。」
Rollback 的設計邏輯:Prompt 版本控制讓我在 1 分鐘內 Rollback,不需要改代碼重新部署。模型版本釘選防止 Google 的更新悄悄改變系統行為。Canary 部署讓我在 10% 流量上驗證 24 小時,確認沒問題再全量。」
