最近有球友問:「三哥,我們團隊在做 AI 客服,對話一長 token 消耗扛不住。有沒有一種方案,既能保留完整上下文記憶,又能省 token?」
這位朋友的問題,恰恰戳中了當下 AI 應用開發最頭痛的痛點。
既要馬兒跑得快,又要馬兒不吃草。
這聽起來像是矛盾,但經過這兩年的摸索,我發現在某些條件下,確實存在「相對兩全」的解法。
今天這篇文章就專門跟大家一起聊聊這個話題,希望對你會有所幫助。
更多項目實戰在 Java 突擊隊網:susan.net.cn
很多小夥伴可能覺得,大模型就像一個人,你說過的話它應該天然記得住。
錯!
大模型本質上是一個無狀態的函數。
每次呼叫都是獨立的,它沒有任何「記憶細胞」。
為了讓 AI 記住之前聊過什麼,唯一的辦法就是:把歷史對話拼接到下一次請求裡。
這就是所謂的「上下文注入」。

看到沒?
第 N 次請求攜帶的歷史,是前 N-1 輪的總和。
token 消耗隨著對話輪數線性增長——更準確地說,是 O(n) 級別的增長。
但事情沒這麼簡單。
Transformer 模型的核心是自注意力機制,它的計算複雜度是O(n²)。
也就是說,輸入長度翻一倍,計算量翻四倍。
更可怕的是,當輸入過長時,模型會患上「中間迷失症」——位於長文本中間的資訊被嚴重忽略。
所以,我們的真實困境是:
保留全部歷史 → token 爆炸 + 注意力稀釋 → 又貴又笨
丟棄歷史 → 資訊丟失 → AI 變「金魚腦」
有沒有一條中間道路?
有。
下面我會介紹 8 種方案,從簡單到複雜,從廉價到智能,你可以根據自己的場景按需選擇。
簡單粗暴,但不推薦。
這是最直覺的實現:把所有對話都存下來,每次請求全部帶上。
程式碼解析:邏輯非常直接——fullHistory 列表保存所有訊息,buildContext() 把它們全部拼接成字串。沒有任何優化。
優點:
缺點:
適用場景:只適合 Demo 演示、除錯測試,或者保證對話不超過 10 輪的極短場景。
生產環境慎用。
省 token,但記性差。
滑動視窗只保留最近 N 輪對話,超出視窗的直接丟棄。
程式碼解析:ArrayDeque 作為佇列,offer() 在尾部新增,當大小超出 windowSize * 2(因為一輪包含使用者和助理兩條訊息)時,poll() 移除最舊的。
這樣視窗始終保持固定大小。
優點:
缺點:
適用場景:客服快速問答、閒聊機器人、臨時對話——那些不需要記住早期資訊的場景。
讓 AI 自己總結記憶。
這個方案的想法很巧妙:不保留原始對話,而是定期讓大模型把舊對話「壓縮」成一段摘要,只保留關鍵資訊。
程式碼詳解:
summary 欄位儲存壓縮後的歷史摘要,初始為空。recentMessages 儲存尚未被壓縮的新訊息。compress()。recentMessages,但也可以選擇保留最後 1-2 輪,防止摘要丟失近期細節。buildContext() 回傳摘要 + 最近訊息的拼接,作為下次請求的上下文。優點:
缺點:
適用場景:長週期對話(幾十到幾百輪),對資訊完整性要求不是 100% 嚴謹的場景,比如教育輔導、角色扮演。
檢索相關而不是保留全部。
這是目前工業界最主流的方案。
思路是:不保存全部歷史,而是把歷史訊息向量化後存入資料庫,每次只檢索最相關的幾條歷史。
程式碼詳解:
embeddingClient.embed() 將其轉為高維向量(比如 1536 維)。topK 條歷史訊息。優點:
缺點:
適用場景:絕大多數生產環境——智能客服、AI 助手、個人化推薦等。
這是目前最推薦的方案。
它是工業級最強方案。
沒有單一方案是完美的。真正的工業級系統,往往會組合多種策略,形成分層記憶。
下面這張圖展示了一個典型的混合記憶架構:
Java 實現的核心骨架:
程式碼解析:
優點:
缺點:
適用場景:大型生產系統、企業級 AI 應用,對體驗和成本都有高要求的場景。
該方案需要極致的結構化壓縮。
有些場景下,真正需要記憶的不是整個對話,而是幾個關鍵狀態變數。
比如訂票機器人只需要知道:{目的地: "北京", 日期: "2026-05-01", 人數: 2}。
優點:
缺點:
適用場景:任務型對話、表單填寫、配置導引。
把記憶「外包」給外部系統。
大模型不是萬能的,記憶完全可以交給外部資料庫。
模型只需要學會呼叫「儲存記憶」和「查詢記憶」的工具。
這種方案讓模型自主管理記憶——它覺得重要就存,需要就用。這是目前 AI Agent 的主流做法。
優點:極其彈性,模型可以按需存取;token 消耗幾乎為零(只傳工具呼叫結果)。
缺點:依賴模型自身的函式呼叫能力,容易出錯或漏存。
適用場景:Agent 系統、自主決策類應用。
| 方案 | token 節省效果 | 資訊保留能力 | 實作複雜度 | 推薦指數 |
|---|---|---|---|---|
| 全量記憶 | 0%(無節省) | 100% | ⭐ | ❌ 不推薦 |
| 滑動視窗 | 極高(固定) | 差(只留近期) | ⭐⭐ | ⭐⭐⭐ 短對話可用 |
| 摘要壓縮 | 高(70-90%) | 中(可能失真) | ⭐⭐⭐ | ⭐⭐⭐⭐ 長對話 |
| 向量檢索(RAG) | 高(每次 topK) | 高(語義檢索) | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ 首選 |
| 分層混合 | 高極高 | 高極高 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ 工業級 |
| 狀態變數 | 極高(近乎 0) | 中(僅結構化) | ⭐⭐⭐ | ⭐⭐⭐⭐ 任務型 |
| 工具呼叫 | 極高 | 中(靠模型) | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ Agent 場景 |
更多項目實戰在 Java 突擊隊網:susan.net.cn
回到最初的問題:有沒有方案既能保留上下文記憶,又能省 token?
我的答案是:有,但不存在「免費午餐」。
每一分 token 的節省,都換來了系統複雜度的增加或記憶精度的下降。
根據我的實戰經驗,給你幾條直接的建議:
posted @ 蘇三說技術 閱讀(0) 評論(0) MD 編輯 收藏 檢舉