實(shí)戰(zhàn):從原理到代碼的完整指南)
很多剛開始玩大模型 Agent 的朋友第一次做出來的機(jī)器人像個(gè)金魚聊完上一句就忘。這不是模型笨而是我一開始也沒搞懂 Agent 記憶技術(shù)到底在解決什么問題。這篇指南按照我自己從零到能跑通的路線整理面向小白程序員邏輯講透代碼可以直接抄。我會(huì)從原理、分層、代碼、參數(shù)、踩坑五個(gè)角度把“大模型 Agent 怎么記住東西”這件事拆開講清楚。你不需要一開始就懂向量數(shù)據(jù)庫也不需要背一堆新名詞跟著順序看下來基本就能在自己的項(xiàng)目里給 Agent 裝上“記憶”。適合誰讀剛接觸大模型應(yīng)用開發(fā)、想讓自己的聊天機(jī)器人具備跨會(huì)話記憶、做私人知識(shí)助手、或者想在團(tuán)隊(duì)里搭一個(gè)帶記憶的客服問答系統(tǒng)的人。就算你只寫過一點(diǎn) Python也一樣能跟上。1. 先搞清楚 Agent 為什么需要記憶1.1 大模型生來就是“無狀態(tài)”的大模型本質(zhì)上是一個(gè)函數(shù)給它一段文字它返回一段文字。它不會(huì)在上一次調(diào)用結(jié)束后保存任何東西。你發(fā)兩條消息它不會(huì)自動(dòng)記得第一條聊了什么除非你把第一條的內(nèi)容重新塞進(jìn)第二條的輸入里。這一點(diǎn)和人的對話體驗(yàn)差別巨大。人聊天時(shí)會(huì)自然記住“剛才聊到了什么”“對方叫什么名字”“他上次說過喜歡簡潔”。但模型沒有這個(gè)概念。所謂“模型有記憶”實(shí)際上是在模型外面加了存儲(chǔ)和檢索再把檢索到的內(nèi)容放回輸入里。我剛開始做 Agent 時(shí)犯過一個(gè)經(jīng)典錯(cuò)誤以為把歷史消息存進(jìn)數(shù)據(jù)庫Agent 就有記憶了。結(jié)果發(fā)現(xiàn)存了等于沒存因?yàn)槟P透静粫?huì)自己去查數(shù)據(jù)庫。它只認(rèn)當(dāng)前請求里的內(nèi)容。所以你真正要做的事情只有一件在合適的時(shí)機(jī)把合適的記憶內(nèi)容變成當(dāng)前請求的一部分。1.2 記憶的本質(zhì)是上下文管理不是單純存儲(chǔ)很多人把“記憶系統(tǒng)”理解成“聊天記錄存儲(chǔ)系統(tǒng)”這是誤區(qū)。存儲(chǔ)只是最底層記憶系統(tǒng)的核心是上下文管理。上下文窗口就像桌面記憶庫像檔案柜。檔案柜再滿也沒關(guān)系但桌面只有那么大面積。你不能把所有檔案都攤在桌面上不然真正有用的東西反而找不到。Agent 記憶要做的工作是判斷哪些檔案現(xiàn)在有用、把哪幾份抽出來放到桌面上、用完后再收回去。換句話說記憶系統(tǒng)不是“存得越多越好”而是“放得越準(zhǔn)越好”。精確地決定“放什么進(jìn) Prompt”比“存了多少條歷史”重要得多。1.3 這篇指南解決三類問題一類是“記不住”用戶昨天告訴你他喜歡簡短回復(fù)今天你又說了一大篇。這類問題源于跨會(huì)話信息丟失。另一類是“記太亂”歷史記錄、用戶偏好、臨時(shí)狀態(tài)全混在一起塞進(jìn) Prompt 后模型被舊信息帶偏回答前后矛盾。還有一類是“記不起”記憶明明存了但檢索的時(shí)候找不準(zhǔn)。比如用戶問“上次那個(gè)報(bào)錯(cuò)解決了嗎”系統(tǒng)搜不到因?yàn)楫?dāng)時(shí)的記錄里根本沒有“報(bào)錯(cuò)”這個(gè)詞。后面所有內(nèi)容基本都在圍繞“怎么記住、怎么存、怎么取、怎么用、怎么忘”這五件事展開。2. 記憶體系的四層拆分2.1 第一層會(huì)話工作記憶第一層是“正在聊的這段對話”也就是當(dāng)前 prompt 里的消息列表。它由模型自帶的上下文窗口承載需要我們自己管理長度和裁剪策略。典型問題用戶連續(xù)聊二十分鐘后歷史太長超過窗口上限。簡單粗暴的做法是“只保留最近 N 條”但這樣會(huì)導(dǎo)致更早的關(guān)鍵信息丟失。稍好一點(diǎn)的做法是把早期內(nèi)容壓縮成摘要再把摘要放在消息列表最前面。這一層的管理頻率非常高幾乎是每次請求都要做。所以它必須足夠輕不能依賴外部數(shù)據(jù)庫查詢盡量在內(nèi)存里完成。2.2 第二層情景記憶情景記憶存的是“發(fā)生過的事件”。比如“用戶上午反饋了支付失敗”“上次對話里用戶要求換個(gè)方案”“上周已經(jīng)發(fā)送過一封確認(rèn)郵件”。這類記憶的特點(diǎn)是有時(shí)間、有事件、有結(jié)果通常按發(fā)生順序檢索。情景記憶解決的是連續(xù)性。沒有它用戶下次打開對話時(shí)Agent 完全不知道你們之前發(fā)生過什么。有了它Agent 可以說出“上次你提到支付失敗我查了一下可能是銀行接口超時(shí)”。實(shí)現(xiàn)時(shí)一般會(huì)給每條記憶打上時(shí)間戳、事件類型、關(guān)聯(lián)對象這樣既能按時(shí)間排序也能按事件類型過濾。2.3 第三層語義記憶語義記憶存的是“事實(shí)和偏好”不依賴某個(gè)具體事件。比如“用戶喜歡簡潔回復(fù)”“項(xiàng)目部署在測試環(huán)境”“用戶所在行業(yè)是教育”。這些內(nèi)容即使不提時(shí)間也長期有效。語義記憶通常適合用向量檢索。因?yàn)橛脩魡柗ㄇё內(nèi)f化“我上次說過的偏好你還記得嗎”“回復(fù)別那么啰嗦”和“用戶喜歡簡短回答”這句話在字面上差別很大但語義距離很近。向量檢索能抓這種近似關(guān)系。語義記憶要特別注意覆蓋和去重。同一條偏好可能被寫進(jìn)去三次如果不去重檢索時(shí)會(huì)同時(shí)冒出三條重復(fù)記憶既占空間又干擾模型。2.4 第四層程序性記憶程序性記憶是“怎么做某件事”的經(jīng)驗(yàn)比如“遇到數(shù)學(xué)計(jì)算先調(diào)用計(jì)算工具別自己心算”“生成周報(bào)時(shí)按數(shù)據(jù)、結(jié)論、行動(dòng)計(jì)劃三段來寫”。在小項(xiàng)目里這部分通常被寫死在代碼邏輯或系統(tǒng)提示詞里。但做得復(fù)雜的 Agent 會(huì)把它沉淀為可檢索的技能模板。比如一個(gè) Agent 遇到 Excel 處理任務(wù)時(shí)會(huì)自動(dòng)調(diào)出“讀取表格-清洗-分析-出報(bào)告”的流程模板。程序性記憶的本質(zhì)是知識(shí)復(fù)用。它能讓 Agent 不去重復(fù)摸索流程而是直接使用已經(jīng)驗(yàn)證過的方法。四層記憶可以共存。我的經(jīng)驗(yàn)是先把會(huì)話工作記憶和語義記憶做扎實(shí)再考慮情景和程序性記憶。因?yàn)榍皟蓚€(gè)直接決定用戶體驗(yàn)后兩個(gè)更多是錦上添花。記憶類型典型內(nèi)容存儲(chǔ)方式主要用途會(huì)話工作記憶當(dāng)前對話上下文內(nèi)存消息列表保證當(dāng)前對話連貫情景記憶某時(shí)某刻發(fā)生的事件數(shù)據(jù)庫記錄時(shí)間索引跨會(huì)話回溯語義記憶用戶偏好、事實(shí)知識(shí)向量庫規(guī)則過濾回答個(gè)性化問題程序性記憶任務(wù)流程、技能模板配置/模板庫自動(dòng)決定執(zhí)行路徑3. 手把手實(shí)現(xiàn)一套可用的記憶組件3.1 最小版會(huì)話窗口管理先寫一個(gè)最簡單的會(huì)話窗口。作用是控制消息列表長度超出的部分?jǐn)D壓成摘要而不是直接扔掉。import json from collections import deque class SessionWindow: def __init__(self, max_messages20): self.max_messages max_messages self.messages deque(maxlenmax_messages) def add(self, role, content): self.messages.append({role: role, content: content}) def to_prompt(self): return list(self.messages) def compress_old(self): # 保留最近一半消息把更早的文本拼成一條摘要占位 keep_count self.max_messages // 2 old list(self.messages)[:-keep_count] recent list(self.messages)[-keep_count:] summary_text 之前對話摘要 .join(m[content] for m in old if m[content]) self.messages.clear() self.messages.append({role: system, content: summary_text}) for m in recent: self.messages.append(m)這里用deque(maxlen...)可以自動(dòng)丟棄最舊的。但只丟棄不總結(jié)會(huì)丟關(guān)鍵信息。compress_old就是把早期內(nèi)容壓成一條摘要再把摘要放到 system 里。注意摘要不能太頻繁做。每輪都?jí)嚎s等于把每次回答都再調(diào)用一次模型做總結(jié)成本和延遲都會(huì)上去。建議當(dāng)消息條數(shù)達(dá)到上限時(shí)才觸發(fā)。3.2 升級(jí)版向量檢索長期記憶當(dāng)需要跨會(huì)話記住用戶偏好和事件時(shí)純會(huì)話窗口不夠。我們需要一個(gè)“寫進(jìn)去-查出來”的機(jī)制。最通用方案是向量檢索把文本變成向量用余弦相似度找最接近的內(nèi)容。下面用一個(gè)純 Python 標(biāo)準(zhǔn)庫演示核心邏輯。生產(chǎn)環(huán)境一般會(huì)用現(xiàn)成的向量庫或模型服務(wù)提供的 embedding原理一樣。import hashlib import json def tokenize(text): # 簡單按空格和標(biāo)點(diǎn)切分真實(shí)場景可以用分詞庫 return [t.lower() for t in text.replace(,, ).replace(。, ).split()] def hashed_embedding(text, dim128): vec [0.0] * dim for token in tokenize(text): digest hashlib.md5(token.encode()).hexdigest()[:8] index int(digest, 16) % dim vec[index] 1.0 return vec def cosine_similarity(a, b): dot sum(x * y for x, y in zip(a, b)) norm_a sum(x * x for x in a) ** 0.5 norm_b sum(x * x for x in b) ** 0.5 if norm_a 0 or norm_b 0: return 0.0 return dot / (norm_a * norm_b) class VectorMemory: def __init__(self, pathmemory.json): self.path path self.items self._load() def _load(self): try: with open(self.path, r, encodingutf-8) as f: return json.load(f) except FileNotFoundError: return [] def _save(self): with open(self.path, w, encodingutf-8) as f: json.dump(self.items, f, ensure_asciiFalse, indent2) def add(self, text, categorygeneral): embedding hashed_embedding(text) self.items.append({ text: text, category: category, embedding: embedding, access_count: 0 }) self._save() def search(self, query, top_k3): query_vec hashed_embedding(query) scored [] for item in self.items: score cosine_similarity(query_vec, item[embedding]) scored.append((score, item)) scored.sort(keylambda x: x[0], reverseTrue) return scored[:top_k]這個(gè)寫法可以跑通但有個(gè)明顯缺陷哈希詞袋向量對“語義相似”不敏感比如“喜歡簡短”和“別啰嗦”幾乎匹配不到一起。真實(shí)項(xiàng)目里應(yīng)該把hashed_embedding替換成 embedding 模型生成的向量。替換后其他邏輯不用變。搜索后把返回結(jié)果按指定格式拼進(jìn) Prompt 就行memory VectorMemory() results memory.search(用戶喜歡什么風(fēng)格) memory_section \n.join(f- [{r[1][category]}] {r[1][text]} for r in results) prompt f以下是長期記憶\n{memory_section}\n\n請基于記憶回答當(dāng)前問題。每次命中時(shí)最好更新access_count后面做遺忘策略會(huì)用到。3.3 進(jìn)階版寫入與遺忘策略長期記憶最怕兩件事什么垃圾都存、存了永遠(yuǎn)不刪。所以要加兩道流程寫入前過濾定期遺忘。寫入前過濾舉例def should_store(text, min_length10): # 太短的內(nèi)容沒有存儲(chǔ)價(jià)值 if len(text) min_length: return False # 一些臨時(shí)寒暄不值得記 useless [你好, 哈哈, 再見, 不知道] if any(u in text for u in useless): return False return True遺忘策略可以用“低頻且長期未訪問優(yōu)先清理”的思路import time def clean_memory(memory, max_items200, max_age_days30): now time.time() kept [] for item in memory.items: last_access item.get(last_access_ts, now) age_days (now - last_access) / 86400 # 訪問次數(shù)低且超過30天未用準(zhǔn)備淘汰 if age_days max_age_days and item.get(access_count, 0) 3: continue kept.append(item) memory.items kept memory._save()這只是示例生產(chǎn)里更常用加權(quán)分?jǐn)?shù)綜合“最近訪問時(shí)間”“訪問次數(shù)”“內(nèi)容重要性”算一個(gè)衰減分低于閾值就刪除。操作心得遺忘一定要做成定時(shí)任務(wù)而不是每輪對話都掃一遍。原因很簡單記憶表小的時(shí)候怎么掃都無所謂但數(shù)據(jù)到幾萬條后每次掃描都是性能開銷。4. 記憶鏈路的四個(gè)關(guān)鍵步驟與參數(shù)選擇4.1 寫入判斷什么值得記記憶寫入最容易犯的錯(cuò)是“全量寫入”。把每輪對話都原樣存進(jìn)去短期內(nèi)沒感覺時(shí)間一長向量庫塞滿了“今天天氣不錯(cuò)”“好的”“嗯嗯”這類無意義內(nèi)容檢索質(zhì)量直線下降。我自己的篩選標(biāo)準(zhǔn)有三條包含事實(shí)比如用戶所在行業(yè)、項(xiàng)目名稱、聯(lián)系方式、產(chǎn)品版本。包含偏好比如“回復(fù)要簡短”“不喜歡 emoji”“報(bào)告要帶數(shù)據(jù)表”。包含狀態(tài)變化比如“支付失敗已解決”“計(jì)劃從下周二開始實(shí)施”。凡是用戶明確表達(dá)、重復(fù)提到、并且后續(xù)可能再次使用的信息才寫入。相反寒暄、臨時(shí)情緒、一次性的流程確認(rèn)通常不寫。寫入時(shí)還要做歸一化。比如用戶說“以后叫我老王就行”和“請稱呼我為老王”本質(zhì)是同一件事至少要把稱呼統(tǒng)一成“用戶希望被稱呼為老王”。不做歸一化檢索時(shí)會(huì)同時(shí)命中兩條類似內(nèi)容白白浪費(fèi)上下文空間。4.2 檢索如何讓“相關(guān)”變成“精準(zhǔn)”檢索是記憶系統(tǒng)里最影響體驗(yàn)的環(huán)節(jié)。相關(guān)不代表有用。用戶問“昨天那個(gè)問題解決了嗎”檢索出十條“昨天聊過的東西”模型反而不知道具體是哪件事。通用做法是“先過濾再排序”。先用元數(shù)據(jù)縮小范圍比如時(shí)間范圍、對話場景、記憶分類然后做向量檢索按相似度排序最后按分?jǐn)?shù)閾值截?cái)唷O嚓P(guān)參數(shù)我建議這樣設(shè)置top_k從 3 開始調(diào)。太少容易漏太多容易雜。min_score低于 0.2 的記憶不要放進(jìn)上下文。這個(gè)值需要配合你用的 embedding 模型來定不同模型分?jǐn)?shù)分布差很多。recency_bonus給近期內(nèi)容加一點(diǎn)權(quán)重。例如最終得分 相似度 * 0.8 時(shí)間新鮮度 * 0.2。調(diào)參時(shí)建議每次只改一個(gè)變量別同時(shí)動(dòng) top_k 和閾值不然你不知道是哪個(gè)改動(dòng)帶來的效果。4.3 融合檢索結(jié)果如何安全放進(jìn) Prompt檢索結(jié)果進(jìn)了 Prompt不代表模型會(huì)正確使用。你需要告訴模型“哪些是記憶哪些是當(dāng)前對話”。我常用的格式【長期記憶】 - 用戶偏好喜歡簡短回復(fù) - 事實(shí)當(dāng)前項(xiàng)目使用測試環(huán)境 【當(dāng)前對話】 用戶昨天那個(gè)報(bào)錯(cuò)后來怎么解決的這樣模型可以清楚區(qū)分信息來源不容易把舊記憶當(dāng)成新輸入。如果記憶內(nèi)容和當(dāng)前對話沖突比如記憶說“用戶喜歡詳細(xì)報(bào)告”但當(dāng)前用戶說“別廢話直接給結(jié)論”我會(huì)在 Prompt 里加一句“當(dāng)長期記憶與當(dāng)前對話矛盾時(shí)以當(dāng)前對話為準(zhǔn)”。融合階段還要控制體量。我給自己定過一個(gè)預(yù)算記憶內(nèi)容不超過整個(gè) Prompt 的 30%。超過這個(gè)比例模型會(huì)迷失重點(diǎn)回答又臭又長。4.4 遺忘記憶系統(tǒng)必須會(huì)做減法遺忘和寫入同樣重要。沒有遺忘記憶庫就是垃圾堆。舊信息會(huì)干擾新判斷甚至讓 Agent 用過時(shí)信息回答當(dāng)前問題。我項(xiàng)目里至少維護(hù)三種遺忘機(jī)制過期刪除比如“臨時(shí)任務(wù)”類記憶 24 小時(shí)后失效。低頻刪除超過 30 天沒被檢索到的記憶權(quán)重下調(diào)最終清理。沖突覆蓋當(dāng)新記憶與舊記憶語義高度相似且信息更新時(shí)刪除舊記錄。遺忘是記憶系統(tǒng)和日志系統(tǒng)的分界線。日志是”全都要存永不刪除“記憶是”只保留對后續(xù)決策有用的信息“。很多人把這兩者混在一起最后系統(tǒng)既不像日志也不像記憶。5. 落地實(shí)踐五個(gè)經(jīng)典問題5.1 檢索不到用戶覺得你“失憶”了現(xiàn)象是用戶明確告訴你“我上次說過”Agent 卻說“抱歉我沒有找到相關(guān)信息”。先檢查三步寫入有沒有成功、檢索條件是不是太嚴(yán)、文本有沒有分詞或編碼問題。我踩過一個(gè)坑是 embedding 用的是舊模型新對話里的詞分布變化太大導(dǎo)致相似度普遍偏低。換新 embedding 模型后問題消失。如果檢索確實(shí)沒問題但用戶換了說法可以加一層“關(guān)鍵詞向量混合檢索”。關(guān)鍵詞負(fù)責(zé)精確匹配向量負(fù)責(zé)語義近似兩邊各自返回一批候選最后合并排序。這樣能覆蓋“字面不同但意思相近”的情況。5.2 檢索出一堆但全用不上現(xiàn)象是明明返回了記憶模型還是答非所問。原因通常是 top_k 太大或者檢索時(shí)沒有限定記憶類型。比如用戶問的是項(xiàng)目狀態(tài)結(jié)果系統(tǒng)把用戶閑聊偏好、歷史情緒、任務(wù)記錄全檢索出來了。正確做法是按“場景 分類”過濾。查詢前先識(shí)別意圖這是任務(wù)咨詢那就只檢索“任務(wù)類”記憶這是閑聊那就只檢索“偏好類”記憶。過濾后再做向量排序準(zhǔn)確率和效率都會(huì)好很多。5.3 上下文越來越長費(fèi)用吃不住隨著記憶累積每次請求都會(huì)變得越來越長。如果不對上下文做限制Token 費(fèi)用會(huì)線性上漲。我的做法是三層存儲(chǔ)熱記憶最近 1 小時(shí)內(nèi)的會(huì)話直接放內(nèi)存。溫記憶跨天但頻繁使用的內(nèi)容放向量庫按需檢索。冷記憶一個(gè)月前的內(nèi)容壓縮成摘要后歸檔。每次請求前先算一次總 Token。如果超過窗口預(yù)算就降低“溫記憶”的召回條數(shù)。比如正常取 5 條超預(yù)算時(shí)就只取 3 條。優(yōu)先保當(dāng)前對話長期記憶永遠(yuǎn)讓路。5.4 記憶被污染越修越錯(cuò)這是最隱蔽的問題。“污染”指錯(cuò)誤的記憶被寫入后模型每次都會(huì)基于錯(cuò)誤信息回答用戶糾正完后舊的錯(cuò)誤還在又會(huì)被檢索出來。避免污染的關(guān)鍵是更新機(jī)制。當(dāng)出現(xiàn)一條新記憶與舊記憶明顯矛盾時(shí)不應(yīng)“并列存儲(chǔ)”而應(yīng)該做覆蓋。比如舊記憶是“項(xiàng)目部署在測試環(huán)境”用戶今天說“項(xiàng)目已經(jīng)上線生產(chǎn)了”這時(shí)直接刪除舊條目或標(biāo)記為過期只保留新條目。另外必須給用戶提供“刪除記憶”的能力。哪怕只是提供一個(gè)簡單的“清除我的所有歷史記憶”按鈕也能兜底解決大部分污染問題。5.5 安全與隱私怎么處理記憶里往往包含很多個(gè)人信息和業(yè)務(wù)敏感信息。至少要遵守這幾條不記錄密碼、密鑰、Token 等敏感字段。寫入前先做脫敏手機(jī)號(hào)、身份證號(hào)、銀行卡號(hào)用掩碼替換。記憶數(shù)據(jù)按用戶隔離不能在多用戶間串?dāng)?shù)據(jù)。明確告知用戶我們存儲(chǔ)了哪些信息并支持一鍵清除。合規(guī)這塊不能等項(xiàng)目上線才補(bǔ)。從第一版設(shè)計(jì)記憶組件開始就要把數(shù)據(jù)隔離和刪除機(jī)制考慮進(jìn)去。否則后期改造成本會(huì)很高。癥狀可能原因排查順序快速對策完全檢索不到寫入失敗或閾值過高先查寫入日志再查檢索分?jǐn)?shù)放寬 min_score啟用混合檢索檢索結(jié)果不相關(guān)top_k 過大、未按場景過濾看返回條目的類型分布先按記憶分類過濾再向量排序上下文超預(yù)算記憶未分級(jí)、沒有限制條數(shù)統(tǒng)計(jì)每次請求 Token 消耗三層存儲(chǔ)限制溫記憶召回記憶越用越錯(cuò)沖突信息未覆蓋、污染寫入檢查是否有重復(fù)矛盾記錄增加覆蓋機(jī)制提供用戶刪除入口數(shù)據(jù)安全風(fēng)險(xiǎn)敏感字段明文入庫檢查入庫前是否有脫敏邏輯脫敏隔離可刪除6. 進(jìn)階方向與選型建議6.1 從向量檢索邁向知識(shí)圖譜向量檢索擅長回答“語義相近”但不擅長回答“多跳關(guān)系”。比如“A 用戶負(fù)責(zé)的 B 項(xiàng)目里有哪些模塊是用 C 技術(shù)實(shí)現(xiàn)的”這種問題如果只靠向量匹配很難一次命中。知識(shí)圖譜則可以把實(shí)體和關(guān)系串起來支持精確的關(guān)系查詢。但知識(shí)圖譜的構(gòu)建成本高需要維護(hù)實(shí)體、關(guān)系、屬性和更新邏輯。我的建議是先跑通向量記憶等確實(shí)遇到“關(guān)系推理”類需求再引入圖結(jié)構(gòu)。小項(xiàng)目上來就做圖譜大概率會(huì)被建圖工作量拖垮。6.2 記憶壓縮的兩種路線一是摘要壓縮。把長段對話交給模型生成一段摘要放入長期記憶。優(yōu)點(diǎn)是保存的信息密度高缺點(diǎn)是有損細(xì)節(jié)會(huì)丟失。二是結(jié)構(gòu)化壓縮。從對話中抽出結(jié)構(gòu)化信息如字段、時(shí)間、意圖、結(jié)論保存成 JSON。這種格式適合程序處理也適合做條件查詢。一條可行路線是“先結(jié)構(gòu)化再按需摘要”。重要內(nèi)容抽成結(jié)構(gòu)化字段長期不用的內(nèi)容再合并成摘要。這樣兼顧了即時(shí)檢索和長期歸檔。6.3 什么時(shí)候該自研什么時(shí)候用現(xiàn)成組件如果是快速做 Demo、驗(yàn)證想法直接用現(xiàn)成框架自帶的記憶模塊最省事。但默認(rèn)實(shí)現(xiàn)通常比較粗糙比如全量存歷史、簡單截?cái)?、不做遺忘。一旦你的用戶量上來或者對記憶準(zhǔn)確率有要求就值得自己寫一套輕量記憶模塊。我個(gè)人的判斷標(biāo)準(zhǔn)是記憶邏輯不超過幾百行代碼時(shí)自研更劃算。你能精確控制什么時(shí)候?qū)懭?、檢索多少條、如何融合、如何遺忘。而使用重型框架時(shí)光是理解它的記憶生命周期就要花很久。如果你打算在自己的項(xiàng)目里長期迭代 Agent我建議至少把“寫入過濾檢索召回遺忘清理”這三個(gè)核心組件自己寫一遍。這樣獨(dú)立于任何框架后續(xù)遷移也方便。最后再分享一點(diǎn)個(gè)人體會(huì)我最初做的記憶系統(tǒng)很蠢一個(gè) JSON 文件存所有歷史每次對話都把所有歷史塞進(jìn) Prompt。結(jié)果模型越聊越亂成本越燒越高。后來慢慢改成“寫入前過濾、檢索時(shí)排序、融合前控制體量、定期做遺忘”整個(gè) Agent 才穩(wěn)定下來。如果你也在做類似項(xiàng)目我的建議很直白不要一開始就上重型設(shè)施。先在本地跑一個(gè) JSON 存儲(chǔ) 向量檢索的最小閉環(huán)把“寫入-檢索-融合-遺忘”體會(huì)一遍。跑通之后自然知道哪些地方必須換數(shù)據(jù)庫、哪些地方必須加規(guī)則。記憶系統(tǒng)的價(jià)值從來不是存得多而是用得準(zhǔn)。希望這份指南能讓你少走一點(diǎn)彎路。