<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>向量检索 on Renxin's Blog</title><link>https://zh.renxinblog.cn/tags/%E5%90%91%E9%87%8F%E6%A3%80%E7%B4%A2/</link><description>Recent content in 向量检索 on Renxin's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Tue, 26 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://zh.renxinblog.cn/tags/%E5%90%91%E9%87%8F%E6%A3%80%E7%B4%A2/index.xml" rel="self" type="application/rss+xml"/><item><title>第七话｜记忆：上下文、短期、长期</title><link>https://zh.renxinblog.cn/post/c07-memory/</link><pubDate>Tue, 26 May 2026 00:00:00 +0000</pubDate><guid>https://zh.renxinblog.cn/post/c07-memory/</guid><description>&lt;img src="https://zh.renxinblog.cn/images/c07-memory-cover.png" alt="Featured image of post 第七话｜记忆：上下文、短期、长期" /&gt;&lt;!--
第七话演示代码: https://github.com/renxin2024/GYA/tree/main/c07-memory（memory_demo.py，纯标准库）
演进主线: 阶段2 Agent 循环收尾 —— 循环有了、状态显式化了，还差"记住"
上一篇: 第六话 状态管理：从 dict 到 StateGraph
下一篇: 第八话 MCP 协议：为什么需要它
--&gt;
&lt;p&gt;第六话里，我们把&amp;quot;流程控制&amp;quot;从模型手里收回来，交给了 StateGraph。但有一个问题从第五话开始就一直存在，我们假装它不存在：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;模型的记忆。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回顾第五话的代码，我们的&amp;quot;记忆&amp;quot;就是那个 &lt;code&gt;messages&lt;/code&gt; 列表——每次对话，把所有历史都塞进 prompt 喂给模型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 工具调用也塞进历史&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;tool&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;# 观察结果也塞进历史&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前几轮没事。但对话到 20 轮、30 轮呢？&lt;strong&gt;prompt 越来越长，直到撞上上下文窗口上限&lt;/strong&gt;——这时会发生什么？模型开始&amp;quot;忘记&amp;quot;最早说的话，或者更糟：被中间的信息干扰，答错。&lt;/p&gt;
&lt;p&gt;我先说结论：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;上下文窗口 ≠ 记忆。&lt;/strong&gt; 模型本身不&amp;quot;记得&amp;quot;任何东西，它只是每次被我们喂一坨 prompt。
真正的记忆分三层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;上下文（Working）&lt;/strong&gt;：当前窗口内，最易失——塞不下就丢&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;短期（Episodic）&lt;/strong&gt;：会话内关键事实，显式提取——比全量历史省 token、抗干扰&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长期（Semantic）&lt;/strong&gt;：跨会话持久，&lt;strong&gt;检索式&lt;/strong&gt;访问——不检索的记忆等于不存在&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这一篇，我们写一个带三层记忆的最小 Agent，亲眼看看&amp;quot;记忆是怎么补位的&amp;quot;。&lt;/p&gt;
&lt;h2 id="一旧世界把历史塞进上下文的问题"&gt;一、旧世界：把历史塞进上下文的问题
&lt;/h2&gt;&lt;p&gt;先看最朴素的做法——全量历史注入。它有两个硬伤：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬伤 1：上下文窗口有限。&lt;/strong&gt; 假设窗口 8K token，对话到第 30 轮时历史已经 10K token——塞不进去了。要么截断最老的（等于&amp;quot;失忆&amp;quot;），要么压缩（损失细节）。&lt;strong&gt;窗口是物理限制，记忆是软件设计。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬伤 2：Lost in the Middle（中间迷失）。&lt;/strong&gt; 2023 年一篇论文（arXiv 2309.04271）发现一个反直觉现象：模型对长上下文的利用呈 &lt;strong&gt;U 型&lt;/strong&gt;——开头和结尾的信息记得好，&lt;strong&gt;中间的信息最容易丢&lt;/strong&gt;，性能差距可达 25-30%，即使 100K 窗口的模型也一样。把关键信息放在 30 条消息的中间？它很可能被&amp;quot;淹没&amp;quot;。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 A[对话历史&lt;br&gt;不断增长] --&gt; B{超过窗口?}
 B --&gt;|是| C[截断最老&lt;br&gt;= 失忆]
 B --&gt;|否| D[全量塞入&lt;br&gt;中间信息易丢]&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：把历史当&amp;quot;水管&amp;quot;一样无脑灌，是新手 Agent 最大的坑。&lt;strong&gt;塞不下和塞中间，都是&amp;quot;假记忆&amp;quot;&lt;/strong&gt;——看似有，实则不可靠。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="二转折三层记忆各管一段"&gt;二、转折：三层记忆——各管一段
