先纠正一个概念:聊天记录不等于记忆
聊天记录是原始事件:谁在什么时间说了什么。记忆是系统为了后续任务,从这些事件中选择、整理并允许再次使用的信息。两者如果不区分,系统很快会出现两个极端。
第一个极端是全量拼接。每次请求都把从第一轮开始的全部对话交给模型,Token 会随轮次持续增长,旧话题、寒暄和已经失效的条件也会干扰当前问题。上下文窗口再大,也不意味着所有历史都有价值。
第二个极端是固定保留最近几轮。这能控制长度,却会机械地丢掉较早但仍然重要的信息。例如用户先确认了预算,随后讨论十几轮功能细节;只看最近消息,系统可能忘记最初的约束。
因此记忆管理解决的不是“存不存聊天”,而是四个更具体的问题:哪些内容值得保留,保留到哪一层,什么时候应该取回,以及何时必须更新或删除。
多轮 Query 改写关注的是“怎样结合最近对话把当前问题补完整”;本题继续往后追问,专门讨论历史如何写入、隔离、更新、过期和删除。两个问题会使用同一段对话,但验收目标不同。
这里还要把知识库事实单独拿出来。企业制度、产品手册、合同条款属于可验证的静态知识,应由知识检索链路提供;“用户正在办理哪一步”“用户已经确认哪个选项”属于会话状态;“用户明确同意长期保存的语言偏好”才可能进入长期记忆。静态知识更新后,不能让一条旧对话记忆继续覆盖新制度。

三层记忆分别解决什么问题
短期窗口:保证当前任务连贯
短期窗口保存最近的原始消息、当前任务状态和临近上下文,适合按会话 ID 读取。它的优点是信息原始、更新快,模型可以看到用户刚刚确认的对象和条件;缺点是容量有限,窗口外的信息会自然消失。
窗口大小不应只用“几轮”定义。一次回复可能只有几十字,也可能包含长表格或大量引用。更稳妥的做法是同时受消息数、Token 预算和消息重要度约束:优先保留最近用户输入、尚未完成的任务状态和会影响当前回答的确认项,再删除无关寒暄或可从知识库重新获取的内容。
短期数据通常需要 TTL,也就是到期自动失效。在实际设计中,TTL 不能照搬一个固定数字,要根据产品是否需要恢复会话、用户是否登录、数据敏感性和合规要求决定。用户点击“新对话”时,系统也要明确这是只重置当前上下文,还是连持久化记忆一起删除,不能让界面上的“清空”与后台实际行为不一致。
摘要层:压缩旧历史,不创造新事实
当原始对话超出窗口,可以把较早消息压缩成摘要。摘要适合保存已确认目标、关键限制、完成进度、未解决问题和重要决定,而不是把每句话重新写一遍。
自由文本摘要有两个风险。第一,模型可能漏掉否定词、例外条件或数字;第二,多次递归总结后,早期误差会被当作事实继续累积。因此高风险字段最好结构化保存,并关联原消息 ID。摘要写“用户已确认预算范围”时,应能回到产生这一结论的原始消息,而不是只剩无法核对的一句话。
摘要更新也不应覆盖式盲写。可以保留版本、生成时间和来源范围,发生冲突时优先回看原消息。若摘要生成失败,系统应允许只使用最近窗口,而不是把空摘要或错误摘要继续写入下一轮。
长期记忆:跨会话找回真正有用的信息
长期记忆保存跨会话仍有价值的信息,可以放在持久数据库中,也可以为需要语义查找的内容建立向量索引。数据库擅长按用户、类型、状态和时间做精确过滤;向量索引擅长从大量历史里找出语义相关条目。实际设计可以组合两者,但不能把向量相似度当作权限。
长期记忆不等于永久记忆。偏好会变化,任务会结束,旧事实会过期,用户也可能撤回授权。每条长期记忆都应有作用域和生命周期,而不是只存一段文本和一个向量。
一条记忆从产生到消失,应走完七个步骤

