ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

AI Agent记忆系统实战:从上下文窗口到用户画像的优化方案

AI Agent记忆系统实战:从上下文窗口到用户画像的优化方案 先说我前两天踩的一个尴尬现场。用户在客服 Agent 里第三次提交收货地址Agent 第三次反问请提供您的收货地址。我当时真想顺着网线问它上一轮我不是刚告诉过你吗后来我把完整历史记录全部塞给模型它倒是能答上来可每轮都要把十几轮对话从头算一遍响应肉眼可见地变慢token 费用也肉眼可见地飙升。这个场景就是 AI Agent 记忆问题的典型现场模型不笨缺的是一个能让它“记得住你”的结构。这篇文章是《走进AI Agent》系列的第三篇专门聊记忆。我会先拆掉“上下文越长等于记忆越好”这个常见误区然后给出三种从轻到重的落地方案接着用 LangGraph 的思路带你把一套带记忆的 Agent 搭出来最后聊聊我在生产环境里踩过的四个坑。想自己动手写 Agent 的开发者可以照着做正在做 Agent 产品方案、被“记忆”两个字搞到头大的人也能从中找到一个开始抓手。1. 先拆一个误区上下文窗口大不等于记忆好1.1 上下文窗口是“能放多少”记忆是“该放什么”现在各家大模型的上下文窗口越做越长百万 token 级别也不稀奇。很多人第一反应是那还要记忆模块干嘛把聊天记录全塞进去不就完了这个想法有一半是对的长上下文确实让“临时不丢”变得容易了但“全塞进去”不是记忆而是把所有原料倒进锅里让模型自己挑。一百轮对话里可能只有三句话对当前问题有用剩下九十七句全是噪音。模型在长上下文里找关键信息的本事确实在涨但远没有你想的那么可靠而且每次请求都全量发送成本和时延都会跟着涨。我见过一个团队把两周的客服聊天全量塞进上下文单次请求的 token 数从两千涨到一万二账单涨了六倍追问率反而没降多少。记忆的本质是“取舍”把什么放进上下文、用什么形式放、什么时候放、放多少。上下文窗口只是容器记忆机制才是决定容器里装什么的那只手。没有了这只手别说百万 token就算给一个亿 token模型也只是在一个更大的垃圾场里找针。1.2 四种记忆类型别再只盯着聊天记录做记忆前先分类。早期做智能对话系统时学术界习惯把记忆分成四类工作记忆、情景记忆、语义记忆、程序记忆。放到 AI Agent 的工程语境里可以这么理解工作记忆对应当前这轮任务的临时信息比如用户上一个问题、刚才返回的中间结果通常就放在 prompt 的上下文里任务结束就清掉。情景记忆是对历史对话事件的记录比如“用户上周三问过怎么注销账号”“他昨天对价格方案表达了不满”。语义记忆是从这些事件里提炼出来的稳定事实比如“用户名是张三”“偏好使用微信支付”“家里养了一只猫叫煤球”。程序记忆则是 Agent 的行动经验比如“遇到退款问题应该先查订单状态再走工单流程”这类记忆很多时候不是存在对话记录里而是固化在系统提示词、工具描述或者工作流配置里。大多数人对“让 Agent 记住你”的理解还停留在情景记忆层面也就是聊天记录。但如果只做聊天记录Agent 顶多算是有“回放”能力谈不上“懂你”。真正让用户体验到“被记住了”的往往是语义记忆和用户画像它得知道你是谁、你的偏好、你上次没办完的事。所以标题里说的“记住你”我建议拆成两条线来做一条线管对话历史负责上下文连续性另一条线管用户画像负责个性化。1.3 为什么全量塞历史效果反而更差很多人相信模型能力提升之后长上下文会自然吸收掉记忆需求。我不否认长上下文会缓解一部分问题但在当前阶段全量塞历史有三个绕不开的硬伤。第一是注意力稀释。关键信息埋在一堆无关历史里模型容易记了后面忘了前面尤其是那种长对话里只出现一次的关键细节。第二是信息冲突。用户昨天说“我喜欢喝美式”今天改成“最近戒咖啡了”两条都在上下文里模型不知道应该信哪条。第三是成本和延迟。token 直接等于钱和响应速度每轮多传几千 token用起来就是肉眼可见的变慢。所以结论很直接长上下文要用来做记忆系统的兜底而不是替代记忆系统。该做索引的做索引该做摘要的做摘要该做画像的做画像。接下来我们看具体怎么落地。2. 三种主流记忆实现从“有手就行”到“生产可用”2.1 滑窗加摘要最省事的记忆方案最朴素的记忆方案其实是滑窗加摘要它不需要向量数据库不需要额外服务很多开源项目里都能见到。思路很简单只把最近 N 轮对话完整放进上下文超过窗口的旧对话让大模型生成一段摘要再和本次对话拼在一起。比如窗口设为 10 轮prompt 结构就是“以下是之前对话的摘要[摘要]以下是最近对话……”。这个方案的好处是结构简单、成本低、容易调试。坏处也很明显摘要是一次性的随着时间拉长早期细节会被压缩得面目全非。用户三个星期前提过一句“我对花生过敏”如果当时没被写进摘要后面就彻底丢了。所以滑窗加摘要更适合临时性场景比如一次性任务、客服单轮问答不太适合需要长期陪伴或深度个性化的产品。2.2 向量检索按需召回相关记忆真正让“记住你”有质变的是把历史记忆向量化然后按相关性召回。做法不复杂把一段有价值的对话切片比如按用户意图切一段或者按一轮问答切一块用 embedding 模型转成向量存进向量数据库。每当 Agent 要回答新问题时先把问题转成向量去库里做相似度搜索找出最相关的若干条记忆塞进 prompt。用到的数据库可以是 Qdrant、Milvus、Weaviate也可以是 PostgreSQL 的 pgvector小项目用 Chroma 或 FAISS 完全够。这套方案解决了全量塞历史的注意力稀释问题因为它每次只带几条最相关的记忆。但这不代表没有新问题召回质量取决于切片质量、embedding 模型和相似度算法而且“相关”和“重要”常常不是一回事。用户最关心的一条吐槽可能在向量空间里和“冰箱制冷效果”更接近而不是和“售后服务”更接近。所以向量检索只是基础上面通常还要再接一个排序甚至重排的环节具体我在第四章细说。2.3 记忆服务与 MCP Memory开箱即用如果不想自己造轮子市场上已经有一批现成的记忆方案。Mem0 把记忆分成短期和长期两层能自动从对话中抽取需要长期保留的条目也支持用户直接写入。Zep 是类似思路内置了对话摘要、实体提取、时间线记忆并且提供了专门 API前后端都能接。另一个值得关注的方向是 MCP 协议里的 Memory 服务。MCP 把 Agent 的能力统一抽象成工具记忆也可以做成一个独立的 memory server通过标准协议暴露“保存记忆”“读取记忆”“搜索记忆”这些接口。用现成服务的好处是省掉很多脏活累活尤其是实体识别、记忆冲突处理和遗忘策略自己实现一遍非常耗时。但坏处是数据链路会绕一圈调试和定制受限而且记忆数据往往和业务强相关交给第三方之前要仔细想清楚数据合规和隐私边界这个我在第五章展开。如果你用的是 Spring AI 这类 Java 框架里面也有 ChatMemory、SearchMemory 之类的抽象用法本质相同一个是存历史一个是按需查别被框架之间的名词绕晕。2.4 选型建议到底选哪一级我的判断标准很简单先想清楚产品要的是“上下文连续”还是“长期个性化”。只要上下文连续滑窗加摘要就够了需要跨会话记住用户偏好向量检索是主流选择团队人力紧张且不介意数据链路多一跳可以先上 Mem0 或 Zep 这类服务跑通业务等量大了再自研。没有最好的方案只有最适合当前阶段的方案。做 Agent 最容易犯的错就是第一个版本就上最重的架构结果没调明白之前先把团队精力耗光了。另外如果你的 Agent 是 multi-agent 架构记忆的归属也要提前想清楚。我目前的经验是共享记忆库放用户事实和任务状态各子 Agent 的工作记忆本地保留别一股脑全塞公共库否则消息风暴会先把记忆库冲垮。3. 实操给 Agent 装一套“记得住你”的记忆系统3.1 技术栈与整体数据流这一节以 LangGraph 为例讲一个可直接参考的实现骨架。选 LangGraph 不是因为它最流行而是它有清晰的节点和状态模型非常适合把记忆写入和记忆召回拆成独立节点。向量库我用 pgvector因为存量业务多半已经有 PostgreSQL可以少引入一个组件。embedding 模型用通用的文本嵌入模型即可中文场景稍微关注一下分词和模型对中文的适配。整体数据流是这样的用户消息进入 Agent先走记忆召回节点用当前问题去查向量库把命中的历史事实和用户画像塞进 prompt大模型生成回复之后走记忆写入节点把这条有信息量的对话切片转成向量并同步更新用户画像最后把整轮对话追加到短期上下文。注意顺序很关键先召回再生成生成完再写入。如果把写入放在召回前这一轮还没回答就先把问题记下来了容易把无效信息也存进去。存储结构不用设计得太复杂核心字段可以参考下面这个 JSON 结构{ user_id: u_12345, content: 用户提到家里养了一只猫名字叫煤球, embedding: [], memory_type: semantic, confidence: 0.8, created_at: 2025-06-01T10:00:00Z, last_accessed_at: 2025-06-01T10:00:00Z }3.2 记忆写入什么值得存存成什么样子写入是最容易走偏的一步。很多人把每一条对话都存下来结果向量库里全是“嗯”“好的”“谢谢”这类无意义内容召回时又把它们带回来。我建议用一句话来判断这条对话里是否包含以后可能用得上的事实、偏好或待办如果只是寒暄或者流程性确认不存。存放的字段最好不要只有原文尽量做一层信息提炼。比如原文是“我对价格已经无语了你们自己看吧”可以提炼为“用户对当前价格方案不满”这样召回时语义更清楚也方便后续做情绪分析。提炼可以用大模型做但别每轮都调大模型去抽成本会很高。我会给写入节点加两个触发条件一是用户消息里包含明显的偏好词或事实词比如“我喜欢”“我住在”“我是做……”二是完成了一次带有结果的交互比如提交了订单、改过收货地址。满足之一才进入提炼和写入。3.3 记忆召回什么时候查、查几条、怎么用召回要做减法而不是把库里所有相关记忆都拉出来。我的经验是召回数量控制在 3 到 8 条具体看场景。客服问答 3 到 5 条就够个性化推荐或陪伴式聊天可以放到 8 到 10 条。召回方式分两级第一级用向量相似度粗筛第二级按时间加权或者把用户画像中明确的键值对直接带上。这里有一个很容易踩的坑永远不要让记忆原样堆叠在 prompt 里。最好给每条记忆加上时间和来源描述比如“2025年4月12日用户提到他住杭州西湖区”。模型看到时间信息就不会把一条去年的旧习惯当成今天的指令。还有一种召回是主动的用户问“我的订单怎么样了”时Agent 不一定真要从历史对话里猜而是应该直接去查业务数据库。记忆系统管的是对话侧的信息业务状态应该走正经的 API 和数据库查询。把这个边界划清楚能避免很多“它明明知道但又答不上来”的奇怪事故。3.4 用户画像让临时记忆沉淀为长期认知要让 Agent“记住你”只靠对话历史还不够。我会在记忆系统里单独维护一张用户画像表字段不固定用键值对形式存储比如“姓名:张三”“偏好支付:微信”“住址:杭州西湖区”“宠物:猫煤球”。它的更新方式和对话记忆不同对话记忆是增量添加用户画像是覆盖更新。每次写入新事实时对比已有键值如果冲突以最新一次为准。这一步非常关键否则会出现一个场景用户这周说“我现在不用微信支付了”画像里却还留着上个月的“偏好支付:微信”。画像抽取也不需要把整本对话史都翻出来每次对话结束后跑一次轻量级的画像更新 prompt把当前这轮的更新点提取出来再和旧画像合并。对于中文用户我还有一个实用经验姓名、地址、电话号码这类实体用专门的信息抽取模型要比用通用大模型更稳。大模型适合做语义层面的偏好归因不适合做严格的结构化抽取。4. 从“记得住”到“记得准、记得对”调优与修正4.1 召回结果的重排与打分向量检索跑出来的结果只能算候选集直接塞给大模型往往差强人意。我之前做过一次对比同一组问题直接召回 Top5 写入和加了一道重排之后的 Top5 写入用户对“是否感觉被理解”的评分差了快 20%。重排的常用做法有三种一是加入时间衰减因子太久远的记忆降权近期记忆适当升权二是按记忆类型加权用户画像类记忆权重高于一次性的情景记录三是用一个小排序模型或规则对召回结果做融合。如果项目里没有专门的重排模型最简单的做法是写几行规则先定一个基础分向量相似度给一个分数时间衰减给一个分数是否包含当前问题里的关键词再加分最后按总分排序。这个规则先用脚本跑一段离线样本手动看排序效果再逐步调参比一上来就上模型务实得多。4.2 记忆的更新、遗忘与冲突处理记忆不是写完就完事了。时间久了会碰到三种情况用户改主意了、用户对同一件事前后说法不一致、记忆条目已经过时。我的更新策略很简单语义记忆和用户画像采用覆盖更新以最近一次为准情景记忆采用追加加时间戳不覆盖旧记录只标注新旧关系。举个例子用户先说“我在北京”后来改到“我搬去上海了”画像里直接覆盖成“城市:上海”情景记忆里保留两条带时间的记录。这样既不会让旧信息污染当前判断也保留了回溯能力。遗忘策略同样重要大部分记忆如果不是用户主动要求其实都不需要永久保存。可以设置一个保留周期比如一年没访问过的情景记忆自动归档。这个过程不一定要删除做成冷热分层也行热数据进向量库冷数据进对象存储。真要删除的场景也有比如用户要求“把你记住的关于我的信息都删掉”这属于合规操作必须支持。所以从设计第一天起每条记忆都要带上 user_id 和创建时间别做成一个全局的大列表否则后面连谁说了什么都查不出来。4.3 允许用户纠正Agent 要能“忘掉说错的话”生产环境里最打击用户信任感的瞬间不是 Agent 答不上来而是它“记得”了一件错误的事还反复根据错记忆做决策。比如用户明明从来不吃香菜某次聊天时随口开玩笑说“我顿顿都吃香菜”若被当成事实写进了画像后续每次推荐都给他推香菜相关的东西那就太灾难了。所以记忆系统一定要留一个纠正入口。最简单的做法是在识别到用户明确的否定表达时比如“我不是……”“我说错了”“把这个忘了吧”触发一次记忆修正流程删除或覆盖对应条目。更稳妥的做法是所有写入用户画像的事实都要带置信度随口一提的置信度低重复出现过或用“我确定”这类表达的置信度高。低置信度条目在召回时可以做弱化处理避免一句玩笑话被当成铁律。5. 实战中绕不开的四个坑5.1 记忆污染历史里的错话成了“事实”记忆污染的典型路径是这样的某条用户消息被错误抽取存进画像后续每次回答都被这个假事实影响而且因为 Agent 自己记得了它会越来越自信地使用这个错误信息形成自洽的幻觉闭环。要避免这个坑只能从源头把关写入时宁可少存不要错存对置信度低的条目做标记召回出来后在 prompt 里注明“以下记忆可能不准确请结合当前对话判断”。最后这条很有效相当于给模型一个允许质疑记忆的开关。别小看这句话它能让模型在旧记忆和新信息冲突时倾向于相信新信息而不是被旧记忆带偏。5.2 隐私与授权记住你也要守住边界让 Agent 记住你其实涉及大量个人信息。做产品时这条线一旦越界不只是口碑问题是合规问题。我的建议是先拿到用户授权再开始存长期记忆在界面上让用户能看到“Agent 记住了哪些关于我的信息”并提供一键清除入口。技术上要做到按 user_id 隔离千万不能出现多用户数据互相串的情况。多租户隔离和权限校验在记忆系统里比在业务系统里更容易被忽略因为记忆数据混合了对话内容和结构化事实抽数、上模型、做聚类的时候都容易误触敏感数据。哪怕只是一个内部 demo也建议把隔离和授权从第一天就做好不然后面补起来非常痛苦。5.3 成本与延迟每个记忆模块都不是免费的给 Agent 加记忆等于加了好几个额外环节embedding 调用、向量检索、大模型摘要提炼、画像更新。这些环节都会增加成本和延迟。我见过一个项目加了记忆模块后一次对话的平均响应时间从 1.2 秒涨到 3 秒成本涨了 40%。优化思路有几个embedding 结果做缓存同一个问题短时间内不重复嵌入记忆召回和画像更新改异步执行让用户在回复完成后不感知额外等待大模型提炼只对增量文本做不每次都全量跑。小流量的 demo 可以不在乎这些但只要想上线就要把“记忆是有成本”这个概念刻在脑子里。每次新增一个记忆环节之前先问一句这一步不加行不行很多所谓高级记忆最后都只是给延迟和账单添堵。5.4 测试与观测没有记忆可视化就等于盲调最后一个坑也是最隐蔽的记忆系统很难直接观察到。出了问题你根本不知道是召回没召回来还是召回了但模型没用或者是写入时就写错了。所以我会在开发早期就把观测做进去最简单的做法是每次请求的日志里记录三样东西这轮召回了哪些记忆、每条记忆的得分、最终 prompt 里记忆部分的实际内容。在调试界面里最好能按 user_id 直接查看它的画像和最近写入的记忆。有了这些你才能从“用户说体验不对劲”这种模糊反馈里快速定位到具体是哪个环节出的问题。记忆系统本质上是一个数据系统凡是数据系统可观测性就是第一生产力这个钱省不得。最后再多说一句记忆系统这东西务实地讲90% 的场景用滑窗加摘要再加一个简单用户画像就够了真正需要上向量检索和记忆服务的是那些用户会和 Agent 长期反复交互的产品。先把基础链路跑通再考虑怎么让它更懂你。脑子里的坑越少Agent 反而越像个正常人。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表