&lt;/h2&gt;&lt;p&gt;认知科学早就给了我们答案：人的记忆也不是一个池子，而是分层的。Agent 照搬这个分层：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层&lt;/th&gt;
					&lt;th&gt;存什么&lt;/th&gt;
					&lt;th&gt;生命周期&lt;/th&gt;
					&lt;th&gt;访问方式&lt;/th&gt;
					&lt;th&gt;类比&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;上下文（Working）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;当前轮次消息&lt;/td&gt;
					&lt;td&gt;窗口内&lt;/td&gt;
					&lt;td&gt;直接注入 prompt&lt;/td&gt;
					&lt;td&gt;你正在读的这句话&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;短期（Episodic）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;会话内关键事实&lt;/td&gt;
					&lt;td&gt;会话级&lt;/td&gt;
					&lt;td&gt;显式提取 + 摘要注入&lt;/td&gt;
					&lt;td&gt;今天上午聊过的事&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;长期（Semantic）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;用户偏好/知识点&lt;/td&gt;
					&lt;td&gt;跨会话（近乎永久）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;向量检索&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;你记得朋友爱喝什么&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;关键设计原则：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① 短期记忆 = 显式提取，不是全量存储。&lt;/strong&gt;
全量历史是&amp;quot;录像带&amp;quot;——什么都录了，但长、贵、噪音多。短期记忆是&amp;quot;笔记&amp;quot;——只记关键事实（名字、偏好、决定），结构化、省 token、抗干扰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 长期记忆 = 检索式访问，不是注入式。&lt;/strong&gt;
你不可能把&amp;quot;用户爱喝龙井、职业是 Java 工程师、博客写 AI Agent&amp;quot;全塞进每次 prompt。正确做法是：&lt;strong&gt;提问时检索出相关的几条，只注入那几条&lt;/strong&gt;。这就是 RAG（检索增强生成）的核心思想——记忆库很大，但每次只&amp;quot;想&amp;quot;起相关的部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ 记忆要有生命周期：巩固与遗忘。&lt;/strong&gt;
不是所有信息都值得长期保存。工程实践通常给记忆打分（importance）：高价值 → 升级到长期；低价值 → 过期遗忘。&lt;strong&gt;遗忘不是 bug，是 feature&lt;/strong&gt;——没有遗忘，记忆库会堆满垃圾，检索质量反而下降。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 A[对话] --&gt; B{短期记忆&lt;br&gt;提取关键事实}
 B --&gt; C[上下文&lt;br&gt;当前轮]
 B --&gt; D[长期记忆&lt;br&gt;向量检索]
 C --&gt; E[回答]
 D --&gt; E&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：三层记忆不是&amp;quot;三个数据库&amp;quot;，而是&lt;strong&gt;三种访问模式&lt;/strong&gt;——上下文是注入式（全量）、短期是摘要式（精炼）、长期是检索式（按需）。访问模式决定了它们各自解决什么问题。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="三原理讲透为什么不检索的记忆等于不存在"&gt;三、原理讲透：为什么&amp;quot;不检索的记忆等于不存在&amp;quot;
