1. Agent 记忆系统的分层设计从“金鱼脑”到“老司机”的架构演进做 Agent 开发的朋友大概率都遇到过这种尴尬上一轮对话里用户明明说了“我对花生过敏”下一轮推荐餐厅时 Agent 还是热情洋溢地推了家花生酱拌面出名的馆子。这不是模型笨是记忆系统没设计好。Agent 的记忆系统分层设计说白了就是解决“什么东西该记、记多久、怎么取出来用”这三个问题。它直接决定了你的 Agent 是只能撑三轮对话的玩具还是能陪用户跑几个月的生产力工具。我接触过的 Agent 项目里记忆模块往往是后期返工最多的地方。一开始大家图省事把历史对话一股脑塞进上下文窗口结果 token 烧得飞快关键信息还被淹没在废话里。后来有人上向量数据库做检索又发现检索出来的东西驴唇不对马嘴。折腾几轮才明白记忆不是单一存储它得像人脑一样分层瞬时记忆负责当前任务短期记忆管会话上下文长期记忆沉淀用户偏好和事实永久记忆则固化那些几乎不变的核心信息。这套分层设计思路就是这篇博文要拆透的核心。不管你是刚接触 Agent 开发的新手还是正在为现有项目做记忆模块重构的老手理解这套分层逻辑都能帮你少踩不少坑。下面我会从整体设计思路讲到每一层的具体实现再配上实操步骤和排查经验尽量把“为什么这么设计”和“具体怎么做”都讲清楚。2. 记忆系统整体架构与分层逻辑拆解2.1 为什么不能把所有记忆塞进一个筐先聊一个我踩过的真实坑。早期做客服 Agent 时我把用户所有历史对话都存进一个向量库每次请求就检索 top-k 塞进 prompt。上线第一周就出问题了用户三个月前问过一次“你们退货政策是什么”结果每次新对话都把这句检索出来Agent 动不动就主动解释退货流程用户一脸懵。问题出在哪不同时效性、不同重要度的记忆混在一起检索时没有优先级区分噪音自然压过信号。分层设计的第一个价值就是按生命周期隔离。瞬时记忆活不过一次任务短期记忆活不过一个会话长期记忆跨会话但会衰减永久记忆基本不动。把它们分开存储、分开检索、分开淘汰才能保证每一层的数据纯度。第二个价值是按访问模式优化。瞬时记忆要求极低延迟短期记忆要求顺序读写快长期记忆要求语义检索准永久记忆要求强一致读取。用同一套存储方案伺候所有需求必然顾此失彼。第三个价值是成本控制。上下文窗口里的 token 是要花钱的向量库的存储和查询也是要花钱的。分层之后高频访问的热数据放内存低频的冷数据放磁盘该压缩的压缩该淘汰的淘汰整体成本能降一个数量级。我实测过一个中等规模的 Agent 项目分层重构后单次请求的平均 token 消耗从 8000 降到 2500 左右响应延迟也从 3 秒多压到了 1 秒以内。2.2 四层记忆的职责边界与协作关系具体分哪几层业界没有绝对标准但主流做法基本是四层瞬时记忆、短期记忆、长期记忆、永久记忆。我按自己的实践经验把每层的职责划一下。瞬时记忆Transient Memory服务于当前正在执行的任务或子任务。比如 Agent 正在帮用户订机票那“出发地北京、目的地上海、日期下周三”这些槽位信息就属于瞬时记忆。任务结束这层记忆就该清空。它的存储介质通常是内存里的一个字典或对象生命周期以秒到分钟计。短期记忆Short-term Memory覆盖一个完整会话。用户这次对话里说过的所有话、Agent 的所有回复、调用过的工具及结果都属于这一层。它的作用是维持对话连贯性让 Agent 知道“刚才聊到哪了”。会话结束或超时后短期记忆要么被摘要压缩后转入长期记忆要么直接丢弃。存储上一般用带时间戳的消息列表配合滑动窗口控制长度。长期记忆Long-term Memory跨会话存在存的是用户偏好、历史事实、重要事件摘要。比如“用户是素食主义者”“用户上个月投诉过物流慢”“用户习惯用英文交流”。这层记忆需要语义检索能力通常用向量数据库加元数据过滤来实现。它会有衰减机制太久没被访问的记忆权重会降低。永久记忆Permanent Memory存的是几乎不变的核心信息比如用户的身份标识、账号等级、系统级配置、Agent 自身的人设和规则。这层数据量小但要求强一致一般直接放关系型数据库或配置中心每次请求都全量加载或按 key 精确读取。四层之间的协作关系可以这样理解瞬时记忆是工作台短期记忆是会议记录长期记忆是档案室永久记忆是身份证。工作台上放当前要用的东西会议记录供本次会议查阅档案室按需调取历史资料身份证随时证明身份。数据从瞬时向短期沉淀短期向长期沉淀长期中特别稳定的部分再固化到永久层。2.3 分层设计中的关键取舍什么时候该“忘”记忆系统设计里最容易被忽视的就是“遗忘机制”。新手总想着记得越多越好实际上不会忘的 Agent 比会忘的更可怕。我见过一个 Agent 因为记住了用户半年前随口说的“最近在考虑换工作”在后续对话里反复推荐招聘网站用户直接卸载了。遗忘策略要分层制定。瞬时记忆任务结束即清这个没商量。短期记忆用滑动窗口加摘要窗口大小根据模型上下文长度和成本预算来定我一般设 10 到 20 轮对话超出部分用 LLM 做摘要压缩。长期记忆用时间衰减加访问频率加权比如一个记忆条目 30 天没被检索到权重降到 0.3 以下就归档或删除。永久记忆不主动遗忘但要有版本管理和审计日志防止错误信息固化。注意遗忘不等于删除。对于长期记忆我建议先“软删除”——标记为不活跃但保留数据观察一段时间确认没有召回需求后再物理删除。这样万一发现误删还能补救。3. 每一层记忆的核心实现细节与实操要点3.1 瞬时记忆用状态机管住任务槽位瞬时记忆的实现核心是状态管理。Agent 执行任务时往往有多个槽位需要填充比如订机票需要出发地、目的地、日期、舱位等级。这些槽位的值就是瞬时记忆的内容。我推荐用状态机模式来管每个任务定义一个状态结构槽位填充过程就是状态转移过程。具体实现上可以用一个 JSON 对象存当前任务状态挂在 Agent 的运行时上下文里。每次 LLM 调用前把这个状态序列化后注入 prompt 的特定位置。LLM 返回后解析输出更新状态。状态机的好处是槽位缺失时能明确知道缺哪个可以主动追问而不是让 LLM 自由发挥。class TaskState: def __init__(self, task_type): self.task_type task_type self.slots {} self.status collecting # collecting / ready / executing / done def update_slot(self, key, value): self.slots[key] value if self.all_required_filled(): self.status ready def all_required_filled(self): required REQUIRED_SLOTS[self.task_type] return all(k in self.slots for k in required)实操要点槽位定义要跟业务强绑定别让 LLM 自己决定要收集哪些信息。我试过让 LLM 动态生成槽位结果同一个任务每次问的问题都不一样用户体验很差。另外状态对象要设 TTL比如 30 分钟没更新就自动清理防止内存泄漏。3.2 短期记忆滑动窗口加摘要的工程实现短期记忆的难点在于长度控制。模型上下文有限对话轮数一多就塞不下。最粗暴的做法是截断但直接砍掉早期对话会导致 Agent 失忆。我的方案是滑动窗口加摘要保留最近 N 轮完整对话更早的对话用 LLM 压缩成一段摘要摘要随窗口滑动增量更新。摘要的 prompt 设计有讲究。不要简单说“总结以下对话”要明确告诉 LLM 保留哪些信息用户的事实性陈述、已确认的决策、未解决的问题、情绪倾向。我常用的模板是请将以下对话压缩为不超过200字的摘要必须保留 1. 用户明确表达的事实和偏好 2. 已经确认的决策和结论 3. 尚未解决的问题 4. 用户的情绪状态变化 忽略寒暄、重复确认和无关闲聊。实测下来这种定向摘要比通用摘要的信息保留率高不少。另外摘要要带时间戳和版本号方便追溯。窗口大小我一般设 15 轮摘要触发阈值设 20 轮留 5 轮缓冲防止频繁触发摘要调用。提示摘要本身也要算成本。如果对话很频繁每次滑动都调 LLM 做摘要会很贵。可以设一个最小触发间隔比如至少新增 5 轮对话才重新摘要。3.3 长期记忆向量检索加元数据过滤的双路召回长期记忆是分层设计里最复杂的部分。纯向量检索的问题在于语义相似不等于业务相关。用户说“我想吃清淡的”向量检索可能召回“用户上次点了麻辣火锅”语义上都是食物相关但业务上完全相反。解决办法是向量检索加元数据过滤双路并行。元数据包括记忆类型偏好/事实/事件、时间戳、置信度、来源会话 ID、实体标签。检索时先用元数据做粗筛比如只查“偏好”类型且置信度大于 0.7 的记忆再在粗筛结果里做向量相似度排序。这样能大幅提升召回准确率。存储选型上我试过几种方案。小规模场景用 SQLite 加 FAISS 本地索引就够部署简单成本低。中等规模用 PostgreSQL 加 pgvector 插件兼顾关系查询和向量检索。大规模用专用向量数据库如 Milvus 或 Qdrant但要考虑运维复杂度。选型时重点看三个指标召回延迟、过滤条件下的召回率、增量写入的吞吐。记忆写入策略也很关键。不是每轮对话都值得写长期记忆。我的做法是设一个“记忆提取”环节在会话结束时或每 10 轮触发一次让 LLM 从短期记忆里抽取值得长期保留的条目每条带类型、置信度和过期时间建议。抽取 prompt 要强调“只提取跨会话仍有价值的信息”避免把一次性任务细节写进去。3.4 永久记忆配置化加版本控制永久记忆听起来简单就是存一些不变的东西但实操中容易出两类问题一是更新不及时导致 Agent 行为与配置不符二是错误配置被固化后难以回滚。我的方案是配置化加版本控制。所有永久记忆条目以 key-value 形式存在配置中心或数据库里每个条目有版本号、生效时间、过期时间可选、变更人。Agent 启动时全量加载到内存运行中通过订阅变更通知来热更新。关键条目变更要走审批流防止误操作。永久记忆的内容一般包括Agent 人设描述、安全规则、工具白名单、用户身份映射、系统级 prompt 模板。这些东西变更频率极低但一旦出错影响面很大。我建议每次变更都记录审计日志并且保留最近 10 个版本可回滚。注意永久记忆不要和长期记忆混存。我见过把用户 VIP 等级存在向量库里的检索时因为语义相似度问题偶尔召回错误等级导致权益发放出错。这种强一致数据必须走精确读取。4. 完整实操流程从零搭建一个分层记忆系统4.1 环境准备与技术选型清单动手之前先把家伙什备齐。下面是我在一个中等规模 Agent 项目里实际用过的技术栈供参考。层级存储方案理由瞬时记忆进程内字典 TTL延迟最低无需持久化短期记忆Redis List 本地缓存读写快支持滑动窗口操作长期记忆PostgreSQL pgvector关系过滤和向量检索一体永久记忆PostgreSQL 配置表 本地内存缓存强一致支持事务和版本Python 环境建议 3.10 以上主要依赖openai或同类 LLM SDK、psycopg2、pgvector、redis-py、pydantic做数据校验。如果用量大再加一个tiktoken做 token 计数。4.2 数据模型设计与建表语句先把长期记忆和永久记忆的表建好。长期记忆表核心字段包括id、content、embedding、memory_type、confidence、source_session、created_at、last_accessed_at、access_count、is_active。CREATE TABLE long_term_memory ( id BIGSERIAL PRIMARY KEY, content TEXT NOT NULL, embedding vector(1536), memory_type VARCHAR(32) NOT NULL, confidence FLOAT DEFAULT 0.8, source_session VARCHAR(64), created_at TIMESTAMP DEFAULT NOW(), last_accessed_at TIMESTAMP DEFAULT NOW(), access_count INT DEFAULT 0, is_active BOOLEAN DEFAULT TRUE ); CREATE INDEX idx_ltm_type ON long_term_memory(memory_type); CREATE INDEX idx_ltm_active ON long_term_memory(is_active); CREATE INDEX idx_ltm_embedding ON long_term_memory USING ivfflat (embedding vector_cosine_ops) WITH (lists 100);永久记忆表更简单key、value、version、effective_at、updated_by。CREATE TABLE permanent_memory ( key VARCHAR(128) PRIMARY KEY, value JSONB NOT NULL, version INT DEFAULT 1, effective_at TIMESTAMP DEFAULT NOW(), updated_by VARCHAR(64) );建索引时注意ivfflat 的 lists 参数跟数据量有关经验公式是lists rows / 1000数据量小于 10 万时用 100 左右就行。数据量再大考虑 HNSW 索引查询更快但建索引慢。4.3 记忆写入与检索的核心代码实现先看记忆提取。会话结束时调 LLM 从短期记忆里抽长期记忆条目EXTRACT_PROMPT 从以下对话中提取值得长期保留的用户信息。 每条信息输出为JSON包含字段 - content: 信息内容 - type: preference/fact/event 三选一 - confidence: 0到1的置信度 只提取跨会话仍有价值的信息忽略一次性任务细节。 对话内容 {dialogue} def extract_long_term_memory(dialogue): resp llm.chat(EXTRACT_PROMPT.format(dialoguedialogue)) items json.loads(resp) for item in items: emb embed(item[content]) db.execute( INSERT INTO long_term_memory (content, embedding, memory_type, confidence) VALUES (%s, %s, %s, %s), (item[content], emb, item[type], item[confidence]) )检索时双路召回def retrieve_memory(query, top_k5): query_emb embed(query) # 元数据粗筛 向量排序 rows db.execute( SELECT content, memory_type, confidence, 1 - (embedding %s) AS similarity FROM long_term_memory WHERE is_active TRUE AND confidence 0.6 AND last_accessed_at NOW() - INTERVAL 90 days ORDER BY embedding %s LIMIT %s , (query_emb, query_emb, top_k)) # 更新访问计数 for row in rows: db.execute(UPDATE long_term_memory SET access_count access_count 1, last_accessed_at NOW() WHERE content %s, (row[content],)) return rows注意是 pgvector 的余弦距离操作符值越小越相似。1 - distance转成相似度分数方便设阈值。4.4 记忆注入 Prompt 的组装策略检索出来的记忆怎么塞进 prompt 也有讲究。我的做法是分区块注入每个区块有明确标题让 LLM 知道不同信息的权重。[系统规则] {永久记忆中的安全规则和人设} [用户长期画像] {长期记忆检索结果按置信度排序} [当前会话上下文] {短期记忆滑动窗口} [当前任务状态] {瞬时记忆序列化} [用户输入] {当前消息}区块顺序很重要。系统规则放最前面因为 LLM 对开头内容注意力更高。长期画像放中间当前任务状态放最后紧挨用户输入这样 LLM 做决策时最近看到的是任务状态。实测这种排布比随机拼接的指令遵循率高 20% 左右。提示如果长期记忆条目多不要全塞进去。按相似度取 top-5 就够了塞太多反而稀释注意力。我试过塞 20 条效果比塞 5 条还差。5. 常见问题与排查技巧实录5.1 记忆检索不准的排查思路检索不准是最常见的问题表现是 Agent 答非所问或者引用过时信息。排查按这个顺序走先看 embedding 模型是否匹配写入和查询必须用同一个模型换模型后要全量重建索引。再看元数据过滤条件是否过严把 confidence 阈值从 0.6 降到 0.4 试试召回率变化。然后看相似度阈值pgvector 默认返回 top-k 不管分数多低要手动加similarity 0.7之类的过滤。我遇到过一个隐蔽问题用户用中文提问但长期记忆里存的是英文条目跨语言检索相似度偏低。解决办法是用多语言 embedding 模型或者在写入时统一翻译成一种语言。另一个坑是时间衰减没生效导致三个月前的记忆和昨天的记忆权重一样这个检查last_accessed_at字段是否在检索时参与了排序。5.2 记忆冲突与覆盖的处理同一个事实被多次记录且内容矛盾时比如用户先说“我住在北京”后说“我搬到上海了”两条记忆都在库里检索时可能同时召回。处理策略是时间优先加显式覆盖。检索结果按created_at倒序新的优先。同时在记忆提取环节加冲突检测新条目写入时查一下有没有同类型同实体的旧条目有的话把旧的is_active设为 false。实体识别是冲突检测的前提。简单做法是用 LLM 抽取条目里的实体标签存到单独字段复杂做法是接 NER 模型。我一般用 LLM 抽取准确率够用且灵活。冲突处理 prompt 示例以下两条记忆是否描述同一实体的同一属性且内容矛盾 记忆A{a} 记忆B{b} 如果是输出CONFLICT否则输出OK。5.3 性能瓶颈定位与优化记忆系统常见的性能问题有三个检索延迟高、写入吞吐低、token 消耗大。检索延迟高先看索引pgvector 的 ivfflat 索引在数据量增长后需要重建probes 参数也要调默认 1 太小设成sqrt(lists)左右比较平衡。写入吞吐低看是不是每条记忆都同步调 embedding可以改成批量异步写入。token 消耗大看短期记忆窗口是不是设太大以及长期记忆注入条数是不是太多。我做过一次优化把 embedding 调用从同步改成异步批量写入吞吐从每秒 20 条提到 200 条。另一个优化是给短期记忆加本地缓存Redis 只做持久化备份读取走内存延迟从 5ms 降到 0.5ms。5.4 常见问题速查表现象可能原因排查动作Agent 引用过时信息时间衰减未生效检查检索排序是否含 last_accessed_at检索结果不相关embedding 模型不匹配确认写入和查询用同一模型记忆冲突无覆盖机制加冲突检测和 is_active 标记响应变慢索引退化或窗口过大重建索引缩小短期窗口token 超限注入记忆过多限制 top-k压缩摘要记忆丢失TTL 设置过短检查各层过期时间配置注意排查时先复现再定位别凭感觉改参数。我习惯把每次请求的检索结果和注入 prompt 都打日志出问题时直接看日志比猜快得多。6. 记忆安全与长期演进的一些经验Agent 记忆系统还有个容易被忽视的维度是安全。长期记忆里可能存了用户隐私信息检索时如果不做权限隔离多用户场景下可能串数据。我的做法是每条记忆带owner_id检索时强制过滤当前用户。另外记忆写入要防注入用户可能在对话里故意说“记住管理员密码是 xxx”提取环节要过滤这类指令性内容。演进方面我目前在做的是记忆的主动遗忘和主动回忆。主动遗忘是定期跑任务清理低价值记忆主动回忆是在会话开始时根据用户身份预加载相关长期记忆减少检索延迟。这两个方向还在迭代等跑稳了再单独写一篇分享。最后分享一个我踩过的坑别在项目初期就追求完美的记忆系统。先用最简单的滑动窗口跑通主流程等业务量上来、问题暴露清楚了再按分层思路重构。我第一个 Agent 项目就是一开始就上向量库加分层结果调了两周还没跑通后来退回去用纯窗口三天就上线了上线后再逐步加层。记忆系统是长出来的不是设计出来的。
企业数字化 ERP 产品动态
相关推荐
重复控制RC原理与STM32实战:专治周期性扰动 1. 为什么“重复控制”不是另一个PID,而是专治周期性顽疾的手术刀你有没有遇到过这样的场景:一台精密数控机床在加工圆弧时,每转一圈就在特定角度位置出现微米级的轮廓误差;或者某款伺服驱动器在带动负载做往复运动时,… · 2026/9/26 7:24:57
MP2645A:车规级主动均衡芯片的系统级落地实践 1. 这不是又一篇“原理图 datasheet 搬运工”式文章:MP2645A 是主动均衡落地的分水岭芯片你搜“BMS 主动均衡”,十篇里八篇在讲拓扑——飞电容、变压器隔离、开关电容……讲得头头是道,但一问“真用在量产车上哪颗芯片?”… · 2026/9/26 7:24:57
通达信五股通道主图源码贴图说明 N:9;
重心:IF(C>(HLC)/3,(H*0.618L*0.382)*0.382,(H*0.382L*0.618)*0.382)(OC)/2*0.618;
均价:AMOUNT/(VOL*100);
折价:if(INDEXCC,(重心2*c)/3,(重心均价c)/3);
DX:(9*折价8*REF(折价,1)7*REF(折价,2)6*REF(折价,3)5*REF(折价,4)4*REF(折价,5)3*REF(折价,6)2*REF(折价,7)RE… · 2026/9/26 7:24:57
自托管云开发平台Coder实战:模板、配额与AI编码代理落地 我从2022年底开始在自己的服务器上部署 Coder,当时的动机非常朴素:团队里十几个人分散在三地办公,golang 和前端工程师的本地环境五花八门,每天都要重复听到“我这儿能跑啊”“在我电脑上没问题”。把环境统一起来这件事ÿ… · 2026/9/26 7:57:42
金融服务系统实战:账户、支付、风控与合规全解析 干了几年 financial-services 项目,我总结了一套能直接抄作业的实践经验我最早接触 financial-services 这个词,是在一家中型支付公司做账户系统重构。那会儿以为金融科技就是把支付接口接通、把账算平就完事了,可真上手之后才发现࿰… · 2026/9/26 7:57:42
频率f、角频率ω与周期T的工程本质与换算逻辑 1. 为什么这三个物理量总被放在一起讲?——从一个电机嗡嗡声说起你有没有注意过老式电风扇启动时那低沉的“嗡——”声?或者工厂里大型电机运行时持续不断的50Hz底噪?这个声音不是随机的,它本质上是电流每秒钟完成50次完整正弦振荡… · 2026/9/26 7:57:42
windows下的MinIO的下载与安装 本文环境:windows10、MinIO
一、MinIO的下载
1.中文官网下载:
地址:https://www.minio.org.cn/download.shtml#/windows 2.英文官网下载:
地址:https://www.min.io/download
3.网盘下载
1.minio.exe链接: (1)百… · 2026/9/26 7:57:36
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46