解碼Prompt Caching:從PagedAttention 原理到10 倍降本增效 @dejavucoder 這篇文章深入剖析了Prompt Caching(提示詞快取)的底層原理,特別是基於@vllm_project PagedAttention 技術。作者結合自己在開發中的「踩坑」經歷,修正了許多開發者對於快取機制的常見誤解,提供了極具實操性的最佳化建議。 核心迷思與真相:快取是全域的,不是私有的· 迷思:作者(和咱們很多人一樣)最初認為,Prompt Caching 是基於「使用者會話」的。也就是說,只有同一個使用者在同一個對話框裡的後續發言,才能利用先前的快取。 · 真相:Prompt Caching 是基於內容的,而非基於使用者。 · 核心邏輯:只要你的系統提示詞或工具定義是完全一致的文本,那麼用戶A 產生的緩存,完全可以被用戶B 重複使用。 · 意義:這意味著在高並發場景下,只要前綴一致,系統可以實現“全域復用”,極大降低重複計算。 為什麼需要快取? (成本與速度) LLM 的推理過程分為兩個階段,理解這個差異是理解快取價值的關鍵: · 預填階段:處理你輸入的一大段提示詞,計算出它們的KV Cache。這個過程是計算密集型的,非常消耗算力。 · 解碼階段:逐一產生回應的token。這個過程是記憶體頻寬密集型的。 · 如果沒有快取:每次請求進來,即便前面90% 的Prompt 都是一樣的,模型都要重新算一遍Prefill,既慢又貴。 · 命中快取:可以直接跳過繁重的Prefill 運算,輸入token 的成本可降低10 倍,且首字產生速度顯著提升。 技術揭秘:PagedAttention 傳統的KV Cache 管理非常低效,必須預先分配一大塊連續顯存,容易造成碎片化浪費。 vLLM 引入了作業系統管理記憶體的思路——分頁。 · 分塊(Blocks): 系統不再分配連續大內存,而是將KV Cache 切分成固定大小的「區塊」。這些區塊在物理顯存裡可以是分散的,不連續的。 · 哈希鏈(Block Hashing)-快取生效的關鍵: 系統如何知道「這段話以前算過」?它會計算區塊的雜湊值。 · 父區塊依賴:一個區塊的雜湊值,不僅取決於它自己的內容,還取決於前一個區塊的雜湊值。 · 連鎖反應:這就像區塊鏈一樣。只有當「從頭開始的所有內容」都完全一致時,當前的雜湊值才會匹配。這保證了因果關係的正確性——你不能只重複使用中間的一段,必須是前綴完全匹配。 · 全域查找: 新請求進來時,系統計算其提示詞的區塊哈希,去全域哈希表中查找。如果命中,直接指向現有的顯存區塊,完全不需要計算。 給開發者的實操建議:如何「騙」過系統命中快取? 為了最大化快取命中率,你需要讓系統認為不同的請求是「一樣」的。文章給了幾條黃金法則: · 保持前綴穩定(Stable Prefix) 將所有靜態內容(系統提示詞、工具定義、範例文字)放在最前面。 · 反例:如果你把「目前時間」或「使用者名稱」放在提示字的開頭,那麼整個哈希鏈從一開始就斷了,後面的內容即使一樣也無法復用快取。 · 確定性序列化(Deterministic Serialization) 在使用JSON 格式傳遞資料時(例如工具呼叫),必須確保鍵的順序固定。 · 技巧:在Python 中使用json.dumps(..., sort_keys=True)。因為{ "a": 1, "b": 2 } 和{ "b": 2, "a": 1 } 雖然語意相同,但產生的字串不同,會導致快取未命中。 · 僅追加模式(Append-only) 在維護多輪對話歷史時,盡量只在末尾添加新內容。不要去修改或截斷中間的歷史記錄,一旦中間變了,後面的快取鏈就全失效了。 · 警覺工具定義的變化工具定義通常被模型拼接在系統提示詞附近。如果你動態地為不同使用者開啟/關閉不同的工具,會導致前綴發生變化,進而導致快取失效。 總結 Prompt Caching 的本質不是“記憶”,而是“復用計算結果”。了解底層的分塊和雜湊鏈機制,開發者就能明白為什麼「前綴」如此重要。 一句話總結:把所有不變的東西(系統指令、背景文件、工具清單)永遠放在最前面,把變化的東西(使用者提問、動態變數)放在最後面。 閱讀原文
正在加载线程详情
正在从 X 获取原始推文,整理成清爽的阅读视图。
通常只需几秒钟,请稍候。
