系統整合完成後,今天要來談上線之後最實際的兩個問題:回應速度夠不夠快?運行成本能不能負擔?
一次完整的 RAG 查詢,延遲通常來自以下幾個環節:
問題改寫(LLM) ~0.5-1s
│
向量檢索 ~0.05-0.2s
│
Rerank ~0.1-0.5s
│
LLM 生成答案 ~2-5s(通常是最大的瓶頸)
可以看出,LLM 生成階段通常是延遲的主要來源,其次是需要額外呼叫 LLM 的問題改寫步驟。
即使總生成時間沒有縮短,透過 Day 27 提到的串流輸出(Streaming),使用者可以馬上看到文字逐步出現,體感等待時間會大幅降低。
如果知識庫更新不頻繁,許多使用者可能會問類似或重複的問題,可以針對「問題」做快取:
import hashlib
import redis
cache = redis.Redis()
def get_cached_answer(question):
key = hashlib.md5(question.encode()).hexdigest()
cached = cache.get(key)
return cached.decode() if cached else None
def set_cached_answer(question, answer, ttl=3600):
key = hashlib.md5(question.encode()).hexdigest()
cache.set(key, answer, ex=ttl)
要注意:完全相同字串的問題在真實使用情境中比例可能不高,可以考慮用「語意相似度」判斷是否命中快取(例如問題向量跟快取中的問題向量相似度超過某個門檻,就直接回傳快取的答案),但這樣做要更謹慎,避免誤判導致答非所問。
如果同一份文件的內容沒有變化,不需要重複計算 Embedding:
def get_or_compute_embedding(content, cache_store):
content_hash = hashlib.md5(content.encode()).hexdigest()
if content_hash in cache_store:
return cache_store[content_hash]
embedding = get_embedding(content)
cache_store[content_hash] = embedding
return embedding
RAG 系統的主要成本來源:
| 項目 | 成本特性 |
|---|---|
| LLM 生成 API 呼叫 | 通常按輸入/輸出 token 數計費,是最大宗的成本 |
| Embedding API 呼叫 | 按 token 數計費,但通常遠低於生成成本;且多半是一次性(除非文件常更新) |
| 向量資料庫 | 依儲存量與查詢量計費(若用託管服務)或自架的運算資源成本 |
| Rerank API 呼叫 | 若使用 API 服務,依呼叫次數計費 |
降低成本的常見做法:
效能與成本優化,往往需要在「回答品質」與「速度/成本」之間找到平衡點——不是所有優化技巧都要用到極致,而是依照實際使用情境(使用人數、預算、對即時性的要求)做取捨。明天我們要討論系統上線後的監控與維運機制。