第一步:判断是否值得写
并非每条消息都应该进入长期记忆。“谢谢”“换个话题”通常没有长期价值;用户临时讨论一个方案,也不等于允许系统永久建立画像。写入策略至少要判断:它是否会影响后续任务,是否已经被用户明确确认,是否重复已有信息,是否包含敏感数据,以及产品是否获得了相应保存权限。
对于模型从对话中推断出的偏好,要比用户明确陈述更谨慎。用户说“这次请用简短回答”,更像当前会话要求;如果直接写成“该用户永远喜欢简短回答”,就是把临时指令扩大成长期事实。
第二步:标准化并保留来源
记忆条目不能只有正文。一个最小结构可以包含:
memory_id 全局唯一标识
owner_id 记忆所属用户或组织
session_id 产生记忆的会话
topic/task_id 所属主题或任务
type 偏好、事实、任务状态、摘要等
content 可供后续使用的内容
source_ids 对应原始消息或业务记录
status active、superseded、expired、deleted
created_at 创建时间
expires_at 失效时间(如需要)
sensitivity 敏感级别
version 当前版本
这些字段不是为了把数据表做复杂,而是为了回答面试官一定会追问的问题:这条记忆是谁的、从哪里来的、现在还有效吗、发生争议时能否核对、用户要求删除时能否准确定位。
第三步:选择存储层
最近消息进入短期会话存储;需要审计和精确查询的状态进入持久数据库;需要从大量历史中按语义找回的内容才建立向量表示。相同的 memory_id 应贯穿原始记录、数据库、向量索引和缓存,这样更新和删除才能覆盖全部副本。
如果一条信息已经可以从权威业务库实时读取,就不应再复制成一份难以同步的长期记忆。例如用户订单状态应查询订单系统,而不是从上周对话里“记住”。记忆适合补充上下文,不能替代事实源。
会话状态和自然语言记忆也不要混在同一个字段里。当前步骤、已选对象、待补字段等确定变量,应尽量结构化保存,便于校验、覆盖和回滚;较长背景、解释和历史语境,才适合用摘要或语义检索处理。

