Pi 中的壓縮機制如何運作
編碼代理中的上下文管理
大型語言模型 (LLMs) 在固定的上下文窗口內運作,這限制了它們在單次請求中可以處理的輸入量。在編碼代理的對話階段中,隨著系統提示詞、工具定義、對話歷史和工具輸出不斷累積,輸入量會持續增長。一旦總量超過上下文窗口,LLM 將會因大小錯誤而拒絕請求。
為了防止對話階段失敗,代理必須要麼開始新的對話——這會捨棄所有累積的上下文和先前的決策——要麼實施 compaction (壓縮),即為現有的歷史記錄建立一個更小、更壓縮的表示形式,以便為新訊息騰出空間。
Pi 的壓縮實施方式
Pi 透過摘要化舊的對話內容,同時保留特定數量的近期訊息,來實施壓縮。當上下文限制接近窗口的總大小時,此過程會自動觸發,或者也可以透過 /compact 指令手動觸發。
壓縮流程
Pi 的壓縮遵循特定的工作流程,以確保代理在不浪費 token 的情況下保留關鍵資訊:
- 保留預算 (Retention Budget):Pi 會保留一定數量可配置的近期訊息(預設為 20,000 tokens,大約 5 到 20 輪對話)且不作變動。
- 序列化 (Serialization):所有在保留切分點之前的訊息都會被提取並序列化以進行摘要化。
- 專用請求 (Specialized Request):Pi 會向「上下文摘要助手」發送獨立請求,而非標準的編碼助手。這讓 Pi 能夠使用不同的、可能更具成本效益的 LLM 模型來進行摘要。
- 結構化輸出 (Structured Output):壓縮提示詞會明確要求一個分為三個部分的結構化摘要:goal (目標)、progress (進度) 和 key decisions (關鍵決策)。這將作為下一階段對話的「交接簡報」。
整合與可移植性
生成的摘要將以純文字形式儲存在對話階段中。這種方法確保了壓縮後的上下文對於使用者而言仍然是可讀的,並且可以在不同的 LLM 模型之間移植,讓使用者可以在不丟失摘要後的歷史記錄的情況下切換模型。
對提示詞快取 (Prompt Caching) 的影響
提示詞快取透過允許 LLM 提供商重用對話的前綴,來降低成本和延遲。然而,快取需要精確的 token 對 token 的前綴匹配。
由於壓縮會將一大塊舊的歷史記錄替換為新的摘要,它會改變對話的前綴。這實際上會破壞現有的提示詞快取,這意味著在壓縮後的第一次請求中,摘要之後的所有 token(包括保留的近期對話輪次)都必須重新計算。一旦新狀態建立,隨後的請求將再次受益於快取。
其他上下文策略與社群觀點
雖然 Pi 使用基於 LLM 的摘要化,但開發者和使用者已提出了幾種管理上下文溢出的替代策略:
修剪 (Pruning) vs. 摘要化 (Summarization)
有些使用者認為,修剪——即確定性地移除低價值訊息——優於摘要化。
"I find summarized conversations lead to more frustrating future chats because the LLM misses intent and or context."
建議的修剪策略包括移除 "thinking" 跡象、工具呼叫輸出和程式碼庫探索日誌,同時保留使用者訊息和最終的助手結論。
架構替代方案
- 嵌套執行緒 (Nested Threading):一種方法是將舊訊息移至一個會自我摘要的子執行緒中,在提供乾淨的主執行緒的同時,讓子執行緒中仍可存取完整的歷史記錄。
- 動態修剪 (Dynamic Pruning):某些實作方式使用標籤來動態折疊和展開工具呼叫與對話歷史的摘要。
- KV Cache 操作 (KV Cache Manipulation):對於運行本地堆疊的使用者,有人建議直接在 GPU 上進行操作,在推論過程中清除或用摘要替換舊的工具呼叫,以避免需要發送完整的全新 LLM 請求。
- 交接 (Handoffs):與其進行壓縮,有些人更傾向於「交接」,即指示當前的 LLM 摘要化所有對於全新對話階段所必需的內容。
當前方法的局限性
標準壓縮的批評者指出,對於本地 LLM 而言,僅為了生成一個小摘要而解析 128k tokens 可能在計算上非常昂貴。此外,有些使用者回報,如果工具呼叫迴圈很長,代理可能直到迴圈結束才會檢查壓縮限制,這可能導致記憶體不足 (OOM) 錯誤。
Sources
相關
- Dispatch
- Dispatch
- Dispatch
- Dispatch