&lt;/h2&gt;&lt;p&gt;很多人以为&amp;quot;我的 Agent 存了聊天记录，所以它有记忆&amp;quot;。错。&lt;strong&gt;存储 ≠ 记忆，检索才是记忆。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;想想人的记忆：你知道&amp;quot;朋友爱喝龙井&amp;quot;这件事，不是因为你把这句话背下来了，而是因为&lt;strong&gt;在需要的时候你能想起来&lt;/strong&gt;——聊天聊到茶、点单、送礼，这些场景会自动唤起这条记忆。&lt;/p&gt;
&lt;p&gt;Agent 也一样。长期记忆必须支持&lt;strong&gt;按语义检索&lt;/strong&gt;：用户问&amp;quot;他喜欢喝什么？&amp;quot;，Agent 要从记忆库里&lt;strong&gt;找出&lt;/strong&gt;&amp;ldquo;喜欢喝茶，尤其是龙井&amp;quot;这条。怎么找？最基础的方法是&lt;strong&gt;向量相似度&lt;/strong&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1. 把记忆条目转成向量（embedding）——语义相近的文本向量也相近
2. 把用户问题也转成向量
3. 计算余弦相似度，返回最相近的 N 条
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这就是&amp;quot;检索&amp;quot;的本质。演示里我们用纯 Python 实现一个最小版（中文 bigram 分词 + 余弦相似度，零依赖），让你看到机制本身：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# 中文按相邻两字（bigram）切分&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;中文字符&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# 向量相似度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意演示级实现的局限：纯 bigram 对&lt;strong&gt;同义改写&lt;/strong&gt;敏感——&amp;ldquo;爱喝&amp;quot;和&amp;quot;喜欢喝&amp;quot;切出来的 bigram 完全不同，匹配不到。生产环境用真实 embedding（如 OpenAI/DeepSeek embedding API），同义词会投影到相近的向量空间，就没有这个问题。&lt;strong&gt;机制相同，精度不同。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;顺带说一句检索之外的另一半：&lt;strong&gt;巩固（Consolidation）与遗忘（Forgetting）&lt;/strong&gt;。记忆不是存进去就完事了——它有一个生命周期：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;对话产生信息 → 编码 → 存储 → 检索 → 巩固（低→高价值迁移）→ 遗忘（过期清理）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;工程上最常见的做法是给每条记忆打 &lt;strong&gt;importance 分数&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;巩固&lt;/strong&gt;：对话中出现的用户偏好/重要决定，打分 ≥ 0.7 → 从短期升级到长期；分数低的留在短期，会话结束即丢。这模拟了人脑&amp;quot;重要的事记牢，琐事随风散&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遗忘&lt;/strong&gt;：长期记忆也有容量和时效。时间衰减（太久没被检索到的降权）、容量上限（满了淘汰最不重要的）。&lt;strong&gt;没有遗忘的记忆库，最终会被垃圾淹没，检索质量断崖式下降&lt;/strong&gt;——这跟搜索引擎要处理&amp;quot;死链&amp;quot;是一个道理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很多 Agent 项目死在&amp;quot;只存不捡&amp;rdquo;：记忆越堆越多，检索命中率越来越差。&lt;strong&gt;好的记忆系统不是存得多，而是记得准、忘得掉。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="四动手三层记忆-agent-实测"&gt;四、动手：三层记忆 Agent 实测
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;代码&lt;/strong&gt;：&lt;code&gt;https://github.com/renxin2024/GYA/tree/main/c07-memory&lt;/code&gt;（memory_demo.py，纯标准库）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;DEEPSEEK_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-你的key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 memory_demo.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="场景-1短期记忆补位"&gt;场景 1：短期记忆补位
&lt;/h3&gt;&lt;p&gt;用户第一轮说&amp;quot;我叫张三&amp;quot; → Agent 提取存入短期记忆。然后聊两轮无关话题（写文字）——此时张三的名字已经不在模型上下文里了。再问&amp;quot;我是谁？我叫什么名字？&amp;quot;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;模型(带记忆): 你是张三。

对比（无记忆，没有任何上下文）:
模型(无记忆): 在没有上下文的情况下，我无法知道你是谁，也不知道你的名字。
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;这就是短期记忆的价值&lt;/strong&gt;：名字被&amp;quot;挤出&amp;quot;上下文后，显式提取的记忆补上了。注意我们没有把整个对话历史塞回去——只注入了一条关键事实，更省 token、更抗干扰。&lt;/p&gt;
&lt;h3 id="场景-2长期记忆向量检索"&gt;场景 2：长期记忆向量检索
&lt;/h3&gt;&lt;p&gt;向记忆库存入三条用户画像，然后提问检索：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;记忆库:
 - 用户喜欢喝茶，尤其是龙井
 - 用户职业是 Java 后端工程师，擅长并发编程
 - 用户的博客主题是 AI Agent 开发

问『用户喜欢喝什么？』→ 检索到: 用户喜欢喝茶，尤其是龙井
问『用户职业是什么？』→ 检索到: 用户职业是 Java 后端工程师...
问『博客写什么？』→ 检索到: 用户的博客主题是 AI Agent 开发
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;每条问题都准确&amp;quot;想&amp;quot;起了对应的记忆——这就是检索式访问。如果记忆库有 1000 条，我们不会全塞给模型，只注入检索到的那 1-2 条。&lt;/p&gt;
&lt;h3 id="场景-3诚实说明lost-in-the-middle-实测"&gt;场景 3（诚实说明）：Lost-in-the-Middle 实测
&lt;/h3&gt;&lt;p&gt;演示脚本里也放了一个&amp;quot;信息放中间 vs 开头&amp;quot;的对比。&lt;strong&gt;诚实地说：deepseek-v4-flash 对短 padding 抗性很好，两头都答对了&lt;/strong&gt;——这个效应要在 100K 级长上下文才明显（论文数据：中间 vs 两端性能差 25-30%）。demo 放它是让你知道这个坑的存在，正文用论文数据支撑结论。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 A[用户提问] --&gt; B{检索长期记忆}
 B --&gt; C[命中 1-2 条]
 C --&gt; D[注入上下文]
 D --&gt; E[模型回答]
 A --&gt; F[短期记忆摘要]
 F --&gt; D&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：三层记忆合起来的完整流程是——&lt;strong&gt;提问时，短期记忆给摘要、长期记忆给检索结果，一起注入上下文，模型基于&amp;quot;当前问题 + 记得的事&amp;quot;作答&lt;/strong&gt;。模型始终只面对一个&amp;quot;够用的小 prompt&amp;quot;，而不是越来越长的全量历史。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="五工程化延伸生产级记忆系统"&gt;五、工程化延伸：生产级记忆系统