第四步:检索前先做作用域过滤
当前请求到来时,系统先确定用户、组织、会话和任务作用域,再读取短期窗口和长期候选。对于持久数据库,可以按字段过滤;对于向量检索,也要限制在允许访问的分区或候选集合内。
关键原则是:先确定“哪些记忆有资格被看见”,再在其中判断“哪些语义相关”。如果先从全体用户记忆做向量近邻,再在结果末端补权限过滤,不仅可能浪费候选名额,也会增加数据越界风险。
第五步:融合时处理冲突
检索到记忆后不能直接全部拼入 Prompt。系统需要检查时间、状态、主题和来源。当前用户明确修改了偏好,新值应使旧值失效;长期记忆与当前会话冲突时,应优先使用用户刚刚确认的信息;个人记忆与权威知识库事实冲突时,回答事实应以最新权威来源为准,并在必要时请用户澄清。
模型输入中最好区分“当前问题”“知识库证据”“会话状态”“长期记忆”,让各类信息的身份清楚。否则模型无法知道某句话是正式制度,还是用户几个月前的一次猜测。
第六步:使用后更新状态
记忆被使用后,可以记录最后访问时间和命中结果,但不能因为被频繁召回就自动证明它正确。更新应基于明确的新证据:用户更正、任务完成、业务系统状态变化或管理员修订。旧值不一定物理覆盖,可以标记为 superseded 并指向新版本,保留审计链。
第七步:过期和删除
临时任务状态到期应自动失效;用户要求删除时,要处理短期存储、持久库、向量索引和缓存,而不是只删数据库一行。删除动作需要可重试、幂等:同一个删除请求执行多次,最终状态仍然一致。
为了避免删除过程中旧数据再次被召回,可以先把条目标记为不可读,再异步清理各存储副本,最后做一次反向检索验证。审计日志可以记录删除动作和结果,但不应为了证明删除而继续保存原始敏感正文。
隔离问题比“检索准不准”更先验
如果一个用户能召回另一个用户的对话,Recall 再高也没有意义。记忆系统通常需要区分组织、用户、会话和任务,具体采用哪些层级取决于产品边界。
服务端不能直接相信客户端随意传入的 user_id。用户身份应来自已经验证的登录凭证,服务再根据权限确定可访问范围。会话 ID 负责区分同一用户的不同对话,但它不能单独替代用户边界;两个用户即使碰巧使用相同会话字符串,也不应进入同一份记忆。
缓存键也要包含完整作用域。如果缓存只按 Query 文本命中,“报销标准是什么”可能把 A 用户或 A 企业的历史上下文返回给 B 用户。向量索引采用共享集合时,需要可靠的元数据过滤;采用分区或独立集合时,也要考虑创建、迁移和删除成本。无论哪种方案,都必须有负向测试证明越界请求得不到内容。
敏感信息还需要更严格的写入策略。不是所有姓名、联系方式、健康或财务信息都应该进入长期记忆。能不存就不存,必须存时再考虑加密、访问控制、最短保留期和审计。这里的目标不是让模型“更懂用户”,而是在明确授权和最小必要范围内服务当前任务。
记忆召回不能只看语义相似度
向量检索能找到“说法相近”的历史,但相近不代表当前可用。用户去年讨论“系统上线”,今年另一个项目也说“上线”,两个任务的语义很近,事实却不能混用。记忆排序至少要考虑四类信号:
- 语义相关性:内容是否与当前问题相关;
- 作用域一致性:用户、组织、任务和主题是否匹配;
- 时间与状态:记忆是否过期、被替代或已删除;
- 来源可信度:是用户明确确认,还是模型推断、摘要或旧系统同步。
可以先做硬过滤,再对剩余候选综合排序。高敏感或高风险场景还可以要求“只有用户明确确认的事实才允许进入上下文”。若候选之间存在冲突,宁可提示用户确认,也不要让模型根据相似度自行决定哪个是真的。
这也是记忆与 Query 改写的边界:Query 改写可以消费最近历史,补齐“它、那个、刚才的方案”等省略成分;记忆管理负责历史从哪里来、是否有权使用、是否仍然有效。前者答的是“怎样把问题改完整”,后者答的是“哪些历史可以提供给改写器”。两篇文章不应混成同一个问题。
怎么评测记忆系统,而不是只演示一次“它记住了”
一段看似连贯的演示不能证明系统可靠。评测集要构造连续对话和跨会话任务,并为每一步标注“应该使用哪些记忆、哪些记忆必须忽略”。至少覆盖下面几组场景。
近期指代
用户刚刚确认一个对象,下一轮用“它、这个、那项”追问。检查短期窗口是否保留正确对象,同时避免把更早的同名对象带入。
回到旧话题
用户切换话题后又回到先前任务。检查系统能否找回相关历史,而不是永远只看最近几轮。此场景适合验证摘要或长期检索的价值。
偏好更新
先给出一个偏好,再明确修改。正确行为是使用新值,并让旧值不可再影响回答。这个场景能检查版本和冲突处理,而不是只检查“能否召回”。
相似但不同的任务
两个项目使用相同术语。检查语义检索是否因为文本相近而串任务,以及主题和任务过滤是否生效。
会话过期与新对话
在 TTL 到期或用户发起新对话后,验证哪些状态应该消失、哪些经过授权的长期记忆仍可使用。测试要对应产品定义,不能默认“清空”只有一种含义。
删除请求
写入一条可检索记忆,分别通过短期缓存、精确查询和向量查询确认它存在;执行删除后,再用原句、同义改写和相关主题查询,验证各层都无法返回。只验证数据库主键查不到,并不能证明向量索引和缓存已经清理。
跨用户攻击测试
准备两个用户的相似信息,让其中一个用户用尽可能相近的 Query 搜索,结果必须为零越界。对记忆系统而言,跨用户泄漏不是“准确率低一点”,而是发布阻断项。
指标可以分成四组:正确记忆的召回率、返回记忆的精确率、过期或被替代记忆的误用率、删除后的残留召回率。再加上跨用户泄漏、检索延迟、上下文 Token 和写入成本。平均值之外,要单独看高风险样本。

