指南)
上個月我在排查一個問答機器人的線上事故用戶在第31輪對話時問了一個極其基礎(chǔ)的問題機器人卻給出了完全驢唇不對馬嘴的答案。翻了一大圈日志最終定位到根因模型壓根就沒看到用戶這句話——它還沒進模型呢就被前面的上下文管理模塊給截斷了。這個故障讓我重新把大模型應(yīng)用里最容易被忽視、卻也最要命的環(huán)節(jié)翻出來研究了一遍也就是今天要聊的 context-mode上下文模式。這個場景挺典型的。很多人在做 RAG檢索增強生成、對話機器人、Agent 工作流時一開始只關(guān)心模型選型、Prompt 設(shè)計、知識庫怎么切分結(jié)果系統(tǒng)一上線就被上下文相關(guān)的問題反復(fù)折磨對話輪數(shù)一多就失憶長文檔分析時關(guān)鍵信息被淹沒在海量文本里Token 成本居高不下甚至模型突然開始胡言亂語。這些問題表面上看五花八門深挖下去全都指向同一個根源——你沒有用正確的 context-mode 來管理上下文。這篇文章我會把 context-mode 掰開揉碎講清楚它是什么、有哪些落地形態(tài)、上下文預(yù)算怎么算、代碼怎么寫以及我過去半年踩過的那些坑和排查思路。適合正在做大模型應(yīng)用開發(fā)、尤其是對話系統(tǒng)和 RAG 項目的工程師參考也適合剛?cè)腴T想搞懂上下文管理原理的同學(xué)。1. 從一次線上事故說起為什么 context-mode 值得單獨拎出來講1.1 那個讓人失眠的失憶Bug先把這個事故展開說說。那是一個基于知識庫的問答機器人接入的是主流大模型 API對話歷史存在 Redis 里每次請求把最近 N 輪消息拼進 Prompt 發(fā)給模型。上線時只測了 5 輪以內(nèi)的對話一切正常。結(jié)果用戶實際使用起來聊到二三十輪機器人就開始慢慢癡呆再往后連用戶剛說完的話都會忽略。我最初懷疑是 Prompt 工程的問題調(diào)了好幾版系統(tǒng)提示詞沒用。然后又懷疑是模型溫度參數(shù)太高降了 Temperature還是沒用。最后把發(fā)送給模型的實際請求體抓出來一看整個人都愣住了因為拼接歷史消息的代碼用了簡單的截斷邏輯——超過最大 token 數(shù)就從頭丟棄舊消息按輪數(shù)來算第31輪提問時前 30 輪對話加上系統(tǒng)提示詞已經(jīng)把 8K 的上下文窗口塞得滿滿當當。用戶最新的那句話是在截斷之后才追加進去的于是被模型視而不見。這個事故的教訓(xùn)非常深刻上下文窗口不是無限物理空間模型能看到什么完全取決于你在調(diào)用之前怎么組織進入窗口的內(nèi)容。這個在調(diào)用模型之前對上下文的獲取、篩選、裁剪、排序和注入策略就是 context-mode 的實戰(zhàn)含義。1.2 一句話定義 context-mode如果非要用一句話概括我會說context-mode 是控制大模型視野范圍的策略機制它決定哪些信息進入上下文窗口、以什么順序進入、以及放不下的時候舍棄什么。這里面有三個關(guān)鍵動作第一是選什么不是所有對話歷史和資料都值得給模型看第二是怎么放系統(tǒng)提示詞、歷史消息、外部知識之間要有優(yōu)先級和結(jié)構(gòu)第三是放不下怎么辦窗口總會有上限必須有降級方案。這三件事合在一起構(gòu)成了一套完整的上下文管理方案而不是某個單一參數(shù)或者某個模型的特性。1.3 適合誰看、解決了什么問題這篇文章對三類人最有價值一是對話式 AI 應(yīng)用的開發(fā)者你需要一套能扛住長對話的方案二是做 RAG 應(yīng)用的同學(xué)你會遇到檢索結(jié)果太多反而干擾回答的問題本質(zhì)上也是 context-mode 的編排問題三是想搞懂模型輸入側(cè)原理、想控制成本的產(chǎn)品或技術(shù)負責人。讀完你至少能回答三個問題我的應(yīng)用當前用的是哪種 context-mode它合不合理如果出現(xiàn)上下文相關(guān)的故障我該怎么排查2. context-mode 的四種主流落地形態(tài)選型前先認清區(qū)別在實際工程里context-mode 不是一個開關(guān)而是一組策略的統(tǒng)稱。我把它梳理成四種主流的落地形態(tài)它們各有適用場景也有各自的代價。很多系統(tǒng)從一開始就有意無意地用了其中一種只是沒有系統(tǒng)性地思考過。2.1 截斷模式最粗暴也最常用截斷模式Truncate Mode是絕大多數(shù)團隊第一版會采用的方式限制消息輪數(shù)或 token 數(shù)超了就從頭部丟棄舊消息。實現(xiàn)極簡單幾乎不消耗額外資源接口延遲穩(wěn)定。但它是典型的頭痛醫(yī)頭方案你永遠不知道被丟掉的那部分歷史里有沒有對當前問題至關(guān)重要的信息。我見過有人用先進先出策略保留系統(tǒng)提示詞和最近 N 輪也有人用先進后出保留開頭幾輪和最新幾輪丟掉中間。后者在某些客服場景里更實用因為用戶描述問題通常在開頭而當前訴求在結(jié)尾。但無論哪種本質(zhì)上都是在做概率博弈——賭被丟掉的內(nèi)容不重要。當對話輪數(shù)超過閾值模型就會出現(xiàn)記憶斷層而這種斷層用戶感知非常明顯信任感會急劇下降。截斷模式適合極短對話場景比如一次性問答、表單式交互或者預(yù)算極其敏感的簡單場景。只要預(yù)期對話輪數(shù)不超過 10 輪它可以是最優(yōu)解一旦超過你就得認真考慮升級方案了。2.2 摘要模式用理解換空間摘要模式Summarize Mode的思路是既然歷史消息占地方那就把早期的對話壓縮成摘要釋放出空間給新內(nèi)容。實現(xiàn)方式通常有兩條路線一是滾動摘要每 N 輪觸發(fā)一次把歷史消息丟給模型生成一段摘要之后用這段摘要替代原文二是按話題聚類對話切換主題時對上一個主題做歸檔摘要當前主題保留完整細節(jié)。摘要模式的最大好處是能記住更久之前的事情對話可以拉得很長。代價也很明顯摘要過程本身要額外消耗 token 和時間而且摘要是不可逆的——模型在壓縮時可能丟掉你認為重要但它覺得不重要的細節(jié)比如用戶提到的某個具體編號、某個時間節(jié)點甚至情緒傾向。一旦摘要生成錯誤錯誤會被凍結(jié)在上下文里后續(xù)所有回答都會被帶偏。所以做摘要模式時我強烈建議不只存一份摘要而是保留摘要 原始終端的最近 K 輪兩層結(jié)構(gòu)。摘要負責長期記憶原始消息負責近期細節(jié)這樣即使摘要丟了對最近的準確度影響也不大。預(yù)算充足時可以在摘要前加一輪關(guān)鍵信息抽取專門提取容易被漏掉的實體、數(shù)字和條件再與摘要合并存儲。2.3 檢索模式按需取用檢索模式Retrieval Mode是目前 RAG 場景最常用的一種 context-mode不把全部歷史或全部資料塞進窗口中而是根據(jù)當前問題從外部存儲向量數(shù)據(jù)庫、ES、甚至關(guān)系型數(shù)據(jù)庫里檢索出最相關(guān)的片段只把這些片段注入上下文。這個模式的核心挑戰(zhàn)在于相關(guān)性的判斷質(zhì)量檢索不準上下文再精煉也是白搭。我在實踐中的體會是檢索模式不能只做一層。純向量檢索在語義相近但關(guān)鍵詞不同的場景下表現(xiàn)不錯但在面對精確數(shù)字查詢、指定條件過濾時就容易翻車。更穩(wěn)的做法是向量檢索 關(guān)鍵詞召回 重排模型的混合管線向量負責找語義相似的候選BM25 或倒排索引負責保證精確命中最后用一個重排模型Reranker把兩路結(jié)果合并打分截取 Top-K 注入上下文。檢索模式的另一個隱含問題是檢索進上下文的片段之間可能互相矛盾。比如用戶兩次問類似問題檢索到的知識庫片段版本不同模型就會困惑并產(chǎn)生幻覺。我在后面第 5 部分會專門講這個上下文污染問題它是檢索模式最隱蔽的坑。2.4 路由與混合模式生產(chǎn)環(huán)境里的真相成熟的系統(tǒng)幾乎不會只用某一種單一模式而是用路由Routing把不同場景分派給不同策略甚至在一次請求內(nèi)部組合多種模式。這就是我所說的混合模式Hybrid Mode。比如第一輪直接走完整對話不加摘要第二輪起歷史超過閾值就把早期內(nèi)容摘要化如果當前問題命中用戶明確指定的某份文檔就優(yōu)先走檢索模式把文檔片段放在對話歷史之前?;旌夏J铰犉饋韽?fù)雜但本質(zhì)上你需要實現(xiàn)的就是一個策略路由給定輸入根據(jù)規(guī)則或分類模型決定走截斷、摘要還是檢索。規(guī)則的粒度可以是對話輪數(shù)閾值、token 占用比例、是否包含檢索意圖的關(guān)鍵詞等。工程上并不需要一次到位可以先寫死規(guī)則跑出數(shù)據(jù)后再慢慢上模型判斷。這個模式最大的價值在于容錯當檢索結(jié)果質(zhì)量不佳時摘要歷史還能兜底當摘要丟失關(guān)鍵信息時原始消息的最近 K 輪還能補位當對話很短時又不愿意多花摘要的錢。多種策略互相疊加比單一策略能扛更多極端場景。3. 核心參數(shù)與計算邏輯手把手教你算清上下文預(yù)算很多上下文問題本質(zhì)上不是模型能力問題而是預(yù)算估算失誤。你以為塞進窗口的是 2000 token實際可能是 8000。這一部分我把 Token 計費、窗口分配、動態(tài)水位線這些最要命的計算邏輯講透全部可以直接套用。3.1 Token 不是字數(shù)先搞懂單位換算Token 是模型處理文本的最小單位一個 token 不一定是一個字它可能是半個詞、一個詞、一個標點甚至幾字節(jié)。中文場景最實用的估算方法是1 個漢字大約對應(yīng) 1.5 到 2 個 token1 個英文單詞大約對應(yīng) 1.3 到 1.5 個 token。穩(wěn)妥起見做容量規(guī)劃時我會按中文 2 token/字、英文 1.5 token/詞的上限來估算留出緩沖。舉個例子一段 500 字的中文產(chǎn)品說明按 2 換算就是約 1000 token。如果你用的是 8K 上下文的模型這筆賬就要這么算系統(tǒng)提示詞占 1500外部文檔占 2500一輪用戶消息加助手回復(fù)大概 400 token那么 8K 窗口最多只能裝 (8000 - 1500 - 2500) / 400 10 輪對話。超過這個輪數(shù)無論你代碼里怎么拼最終都會被 API 服務(wù)端截斷。這個計算一定要前置不要等線上爆了再回頭算。3.2 上下文窗口的三層分配法我建議把所有進入上下文窗口的內(nèi)容分成三層按優(yōu)先級順序分配預(yù)算第一層是系統(tǒng)提示詞與任務(wù)指令包括角色設(shè)定、輸出格式、回答邊界這部分絕對不能被截斷預(yù)算占比建議 10% 到 20%。第二層是外部知識和檢索結(jié)果這是回答問題的資料占比建議 40% 到 50%但如果檢索質(zhì)量不高寧可少給不要硬塞。第三層是對話歷史占比建議 30% 到 50%且必須按從新到舊排列最近的對話擁有最高保留優(yōu)先級。這個分配比例不是拍腦袋。系統(tǒng)提示詞決定模型的行為框架沒了它模型就像沒領(lǐng)到任務(wù)的實習(xí)生外部知識決定回答的信息來源是用戶價值的核心對話歷史則負責提供對話連續(xù)性和用戶偏好。三者如果爭搶空間犧牲的順序應(yīng)該是對話歷史中最舊的部分而不是壓縮系統(tǒng)提示詞更不是砍掉檢索資料。3.3 一個可復(fù)用的預(yù)算公式我在項目里通常會維護一個工具函數(shù)它接收模型窗口上限、系統(tǒng)提示詞 token 數(shù)、外部知識 token 數(shù)然后返回當前可用的歷史消息輪數(shù)??捎脷v史 Token 窗口上限 - (系統(tǒng)提示詞 Token 外部知識 Token 安全緩沖) 可用對話輪數(shù) 可用歷史 Token / 單輪平均 Token安全緩沖一般是窗口上限的 10% 到 15%用于應(yīng)對 Token 計數(shù)偏差和模型可能追加輸出占用的位置。注意許多 API 的輸入和輸出共享同一個上下文窗口模型答復(fù)也會占用空間。如果忽略了輸出預(yù)留你在輸入側(cè)壓滿窗口模型可能只能輸出很短就觸頂。再給個實際案例模型窗口 128K系統(tǒng)提示詞 2000知識庫檢索需注入 15000安全緩沖 10% 即 12800那么可用歷史 Token 就是 128000 - 2000 - 15000 - 12800 98200。假設(shè)單輪對話平均 800 Token你可以保留約 122 輪歷史。但如果系統(tǒng)提示詞被某次迭代膨脹到 8K知識檢索又調(diào)大到了 50K那可用歷史就只剩 57200可保留輪數(shù)直接掉到 71 輪。你的上下文策略不變但效果會肉眼可見地下降——這就是為什么每次改動 Prompt 或檢索策略后都要重新算一遍預(yù)算。3.4 用水位線動態(tài)調(diào)整窗口策略固定閾值的問題在于它是靜態(tài)的而對話是動態(tài)的。我采用的方法是定義一個三段水位線當已用 Token 低于窗口的 50% 時走完整歷史模式不做任何壓縮和摘要保證信息無損。當達到 50% 到 80% 時開啟溫和壓縮策略把最舊的對話按話題聚合成摘要保留當前話題的完整原文。當超過 80% 時進入緊急模式全部歷史改為摘要 最近 5 輪原始消息檢索結(jié)果只保留重排后的 Top 3系統(tǒng)提示詞裁剪掉冗長的示例。這個水位線的具體數(shù)值可以根據(jù)你的成本和體驗?zāi)繕苏{(diào)整但思路是關(guān)鍵不要等窗口快滿了才手忙腳亂地截斷而要提前分層降級。用戶是無感的但模型看到的上下文結(jié)構(gòu)始終處于健康狀態(tài)。4. 落地實現(xiàn)一個支持多模式切換的 context 管理器講完選型和參數(shù)這一部分直接上工程實現(xiàn)。我會展示一個極簡但足夠支撐生產(chǎn)環(huán)境的 ContextManager 核心結(jié)構(gòu)它在設(shè)計上預(yù)留了模式插槽方便你按需要替換具體策略。4.1 工程結(jié)構(gòu)設(shè)計核心類只做三件事記錄消息、管理模式、構(gòu)建最終發(fā)給模型的消息列表。from enum import Enum from typing import List, Dict, Optional class ContextMode(Enum): TRUNCATE truncate SUMMARIZE summarize RETRIEVAL retrieval HYBRID hybrid class ContextManager: def __init__(self, max_tokens: int 8000, mode: ContextMode ContextMode.HYBRID): self.max_tokens max_tokens # 模型上下文窗口上限 self.system_prompt 你是智能助手... # 系統(tǒng)提示詞單獨存儲 self.history: List[Dict] [] # 編碼后的歷史消息 {role: ..., content: ...} self.summary: Optional[str] None # 長期摘要 self.mode mode def add_message(self, role: str, content: str) - None: # 先選擇是否觸發(fā)摘要壓縮再追加新消息 if self._should_summarize(): self._roll_summary() self.history.append({role: role, content: content}) def build_context(self, query: str, extra_docs: Optional[List[str]] None) - List[Dict]: # 根據(jù)模式和 token 預(yù)算組裝最終消息列表 ...實際工程中我會把 System Prompt 單獨存一份從來不塞進 history它是所有模式都要無條件保留的骨架。history 里的每一條都記錄消息內(nèi)容和 token 估算值避免每輪臨時重新計算整段 token。4.2 截斷與摘要的代碼骨架截斷模式的核心是裁剪后的消息列表必須保持在預(yù)算內(nèi)。比較穩(wěn)的做法是先計算整體 token再按從新到舊的順序逐條往回加直到預(yù)算耗盡。def _build_truncate_context(self) - List[Dict]: result [{role: system, content: self.system_prompt}] remain self.max_tokens - estimate_tokens(self.system_prompt) - RESERVED_OUTPUT # 從最新消息往前加始終保持新消息優(yōu)先 for msg in reversed(self.history): t estimate_tokens(msg[content]) 4 # 4 是角色標記等額外開銷 if remain - t 0: break result.append(msg) remain - t # 由于是倒序追加需要翻轉(zhuǎn)回時間正序 non_system [m for m in result[1:]][::-1] return [result[0]] non_system注意這個順序處理很多人直接正序遍歷舊消息結(jié)果最新消息反而被截斷就是最開始說的那個事故。摘要模式則是在截斷之外把早期歷史送給摘要模型再把 summary 以system身份注入def _roll_summary(self) - None: # 取最舊的若干消息生成摘要替代原始內(nèi)容 target self.history[:-KEEP_RECENT] # KEEP_RECENT 為保留的最近消息數(shù) if not target: return prompt f請把以下對話壓縮為不超過300字的摘要保留關(guān)鍵數(shù)字、實體和用戶偏好{target} self.summary call_llm(prompt) self.history self.history[-KEEP_RECENT:]實際操作里摘要生成不能把整個歷史全塞進一個 Prompt要做分塊聚合。先對每 10 輪生成一個分段摘要再把這些分段摘要合并成最終摘要避免長文本超出摘要模型自身的窗口。4.3 檢索模式接入檢索模式與截斷/摘要最大的區(qū)別是它不依賴 history 作為主要上下文而是由外部檢索結(jié)果主導(dǎo)。接口上ContextManager 需要接受外部傳入的 docs并把它們按知識片段的形式放在 system prompt 之后、對話歷史之前def _build_retrieval_context(self, query: str, docs: List[str]) - List[Dict]: knowledge \n\n.join(f[資料{i1}] {doc} for i, doc in enumerate(docs)) k_system self.system_prompt \n\n請嚴格依據(jù)以下資料回答\n knowledge return [{role: system, content: k_system}] self._build_truncate_context()注意這里的優(yōu)先級順序知識片段跟著系統(tǒng)提示詞走而不是跟著用戶消息走。這樣模型會把知識當作必須遵守的背景材料而不是把它當作普通的歷史對話。檢索結(jié)果的排序也很有講究我在拼接前會用重排模型把最相關(guān)的三個片段放在最前面并在片段之間加序號。實踐表明模型對前兩個片段的關(guān)注度顯著高于后面的Top 3 之后的片段很多情況下只是湊數(shù)甚至帶來噪聲。4.4 模式切換的自動決策規(guī)則混合模式的實現(xiàn)核心是決策函數(shù)。我建議先用可解釋的規(guī)則不要一上來就用分類模型因為你很難調(diào)試。def decide_mode(self, query: str, docs: Optional[List[str]] None) - ContextMode: used_ratio self.estimate_used_tokens() / self.max_tokens if docs and self._has_retrieval_intent(query): return ContextMode.RETRIEVAL if used_ratio 0.5: return ContextMode.SUMMARIZE return ContextMode.TRUNCATE檢索意圖的判斷可以樸素一點用戶問的是知識庫中存在的事實性問題且問題中包含主體名詞就優(yōu)先走檢索如果是閑聊或延續(xù)性追問就走歷史模式。這個規(guī)則雖然簡單但比所有請求一律檢索要省錢且更準。等積累足夠多的日志后再把 decision 換成小粒度分類模型但決策函數(shù)的外部接口保持不變。5. 我踩過的那些坑context 相關(guān)的典型故障與排查這部分是我最想分享的實戰(zhàn)內(nèi)容。上下文管理的問題有一個特點現(xiàn)象在模型輸出側(cè)根因在輸入側(cè)排查鏈路過長非常容易誤判。我把典型的故障現(xiàn)象、根因和排查路徑整理成了一張速查表。5.1 癥狀與根因速查表癥狀可能根因排查方向?qū)υ捿啍?shù)一多就失憶截斷策略把早期關(guān)鍵信息丟棄檢查實際發(fā)給模型的請求體確認截斷順序模型重復(fù)說同一句話上下文窗口內(nèi)信息冗余模型陷入自激檢查歷史中是否存在大量近似重復(fù)的助手回復(fù)回答與資料不符檢索結(jié)果內(nèi)混入低相關(guān)片段干擾判斷檢查注入的知識排序和閾值響應(yīng)延遲突然升高注入 token 太多或摘要生成鏈路過長統(tǒng)計各模式下的平均請求 token 數(shù)用戶連續(xù)追問時答非所問模式切換邏輯錯誤檢索模式丟失了對話意圖查看決策函數(shù)的輸入特征是否包含最近提問這張表我在團隊里貼了好幾個月每次線上出問題第一件事不是去調(diào) Prompt而是先對著這個表做輸入側(cè)體檢。結(jié)果發(fā)現(xiàn)超過一半的上下文問題都不是模型問題而是消息構(gòu)建不對、預(yù)算估算錯誤或模式切換策略不合理。這個認知很重要別一遇到輸出不對就調(diào) Prompt先往前看輸入。5.2 上下文污染的隱形殺手5.3 上下文污染的隱形殺手上下文污染是我排查時最頭疼的問題它隱蔽在正常輸出之下極難察覺。最常見的污染源有三個第一是系統(tǒng)提示詞里殘留了之前實驗用的示例內(nèi)容比如你測試過旅游推薦忘了刪掉示例后面所有回答都被帶出旅游行業(yè)的味道第二是工具調(diào)用的結(jié)果殘留Agent 調(diào)用搜索引擎后把大段 HTML 或 JSON 結(jié)果留在上下文中后面幾輪即使與搜索無關(guān)這段噪聲也在持續(xù)影響模型第三是檢索片段之間的矛盾知識庫不同版本對同一問題的回答沖突模型為了調(diào)和兩者產(chǎn)出了一個看似合理但兩邊都不沾的幻覺答案。針對污染問題我的排查經(jīng)驗是把發(fā)送給模型的完整消息列表可視化逐條標出每條消息的來源標簽。標注來源后污染源通常一眼就能看出來。修復(fù)手段不是簡單刪除而是給非必要的工具結(jié)果和低置信度檢索片段設(shè)置過時淘汰機制——比如工具結(jié)果只保留最近一輪檢索片段在規(guī)定輪數(shù)后自動移除。干凈上下文是模型輸出的地基這遠比優(yōu)化模型參數(shù)管用。5.4 排查利器上下文可視化與最小復(fù)現(xiàn)分享兩個非常有效但很少被人提到的排查手段。第一個是上下文可視化抓包在代碼里封裝一個 debug 開關(guān)把每次實際發(fā)給模型的消息按照 system/user/assistant 分段打印標注每段的 token 占比和來源。線上開啟之后問題復(fù)現(xiàn)時我能在幾秒內(nèi)看到模型到底看了什么。第二個是最小復(fù)現(xiàn)法拿到故障請求后不斷裁剪上下文直到問題從復(fù)現(xiàn)變成不復(fù)現(xiàn)被裁剪掉的部分就是可疑信息。用二分法手工刪除通常七八次定位就能找到根因。這兩個手段比反復(fù)修改 Prompt 要高效得多。我自己有個切身體會有一次模型反復(fù)輸出格式錯誤的 JSON我調(diào)了二十多版提示詞都沒用最后用最小復(fù)現(xiàn)法發(fā)現(xiàn)問題出在歷史消息里有一條被截斷了半個字的舊用戶消息觸發(fā)了模型的補救心理導(dǎo)致它在 JSON 里塞了額外的解釋文本。這種坑只有把輸入側(cè)完完整整攤開看才能發(fā)現(xiàn)。5.5 三個省 Token 的實操技巧最后聊一下大家最關(guān)心的成本問題。在上下文預(yù)算里省錢核心不是一味壓縮而是減少無效注入。我長期使用三個技巧第一個是去重再注入。檢索出的 Top K 片段之間經(jīng)常有大量重復(fù)內(nèi)容比如同一份文檔的多個分塊互相重疊。在拼接進上下文之前先做一次基于 MinHash 或簡單文本哈希的相似度去重通常能砍掉 10% 到 20% 的 token而且回答質(zhì)量不降反升。第二個是指令瘦身。系統(tǒng)提示詞里經(jīng)常堆了大量示例和冗長的邊界描述但模型根本用不到那么多。把到一個穩(wěn)定版本后你可以做一次精簡把每條指令拿掉跑一遍回歸測試集如果輸出質(zhì)量不變就永久拿掉這個過程反復(fù)迭代幾次系統(tǒng)提示詞能縮到 60%。第三個是把歷史降采樣做到策略里。對早期對話不需要每一條都保留完整原文每隔 N 條取一條快照就能維持連續(xù)性再配合摘要兜底。這個方案比全量摘要更便宜也比純截斷更安全。我目前的主力項目就是這個策略在支撐長會話場景成本比最初的全量歷史方案下降了差不多 40%用戶的失憶投訴基本消失。6. 寫在最后的幾條個人體會做上下文管理這一年多有個很深的體會很多人把大模型應(yīng)用的核心競爭力押在模型選擇和 Prompt 上但上線之后真正拉開體驗差距的往往是 context-mode 這種輸入側(cè)基建。模型再強看不到該看的信息輸出也是空中樓閣上下文組織得好哪怕是通用模型也能在復(fù)雜任務(wù)里表現(xiàn)得像定制模型。如果你現(xiàn)在正要開始做一個 AI 應(yīng)用我的建議很簡單先花一晚上把上下文預(yù)算公式寫出來再選擇一個 ContextManager 骨架給每一種模式做好插槽不要急著在第一個版本里就把所有策略都寫滿。從截斷開始加上水位數(shù)統(tǒng)計當數(shù)據(jù)證明你需要摘要和檢索時再逐步引入。這個演進路線比一開始就堆復(fù)雜方案要穩(wěn)妥得多。最后再說一個小技巧給每條進入上下文的消息打一個來源標簽字段它可以是一條 debug 注釋也可以是一個結(jié)構(gòu)化元數(shù)據(jù)。這個習(xí)慣看起來不起眼但在你排查幻覺問題、分析 token 消耗、優(yōu)化策略路由時能讓你少走無數(shù)彎路。上下文管理是細活所有省下的時間最后都會以故障的形式還回來。把基礎(chǔ)打牢比臨時抱佛腳調(diào) Prompt 有用一萬倍。