&lt;/h2&gt;&lt;p&gt;demo 是概念演示，生产要补的东西不少：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;能力&lt;/th&gt;
					&lt;th&gt;demo（本篇）&lt;/th&gt;
					&lt;th&gt;生产要补的&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;短期记忆&lt;/td&gt;
					&lt;td&gt;内存 dict&lt;/td&gt;
					&lt;td&gt;会话级存储 + 上限管理（FIFO/TTL）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;长期记忆&lt;/td&gt;
					&lt;td&gt;内存 list + bigram&lt;/td&gt;
					&lt;td&gt;向量库（Qdrant/Chroma）+ 真实 embedding&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;巩固&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;重要性打分（如 ≥0.7 升长期）+ 定期 Consolidation&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;遗忘&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;时间衰减/容量上限，防止记忆库膨胀&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;记忆 vs RAG&lt;/td&gt;
					&lt;td&gt;混在一起&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;明确边界&lt;/strong&gt;：Memory 存对话产生的个人事实，RAG 存外部知识库&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;记忆 vs RAG 的边界&lt;/strong&gt;值得单独强调——这是最常见的混淆：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory（记忆）&lt;/strong&gt;：对话中自然产生的——&amp;ldquo;用户叫张三&amp;quot;&amp;ldquo;用户爱喝龙井&amp;rdquo;。换个用户，答案就变。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAG（检索增强）&lt;/strong&gt;：外部知识库——&amp;ldquo;什么是 ReAct&amp;quot;&amp;ldquo;Java 并发怎么调优&amp;rdquo;。所有用户共享，答案不变。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;把用户偏好存进 RAG？你会得到&amp;quot;所有用户都爱喝龙井&amp;rdquo;。把外部知识存进 Memory？每次都要重新&amp;quot;对话产生&amp;rdquo;，浪费。&lt;strong&gt;各司其职&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="下一步"&gt;下一步
&lt;/h2&gt;&lt;p&gt;阶段 2（Agent 循环）到此收尾：我们有循环（第五话）、有状态（第六话）、有记忆（第七话）——一个&amp;quot;会干活、能记住&amp;quot;的 Agent 成型了。&lt;/p&gt;
&lt;p&gt;但还有一个痛苦没解决：&lt;strong&gt;工具的接入&lt;/strong&gt;。第四话我们手写了注册表，接一个新工具要写代码、注册、测试。如果你要接 10 个不同的服务（GitHub、数据库、日历、邮件），每个都要写适配代码——&lt;strong&gt;N×M 的集成地狱&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下一篇进入阶段 3：&lt;strong&gt;MCP 协议——为什么需要它&lt;/strong&gt;。一句话预告：MCP 是&amp;quot;工具的 USB-C 接口&amp;quot;，让工具接入标准化。&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;演示代码&lt;/strong&gt;：&lt;code&gt;https://github.com/renxin2024/GYA/tree/main/c07-memory&lt;/code&gt;（memory_demo.py，纯标准库；DeepSeek 官方 API，默认模型 &lt;code&gt;deepseek-v4-flash&lt;/code&gt;）。Java 21 等价实现见独立仓库 &lt;code&gt;https://github.com/renxin2024/GYA-Java&lt;/code&gt;（&lt;code&gt;c07-memory/&lt;/code&gt;，Gradle 工程，&lt;code&gt;gradle run&lt;/code&gt;）。
&lt;strong&gt;参考&lt;/strong&gt;：Lost in the Middle 论文 arXiv 2309.04271（U 型注意力、中间性能差 25-30%）；四层记忆与巩固/遗忘机制来自 Agent 记忆系统工程实践（hello-agents 讲义延伸）；Memory vs RAG 边界为行业共识；demo 输出为 2026-05-26 本机实测（deepseek-v4-flash，Python 与 Java 双跑）。&lt;/p&gt;

 &lt;/blockquote&gt;</description></item></channel></rss>