AI Harness 构建完整记忆系统:何为AI智能客服?
客服热线第三次接到同一位客户,他把同一个问题完整讲了一遍,这已经是第三遍。
三次,客户都得重新报上订单号,以及上周聊到了哪一步,因为所有 Agent 的出厂状态,LLM 那一侧没有记忆。
模型不存昨天,每一次请求对它都是初次见面。
对内部工具、一次性问答机器人来说,这固然无所谓,但在面向客户的真实场景里,支持、销售、预约、客户管理——这是底线。
因为客户记得很清楚:自己被遗忘过几次。
一个 Agent 是聊天机器人,还是一段关系,差别就在这里,它决定了下一次开口时,Agent 是只能问一句今天我能帮您什么,还是能接上一句上次那个账单、我帮您查一下进展。
下面我们按三层把记忆系统拆开讲——会话、持久、语义,再故意把它打碎,看看当真实用户涌进来时,它会在哪些地方翻车。
一、失忆的AI智能客服系统:为什么能对话不等于有关系
LLM 是无状态的,它不记得任何东西,每一次它只是被喂进一段文本,然后预测下一段文本。
所谓记住上下文,其实是调用方把历史消息重新拼进请求里——记忆的载体不在模型里,在你这一侧的工程里。
这就带来一个绕不过去的硬约束:随着多轮次长任务对话,上下文信息量会超线性增长,而窗口是有限的。
而真实对话不会为了迁就窗口而变短,窗口一满,最旧的那几轮就得腾位置——而且是被硬生生挤出去且不留副本。
上下文压缩不就好了?上下文窗口无论是滑动窗口还是摘要压缩都会失真,如何尽可能确保上下文压缩不失真又是一个大话题,后续另起文章单独讲解。
客户第一轮就报过的订单号,聊到中段时已经不在请求里了:不是模型忘了,是它压根没被送进去。
更麻烦的是,这个问题不会自己暴露,演示时你不会发现,因为演示永远只有几轮对话。
它只在长会话、老客户、反复来电的场景里发作,而这类场景恰恰是面向客户业务的主战场。
所以:对话是模型的默认能力,关系是工程的额外投入。
模型天然能接话茬,但只有你给它建了记忆,它才可能在下一次开口时,说出上次我们聊到……
二、AI智能客服绕不过去的三大历史难题
面向客户的 Agent,会同时撞上三种问题,它们的时间尺度不同、该存的东西不同、失效方式也不同。
问题一:会话连续性。
客户提起刚才讲过的事,Agent 却接不上,那句话已经不在它此刻能看到的内容里了,不是它不认真听,是它这一轮根本没拿着那句话。
问题二:跨会话记忆。
昨天客户来问过账单,今天又来跟进,Agent 对昨天一无所知,于是客户只能把来龙去脉、试过什么、你回复过什么,全部再讲一遍,每一位回头客,都从零开始。
问题三:事实偏好。
打交道次数多了,规律自然会浮现:性格,喜好,语气等等,每一次接触都是一座孤岛。
三种问题,对应三层记忆:
|
记忆层 |
生命周期 |
取回方式 |
解决的问题 |
典型触发 |
|
会话记忆 |
单次会话(分钟/h) |
顺着对话带着走 |
会话连续性 |
就像我刚才提到的…… |
|
持久记忆 |
跨会话(天/周) |
按实体键取 |
跨会话记忆 |
上次我们聊过…… |
|
语义记忆 |
跨会话(数月/永久) |
按相似度取 |
事实偏好 |
您更喜欢这款产品…… |
这三层会像积木一样往上叠:会话记忆管这一通电话别跑题,持久记忆管下一次电话有上下文,语义记忆管该记的记很久、但别一股脑全塞回去。
这里有个容易搞混的点值得先点破:三层记忆不是三种存储介质。
你完全可以用同一个数据库存三层——真正的差别不在介质,在生命周期和取法,如果把三层混成一坨,三层都会作废。
不过,这只是记忆的其中一种分法,你在别处见过的另外两套分法,下一章我们先把坐标系对齐,再一层一层往下看。
三、AI Agent三类记忆分法,三种不同的视角
在钻进每一层之前,先把坐标系对齐,因为你去翻资料,会发现记忆的分法不止一种,而且经常互相打架:有人分三层,有人分四层,还有人的第一层叫身份。
- 产品视角:存多久——身份(Identity)、短期记忆(Short-term)、长期记忆(Long-term)。
- 认知学视角:存什么——程序记忆(Procedural)、情景记忆(Episodic)、语义记忆(Semantic)。
- 工程学视角:存多久——工作记忆(Working)、会话记忆(Session)、语义记忆(Long-term)。
第一套里的身份,本质上不在这把尺子上,它一半是从长期记忆里切出来的视图——关于这位客户是谁,内容以语义事实为主;另一半是作用域键——这些记忆归谁,产品上它极其好用,逻辑上它跟短期、长期并不同类。
我们按照生命周期分才一目了然,什么短期记忆,会话记忆,持久记忆到底在哪一层:
|
层级 |
类比 |
生命周期 |
|
Working Memory |
工作记忆 |
单次请求 |
|
Short-term / Session Memory |
短期记忆 |
单次会话 |
|
Long-term Semantic Memory |
语义记忆 |
跨会话持久 |
|
Episodic / Procedural Memory |
情景/程序记忆 |
跨会话持久 |
综上为常见记忆分层架构设计,但一味生搬硬套不可取,记忆分层架构设计取决于具体的产品形态。
拿WorkBuddy举例,其产品形态决定了需要根据作用域来划分为四层:
- 身份(Identity):用户画像
- 用户级(User Level):跨项目
- 工作区(WorkSpace):当前项目
- 技能记忆:系统提示词(归一为程序记忆)
程序、情景、语义,并不是并排的三格,它们的关系通过如下表格可清晰说明
|
大类 |
子类 |
是什么 |
客服场景里的例子 |
|
陈述性 |
情景记忆 |
绑着时间、地点的具体经历 |
上周三那通电话,客户说账单对不上 |
|
陈述性 |
语义记忆 |
剥离时空后剩下的事实与偏好 |
这位客户习惯用文字沟通 |
|
非陈述性 |
程序记忆 |
会不会做——说不出口,但做得出 |
退款流程该怎么走 |
情景和语义是亲兄弟,程序是堂兄弟。
它们之间还有一条沉积通道:同一类事反复发生,描述就会被一次次压扁——上周三那通电话、上个月那次退款、三个月前那次改地址,攒够了,就沉成一条记忆这位客户习惯用文字沟通。
语义记忆往往是情景记忆的沉淀物,情景记忆到语义记忆的过程又称之为:反思或者记忆巩固或者记忆蒸餾。
在今天的 Agent 框架里,程序记忆通常不放在记忆层,它被挪到了三个地方:
- 系统提示——你的角色、要遵守的规则、遇到什么情况该怎么处理;
- 工具定义——每个工具叫什么、要什么参数、什么时候该调;
- 工作流编排——先查订单、再判断能不能退、最后回复,这条路径本身就是程序记忆。
为什么被挪走?因为它跟另外两类的性质完全不同。

