ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent记忆底座怎么搭?从AI数据库选型到上下文组装全解析

Agent记忆底座怎么搭?从AI数据库选型到上下文组装全解析 最近好几个团队找我聊 Agent 记忆聊来聊去总会绕回同一个场景历史对话、用户画像、业务知识全都接进了 AI 数据库Agent 表面上也“记得”以前的交互可一到真正回答的时候就露馅——要么把上周的库存当今天的要么把用户随口说的一句话当成永久偏好要么在同一轮对话里自相矛盾。更尴尬的是你把日志翻出来一看数据库里明明白白存着那条记录检索结果也是对的模型偏偏还是用错了。这个现象我得说句实话绝大多数 Agent 项目把记忆做成了“存进去就行”根本没把记忆当成一个工程系统来设计。AI 数据库要当 Agent 的记忆底座关键不在“能不能存”而在“存得对不对、查得准不准、喂给模型的时候有没有管好优先级”。这篇文章我从实际做过的项目出发把 Agent 记忆底座的选型思路、数据结构、检索链路、上下文组装这些环节拆开讲重点分析“记住了为什么还会用错”这个高频问题最后附一套可以直接抄的排查手册。适合正在搭 Agent 应用、或者做完 demo 之后发现记忆不靠谱的工程师参考。1. 先搞清楚AI 数据库到底在 Agent 里扮演什么角色1.1 为什么 Agent 需要“记忆底座”它和普通数据库有什么区别传统业务系统的数据库解决的是“数据持久化”问题——订单存进去查出来事务保证一致性这就可以了。但 Agent 需要的记忆底座完全不是这个逻辑。Agent 的记忆是一个“活”的系统写入发生在不可控的对话过程中读取发生在用户每次提出新问题时而读取出来的内容还要影响模型的推理输出。这意味着 AI 数据库不仅要存得住还要能按语义找得到、按时间排得准、按优先级放得好。我做项目时内部常用一个分类法Agent 的记忆大致分成四层。第一层是工作记忆就是当前这轮任务中正在处理的临时状态——用户刚上传的文件、刚选择的参数通常放 Redis 这类 KV 存储里过期时间很短。第二层是情景记忆指过去发生过的具体交互事件——“上周二用户问过库存问题当时回复数字是 X”这类记忆适合用向量数据库做语义检索。第三层是语义记忆是用户长期稳定的画像和明确的业务规则——“这家客户偏好蓝色包装”“这批货的毛利底线是 30%”适合放结构化存储并强调准确性。第四层是流程记忆是 Agent 学会的解决问题步骤和方法通常沉淀成 skill 或提示词片段。这四层记忆的读写频率、一致性要求、存储形态完全不同指望用一个库全包解决后面一定会出问题。很多人问“AI 数据库是不是就是向量数据库”我一般会回答向量库只是记忆底座的一个组件而且往往是最容易被高估的那个组件。1.2 AI 数据库不是“一个库”而是一套存储组合实际落地时我建议你把它拆成一套“存储矩阵”来设计没必要追求某个“All-in-one”的神器。关系型数据库继续保留它的位置用来存用户画像、业务事实、事件日志这类强结构化数据事务和一致性是它的主场。向量数据库负责语义检索处理“用户之前提过的类似问题”“语义相近的历史片段”这类非精确匹配需求。KV 存储重点服务工作记忆扛住高并发场景下对温度、临时状态的快速读取。图数据库则在实体关系复杂、需要多跳推理的场景里有用比如“这个用户参与过哪些项目项目关联了哪些物料”这类问题。这里有个经验很多人把向量库当万能库把什么都塞进去结果既丢了结构化查询的能力又因为向量维度稀释导致召回质量急剧下降。我自己踩过这个坑早期项目里把用户 ID、时间戳、业务标签全拼进文本再灌进向量库后来发现过滤条件根本没法精确执行只能靠相似度硬扛效果惨不忍睹。正确的姿势是“主键和元数据分离”——向量库负责语义相似度的粗筛真正的结构化强约束条件时间范围、用户 ID、业务类型要放在元数据过滤里做精确的 pre-filter 或 post-filter。1.3 别把向量检索当成记忆读取的全部还有一个常见的认知偏差以为“记性好”等于“相似度检索做得好”。实际上在 Agent 记忆场景里向量检索只是入口。你还会需要关键词检索BM25来兜底那些专有名词和精确数字——向量检索对“编号 ABC-1234”这类信息经常失效但用户问“上次的 ABC-1234 报价还在吗”时恰恰需要精确命中。你也需要元数据硬过滤来保证时效性和归属正确比如“只查这个用户最近 30 天内的记录”“排除来源是测试环境的日志”。我把这套组合策略称为“粗筛精筛兜底”向量做语义粗筛检索出候选集元数据过滤做精筛砍掉不符合硬条件的记录BM25 做兜底专门捞向量漏掉的精确匹配片段。三道关卡都过了候选集才有资格进入模型上下文。很多“记住了但用错”的案例往前追根因都是漏了其中某道关卡。2. 记忆底座怎么搭从数据模型到写入策略2.1 记忆单元的数据结构别只存一段文字和向量我见过太多团队建的记忆表只有三列id、content、embedding。这种设计放到 demo 里跑没问题上线之后必坑。原因很简单模型拿到一条记忆时光有文字是不够的它需要知道这条记忆是什么时候发生的、是谁说的、可信度多高、属于哪类记忆、当时上下文是什么。这些信息不结构化模型就只能瞎猜一猜就出错。给你一份我在生产环境用过的记忆单元字段模板重要程度从高到低排。身份信息是最关键的agent_id、user_id、session_id 必须独立建字段并且强制要求写入时填充这是后续做归属过滤的基础。时间信息也是一样重要包括发生时间、首次记忆时间、最后访问时间有了这些字段才能做时效衰减和过期清理。内容层面原始文本和建议摘要要分开存原始文本保证信息不丢摘要用于快速浏览和摘要级检索。来源信息方面来源渠道要记录是用户主动说的、系统推断的、还是外部系统同步的这个字段在冲突处理时权重很高。业务信息像所属业务域、关联实体 ID、重要程度评分用于精筛和排序。最后状态信息标明记忆是否被用户纠正过、是否已经过期能避免模型把旧信息当成当前事实。这些字段看起来麻烦但每一列都在回答同一个问题当模型拿到这条记忆时它有足够的信息判断“这条记忆现在还能不能用、有多可信”。没有这些元数据的记忆本质上是没有保质期的错误来源。2.2 写入策略不是所有对话都值得记很多 Agent 项目把“对话日志”和“记忆”混为一谈凡是用户说过的都往记忆库里写。这个习惯是记忆系统的头号杀手。对话日志追求完整性和可追溯性记忆追求的是“当前和未来决策有参考价值的信息”。全量写入的直接后果是记忆库迅速被闲聊、重复内容、临时状态灌满向量检索信噪比越来越低最后模型动不动就从一堆无关记忆里强行找关联。我的做法是给写入加上“记忆价值评估”这道闸门。每个对话片段经过一个轻量的判断流程常见的触发记记忆的条件包括用户主动表达偏好“我更看重性价比”用户确认了一个事实“这个方案定了”出现了可复用的业务约束“报价低于成本价不要发”用户明确纠正了先前的信息“我说的不是那个是另一个”以及完成了一个关键任务节点“第二轮筛选完成剩余 3 家”。判断方式可以用一条精简的 prompt 交给大模型也可以先用规则快速拦截明显没价值的片段。这里有个工程细节值得提对话里出现“用户纠正信息”时不能只追加一条新记忆必须在旧记忆上打一个“已失效”标记否则新旧两条记忆会同时被召回模型就陷入自相矛盾。类似地用户重复表达同一偏好时要合并而不是堆积否则检索时同一偏好会出现多个不同措辞的版本影响一致性。2.3 记忆入库的原子操作一次写入要更新几个地方记忆写入不是“insert 一条记录”这么简单。一条新记忆的产生至少应该同步做这几件事生成文本摘要判断这段记忆的类型更新或创建对应的结构化画像字段生成向量并写入向量索引可能的话还要触发对关联旧记忆的合并或失效检查。这套操作如果不能保证原子性就会出现数据不一致的隐患摘要更新了旧向量还在索引里模型一搜就搜到过期内容。从时序上我推荐“先写事实库再写索引库”的顺序。因为事实库关系型存储是源向量库是派生的检索索引。万一向量写入失败还可以从事实库重建反过来如果事实丢了只剩向量片段想回溯原始信息就难了。用工程术语说这就是一条数据两种视图事实视图负责保真检索视图负责发现二者必须通过同一主键关联。这个主键设计我会建议直接用业务 ID 而不是自增 ID方便追溯对账。3. 核心问题拆解记住了为什么还会用错3.1 检索层召回的不是“对的记忆”而是“像的记忆”先看最表层的环节检索。向量检索的原理是通过 embedding 把文本映射成高维向量用距离度量语义相似度。问题是“语义相似”和“当前问题真正需要”之间有一道鸿沟。举个真实例子用户问“我们上个月的采购成本大概是多少”系统里存着的历史记录“上个月采购了三批原材料总成本 XX 万”在语义上确实相似如果同时还存着“去年上个月采购成本 XX 万”向量距离可能同样很近。模型得到这两条记忆后如果检索环节没有做时间优先级控制完全可能报出错误数字。这里还有一个容易被忽略的细节embedding 模型对长文本的语义表达并不稳定。你入库时存的是整段对话转录可能几百上千字向量是整段池化出来的关键信息具体数字、关键实体被大量无关闲谈稀释。用户问“库存还剩多少”你检索到的向量匹配对象是“当时聊到库存问题时的完整对话”但精确的剩余数字可能只藏在对话转录的某个角落。模型拿到的是一条“语义上像、内容上不精确”的记忆。解决办法是入库前做切分和摘要结构化让向量检索的粒度更细宁可一条大记忆拆成几条原子记忆。3.2 编排层有用的记忆被淹没在上下文里检索出的记忆最终要拼到 prompt 里交给模型。这个环节的问题是“查到了但没用上”。翻车原因大多出在上下文管理上。一方面有些工程实践喜欢把检索到的记忆全部拼进 prompt不做截断和排序。Bad idea。大语言模型有明确的注意力偏置研究里常提的“lost in the middle”现象就是中间位置的信息容易被忽略。你把一堆记忆按检索分数排好塞进去模型可能只看开头和结尾中间那段最关键的反而没被参宿。另一方面记忆的呈现方式也有讲究。同样的信息“用户偏好气泡水”放在一大段对话记录里和单独成行写在“## 用户核心偏好”小节里对模型的注意力权重影响天差地别。我的经验是交给模型的记忆必须要经过“重组织”而不是把原始检索结果原样输出。可以按角色拆分成用户画像、业务规则、历史事实三个区块每个区块内按重要度排序关键信息前置。顺序上有个稳妥的做法让最新且最重要的记忆靠近 prompt 开头和结尾这两个注意力高地中间放次重要的内容。3.3 模型层模型对记忆的信任方式比你想的更“肤浅”即使检索准了、编排也合理了模型还是可能用错。这里涉及模型本身对证据的整合能力。模型不会像人一样自动区分“记忆里的旧事实”和“当下的新语境”它会把 prompt 里所有的信息当作一个整体来做推理然后倾向用最近出现的、表述更明确的说法。如果你在 prompt 后面输出了用户当前诉求又在前面塞了历史记忆两者在时间逻辑上有冲突时模型不一定能正确选择“该以哪个为准”。它可能按位置就近原则用了新语境也可能被历史记忆带偏用旧的约束去回答新问题。更麻烦的是很多团队在提示词里写“请基于记忆回答”这句话太弱了。模型需要的是明确的决策规则比如“当记忆内容与用户当前提供的信息冲突时以用户当前信息为准并说明原因”“当记忆内容超过 30 天且未被再次确认时默认作为参考而非事实”。没有这些决策边界模型就只能凭语感选择出错是必然的。还有一点模型对“记忆的可信度”没有天然判断力你需要在 prompt 里显式传递每条记忆的元数据比如“该条记忆来自用户当时明确确认可信度高”或“该条记忆为系统推测需谨慎参考”。给记忆打上可信度标签模型犯错的概率会明显下降。3.4 更新层记忆过期、冲突和覆盖机制缺失最后是更新层也是最多人忽略的一层。记忆是动态的用户偏好会变业务状态会变外部系统数据也会变。如果你没有设计“记忆更新机制”就会看到 Agent 拿着三个月前的数据信誓旦旦地回答当前问题。核心要做三件事时效过期、合并冲突、主动回写。时效过期不只是删除旧数据而是要把“这条记忆最后一次被验证的时间”纳入检索排序。我常用“指数时间衰减”的思路把记忆按重要度和新鲜度加权排序旧而不重要的排后同时对于超过业务时限的记忆比如库存这种实时数据应直接从检索候选集排除而不是靠排序压后。合并冲突的处理在前面提到过新事实进来时打旧失效是保持记忆库一致性的关键。主动回写则是把外部系统的最新状态同步进记忆库比如库存系统的实时库存量每日写一条权威记录历史记录只留趋势参考。没有主动回写机制你的记忆库会越用越“脏”。4. 一套可落地的记忆检索与上下文组装方案4.1 检索前的第一步Query 改写与意图判断当用户抛出一个新问题直接拿原始问句去做向量检索通常效果一般因为口语化问句信息量低而且可能省略了关键的限定条件。需要先做一个检索前处理把用户问句改写成一个更适合检索的查询语句并识别这次的检索要做哪些元数据过滤。仍以库存场景为例用户说“上次那批货还有吗”直接去查“那批货”基本查不出来因为“那批货”是个指代词。改写后的查询应该是“XX 型号原材料的库存数量现状”同时根据对话上下文判断要过滤的业务域和用户归属。这个改写可以用 prompt 让 LLM 完成但要注意控制改写也不宜过度别把问句扩展到完全不同的范围。一个工程小技巧把你允许的改写动作限定为几个固定模式补充缺失的限定词替换指代词为具体实体补充业务域标签。超出这些模式就不要强行改写宁可用原始 query 去检索。4.2 混合检索向量、关键词和元数据过滤怎么配合正式检索阶段前端先并行执行两个通道向量通道用当前 query 的 embedding 在向量库里找 top 50 个候选关键词通道走 BM25针对实体名、编号、精确名词做匹配也返回 top 50 个候选。两侧结果合并之前都要先过元数据过滤字段包括所属用户、业务域、时间范围、记忆类型、状态标记。过滤这一步我建议前置在向量检索里用 pre-filter 方式做而不是等结果出来再滤否则过滤后的结果太少白白浪费检索资源。两通道合并之后把重复项合并得到最终候选集。这里有个执行细节关键词通道的 BM25 在很多现代向量数据库里不是默认开启的需要单独配索引或走外部 ES/Meilisearch维护成本会高一些。如果初期业务规模不大也可以简化成“向量为主、精筛兜底”两级但一定要在意识和数据结构上留好关键词检索的扩展位否则后面想加就要重构。4.3 Rerank给记忆排序的不该只有向量距离候选集出来以后按什么顺序排给模型绝大多数默认实现是按向量相似度降序排列但这远远不够。向量相似度代表“语义像”排序应该综合更多信号。我常用一个轻量级 rerank 方案不需要额外部署一个专门的 rerank 模型虽然那样效果更好而是用一个加权打分公式综合分 语义相似度分数 重要度分数 时效新鲜度分数每项按场景设定不同权重。举一个具体的加权经验值供参考语义相似度权重 0.5重要度权重 0.3时效权重 0.2。重要度来自记忆写入时打的业务重要程度标记比如用户明确的规则性约束记 5 分、一般的对话陈述记 2 分。时效则按记忆最后确认时间做衰减最近一周内的满分超过一个月的乘 0.5超过三个月的乘 0.2。同时加一个硬性逻辑业务上有明确时效要求的信息类型一旦超过业务有效期直接排除而不是排后。这套分数计算可以用简单的 SQL 或内存脚本完成不需要模型参与性价比很高。4.4 上下文组装把记忆放在 prompt 的哪个位置、占多大比例最后一步是把选好的记忆拼进要发给模型的 prompt。我在项目里以“组装区块”的方式来管理而不是简单的“追加到对话尾部”。首个区块是确认的“事实层”在这块列出经过筛选的硬事实用户身份信息、明确的业务规则、经过确认的当前状态。这个区块放在系统提示词后面、对话内容之前让模型在“世界观”层面直接建立认知。第二个区块是“背景层”放历史事件摘要、参考案例这块内容的重要性低于事实层放在对话内容中间即可。第三个区块是“即时语境”对应当前这一轮的对话上下文放在结尾。从比例上我通常会做总量控制。硬性规则是记忆内容占 prompt 总 token 的比例最好不要超过 30%超过这个比例信息密度太高模型很难兼顾当前对话焦点。宁可多轮检索也不要一次性把所有候选记忆全塞进去。你换一个角度想让模型在大量记忆里“找重点”不如你把重点提炼好再交给模型。这就是为什么我强烈建议每条记忆入库时同步生成摘要上下文组装时优先放摘要原始长文本仅在模型明确需要时以展开形式提供。5. 常见问题排查手册与真实案例5.1 六个高频症状的排查路径下面这些场景我在实际排查里反复遇到整理成了一个速查表基本覆盖了“记住但用错”的各个根因层面。症状可能根因排查方法修复建议回复引用了很久以前的过时数据检索排序没有做时间衰减或过期记忆未被标记失效查看检索命中的候选集中 created_at 的分布确认过期数据是否排在最前增加时效权重对明确会过期的类型做硬性排除检索返回的内容与当前问题完全无关只用了向量检索语义被噪声干扰或者阈值设置过低检查召回结果的相似度分数对比关键词检索的结果加入 BM25 关键词通道提高相似度阈值启用元数据过滤用户纠正后 Agent 仍然坚持旧信息纠正确认没有回写记忆库旧的失效标记缺失检查记忆库中该条记忆的 status 字段和更新时间建立“用户纠正”触发机制强制原记忆失效并写入新事实同一事实在回答中多次冲突记忆没有去重合并多个不同版本并存搜索记忆库中同实体关联的同主题记录是否重复引入合并策略写入时按实体做查重和版本合并检索对了但模型没用到关键记忆记忆被淹没在长上下文中注意力被无关内容抢占检查最终 prompt 中记忆区块的位置和截断策略做区块化重组重排顺序压缩记忆占比Agent 对记忆内容过度自信把推测当事实记忆缺少可信度元数据模型无法区分依据强弱检查记忆记录的 confidence 字段是否为空为每条记忆补充来源和可信度标签并在 prompt 中显式标注5.2 一个真实的 case库存数据报错事件排查全过程有个项目找我来复盘过一次事故场景很典型。客户的 Agent 负责给销售团队报库存和报价上线两周后销售反馈“报出来的库存数比实际多了不少”。当时团队的直觉是数据同步出了问题于是先去查外部库存系统的对接任务但日志显示每天的库存同步任务都在凌晨正常跑完数据源的库存量也是对的。问题转向记忆底座我们用检索日志回放的方式定位到一条关键记录那天早上九点销售问“A 型号现在能出多少货”Agent 的检索链路召回了两条相关的记忆片段。其中一条是五天前的“A 型号盘点剩余 120 件”另一条是当天凌晨同步的“A 型号库存 38 件”。理论上当天那条应该排在前面但实际排序时两条记录都没有带时间过滤条件比较时候选集只按向量相似度排结果“120 件”那条因为和问句的表述方式更像而排在了第一位。模型拿到 prompt 后又是按顺序使用信息直接采信了前面的旧数字。这个案例里错误不在数据源不在模型能力而在记忆底座缺了最基础的一项设计时间硬约束。修复方案也很简单给库存这类需要时效类型记忆加一个 hard filter检索时只允许返回最近 24 小时内入库的库存记录超出时限的一律不进入候选集。加上这个条件之后同类问题再没有复现过。这个 case 给我的启发是排查 Agent 记忆问题永远先看检索日志里进了哪些候选再看排序权重最后才轮到怪模型。5.3 几个值得养成的工程习惯关于 Agent 记忆相关的项目我在收尾时想强调几个工程习惯都是踩坑踩出来的经验。第一个习惯是“一切可回放”线上 Agent 的每次检索请求必须记录完整的 query、最终 prompt、候选集排序、模型输出这四样东西。没有这套日志任何一次记忆错乱问题复盘都是盲人摸象。第二个习惯是“先定时效策略再谈检索质量”任何一条记忆从写入那天起就要明确它的保质期因为检索排序只能在优先级上做调整真正能兜底的还是硬过滤。第三个习惯是“对 Agent 做记忆评测要用对抗性问题”真正检验记忆系统的题不是“用户上次说喜欢什么”而是“用户这次说的情况和上次的偏好冲突时怎么办”“用户问的是已经过期的信息时 Agent 会不会纠正”。用这类的坏case去压测才能把问题提前炸出来。第四个习惯可能最容易被忽略定期做记忆库的健康度检查。检查维度包括重复率同一实体是否堆积了大量相似记忆、失效占比已标记失效的记忆是否还被检索到、脏数据率无身份字段、无时间戳的记录数量。我一般建议两周做一次每次只需要跑几条 SQL 看分布但能提前避免很多线上事故。我自己做 Agent 记忆功能这两年最大的体会是AI 数据库这个底座真正难的不是数据库本身而是你对记忆生命周期有没有完整的管理思路。存储只是起点检索是第二阶段的重活更新和失效才是决定成败的关键。下次你遇到 Agent 乱用记忆先别急着换更大的模型按检索、排序、时效、上下文组装这条链路线性排查一遍多半就能找到那个真正让你“记住了却用错”的元凶。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进