戰(zhàn):解決大模型對(duì)話失憶的上下文管理策略)
我最早被“失憶”坑到是在做一個(gè)客服機(jī)器人項(xiàng)目。線上跑了兩個(gè)月前20輪對(duì)話一切正常到第35輪左右機(jī)器人突然開(kāi)始一本正經(jīng)地編造訂單狀態(tài)甚至把A用戶的數(shù)據(jù)安到B用戶頭上。我第一反應(yīng)是模型能力不行差點(diǎn)去換底座大模型。后來(lái)把請(qǐng)求日志翻出來(lái)對(duì)比才發(fā)現(xiàn)問(wèn)題根本不在推理而在上下文——發(fā)給模型的消息列表里最早的約束已經(jīng)被擠出了窗口模型壓根沒(méi)“看見(jiàn)”它。從那天起我開(kāi)始認(rèn)真研究context-mode也就是上下文管理模式。簡(jiǎn)單說(shuō)就是你決定“把哪些內(nèi)容放進(jìn)模型這一次請(qǐng)求里”的策略。它解決的核心問(wèn)題不是模型會(huì)不會(huì)推理而是模型能不能拿到足夠且正確的信息來(lái)推理。這篇文章我會(huì)把我在實(shí)際項(xiàng)目里落地的幾種context-mode方案、代碼、量化對(duì)比和踩過(guò)的坑全部寫出來(lái)希望能幫正在做Chatbot、AI Agent、RAG應(yīng)用的人少走一點(diǎn)彎路。1. context-mode要解決的是哪個(gè)“失憶”問(wèn)題1.1 一次讓我尷尬的項(xiàng)目事故先說(shuō)前面提到的那個(gè)客服機(jī)器人。業(yè)務(wù)方要的是一個(gè)能處理“訂單查詢、退換貨、催開(kāi)發(fā)票”的助手我們?cè)缙趯?shí)現(xiàn)非常簡(jiǎn)單把聊天歷史全部塞進(jìn)prompt丟給模型讓它回答。demo階段一切美好因?yàn)榇蠹覝y(cè)試最多聊十輪八輪。但上線后真實(shí)用戶不會(huì)按你的劇本走有人連著聊了五六天同一個(gè)會(huì)話里反復(fù)追問(wèn)不同訂單的狀態(tài)。然后事故就來(lái)了。第30輪之后模型開(kāi)始“忘記”用戶最開(kāi)始強(qiáng)調(diào)的“我是白金會(huì)員所有優(yōu)惠都要按最高折扣算”。更離譜的是有一輪我手動(dòng)翻日志發(fā)現(xiàn)模型把用戶A的收貨地址當(dāng)成用戶B的來(lái)比對(duì)。Root cause非常清晰模型一次請(qǐng)求的上下文窗口有限消息列表只能容納最近的十幾輪內(nèi)容早期關(guān)鍵信息被后面的對(duì)話給“擠沒(méi)”了。這個(gè)事故讓我意識(shí)到做AI應(yīng)用和做傳統(tǒng)后端完全不同。你不只是在寫一套接口你是在替模型決定“它應(yīng)該看什么材料”。這個(gè)決策本身就是應(yīng)用的核心邏輯。1.2 上下文窗口的本質(zhì)模型并沒(méi)有“記住”很多人對(duì)上下文窗口有個(gè)錯(cuò)誤理解覺(jué)得模型聊得多了就“記得”前面聊了什么。實(shí)際上大語(yǔ)言模型的上下文窗口更像是一個(gè)臨時(shí)的“閱讀稿”。它只在這一次推理時(shí)把窗口里的內(nèi)容全部讀一遍然后生成回復(fù)生成完了這次讀過(guò)的內(nèi)容就丟了。下次推理你又重新把材料遞進(jìn)去。所以所謂“長(zhǎng)記憶”根本不是模型的能力項(xiàng)而是應(yīng)用層不斷把歷史內(nèi)容搬回窗口里。窗口總是有限的GPT-4o一類的模型常見(jiàn)上下文是128K token看著很大但真實(shí)業(yè)務(wù)里塞幾個(gè)長(zhǎng)文檔、幾十輪歷史、一段工具返回結(jié)果很快就能吃滿。而且窗口越大單次請(qǐng)求的成本和延遲也跟著漲。context-mode的本質(zhì)就是在這個(gè)“有限的閱讀稿”里做取舍決策。它需要回答三個(gè)問(wèn)題哪些內(nèi)容必須進(jìn)窗口哪些內(nèi)容可以降級(jí)處理哪些內(nèi)容可以直接丟棄1.3 context-mode的三個(gè)核心指標(biāo)我在項(xiàng)目里給自己定了三個(gè)可量化的指標(biāo)所有模式優(yōu)化都圍繞它們來(lái)評(píng)估信息保留率模型回答需要的關(guān)鍵實(shí)體、約束、指令最終是否還留在上下文里。我一般用一組構(gòu)造好的“必須知道”測(cè)試題來(lái)驗(yàn)證比如把用戶設(shè)置的折扣約束放進(jìn)第40輪歷史看第50輪模型還能不能復(fù)述出來(lái)。單輪token成本每發(fā)一次請(qǐng)求實(shí)際消耗的輸入token數(shù)量。這直接決定賬單大小特別是高頻客服場(chǎng)景成本差一倍月結(jié)單就完全不同。響應(yīng)延遲上下文越長(zhǎng)prefill階段耗時(shí)越長(zhǎng)。正常情況下幾百token和幾千token差距不大但一旦塞入上萬(wàn)token首字延遲會(huì)明顯上升。所有context-mode方案本質(zhì)都是在三者之間找一個(gè)適合業(yè)務(wù)場(chǎng)景的平衡點(diǎn)。沒(méi)有最優(yōu)只有最合適。2. 三種主流context-mode的取舍滑動(dòng)窗口、摘要壓縮、檢索增強(qiáng)2.1 滑動(dòng)窗口把最近N輪留下滑動(dòng)窗口是最容易想到的方案也是我當(dāng)時(shí)第一個(gè)實(shí)現(xiàn)的方式。思路很簡(jiǎn)單每條消息按時(shí)間排序構(gòu)造請(qǐng)求時(shí)只取最新的若干條直到接近token預(yù)算就截止。它的最大優(yōu)勢(shì)是行為可預(yù)期。代碼量小邏輯直白不會(huì)出現(xiàn)“模型因?yàn)檎^(guò)擬合而胡說(shuō)”的情況。你放進(jìn)去的就是原文模型讀到的東西沒(méi)有經(jīng)過(guò)二次加工信息失真風(fēng)險(xiǎn)低。但它有個(gè)非常致命的短板早期關(guān)鍵信息會(huì)被無(wú)差別丟棄??头永锏陌捉饡?huì)員約束如果是第2輪說(shuō)的第35輪已經(jīng)不在窗口里了模型根本不知道這個(gè)約束存在。所以滑動(dòng)窗口只適合那種“最新內(nèi)容最重要”的場(chǎng)景比如閑聊機(jī)器人、短期任務(wù)助手。2.2 摘要壓縮把對(duì)話變成“工作筆記”摘要壓縮是我第二個(gè)嘗試的模式。它的動(dòng)機(jī)很簡(jiǎn)單模型真正需要的往往不是對(duì)話的逐字原文而是其中蘊(yùn)含的“事實(shí)和意圖”。與其保留每一句話不如定期讓模型把歷史對(duì)話整理成一份結(jié)構(gòu)化摘要下次請(qǐng)求時(shí)把摘要加原文一起放進(jìn)窗口。舉個(gè)例子用戶在第3輪說(shuō)“我周五要去上海出差幫我訂虹橋附近的酒店”后面又聊了一堆茶葉價(jià)格之類無(wú)關(guān)話題。第20輪用戶說(shuō)“幫我看看之前說(shuō)的酒店”這時(shí)候模型需要的是“周五、上海、虹橋附近”這幾個(gè)信息而不是中間17輪閑聊。我的實(shí)現(xiàn)方式是滾動(dòng)摘要每隔一段時(shí)間或一定token量把當(dāng)前摘要與新消息一起丟給模型生成更新的摘要。這類似工作里記筆記不斷往里補(bǔ)增量。摘要壓縮的優(yōu)點(diǎn)是信息保留率高能把大量歷史濃縮成幾百字并且保留全局語(yǔ)義。缺點(diǎn)也很明顯摘要本身有損壓縮過(guò)程中可能丟掉關(guān)鍵細(xì)節(jié)而且摘要調(diào)用本身也要花token和時(shí)間。2.3 檢索增強(qiáng)讓上下文不再連續(xù)而是“按需取用”檢索增強(qiáng)是我后來(lái)最常用的模式也就是把上下文從“連續(xù)的切面”變成“可查詢的知識(shí)庫(kù)”。核心思路是每條歷史消息都向量化存入向量數(shù)據(jù)庫(kù)當(dāng)用戶提出新問(wèn)題時(shí)先對(duì)問(wèn)題做語(yǔ)義檢索只把相關(guān)的歷史消息片段取出來(lái)放進(jìn)上下文。這個(gè)模式和RAG在外觀上很像但目的不同。RAG檢索的是外部知識(shí)庫(kù)檢索增強(qiáng)檢索的是對(duì)話自身的記憶。它解決的是“歷史很長(zhǎng)但高度離散”的場(chǎng)景比如一個(gè)用戶零零散散地在不同時(shí)間問(wèn)過(guò)多個(gè)不同訂單的問(wèn)題每個(gè)問(wèn)題之間沒(méi)有強(qiáng)關(guān)聯(lián)。檢索增強(qiáng)的優(yōu)勢(shì)是信息保留率可調(diào)你可以只取top-k相關(guān)片段也可以額外加一個(gè)關(guān)鍵詞過(guò)濾條件。它不會(huì)像滑動(dòng)窗口那樣犧牲早期的關(guān)鍵信息也不會(huì)像摘要那樣把細(xì)節(jié)抽象掉。缺點(diǎn)是系統(tǒng)復(fù)雜度明顯上升需要維護(hù)向量庫(kù)、 embedding、檢索鏈路并且檢索質(zhì)量直接決定回復(fù)質(zhì)量檢索不到模型就真的不知道。2.4 三種模式的量化對(duì)比我把自己項(xiàng)目里的實(shí)測(cè)數(shù)據(jù)整理成了一張表方便你在方案選型時(shí)直接參考基于128K窗口、中文對(duì)話場(chǎng)景模式信息保留能力單輪token成本延遲影響實(shí)現(xiàn)復(fù)雜度典型適用場(chǎng)景滑動(dòng)窗口低早期信息易丟低低最簡(jiǎn)單閑聊、短期任務(wù)、客服的“最近意向”判斷摘要壓縮中高但細(xì)節(jié)有損中額外摘要調(diào)用中中等長(zhǎng)會(huì)話總結(jié)、需要全局語(yǔ)義、關(guān)鍵約束密集檢索增強(qiáng)高但依賴檢索質(zhì)量低-中中檢索耗時(shí)較高知識(shí)密集、問(wèn)題高度離散、長(zhǎng)期多主題對(duì)話需要注意這三種模式不是互斥的。我在最終版本里做的是混合模式全局摘要保底 滑動(dòng)窗口保近期 向量檢索補(bǔ)細(xì)節(jié)后面我會(huì)寫具體實(shí)現(xiàn)。3. 我的落地實(shí)現(xiàn)一套可切換的context-mode框架3.1 數(shù)據(jù)結(jié)構(gòu)給每條消息打上“標(biāo)簽”和“權(quán)重”在寫任何模式之前我先把消息數(shù)據(jù)結(jié)構(gòu)重新設(shè)計(jì)了。這一步非常重要后期所有策略都建立在消息的meta信息之上。我的每條消息包括五個(gè)字段dataclass class ChatMessage: role: str # system / user / assistant / tool content: str msg_id: str # 全局唯一 ts: float # 時(shí)間戳用于排序和時(shí)效判斷 category: str chat # chat / constraint / fact / tool_result / greeting retention: int 1 # 保留權(quán)重0可選丟棄1默認(rèn)2重要3絕不可丟category和retention是我自己加的?!癱onstraint”是用戶明確的約束性指令比如“不要推薦含糖飲料”“fact”是事實(shí)型實(shí)體比如訂單號(hào)、日期、金額“tool_result”是工具返回的原始結(jié)果“greeting”是寒暄。retention用于告訴上下文構(gòu)造器這條消息的丟棄優(yōu)先級(jí)。有了這兩個(gè)字段構(gòu)造上下文時(shí)就靈活多了。系統(tǒng)約束永遠(yuǎn)保留retention3用戶明確指令保留retention2工具結(jié)果和事實(shí)按需保留retention1寒暄直接丟棄retention0。3.2 token預(yù)算的精確計(jì)算構(gòu)建上下文的第一步永遠(yuǎn)是算預(yù)算。我封裝了一個(gè)token計(jì)數(shù)器用tiktoken來(lái)估算import tiktoken enc tiktoken.encoding_for_model(gpt-4o) def count_tokens(text: str) - int: if not text: return 0 return len(enc.encode(text))然后定義預(yù)算結(jié)構(gòu)。核心原則是先留出模型回復(fù)的空間再裝system prompt再裝本次新消息最后剩下的空間才分給歷史內(nèi)容。def build_sliding_context( system_prompt: str, history: list, pending: list, max_tokens: int 16000, reserve_output_tokens: int 2000, ): budget max_tokens - reserve_output_tokens system_msg {role: system, content: system_prompt} budget - count_tokens(system_prompt) # 本次必須帶上的新消息 for msg in pending: budget - count_tokens(msg[content]) # 從歷史最末端最新的消息往回收集塞滿剩余預(yù)算 selected [] for msg in reversed(history): cost count_tokens(msg[content]) if budget - cost 0: break selected.append(msg) budget - cost selected.reverse() return [system_msg] selected pending有兩個(gè)細(xì)節(jié)容易被忽略。第一reserve_output_tokens不能設(shè)得太小否則模型生成到一半就被截?cái)唷N乙话愀鶕?jù)業(yè)務(wù)回答長(zhǎng)度估算客服場(chǎng)景設(shè)2000長(zhǎng)文生成場(chǎng)景至少4000。第二budget - cost 0才break而不是0這樣能盡量利用最后一點(diǎn)剩余空間避免白白浪費(fèi)。3.3 摘要壓縮的實(shí)現(xiàn)細(xì)節(jié)摘要模式我并沒(méi)有簡(jiǎn)單地把整段歷史一次性丟給模型總結(jié)那樣很容易超窗口。我采用的是“分批滾動(dòng)摘要”的方式def incremental_summary(prev_summary: str, new_messages: list, client) - str: content \n.join(f{m[role]}: {m[content]} for m in new_messages) prompt f你正在管理一段長(zhǎng)時(shí)間對(duì)話的記憶。請(qǐng)合并以下兩部分內(nèi)容輸出一份新的結(jié)構(gòu)化摘要。 要求: 1. 保留所有用戶明確的指令、偏好和約束 2. 保留關(guān)鍵實(shí)體訂單號(hào)、日期、金額、人名、地址等 3. 去掉寒暄、重復(fù)表達(dá)和低信息量?jī)?nèi)容 4. 摘要保持在300字以內(nèi)。 【已有摘要】 {prev_summary} 【新對(duì)話】 {content} resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: prompt}], temperature0.2, ) return resp.choices[0].message.content每次調(diào)用前我先統(tǒng)計(jì)新消息的總token量如果超過(guò)4000就自動(dòng)切成多個(gè)小批然后循環(huán)調(diào)用incremental_summary把上一輪的摘要作為下一輪的“已有摘要”傳進(jìn)去。這樣做的好處是無(wú)論對(duì)話多長(zhǎng)摘要調(diào)用的token開(kāi)銷都是可控的不會(huì)出現(xiàn)“為了省token反而燒掉更多token”的尷尬。另外一個(gè)我踩出來(lái)的經(jīng)驗(yàn)摘要生成用mini模型就行不必用旗艦?zāi)P?。因?yàn)檎蝿?wù)本身對(duì)推理要求不高關(guān)鍵是提取準(zhǔn)確性。我個(gè)人用gpt-4o-mini實(shí)測(cè)信息保留率和旗艦?zāi)P拖嗖畈淮蟮杀镜土瞬畈欢嘁粋€(gè)數(shù)量級(jí)。如果你用的是開(kāi)源模型做底座摘要生成也可以復(fù)用同一套模型只是速度會(huì)慢一些。3.4 自動(dòng)切換策略什么情況用什么模式做了三種模式之后新的問(wèn)題來(lái)了每次請(qǐng)求到底用哪個(gè)我最后寫了一個(gè)簡(jiǎn)單的策略決策器規(guī)則不復(fù)雜但足夠有效def decide_mode(app_state): # 歷史占總窗口預(yù)算的比例 ratio app_state.history_tokens / app_state.max_tokens if ratio 0.4: return full # 歷史遠(yuǎn)沒(méi)到預(yù)算直接全量 if app_state.fact_density 0.2: return sliding # 事實(shí)密度低大多是無(wú)關(guān)聯(lián)的閑聊 if app_state.query_discrete: return hybrid # 問(wèn)題之間離散單點(diǎn)查詢居多用檢索 return summary # 默認(rèn)用摘要壓縮這個(gè)決策器依賴兩個(gè)額外信號(hào)fact_density我給每條消息打了category標(biāo)簽統(tǒng)計(jì)最近N條消息里“fact”和“constraint”占比占比高說(shuō)明這段對(duì)話信息密集不能隨便丟。query_discrete用戶在連續(xù)多輪里是否在問(wèn)完全不同的問(wèn)題。這個(gè)可以通過(guò)向量相似度來(lái)算如果相鄰問(wèn)題間的平均相似度低于閾值就認(rèn)為是離散多頭查詢。hybrid模式是我最終推薦的方式系統(tǒng)約束全量保留近期消息用滑動(dòng)窗口再疊加一層向量檢索補(bǔ)充細(xì)節(jié)。它稍微復(fù)雜一點(diǎn)但在長(zhǎng)會(huì)話場(chǎng)景里效果最穩(wěn)。4. 實(shí)測(cè)中踩過(guò)的坑與優(yōu)化建議4.1 上下文污染摘要把工具輸出當(dāng)成了“事實(shí)”第一個(gè)坑出現(xiàn)在摘要模式上線當(dāng)天??头C(jī)器人在查詢天氣工具時(shí)返回了“明日有暴風(fēng)雨”摘要把它記成了一條事實(shí)。第二天用戶問(wèn)“明天適合戶外活動(dòng)嗎”模型根據(jù)摘要里的“暴風(fēng)雨”給出否定建議。問(wèn)題在于那條工具結(jié)果是2小時(shí)前的天氣早就變了。這種問(wèn)題我稱為“上下文污染”模型把某個(gè)時(shí)刻的工具輸出當(dāng)成了永久事實(shí)。工具結(jié)果天然有時(shí)效性不能進(jìn)入長(zhǎng)期摘要至少必須帶上時(shí)間戳。我的解決方案是給工具結(jié)果單獨(dú)設(shè)置categorytool_result并且默認(rèn)retention1。在做摘要壓縮時(shí)把tool_result排除在“摘要對(duì)象”之外只保留“這條工具結(jié)果回答了什么問(wèn)題”這樣的元信息。比如不記“明日有暴風(fēng)雨”而是記“用戶詢問(wèn)了明日天氣已返回預(yù)報(bào)結(jié)果”。等到需要精確數(shù)據(jù)時(shí)走檢索增強(qiáng)去拿原始記錄。4.2 摘要的“歧義塌縮”關(guān)鍵實(shí)體被抽象掉了第二個(gè)坑比較隱蔽也最難發(fā)現(xiàn)。在某次長(zhǎng)會(huì)話里用戶先提到“張總”后來(lái)又提到“張經(jīng)理”其實(shí)指的是同一個(gè)人。摘要模型在壓縮時(shí)統(tǒng)一成了“張總”這沒(méi)問(wèn)題。但另一段對(duì)話里“張經(jīng)理”是另一個(gè)部門的人摘要也統(tǒng)一成了“張總”。結(jié)果模型在回答“張經(jīng)理負(fù)責(zé)什么業(yè)務(wù)”時(shí)把兩個(gè)部門的信息混在了一起。這就是摘要壓縮的“歧義塌縮”。模型為了把內(nèi)容壓縮進(jìn)有限字?jǐn)?shù)會(huì)傾向于做實(shí)體合并而合并產(chǎn)生的歧義水平無(wú)法被下游輕易察覺(jué)。我的對(duì)策是雙重的第一摘要prompt里強(qiáng)制要求“實(shí)體出現(xiàn)時(shí)保留完整稱謂不縮寫不合并若不確定則并列保留”第二在摘要之外單獨(dú)維護(hù)一個(gè)“關(guān)鍵實(shí)體表”用正則和命名實(shí)體識(shí)別抽取出訂單號(hào)、人名、日期、金額這類數(shù)據(jù)不做壓縮始終原始保留。這個(gè)實(shí)體表非常值得單獨(dú)做。需要精確查詢時(shí)它比摘要可靠得多而且是結(jié)構(gòu)化數(shù)據(jù)可以直接參與規(guī)則判斷不一定要經(jīng)過(guò)模型。4.3 token成本失控摘要調(diào)用反而把賬單推高了第三個(gè)坑和錢有關(guān)。我最初設(shè)計(jì)是“每當(dāng)歷史超過(guò)閾值就觸發(fā)一次摘要”結(jié)果遇到一個(gè)話癆用戶幾乎每三四輪就觸發(fā)一次摘要調(diào)用而且每輪主請(qǐng)求還是全量發(fā)送。月底一看賬單摘要花費(fèi)占了總成本的35%。這個(gè)教訓(xùn)是摘要不能是“高頻操作”它應(yīng)該是“低頻兜底操作”。我把觸發(fā)閾值從4000token調(diào)高到12000token并且加了冷卻時(shí)間——兩次摘要之間至少間隔30分鐘或20條新消息。另外一個(gè)優(yōu)化是不把摘要結(jié)果立即放進(jìn)下一輪請(qǐng)求而是先讓它存儲(chǔ)在內(nèi)存只有當(dāng)歷史即將撐爆窗口時(shí)才加載。4.4 精心設(shè)計(jì)評(píng)估怎么判斷context-mode改好了還是改壞了context-mode做得對(duì)不對(duì)不能靠感覺(jué)。我后來(lái)搭了一套專門的評(píng)估集這里分享一個(gè)最值得做的“關(guān)鍵信息保持”測(cè)試準(zhǔn)備一組20個(gè)“關(guān)鍵約束”分別散布在對(duì)話歷史的第1、第10、第30、第50輪。讓測(cè)試腳本自動(dòng)運(yùn)行對(duì)話到第60輪然后向模型提問(wèn)每個(gè)約束對(duì)應(yīng)一個(gè)問(wèn)題。統(tǒng)計(jì)答對(duì)率對(duì)比不同模式下的得分。我實(shí)測(cè)下來(lái)單純用滑動(dòng)窗口時(shí)第30輪之前的約束答對(duì)率只有約40%摘要壓縮能到75%左右混合檢索模式可以穩(wěn)定在85%以上。這組數(shù)據(jù)很有說(shuō)服力也很容易讓業(yè)務(wù)方理解“為什么需要做context-mode”。同時(shí)還要監(jiān)控兩個(gè)反向指標(biāo)回復(fù)的“串線率”把不同主題的信息混在一起的比例和每條消息的平均成本。有時(shí)候一個(gè)方案信息保留率很高但成本高得離譜那就得調(diào)整策略。5. 場(chǎng)景化落地建議不是所有應(yīng)用都需要最強(qiáng)模式5.1 先判斷你的業(yè)務(wù)屬于哪一型我見(jiàn)過(guò)很多團(tuán)隊(duì)一上來(lái)就上向量檢索結(jié)果項(xiàng)目跑了一個(gè)月發(fā)現(xiàn)瓶頸根本不在上下文而在意圖識(shí)別。這里我把常見(jiàn)應(yīng)用分成四類你可以對(duì)照著選模式應(yīng)用類型典型特征推薦context-mode客服輔助會(huì)話長(zhǎng)、問(wèn)題離散、事實(shí)密集混合模式摘要檢索個(gè)人助理短期任務(wù)多、最新意圖重要滑動(dòng)窗口輕量摘要文檔問(wèn)答外部知識(shí)為主、對(duì)話歷史短滑動(dòng)窗口即可重點(diǎn)是RAG角色扮演/閑聊全局人設(shè)重要、細(xì)節(jié)容忍度高摘要壓縮這個(gè)表不是絕對(duì)標(biāo)準(zhǔn)但能幫你快速定位。最重要的是先量化你的歷史特征再選模式。我每次接到新項(xiàng)目都會(huì)先跑一遍真實(shí)對(duì)話日志統(tǒng)計(jì)平均會(huì)話長(zhǎng)度、事實(shí)密度、問(wèn)題相似度然后才動(dòng)手設(shè)計(jì)。5.2 給初次落地的人一個(gè)靠譜的推進(jìn)路徑如果你是第一次做context-mode我建議不要直接堆復(fù)雜方案。按下面的順序演進(jìn)第一版只做滑動(dòng)窗口但把消息加好category和retention標(biāo)簽。這步很快一兩天就能完成。上線后收集真實(shí)日志統(tǒng)計(jì)“最早出現(xiàn)的關(guān)鍵約束在第幾輪被擠出窗口”找到一個(gè)可復(fù)現(xiàn)的失憶案例。加入摘要壓縮配上實(shí)體表。先讓摘要只保留“關(guān)鍵指令和事實(shí)”不要貪全。如果還有離散查詢場(chǎng)景回答不好再上向量檢索。每一步都留出觀察時(shí)間至少跑一周真實(shí)流量用上一節(jié)說(shuō)的評(píng)估集量化效果。不要跳步否則出了問(wèn)題你根本沒(méi)法定位是摘要丟信息還是檢索沒(méi)召回。5.3 后續(xù)可以繼續(xù)擴(kuò)展的方向context-mode這套東西寫完并不代表一勞永逸。我接下來(lái)計(jì)劃做幾件事第一把摘要和檢索的觸發(fā)條件從規(guī)則改成可學(xué)習(xí)策略?,F(xiàn)在已經(jīng)積累了不少“哪些消息最終幫助正確回答”的日志數(shù)據(jù)后續(xù)可以用這些數(shù)據(jù)訓(xùn)練一個(gè)輕量級(jí)模型來(lái)決定上下文構(gòu)成而不是靠人工閾值。第二做跨會(huì)話記憶。現(xiàn)在的context-mode只解決單會(huì)話內(nèi)部的消息管理但很多用戶會(huì)多次回訪下一次會(huì)話其實(shí)也應(yīng)該帶上之前會(huì)話的關(guān)鍵摘要。這個(gè)方向我已經(jīng)在規(guī)劃本質(zhì)上是把“會(huì)話級(jí)摘要”升級(jí)成“用戶級(jí)長(zhǎng)期記憶”。第三把上下文預(yù)算做成可觀測(cè)的可視化儀表盤讓運(yùn)營(yíng)人員能實(shí)時(shí)看到每一輪請(qǐng)求里“system占多少、歷史占多少、檢索片段占多少”這樣調(diào)參就有數(shù)據(jù)支撐。如果讓我重新來(lái)一次我會(huì)在項(xiàng)目第一天就加一個(gè)“輸入輸出token計(jì)數(shù)”的中間件把每條消息的類別和保留權(quán)重在入庫(kù)時(shí)打好。context-mode不是一個(gè)開(kāi)關(guān)而是一套工程習(xí)慣在寫代碼之前先想清楚哪些信息不能丟哪些可以壓縮哪些壓根不用看。你把這個(gè)想明白了后面所有模式實(shí)現(xiàn)都會(huì)順很多。