一条可复现的记忆 Trace 应该记录什么
记忆答错时,如果日志只有最终 Prompt,很难知道错误在哪一步。最小 Trace 可以记录:请求所属作用域、短期窗口选中了哪些消息、长期检索返回了哪些 memory_id、过滤掉哪些候选及原因、最终注入哪些记忆、使用了哪个摘要版本,以及本轮是否产生更新或删除动作。
日志不要直接复制全部敏感正文,可以记录 ID、类型、状态和脱敏摘要。调试人员通过受控权限再访问原记录。这样既能复现“为什么用了这条记忆”,也不会让排障日志变成新的隐私副本。
出现错误时按链路排查:
- 该信息当初是否应该写入;
- 条目的用户、任务和状态是否正确;
- 检索前过滤是否遗漏;
- 语义召回是否选错相似历史;
- 冲突合并是否让旧值覆盖新值;
- 过期或删除是否没有同步到某个副本;
- 最终模型是否忽略了明确标注的来源优先级。
每修复一个 bad case,都应补进回归集,并同时加一个相邻反例。例如修复“能找回旧预算”后,再增加“同一用户另一个项目的预算不能被召回”,避免为了提高召回把隔离边界放宽。
面试官继续追问,怎么接
为什么不把全部历史直接交给大模型?
因为历史会持续增长,而且旧话题和失效信息会干扰当前任务。应按短期窗口、摘要和长期记忆分层选择,而不是把上下文窗口当数据库。
摘要为什么不能直接替代原始消息?
摘要可能漏掉否定、数字和例外条件。重要摘要应带原消息来源和版本,高风险字段可以结构化保存,发生冲突时能回查原文。
长期记忆是不是建一个向量库就行?
不是。向量库只解决语义候选,还需要用户和任务过滤、来源与状态、冲突更新、过期删除以及跨用户隔离。相似度不能替代权限。
用户偏好变化了怎么办?
新确认值应产生新版本,旧值标记为被替代并停止参与检索。不能简单追加两条互相矛盾的记忆,再让模型猜。
用户点“清空”时应该删什么?
先由产品定义清空当前会话、全部短期历史还是包含长期记忆。实现上要同步处理缓存、会话存储、持久库和向量索引,并在删除后做反向检索验证。
怎么防止不同用户串记忆?
身份从服务端验证结果获取,检索前先限定组织、用户、会话和任务作用域,缓存键也包含这些边界;再用负向测试证明越界 Query 返回不了任何记忆。
怎么证明记忆真的有效?
不能只看一次演示。要用近期指代、回到旧话题、偏好更新、相似任务、过期、删除和跨用户测试,分别统计正确召回、错误注入、旧值误用和残留数据。
写入链和读取链也要分开验证。写入前先判断这条信息是否值得保存、是否需要用户确认、保存多久以及谁能读取;模型抽取出的内容只能作为候选,不能自动升级成永久事实。读取时则先限定身份和任务范围,再比较相关性、时效、来源权威度与冲突状态。把两条链混成一次向量搜索,会让“模型猜到的偏好”悄悄变成长期事实。
当用户纠正旧信息时,我不会直接覆盖到无法追溯。新值应指向被替代版本,旧值退出默认召回,但保留必要的审计关系;撤回或删除则按适用的数据规则处理实体记录、向量副本与缓存。这样既能解释系统为什么使用当前值,也能检查旧值是否仍在错误注入。
记忆进入 Prompt 时也应保留来源类型与确认状态。用户明确确认的事实、模型从对话中推断的偏好和系统自动摘要不能拥有相同权重,否则一次错误推断就可能在后续会话里被反复强化。
对话记忆的完整回答:存什么、何时取、怎样删
我会把对话记忆设计成一个有生命周期的上下文系统,而不是聊天记录数组。静态制度和产品事实由知识库提供;短期窗口保存当前会话最近消息和任务状态;摘要压缩较早历史;只有跨会话仍有价值且允许保存的信息,才进入长期记忆。
每条记忆都要有用户、会话、任务、来源、状态、时间、敏感级别和统一 ID。检索时先做权限与作用域过滤,再按最近窗口或语义相关性取回;融合时处理新旧冲突和权威来源;使用后允许版本更新、过期和删除。删除要覆盖缓存、短期存储、持久库和向量索引,并通过反向检索确认没有残留。
评测时我不仅看系统是否记得,还会测试它是否会误用旧记忆、串到别的任务或用户、在偏好更新后继续使用旧值,以及删除后能否彻底消失。对话记忆的质量标准不是“记得多”,而是在正确边界内只取回真正有用的信息,并且每次使用都能解释、更新和撤销。