四、第一层:会话记忆,让当前对话不跑题
会话记忆是最简单的一层:它跟踪当前这通对话,别让 Agent 在中途把线头丢了。
它要存的东西很朴素——这一轮里用户说了什么、Agent 回了什么,不需要智能,不需要检索,甚至不需要持久化,它的全部价值只有一条:让刚才提到的那种回指,有明确的指向。
但这一层有个天然的短命属性:它跟着会话生,也跟着会话死,通话一结束,这一层就该被清空。
客户早在通话开头报过的那个工单号,等聊到中段时已经不在 Agent 眼前了;它只好开口再问一次,而客户已经在电话那头叹了一口气。
站在记忆系统的角度,关于这一层只需要记住两件事:它是最短命的一层,它的产物不应被当成长期记忆事实;而且它丢东西的时候,是无声的。
会话记忆自己不脏,脏的是从会话里抽出来的东西,被当成事实存了下去,这正是第 08 章记忆污染要讲的事。
五、第二层:持久记忆,让下一次通话有上下文
持久记忆存的是关于实体的事实——客户、账户、对话,它们比任何单次会话活得更久,每次对话结束后,你把重要的部分抽出来,存到未来会话找得到的地方。
存储本身没什么花样:每条记忆要有唯一标识、归属对象、内容、来源、创建时间,再加访问次数和最近访问时间。
难的是判断该往里放什么。
整段对话原样扔进去是最省事的,但那是知识库,不是记忆。
区别在指向:知识库回答我们有什么规定,记忆回答这位客户是什么情况。
所以要有一道抽取:对话结束后,让模型通读一遍,只挑出下次这位客户再来时用得上的,偏好、诉求、承诺、账户信息——这些要留;寒暄、您好请问有什么可以帮您、客户提了个问题,这类没有信息量的描述,一句都别留。
抽出来的每条还得能自己站住,因为一条记忆将来要能被单独召回、单独比较、单独替换,它先得是一句完整、独立的话,而不是半截需要回原文才能读懂的片段。
1.实体范围界定。
一条记忆首先得回答它属于谁——这就是实体范围界定:它该挂在某位客户名下,还是挂在某个账户、某次会话名下?边界划不清,后果很直接。
如果所有记忆都丢进一个公共池子、按相似度去捞,那客户 A 打进来时,系统完全可能把客户 B 的信息递上去——这不是准不准的问题,是能不能出事的问题。
2.TTL(生存周期)。
这位客户在等回电,今天有用,两周后就是干扰;这位客户习惯用文字沟通,放几个月都成立——不同事实,该活的时长并不一样。
不给每条记忆各自设一个 TTL,库里就会积压一批说起来没错、用起来误事的旧条目。
3.溯源追踪。
这条记忆是机器从对话里抽的,还是手工补的?抽的方便,但也更容易错——模型可能抽偏、抽漏,甚至把一句气话当成结论。
手工的可靠性更高,所以要把它的来路一并存下:哪次对话、什么时候写进来的,有了这条链路,日后才能按出处给不同记忆配不同权重,出了问题也追得回去——这就是溯源追踪。
4.去重。
同一位客户十次提到偏好邮件,如果不去重,库里就躺着十条几乎一样的内容。等召回时,这几条会把名额占满,把别的有用信息挤出去。
去重要放在写入那一刻:持久层至少先过一道粗略的相似检查,精细的合并留到语义层。
六、第三层:语义记忆,在对的时刻捞回对的记忆
一位客户身上可能存着几百条记忆,Agent 需要的是其中与当前这轮对话相关的那几条——而不是把全部记忆倒进模型。
客户问起那个物流的事,你要找的是那条关于包裹延误的记忆,而不是关于账单偏好的那条。
可关键词在这里帮不上忙——客户嘴里说的是物流,而库里那条写的是三号仓发出后被转运中心扣住、预计月底才能派送,两边一个字都不重合,但谁都知道该选哪条。
语义检索用嵌入解决这个问题:把一段文字转成一组数字(向量),这组数字代表它的语义,意思越接近的两段文字,它们的向量在空间里就越靠近。
于是找相关记忆就被翻译成了算距离——把当前问题也转成向量,再和库里每一条比一比,取最近的几条。
衡量靠近的常用尺度是余弦相似度:看两个向量的方向是否一致,结果落在 0 到 1 之间。越接近 1,语义越像。
检索里最要紧的参数,不是取几条,而是最低分。
如果只是按相似度排序取前几名,那每一次查询都会有结果——哪怕库里根本没有相关的记忆,客户问价格,系统照样把一条物流记忆以 0.1 的相似度递上来,还觉得自己完成了任务。
这些不相关的条目混进来,只会干扰模型。定一条底线(比如 0.3),低于它的一条都不要,宁可什么都不给,也别给噪声。
七、三层记忆拼接:如何合成系统提示词?
三层都齐了,接下来要把它们合成一个装配器:在 Agent 每次作答之前跑一遍,把这位客户身上值得说的东西拼成一段文字,作为系统提示的一部分送进去。
拼的顺序本身就是一种判断:
先放客户档案。
这位客户的全部持久事实,按最近访问、访问频次排个序,但一定要卡数量——不卡的话,一位老客户能轻松把窗口占满,十条左右是个稳妥的起点。
再放相关过往。
语义检索挑出来的那几条历史互动,这里不用再筛——语义层已经筛过了,再加一道只会削弱信号,可以把相关度一并带上(比如 89% 相关),让模型自己掂量该有多看重。
最后放当前对话。
正在进行的这一通,压在末尾。
为什么当前对话要放最后?因为模型对一段输入的开头和结尾更敏感,而现在正在发生什么,是它此刻最该盯住的,越具体越靠前,越当下越靠后——这条经验法则值得记住。
拼完之后,Agent 才第一次说得出这样一句:我看到上周在处理您的物流延误,让我查一下最新进展,而不是让客户从头讲起。
三层到这里就齐了:会话记忆管当前这通别断线,持久记忆管事实跨会话存活,语义记忆管在对的时刻取回对的那条。
八、面向真实用户的AI智能客服系统:五种生产故障模式
上面三层,在演示环境里都不会出问题,一个人、一个测试账号、几十条记忆、输入可控。
一旦真实客户进来,情况就变了,下面五处,是这套记忆系统会翻车的地方——而且每一处都比看起来更难补。
1.记忆污染
Agent 遇到过一通难缠的电话,客户情绪很激动,说了不少重话,抽取环节照实记下了一条:这位客户对服务强烈不满,态度对抗。
三个月后,客户来问一件毫不相干的小事,Agent 把那条记忆捞了出来,开场白成了这样一句:我注意到您过去对我们有些不满,这次我一定格外仔细。
客户早把那次不愉快丢在脑后,现在却被重新提醒了一遍,更糟的是,Agent 的语气变得过分小心、过分抱歉,而对方只是想要一个干脆的答复。
旧情绪没到期,就会污染新关系。
修法不止是加个期限,有些事实记忆(账户信息、偏好)本来就该长期保留,一刀切地设短过期时间,只会把有用的东西一起清掉。
你需要先给记忆分类:事实 vs 情绪,可操作 vs 仅历史;再让情绪类的衰减速度快于事实类。
而这要求在写入的那一刻就打上类别标签——事后回头补,是补不上的。
2.隐私与合规
客户随口提了一句:我听力不太好,您说慢一点。
抽取环节贴心地记了下来,于是库里多了一条健康信息,取决于行业,这可能构成相关违规。
隐私友好的记忆,需要在写入那一刻就做内容识别:在敏感信息落进持久存储之前就认出来、打上标。
它还需要按类别划分的保留策略,以及谁在什么时候读了哪条记忆的审计日志。这三样,都得在存储层设计阶段就留好位置。
3.跨Agent污染
客服 Agent 留下过一条:这位客户在比较其他家的方案,后来销售 Agent 在另一通对话里把它捞了出来,顺势改成挽留话术:听说您在对比别家,那我给您重点讲讲我们新上的能力。
客户从没主动跟销售提过这件事,他的第一反应不是被重视,而是被盯上了——那通客服对话本应是保密的,现在却被拿去对付他自己。
这是Agent作用域问题,多Agent系统里,记忆不该在不同角色的代理之间自由流动,客服记忆是客服上下文,销售记忆是销售上下文,有些可以共享(账户信息、账单状态),但情绪上下文和竞争情报,默认应当隔离。
难点在默认隔离这个方向,如果系统一开始是全局共享的,事后想补作用域,就得把每一条已有记忆重新过一遍——还要逐条判断谁有权访问,这是一场没有终点的考古。
4.规模与成本
算一笔账,一万个客户,人均 50 条记忆,就是 50 万条带向量的条目。
单个客户打进来时,检索只在他的记忆里比——大概 50 次比较,很快,但那次把问题转成向量的调用本身就要几十到上百毫秒,在延迟预算低于 300 毫秒的语音场景里,这是一笔不小的开销。
再把抽取算进来,每通对话结束触发一次抽取,每条抽出来的事实再触发一次向量化,按每天 200 通算,就是 200 次抽取,外加大约 600 次向量调用。
单次成本很小,但它在持续累积——而且它会随着客户数和使用量线性增长,不会自己收敛。
更要命的是检索方式,如果在内存里逐条比对,开销随记忆条数线性上升,某位高接触企业客户攒到上万条记忆时,检索延迟就肉眼可见了。
生产系统用的是近似最近邻(ANN)索引——HNSW、IVF 之类等等,用一点点精度换大幅度的速度提升,这是从能跑到能规模化的分水岭。
5.去重噩梦
客户在三个月里换着说法提过十几次收货地址,每次抽出来的措辞都不太一样:
- 客户地址是杭州西湖区某某路 12 号
- 收货地点:杭州市西湖区某某路 12 号 3 单元
- 寄往杭州西湖区的那个地址
- 客户说东西寄到他杭州那边就行
任何和地址沾边的查询,都会一次返回其中三四条,它们说的是同一件事,但每一条都在吃掉本可以装更有用信息的空间。
插入前先查一下有没有相似的——听起来简单,可相似这个词本身就是模糊的,精确匹配会漏掉上面所有变体;阈值定得太高(比如 0.95),又会把语义相近、但确实不同的两条记忆误并成一条。
而且,记忆更新了怎么办?客户搬家了,这时候新地址应该顶掉旧地址,而不是与它并列,系统得能分清这条是推翻了那条,还是补充了那条——而这两者在文字层面可能长得很像。
生产级去重需要四件事:插入前的相似检测、近似条目的合并、矛盾条目的取代,以及区分同一件事的不同说法,与两条听起来像、其实是两件事。
五种模式摊平来看
|
故障模式 |
表现 |
本质 |
需要补的能力 |
|
记忆污染 |
旧情绪污染新交互 |
情绪记忆衰减不够快 |
记忆分类 + 差异化衰减 |
|
隐私与合规 |
敏感信息入库、删除不彻底 |
缺写入时的分类与保留策略 |
内容识别、保留策略、审计日志 |
|
跨Agent污染 |
角色之间记忆越界 |
没有Agent作用域概念 |
Agent作用域 + 显式共享 |
|
规模与成本 |
检索延迟与费用失控 |
暴力检索 + 逐条向量化 |
ANN 索引 + 向量库 |
|
去重噩梦 |
同一事实多条并存 |
相似判定模糊、缺更新语义 |
相似检测 + 合并 + 取代 |
看一眼本质那一列,会发现它们有个共同点:没有一个是实现有 bug, 全都是架构缺一层,每一个都要求你在存储层重新做决定,而不是在业务代码里打补丁。
资料展示:
下面是我整理的AI大模型 学习资料和工具包预览,适合收藏后按主题逐步学习






更多推荐


所有评论(0)