恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Agent记忆系统设计:短期对话窗口与长期向量存储工程实践

  • 首页
  • 资讯中心
  • /
  • Agent记忆系统设计:短期对话窗口与长期向量存储工程实践

相关资讯

实时数仓维表关联性能优化:手写Flink HBase LookupFunction实战 2026/10/18 19:32:37
手写生产级XHR工具类:原生XMLHttpRequest深度实践 2026/10/18 19:32:37
三维泊肃叶流C++代码实现:速度剖面、流量验证与CFD基准解析 2026/10/18 19:32:37

最新资讯

基于SpringBoot+Vue的家禽养殖系统:从数据对不上到全链路跑通
Moodle管理实战指南:从部署到性能优化的完整避坑手册
malloc地址单元符号化:angr符号执行的关键技巧
angr 中 malloc 地址与地址单元符号化:堆内存路径探索实战
Flutter MethodChannel原理解析与实战避坑指南
DeepSeek 半夜上新 V4.1-Flash-1017:模型名没变、价格没变,11 项跑分全涨了

今日推荐

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Agent记忆系统设计:短期对话窗口与长期向量存储工程实践

发布时间:2026/10/18 19:32:37
Agent记忆系统设计:短期对话窗口与长期向量存储工程实践 1. 记忆系统要解决的真实痛点不是存什么而是忘什么标题里这句短期记对话、长期存向量基本就是Agent记忆系统的骨架。但我带过好几个项目发现绝大多数人第一次动手都是这么干的把所有对话塞进上下文塞不下就粗暴截断然后找个向量库每轮对话结束后傻乎乎地全量Embedding再插入。结果呢上下文一长模型回复质量断崖式下降向量库里的数据倒是存了一堆检索出来全是废话——用户昨天问过天气今天问股票照样搜出来一堆明天有雨的碎片。问题不在于存这个动作而在于你根本没想清楚什么时候该记、什么时候该忘、记下来的东西怎么被重新唤醒。短期记忆和长期记忆不是两个存储桶而是两条能力链路短期记忆管当前对话的连贯性长期记忆管跨会话的连续性。两者的边界、数据形态、读写时机完全不一样混在一起设计后期必炸。这篇文章我把一套经过多轮线上验证的记忆架构拆开讲覆盖短期上下文的窗口管理、长期记忆的向量化存储与分块策略、召回与注入机制、记忆的更新和遗忘策略以及实测中踩过的坑。适合正在做Agent应用开发、或者准备给现有机器人加记性的团队参考。我不讲大理论只讲能一次跑通的实现路径。1.1 短期记忆和长期记忆的分工边界先给个直觉定义。短期记忆就是对话还在进行时模型需要临时握住的信息它活在Prompt上下文里数据结构上就是一个messages数组。用户说他家在杭州、最近想换车、预算是30万这些信息在当前这几轮对话里必须被模型持续看到否则聊两句就忘用户体验极其割裂。长期记忆则活在你自己的存储系统里形态是向量化之后的文本片段。它解决的问题是明天用户又来他说上次看的那辆车我家车位可能停不下。如果系统不记得昨天聊过SUV尺寸这句话就是一句无头无尾的话。长期记忆把昨天的对话转成可检索的向量今天靠语义匹配捞回来再注入当前的上下文模型才知道上次看的那辆车指的是什么。关键的分界线在这里短期记忆是给模型看的上下文长期记忆是给检索用的索引。前者追求全、近、快后者追求准、稳、可淘汰。很多人把长期记忆设计成换个地方接着记对话这是个致命的误解。长期记忆不该存原始对话流而该存结构化的事件、事实、偏好片段。对话流是过程数据记忆是沉淀结果两码事。1.2 没有记忆层的Agent是什么体验我劝所有想直接上手写代码的人先亲手体验一下无记忆Agent的窘境。你搭一个最简客服机器人上下文窗口设8轮用户问完A问题再问B问题答案还能接上一旦用户说我刚才不是说过了吗这个机器人就开始装失忆。真实场景比这残酷得多。用户隔天回来上来第一句是那件事怎么样了你连那件事是哪件事都不知道。用户改了需求说预算提到35万吧系统判断不了这是新需求还是修改旧需求。用户在10轮之前提过一个关键约束被滑动窗口挤掉了后面所有回复全部跑偏。这些都是无记忆系统的原生缺陷——不是模型能力不够是你根本没给它可回忆的素材。1.3 记忆设计的三个核心动作写入、召回、遗忘我画过一张特别简单的图记忆系统干的事就三件——写入、召回、遗忘。写入发生在对话进行中或结束后来自短期上下文的沉淀与提炼。召回发生在每轮新请求进来时把和当前问题相关的记忆片段捞出来塞进短期上下文。遗忘是很多人忽略的一环但恰恰是它决定了长期记忆的精度——一直往里塞、从不清理检索噪声会越来越大最终整个记忆层失去意义。后面几个章节我就按这三个动作逐层拆开讲。先讲短期记忆怎么做再讲长期记忆怎么存、怎么召回最后讲写入和遗忘怎么控制。你可以把整套当成一个可以直接放进自己项目的Memory模块来读不依赖任何特定大模型或商业服务。2. 短期记忆的工程实现对话上下文的数据结构与窗口管理很多人觉得短期记忆就是把messages传回模型这想法太天真。生产环境里上下文空间是稀有资源模型有输入长度上限有token成本有注意力衰减。你塞得越多模型对核心指令的遵循度越差对旧信息的误读率越高。短期记忆设计的全部学问就是如何在有限的窗口里最大化保留对话的连贯性。2.1 上下文对象的基本结构一个成熟的短期记忆不应只存用户说了什么、机器人回了什么。我一般在代码里维护一个结构化上下文对象大概是这个样子{ session_id: sess_20240101_001, start_ts: 1735689600, user_profile_delta: { preferred_city: 杭州, budget_lower_bound: 250000, budget_upper_bound: 350000 }, active_goal: 寻找中型SUV预算30万上下, dialog_buffer: [ {role: user, content: 我家车位长5.2米, ts: 1735689600}, {role: assistant, content: 那这款车长度4.85米停进去没问题, ts: 1735689605} ], pending_tasks: [], last_summary: 用户初步看中两款SUV待比较油耗和后备箱空间 }注意几个字段的意义user_profile_delta是当前会话中浮现出的用户画像增量active_goal是当前的核心任务dialog_buffer是原始的逐轮对话last_summary是压缩之后的历史摘要。模型实际拿到的Prompt不是原始buffer而是这几部分拼装之后的产物。好处是画像和任务始终在对话缓冲可以裁剪压缩摘要兜底。2.2 窗口预算与截断策略窗口预算是最核心的工程决策。假设模型上下文上限是16k token我通常这样分配用途预算占比说明System指令与工具定义20%-25%不可压缩固定占用记忆检索结果15%-20%按当前问题召回当前对话缓冲40%-50%最近几轮原始对话历史摘要10%-15%压缩后的历史输出预留10%留给模型的生成token每次请求进来先算当前buffer占了多少token。超了怎么办顺序是先把最早的对话挪进摘要再把过时的画像增量合并最后才丢弃细节。绝不无脑从中间砍那样对话逻辑会断裂。执行上我封装了一个trim_context函数核心逻辑是维持最近k轮完整对话不动k根据场景设5-8更早的内容交给摘要模块压缩压缩完塞进摘要段。代码示意def trim_context(ctx, max_buffer_tokens, keep_recent_rounds6): recent ctx[dialog_buffer][-keep_recent_rounds * 2:] older ctx[dialog_buffer][:-keep_recent_rounds * 2] old_token_count estimate_tokens(older) if old_token_count max_buffer_tokens * 0.3: summary summarize_dialogs(older) ctx[last_summary] merge_summary(ctx[last_summary], summary) ctx[dialog_buffer] recent ctx[last_trim_ts] int(time.time()) return ctx这段逻辑的精髓在summarize_dialogs不逐句总结而是抽取本轮对话里出现的实体、用户的明确偏好、做出的决策、遗留的任务再和已有的last_summary合并。这样摘要是一条不断追加的事实流而不是一团越来越糊的复述。2.3 短期记忆的中转会话摘要会话摘要是短期记忆和长期记忆之间的桥梁。它有两个职责第一在上下文截断时保住历史关键信息第二在会话结束时把仍然值得长期保留的结论提炼出来交给长期记忆写入模块。我踩过一个典型的坑摘要越写越长最后摘要本身就占了大半个上下文。后来加了两条规则摘要只保留尚未过期的决策和跨轮次引用过的实体如果一条信息被新信息覆盖比如预算从30万改成35万旧条目直接抹掉。摘要不是日记是当前还在影响对话走向的活跃信息集。另外强调一点摘要生成时机不能只在截断时做。我建议每5-8轮对话收敛一次或者每次检测到用户明确表达偏好、决策时立即触发增量摘要。这样摘要永远滞后不超过几轮上下文不会突然大起大落。3. 长期记忆的存储设计向量化、分块与元数据体系进入主力章节长期记忆怎么存。标题里长期存向量五个字听着简单落地时有一堆细节什么样的文本才能向量化多大的块算一块存的时候要附带哪些元数据向量库选什么我会逐个展开。这里的每一项都直接决定后面召回质量的上限。3.1 Embedding与向量化的现实约束向量化不是扔给Embedding模型就完事。Embedding模型有一个隐性假设输入文本的语义是完整、独立、可自洽的。你把一句嗯好的我再看看喂进Embedding模型得到的向量没有任何检索价值——它不是记忆单元只是一个没有语义锚点的碎片。所以向量化之前的一个核心动作是先提炼、后向量化。不能直接把原始对话消息塞进向量库。我一般在会话结束或中断后让大模型把这段对话转成一组结构化记忆条目再对每一条单独做Embedding。比如一段用户纠结选车的对话可以提炼成三条记忆记忆条目A: 用户偏好中型SUV对油耗和后备箱空间敏感 记忆条目B: 用户车位长5.2米对车辆长度有硬性限制 记忆条目C: 用户当前预算区间25-35万已排除某品牌这三条每一条都是一段完整语义向量化之后彼此正交性好检索命中率远高于把10句原始对话一起Embedding。Embedding模型的选择上坦白讲大而全的通用语义模型在垂直场景未必好用。我尝试过多种开源中文Embedding和通用API在客服记录用户画像这类场景上专门用业务数据微调过的Embedding明显比通用底座效果高一截。如果没有微调条件至少在检索前做一下文本归一化去掉语气词、纠正明显的指代这辆车改成具体车型名、统一专有名词说法。这些预处理会让向量召回的稳定度提升不少。3.2 存储单元怎么切事件记忆、事实记忆、偏好记忆长期记忆的粒度问题直接决定后续维护成本。我把记忆条目分三类分别用不同的Retention策略事件记忆一次具体的交互过程比如用户在某日对比了A车和B车最终倾向A。它有时效性但也可能是未来决策的参考。存储时带event_ts和topic_id。事实记忆客观稳定的事实比如用户所在城市杭州家里车位长5.2米现有一辆轿车。这类几乎不随时间变化是召回的最高优先级。偏好记忆用户明确表达的主观倾向比如希望油耗低在意后排空间预算不超过35万。偏好可能变化存储时带confidence字段和updated_ts后续靠更新机制修正。这三类不能混在一个pool里无差别向量化。我的做法是给每个条目加type标签检索时按当前query的类型加权用户问我还有多少预算时优先捞fact和preference事件记忆靠后用户问我上次对比到哪了优先捞event。存储单元的最小单位控制在 50-200字 左右。超过200字的长段落检索到之后模型也不容易精准定位信息太短则语义太薄碰什么都像。如果你手头信息就是长切分时要按语义完整性切不要按字符数硬切宁可相邻块有一句话的冗余也别把一个完整结论劈成两半。3.3 元数据设计召回时真正靠的是标签不只是向量这是很多文章不谈、但实战中最影响效果的部分。向量库里的每条记忆除了embedding和text必须带一份够用的元数据。我实际用的字段大致是{ memory_id: mem_000123, user_id: u_00001, type: fact, topic_id: car_purchase_202401, source_session: sess_20240101_001, created_ts: 1735689600, updated_ts: 1735689600, access_count: 0, importance: 0.8, expire_ts: null }topic_id特别好用。向量检索只能解决语义相似的问题解决不了任务上下文连续的问题。用户聊着车忽然问那明天天气怎么样语义上和买车记忆八竿子打不着但严格说这不算新任务是当前会话的分支。按topic_id做一次过滤把同主题的旧记忆全捞出来比纯粹靠相似度靠谱得多。access_count和importance是遗忘机制的输入信号后面第5章细说。总之元数据不是存储的附属品它就是搜索的骨架。3.4 向量库选型本地起步之后迁移也不慌不少团队一上来就引分布式向量库对一个小项目来说运维成本和收益完全不成比例。我的建议是分阶段原型/小规模千级-万级条目用本地文件型向量库或者SQLite加一个向量扩展就够了。部署简单、调试直观还能直接读库检查写入质量。中等规模十万级换支持数据分片和持久化的集中式向量搜索服务。这类方案通常配套完整的索引参数调优能力。大规模百万级多租户才需要考虑分布式集群。换库的风险没那么大因为上层API无非是 upsert / query / delete 三个动作。只要把存储层封装成一个MemoryStore接口底层实施全隔离后面换引擎就是改一个实现类的事。我在多个项目里都这么干没有一次被存储引擎绑死过。检索参数的默认值TopK 取 5-10score阈值因模型而异一般从0.75起步调。阈值设太低召回一堆无关碎片太高真正有用的信息被过滤掉。没有捷径拿一个有代表性的测试集多跑几轮用二分法定位合理区间。4. 记忆召回检索逻辑、评分阈值与上下文注入存得再好召回不行就是白存。召回机制决定哪些记忆能被想起来我从召回时机、资历过滤、多样性去重、注入位置四个角度讲每一个都和最终效果强相关。4.1 召回时机不是每轮都要查我见过最浪费的做法每轮用户输入都去向量库检索一次然后无论有没有用把Top5统统塞进Prompt。结果就是Prompt里堆满了无关记忆既浪费token又干扰模型判断当前意图。正确的召回时机分几类新会话启动必须召回到user_profile_delta画像和历史关键决策让模型想起这个用户是谁、上次聊到哪。会话中话题切换当模型判断当前输入与最近几轮对话无关可以设一个意图漂移检测触发一次检索。用户显式引用出现上次说的之前那个这类引用词时这是一次高优先级检索信号应该立即召回相关事件记忆。有一个很实用的机制热度检索 延迟加载。每次召回只把精准命中的3-5条直接注入上下文额外检索的候选项延迟缓存如果模型发现上下文信息不足、再走一次补充检索。这样平均每轮只消耗一次检索的p95延迟效果却接近每轮都深度召回。4.2 评分与过滤别让相似度数值决定一切向量库返回的相似度分数只是召回的第一道筛子。只按分数排序会出两个严重问题第一个问题是碎片命中。某个记忆条目里同时提到预算30万、杭州、SUV但用户当前只问了杭州有什么推荐的4S店这条记忆里只有杭州一个词相关其他信息全是噪声但还是会被高分捞上来。过滤办法有两个要么做细粒度切块保证单个条目单主题要么在召回后加一层关键实体对齐检查把记忆文本里的实体和当前问题里的实体做一次重叠校验重叠超过阈值才最终入选。第二个问题是重复信息挤占槽位。同一个事实被存储了多条近似版本比如用户预算是分两次对话慢慢提到35万的生成记忆中可能出现三条相近条目。召回不加以别三条一起进来上下文就是一种变相的重复。我做了一个简单的MMR最大边际相关性重排保证候选集内部互相之间不要太相似。4.3 注入的位置和呈现方式召回出来的记忆不是简单拼到Prompt末尾就完事。模型对不同位置信息的关注度不一样权威性感知也不一样。我在Prompt里设计了专门的记忆区放在System指令之后、会话对话之前结构如下[系统指令] [当前用户画像摘要] [与本轮相关的历史记忆按时间倒序标注来源时间] [本次会话上下文] [用户最新输入]记忆区的每条记录我强制要求以第三人称转述格式写入而不是保留对话原稿。对比一下原稿式用户我想换个空间大的车。记忆式事实用户偏好空间较大的车辆记录于1月12日会话后者模型更容易直接引用、不容易被对话角色绕晕。实际测试下来同样一组记忆改成记忆式呈现后答复准确率能提升不少。注入数量上我控制在3-5条太少记不住事太多模型开始想象记忆之间的关系。另外注入时带上recorded_ts记录时间能显著减少模型的幻觉——模型看到用户预算从30万上调到35万1月14日更新它知道这是最新状态不会再纠结之前那条老记录。5. 记忆生命周期写入、更新、冲突与遗忘机制Writes and deletions are the part people usually skip. 但恰恰是什么时候写入旧记忆怎么更新哪些记忆该淘汰决定了长期记忆层能否长期健康运转。这章讲生命周期管理是整套设计里最见功力的部分。5.1 写入时机与结构化提炼写入不是一个实时动作。我做的是阶段化批量写入分为会话进行中只更新短期记忆不碰向量库。理由很简单对话还没结束意图和结论都在变化过早写入会导致一堆半成品记忆污染索引。会话结束时触发一次提炼把摘要和buffer里的关键信息转成结构化记忆条目再批量Embedding写入。会话中断/超时如果用户没点结束但超过30分钟无新消息系统也会跑一次提炼写入防止信息丢失。每轮提炼我都用一个固定的提示模板要求模型输出合法的记忆条目JSON包含字段type、topic、fact_content、importance、expire_ts。不是让模型自由写故事而是强制抽取结构化事实这点非常关键。自由式的总结句一段话里能揉进三件事将来检索和更新都很难处理。5.2 同实体信息的合并与冲突消解长期记忆最怕数据打架。用户这周说预算30万下周说预算35万如果两句话分别存成独立条目检索时会同时捞出来模型就懵了到底按哪个算我的做法是引入记忆合并器Memory Consolidator。写入新记忆前先按user_id topic_id向量范围过滤一遍已有条目然后做两件事事实更新如果新记忆和旧记忆描述的是同一属性且新版置信度更高通常是更晚的时间戳直接更新旧的fact_content和updated_ts并把旧embedding替换成更新后的新embedding。信息合并两条记忆分别描述同一对象的不同维度比如在意油耗和在意后备箱空间合并成一条复合记忆用户选车在意油耗和后备箱空间这样检索时一次命中全部约束。合并操作在纯向量库里比较别扭所以我在存储层加了一个关系型辅助表记录memory_id和实体的关联。合并时通过辅助表定位所有相关旧条目删除旧向量、写入新向量。整条链路体验下来比在向量库里裸奔游刃有余得多。5.3 遗忘机制让记忆库活下来遗忘是记忆系统能长期工作的重要保障。我维护三个遗忘信号时效过期设置了expire_ts的事件型记忆比如用户本周出差到期直接删除或归档。访问热度衰减长时间没有被召回的记忆access_count长期停留在低位按LRU思路定期清理。重要度降权importance低于某个阈值的记忆召回时不但参与排名的权重低还会被周期性回收站处理掉。我一般在每天低峰期跑一次整理任务流程扫描所有expire_ts now的记录 → 标记归档扫描access_count连续N天为0且importance低于0.4 的记录 → 移除。这个任务不追求实时只要保证长期索引不膨胀就行。5.4 成本控制与数据边界写向量库要花钱存得越多检索越慢、费用越高。除了依赖遗忘机制写入之前还得多一道这事值得长期记吗的闸门。我的标准很简单这条信息在未来3个月用户还会不会用到用户随口说的今天午饭吃了牛肉面就不值得存公司地址在软件园南门就要存。判断逻辑靠importance评分阈值多跑几批真实对话你会找到自己的平衡点。另一个边界是隐私。用户可能明确要求别记我这个信息或者某些字段根本不该入库。我的记忆写入管线里始终带一个PII检测层命中身份证号、手机号、银行卡号等内容的直接脱敏处理绝不进向量库。这不是合规要求的问题是任何生产系统的基本教养。6. 从Demo到可用的坑实测体验与调优心得最后一部分分享几段从这套架构真正落到线上之后踩出来的实操经验。这部分内容不是文档里能查得到的但价值可能比前面所有原理都高。6.1 冷启动阶段记忆系统最容易被误解的时期刚上线的前两周记忆库几乎是空的任何召回都捞不到东西。这个时候团队容易产生两个错觉一是记忆系统没起作用二是既然空先想办法导入一堆历史数据填满它。第一个错觉需要靠测试用例校验设计一批需要记忆才能回答的场景比如昨天说过今天还来问专门验证记忆链路通不通。第二个错觉我强烈建议克制住。导入历史数据没问题但别导入原始聊天记录——我见过导了一堆原始日志的库召回的准确率低到想哭因为原始日志里大半是嗯好的这种噪声碎语。冷启动期先记录新会话的提炼产物等存量自然增长质量远比急急忙忙灌数据强。6.2 多轮对话中短期记忆和长期记忆的掐架实测中最频繁的诡异现象是长期记忆把昨天的事实捞回来了但用户今天已经改了主意——双方在同一个Prompt里打架。比如记忆区写预算30万对话缓冲里用户说预算提到40万了。这个问题的根治方案是在召回时做时效对齐召回结果在注入前先和当前对话缓冲做一次实体和属性的冲突检测。如果发现同一个attribute双方都有值以对话缓冲里的最新值为准记忆区的旧值直接丢弃注入。这个检测不复杂但能救回很多让用户抓狂的回复。6.3 一套省力的评测方法模拟访谈测试如何评测一套记忆系统好不好说实话端到端人工评测最真实但费时费力。我自己常用一个折中方案准备20个跨会话场景的对话集每个场景先让Agent和一个模拟用户A聊完第一轮隔一段时间再让模拟用户B假装同一人聊第二轮第二轮里故意引用第一轮的内容。然后人工打分Agent有没有准确回忆起被引用的信息有没有不被第一轮过时信息误导有没有记忆幻觉编造记忆里不存在的内容。这样一轮跑下来记忆库的质量、召回的精度、注入的合理性都能暴露出来。跑完针对失败case微调召回不足的调低score阈值或增加TopK干扰过多的调高阈值或加实体对齐记忆幻觉的检查条目内容和原始提炼模板。6.4 几个可以直接抄的小技巧最后丢几个实战中积累的细节一个人一个样但都来自真实场景记忆条目的文本格式统一用陈述句不要留对话体否则会话摘要和长期记忆互相引用时人称特别容易乱。向量入库前做个小写归一化和繁体转简体如果面向中文用户能缓解不少检索匹配问题。召回结果按时间倒序排列通常比按相关度倒序更自然用户最近的状态优先级永远最高。给记忆库加一个手工修补入口运营人员发现某条记忆明显错误时能直接编辑或删除。别低估这个能力线上问题排查时它能救你于水火。不要过早做记忆的层次化总结也就是别急着把多条记忆二次聚合成更高阶的主题。在检索没有充分验证之前聚合只会放大错误。我在实际项目里反复调整近一年最大的体会是记忆设计没有什么一次到位的银弹它更像一个需要持续观测和修正的子系统。先把写入、召回、遗忘这条主干架构搭对剩下的指标都是靠一轮一轮真实对话磨出来的。希望这篇文章能帮你少走几条弯路让你从第一版代码开始就走对方向。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号