
RAG 和 Memory 是 Agent 開發里最容易被混在一起的兩個概念。很多人做知識庫問答時第一反應是我用了 RAG是不是就不需要 Memory 了也有人反過來把會話歷史一股腦拼進系統提示詞然后說這就是 Memory。先說結論這兩個東西解決的問題根本不一樣。RAG 解決的是“Agent 不知道外部知識”的問題Memory 解決的是“Agent 記不住剛才說過什么、做過什么、用戶偏好是什么”的問題。它們可以配合但不能互相替代。這篇文章適合正在選型 Agent 框架、準備做知識庫問答、或者想優化多輪對話體驗的開發者。我會先幫你分清這兩個概念再給一套實際可用的選型判斷路徑最后說落地時最容易踩的坑。重點不是堆功能而是讓你能在自己的場景里判斷現在該加 RAG該加 Memory還是兩個都加。1. 先分清問題RAG 解決“信息缺失”Memory 解決“狀態遺忘”1.1 RAG 的本質是給 Agent 裝一個可檢索的外部知識庫RAG 全稱是 Retrieval-Augmented Generation檢索增強生成。它的核心思路不是把知識寫進模型參數而是先從外部文檔里檢索出和用戶問題相關的片段再把片段作為上下文交給語言模型讓模型基于這些片段生成回答。典型場景是企業內部文檔問答、產品手冊查詢、法律法規檢索、學術論文閱讀。這些內容要么不在模型訓練數據里要么更新很快。比如你的產品上周剛改了價格模型知識還停留在半年前這時候就算模型本身很聰明它也會答錯。RAG 的價值就在于把答案的“依據”從模型內部搬到外部知識庫每次回答前先查最新文檔。所以判斷一個場景要不要用 RAG可以問自己一個問題用戶問題的答案是否需要依賴某個具體文檔里的準確信息如果需要那就要考慮 RAG。如果只是常識性問答模型本身就能回答沒有必要上來就做一套檢索鏈路。RAG 的關鍵組件包括文檔加載、切塊、向量化、向量存儲、檢索、重排序、生成。每一步都有參數要調后面我會專門講。1.2 Memory 的本質是讓 Agent 記住交互歷史和狀態Memory 關注的是時間維度的信息。它包含短期的會話上下文也包含長期的用戶畫像、偏好和任務狀態。舉幾個具體例子用戶上一輪說了“我要訂明天早上九點的會議室”這一輪說“改到十點”Agent 需要知道“這間會議室”指的是哪一間。用戶連續問了五個問題最后說“結合前面幾條給我一個總結”Agent 不能只看到最后一句話。用戶已經在系統里綁定過企業 ID 和部門Agent 在后續回答中應該默認記住而不是每次重新問。這些都是 Memory 的職責。實現方式也很多樣把最近幾輪對話拼進系統提示詞、用摘要壓縮歷史、用向量庫存記憶條目、用外部數據庫記錄用戶屬性或者用專門的記憶模塊。判斷場景是否需要 Memory 同樣可以問一個問題用戶問題的答案是否依賴剛才聊過的內容或者用戶長期信息如果是就需要 Memory。光靠 RAG 檢索外部文檔是不夠的因為外部文檔里沒有“用戶剛剛說過什么”這個信息。1.3 最容易出現的誤區把 RAG 和 Memory 混著用我在實際項目里見過兩種典型誤區。第一種把 RAG 庫當成 Memory 用。有人把歷史對話也切塊存進向量庫用戶提問時同時檢索文檔和歷史。這么做不是完全不行但很容易失控。歷史對話噪聲多相關性不穩定檢索出來的片段可能互相矛盾而且會快速消耗上下文空間。更關鍵的問題是歷史對話里的很多信息根本不需要向量化比如“用戶剛說了 OK”這句話沒有知識價值存進向量庫只會干擾檢索。第二種把 Memory 當成 RAG 用。有人為了省事把產品文檔全文塞進記憶模塊每次請求都把文檔拼進提示詞。如果文檔很短還能湊合文檔一長很快超過上下文窗口模型反而抓不住重點延遲也上去了。正確思路應該是RAG 的檢索對象是穩定的知識型內容Memory 的檢索對象是動態的交互狀態和用戶事實。兩者可以在同一個 Agent 里共存但定位完全不同。2. 從 Agent 工作流程看 RAG 和 Memory 到底放在哪個環節2.1 Agent 的典型執行循環一個 Agent 執行任務時通常會經歷這樣的循環接收用戶輸入結合上下文和記憶判斷是否需要外部知識調用工具或檢索生成回復最后更新記憶。在這個循環里Memory 是貫穿始終的。Agent 每一次做出決策都需要知道當前處于什么狀態而 RAG 通常是在“需要外部知識”這個節點觸發不是每次提問都要走一遍檢索。用偽代碼表示會更容易理解user_input receive() context memory.build_context(user_id, session_id) if need_external_knowledge(user_input): docs rag.retrieve(user_input) context docs response llm.generate(user_input, context) memory.save(user_id, session_id, user_input, response)這里 Memory 負責提供背景RAG 負責補充檢索片段。兩者都拼進上下文但來源不同用途也不同。2.2 Memory 在整個會話中的角色Memory 在系統中通常分成短期記憶和長期記憶兩層。短期記憶主要保存當前會話的對話輪次、工具調用結果、臨時變量。它的特點是時效性強但也容易被新消息覆蓋。實現時最常用的是維護一個消息列表每次請求把最近 N 輪拼進提示詞。N 一般由上下文窗口、模型能力和成本共同決定。長期記憶則保存跨會話的穩定信息。比如用戶姓名、公司、偏好、歷史訂單、訂閱狀態。這類信息往往需要結構化存儲或者以記憶條目的形式寫入獨立數據庫。長期記憶要注意一個問題用戶偏好會變化。不能把用戶半年前的選擇當成永遠不變的偏好需要給記憶條目加時間戳或者版本。配置 Memory 時常見的參數有會話 ID、保留最近對話輪數、摘要觸發閾值、記憶寫入條件。不同框架參數名不一樣但你要關心的核心問題是這些信息應該在什么時候寫入什么時候被清理。2.3 RAG 在任務中的觸發時機RAG 不是每次用戶提問都要觸發。如果用戶只是在閑聊或者問題本身在模型知識范圍內走 RAG 反而增加延遲和噪聲。比較常見的做法是增加一個路由判斷先判斷用戶問題是否需要外部知識。可以用規則、分類器也可以讓模型自己決定。比如“查一下最新的政策文件”明顯需要走檢索“幫我寫一段歡迎語”通常不需要。一旦確定要走 RAG流程一般是這樣理解用戶問題必要時擴展成多個子查詢。對查詢做向量化。在向量庫中檢索最相似的片段。對結果做重排序把真正相關的排名提前。把篩選后的片段拼接到提示詞中。讓模型基于片段生成答案并盡量給出引用來源。整個過程里切塊策略對效果影響最大。固定長度切塊簡單但容易把語義切斷按段落和標題切塊更合理但不同文檔結構差異很大。常見做法是先用文檔結構粗切再對特別大的塊做二次切分。3. 到底怎么選先回答五個關鍵問題再看決策表3.1 選型之前先問自己五個問題與其直接問“RAG 和 Memory 用哪個”不如先把場景拆開。我一般會先回答這五個問題用戶的問題是否依賴外部文檔或實時數據用戶的問題是否依賴剛才的對話歷史或用戶長期信息外部知識的更新頻率高不高當前模型的上下文窗口能容納多少內容你更在意回答準確率還是更在意交互的連續性和個性化第一個問題指向 RAG第二個問題指向 Memory第三個問題決定你要不要做文檔同步第四個問題影響你的方案復雜度第五個問題決定你的優化優先級。舉個例子。一個產品手冊問答機器人用戶的問題大多數依賴外部文檔但是單輪問答為主連續追問的情況很少。這種情況 RAG 優先Memory 只需要保留很淺的會話歷史就夠了。另一個例子。一個招聘助手用戶會連續交流自己的經歷、求職意向、薪資期望。這些信息不是外部文檔里的知識而是用戶動態提供的狀態。這種情況 Memory 優先RAG 只在需要查詢崗位信息時觸發。3.2 一張表幫你快速選型場景推薦方案說明產品文檔問答RAG 優先Memory 輔助答案依賴文檔知識需要及時更新多輪對話中的個性化推薦Memory 優先RAG 按需需要記住用戶偏好商品庫查詢適合走 RAGAgent 執行復雜任務兩者結合Memory 記錄任務狀態RAG 檢索操作手冊或規則客服機器人兩者結合Memory 保存用戶訂單和上下文RAG 檢索政策文檔純閑聊機器人只上 Memory不需要外部知識重點在上下文連貫單輪知識問答只上 RAG沒有跨輪依賴Memory 成本可以省掉這張表是經驗判斷不是絕對規則。如果你的場景比較特殊按照自己的數據分布來調整。3.3 兩種常見組合模式除了上面這種表格我再給你一個更簡單的版本。極簡模式只使用 Memory加上模型自帶知識。適合簡單客服、閑聊、任務型對話。優點是開發成本低缺點是沒有私有知識時模型容易編造答案。知識庫模式只使用 RAG做單輪問答。適合文檔檢索場景比如搜政策、搜手冊。優點是不用維護復雜歷史缺點是連續追問效果很差用戶問“剛才說的那個條款呢”模型根本不知道。混合模式RAG 和 Memory 一起用。這是真實 Agent 場景中最常見的選擇。Agent 既需要私有知識又需要跨輪狀態。混合模式不等于把所有功能堆一起而是讓兩條鏈路各司其職。這里有一個很容易被忽視的判斷不要看到一個 Agent 框架自帶 RAG 和 Memory 模塊就以為兩個都用一定更好。如果場景真的只需要文檔檢索強行加 Memory 反而會讓問題復雜化。選型的第一步永遠是看需求而不是看功能列表。4. 實際落地先從最小例子跑通再做混合方案4.1 環境準備動手之前先確認你的運行環境。不用一步到位但下面幾個條件要盡量提前準備好。語言和框架Python 生態下常用 LangChain、LlamaIndex也可以自己用 FastAPI 搭接口。如果用的是 Dify、Spring AI 這類框架模塊會更多一些但核心思路一致。向量庫常見選擇有 Qdrant、Chroma、Milvus、pgvector。學習階段用 Chroma 最輕量生產環境再考慮 Qdrant 或 Milvus。嵌入模型和語言模型可以調云端 API也可以用本地模型。本地模型要額外關注顯存和內存如果機器配置不高先把模型體積選小一點。輸入輸出格式明確你要處理的是 txt、Markdown、PDF 還是 Word 文檔以及對話結果的返回格式。注意原始材料里沒有給出版本號落地時請先確認你所用的框架和依賴版本。不同版本的 API 變化很大不要拿舊教程直接套。4.2 先跑通純 RAG 的最小樣例我建議不要一上來就做混合方案。先把 RAG 單條鏈路跑通再考慮 Memory。最小步驟是加載一個文檔比如一份產品說明的 txt 文件。按長度切片比如每塊 500 字符重疊 50 字符。調用嵌入模型把每個切片轉成向量。把向量存入向量庫。輸入一個測試問題檢索相似片段。把片段拼進提示詞讓模型生成回答。# 偽代碼示例實際參數以你的環境為準 chunks split_text(text, chunk_size500, chunk_overlap50) embeddings embed_model.encode(chunks) vector_store.add(chunks, embeddings) question 這個產品的價格調整政策是什么 results vector_store.search(question, top_k3) prompt f基于以下資料回答\n{results}\n問題{question} answer llm.invoke(prompt)跑通之后先驗證三件事檢索結果是否相關回答是否基于檢索片段以及會不會出現“編造文檔中沒有的內容”。如果回答看起來像模型在自由發揮說明提示詞約束不夠或者檢索片段根本沒有被模型認真使用。4.3 再跑通 Memory 的最小會話RAG 穩定之后再單獨加 Memory。最簡單的做法就是維護一個消息列表每次請求把最近幾輪拼進提示詞。messages memory.get_recent(session_id, max_turns10) user_input 我叫張三 prompt build_prompt(messages, user_input) answer llm.invoke(prompt) memory.add(session_id, user_input, answer)測試時用一組連續問題先問“我叫張三”再問“我叫什么”最后問“我剛才說了什么”。如果模型都能回答說明最小會話記憶是通的。這里先不要急著做摘要。先用原始消息跑通觀察上下文長度對回答質量的影響再決定要不要把早期消息壓縮成摘要。摘要會省 token但也會丟失細節需要權衡。4.4 混合后的最小流程兩條鏈路都穩定后再合并成一個流程# 偽代碼示例 messages memory.get_recent(session_id) if should_use_rag(question): docs rag.search(question) context format_docs(docs) format_messages(messages) else: context format_messages(messages) answer llm.invoke(question, context) memory.add(session_id, question, answer)這已經是一個非常夠用的混合方案。它沒有復雜的路由模型沒有長期用戶畫像但能覆蓋大部分場景有知識時檢索文檔有歷史時參考歷史兩者都滿足時一起用。4.5 判斷標準混合方案跑起來之后不要只看“能回答”就結束還要盯幾個指標單條響應延遲。如果響應變慢優先看檢索耗時和上下文長度。檢索命中質量。隨機抽 20 個問題看檢索結果是否真的覆蓋答案。上下文占用。連續對話到第 10 輪后提示詞占了多少 token如果超過模型窗口的 80%就要做摘要或限制輪數。是否重復引用同一段文檔。如果 top_k 里三塊內容高度重復說明切塊重疊太多需要調整。記憶是否準確。用戶上一輪說的事情這一輪是否被正確復用。5. 混合使用時的架構要點和常見坑5.1 Memory 和 RAG 不要搶同一塊上下文混合方案最常出的問題不是功能不夠而是上下文不夠用。RAG 檢索出來的片段可能很長Memory 里又有十幾輪歷史。兩者都塞進提示詞之后二十分鐘過去模型看到的大部分內容都是歷史對話和檢索片段反而找不到當前用戶問題在哪。解決思路是給上下文做一個預算。比如模型上下文窗口是 8000 token你可以規定RAG 片段最多占 3000Memory 最多占 2500留給模型發揮的空間至少 2000。比例不一定固定但一定要有預算意識。Memory 側可以壓縮最近 2-3 輪保留原始消息更早的用摘要代替。RAG 側可以限制top_k 設成 3 或 5每段長度通過切塊參數控制。不要以為檢索出 10 塊都有用很多時候 3 塊高質量片段比 10 塊噪聲更有價值。5.2 記憶的寫入和清理記憶不是存得越多越好。把所有對話原樣存下來很快會把存儲和上下文都拖垮。寫入策略上我會優先保存有狀態價值的信息。比如用戶明確說過“我偏好某個品牌”“我下周要出差”“我已經完成了第一步”這些信息值得寫入記憶。而“好的”“嗯”“謝謝”這類消息價值很低不寫反而更干凈。清理策略同樣重要。長期記憶里要給每條記錄加時間戳當用戶說“我改主意了”時新記錄要能覆蓋舊記錄而不是讓模型同時看到矛盾信息。會話記憶里超過最大輪數的消息要么丟棄要么摘要不能無限累積。5.3 RAG 檢索質量和切塊策略RAG 最容易翻車的點不是模型而是文檔加載和切塊。常見問題包括PDF 里表格提取后亂掉、頁眉頁腳成為噪聲、掃描件沒有 OCR、文檔編碼不是 UTF-8。這些都會讓后續檢索質量大打折扣。處理文檔時先人工抽查幾個片段別急著全部灌進向量庫。切塊也不是只看字符數。固定長度切塊最容易把一句話切成兩半導致檢索結果語義不完整。更好的辦法是按標題、段落、列表先拆分再對超大塊二次切分。切塊長度和重疊率是互相影響的一般先設 500-800 字符、10% 重疊再根據檢索結果調整。另一個容易忽略的點是引用溯源。企業級 RAG 不能只給答案還要能說明答案來自哪份文檔的哪一段。否則答錯了沒法排查用戶也不敢采信。熱詞里提到的“RAG 的引用溯源與 groundedness”就是這個意思。5.4 混合方案排查鏈路混合方案出了問題時按這個順序排查不要一上來就懷疑模型能力。回答像沒讀過文檔先看檢索片段是否相關。如果片段本來就不對模型再強也答不對。連續對話答錯先看 Memory 是否覆蓋了關鍵信息。有時候是保存了但模型沒有用上有時候是根本沒保存。提示詞超長或響應很慢先看上下文預算、檢索片段數量、歷史輪數。超長通常不是模型問題是策略問題。回答前后矛盾先看 Memory 里的舊信息和新信息是否沖突有沒有清理機制。RAG 命中但生成亂編先看提示詞是否明確要求“只能基于資料回答”并且允許模型在資料不足時說不知道。5.5 值得關注的進階方向如果你已經跑通了基礎的 RAG Memory下一步可以關注幾個更細的方向。Agentic RAG 是一個思路不讓每次請求都固定走檢索流程而是讓 Agent 自己判斷什么時候需要調用檢索工具。這樣能減少無效檢索節省成本和時間。Memory Channel 也是一種參考把記憶拆分成不同通道比如會話記憶、實體記憶、任務記憶。每個通道存不同類型的信息檢索時按需取用。對復雜 Agent 場景來說比單一大列表更穩定。還可以考慮加入知識圖譜或 MCP 這類外部模塊但前提是你的基礎鏈路已經穩定。否則一次堆太多功能出了問題很難定位。我的建議是先跑通最小閉環再逐步加能力。6. 幾個可以直接拿去用的選型經驗6.1 先區分“知識”和“狀態”這是整個選型最核心的一句話。如果信息是一個事實比如“發貨政策是 24 小時內”“這座城市的面積是 1000 平方公里”往 RAG 方向走。 如果信息是動態狀態比如“用戶剛剛選擇了 5 號商品”“用戶當前登錄的是企業賬號”往 Memory 方向走。 如果一個信息既有知識屬性又有狀態屬性比如用戶選擇的產品型號是動態狀態而該型號的官方技術參數是外部知識就要拆成兩段處理狀態放 Memory技術參數走 RAG。6.2 不要一開始就追求大而全很多 AI Agent 框架自帶 Memory 和 RAG 模塊默認配置不一定適合你的場景。我見過不少團隊上來就配置了長期記憶、向量數據庫、重排序、多輪摘要、工具調用結果系統看起來能力很強但用戶隨便問幾個問題就開始亂答。原因就是鏈路太長任何一個環節的噪聲都會被放大。更穩的做法是先用最簡單的方式跑通一個列表存歷史一個向量庫查文檔。驗證核心鏈路之后再逐步加摘要、重排序、權限控制。6.3 用問題反推方案我不太推薦先選框架再想場景。反過來先收集真實用戶問題再做分類會更靠譜。把用戶問題分成四類事實查詢答案能在外部文檔里找到典型如“這個品類的退貨標準是什么”。這類走 RAG。連續追問答案依賴上一輪語氣和上下文典型如“剛才說的那個方案預算改成 2 萬怎么調整”。這類走 Memory。任務執行需要 Agent 記住步驟和狀態同時可能要查操作手冊。這類 RAG Memory 都要。個性化推薦需要記住用戶偏好同時檢索內容庫。這類也是混合方案。分類之后你會發現很多場景其實只需要其中一個不需要一上來就把所有能力全開。6.4 一定要留可觀測性混合方案最怕“看起來能用但出了問題不知道從哪里排查”。我建議每個請求都記錄三份信息這次有沒有觸發 RAG檢索了哪些片段命中分數多少Memory 帶了哪些歷史是否做了摘要最終模型生成了什么答案有沒有引用來源。這些日志存在本地文件或數據庫里都可以關鍵是別省略。有了日志你才能判斷回答錯誤是檢索問題、記憶問題還是模型問題。否則用戶反饋一句“你回答錯了”你連從哪里開始查都不知道。我個人更建議把項目拆成兩個階段第一階段跑通單文檔 RAG 加會話 Memory確認兩條鏈路都穩定第二階段再做路由、摘要、長期記憶和更復雜的 Agentic RAG。不要一開始就把所有高級概念都堆上去。很多問題不是工具能力不夠而是前置環境和輸入材料沒有處理干凈。先把基礎鏈路做扎實后面加什么功能都更容易判斷值不值。