4.2 写入与召回策略


4.2 写入与召回策略

本节摘要:本节补上跨会话记忆的两端手艺。写入端三件事:什么值得记——门槛三问一票否决(下次还成立吗 / 影响未来交互吗 / 能溯源吗),一次性事实、易变状态、可重取数据、会话过程一律不进库;何时写入——三种时机(用户显式信号的立刻写、轮末评估的择优写、会话结束的批量写);记成什么形态——原文引用、抽取事实、结构化笔记三档,Anthropic 把"让 Agent 在任务中维护结构化笔记"列为上下文工程的基本手段(官方)。召回端也是三件事:何时召回(会话开始一次 + 实体触及增量,别每轮都召)、召回多少(预算倒推,宁缺勿滥)、注入哪里(系统提示之后的专门记忆区块,带时间戳与来源,绝不住中部——2.2 节位置效应)。附 ce_memory.py 最小分层记忆示意;最后讲记忆卫生:过期、冲突与遗忘。这两端恰好是 LangChain 四操作中 write 与 select 在记忆成分上的落地(7.1 节回收)。

学习目标

阅读完本节,你应当能够:

  1. 用写入门槛三问对一批信息做入库/拒收判定。
  2. 为自己的应用选写入时机与写入形态。
  3. 设计召回策略:触发时机、召回额度、注入位置与格式。
  4. 读懂并改造 ce_memory.py,说出它与预算口径的衔接点。

一、写入门槛:什么值得记

跨会话记忆的第一个设计错误总是"记太多"。每一条入库记录都是未来每次召回的候选——库里噪声越多,召回越难命中,还挤占那份可怜的 1%~5% 预算(4.1 节)。写入门槛三问,任一答"否"即拒收:

门槛 问的是 拒收的反例
稳定吗 下次会话它还成立吗? "用户当前在看的订单 88880"(易变状态)
有用吗 它会影响未来的交互吗? 本轮的一次寒暄、已完结工单的过程细节
可溯源吗 能注明它来自哪一轮、哪个来源吗? 模型猜测出的"用户可能喜欢……"(推测不是事实)

反例清单再加两条工程常见的:可重取数据不记(政策条文、库存状态——知识库和查询接口随时能给,4.1 节事故一);会话过程不记(试错与中间推理——那是压缩(6.1)用任务简报处理的对象,不是跨会话记忆的对象)。留下来的合格者恰好就是 4.1 节那三样:偏好、事实、约定。

⚠️ 记错比不记更贵:一条错误偏好("用户不要发票")一旦入库,之后每个会话都被召回、被放大,直到某天用户忍无可忍纠正它——而你可能根本查不到它是哪轮被误抽的。这就是第三问"可溯源"存在的理由:每条记忆必须带来源轮次,错了能删。

二、何时写入:三种时机

时机 触发 成本 特点
显式信号 用户说"记住……""以后叫我……" 零额外调用 可靠度最高,应立刻写,别等会话结束
轮末评估 每轮(或每 N 轮)跑一次轻量判定:这轮出现了值得记的信息吗 每轮一次小模型调用(示意) 及时,但要防写入过滥——判定 prompt 里放门槛三问
会话结束 会话关闭时生成摘要、抽取事实入库 一次批处理 成本最友好,牺牲及时性;长会话可降频为"每 20 轮一次"(示意)

写入形态三档,按需选用:

  1. 原文引用:存用户原话("回复别超过三句话")。保真,但长。
  2. 抽取事实:存结构化字段——{"key": "称呼", "value": "王工"}。紧凑、可校验,是首选。
  3. 结构化笔记:带类型、时间戳、来源的半结构化条目,介于两者之间。Anthropic 在其上下文工程长文里把"让 Agent 在任务中主动维护结构化笔记(如笔记文件 / 任务状态)"列为对抗上下文退化的基本手段(官方)——注意这类笔记是会话内的工作记忆(帮当前任务扛住长历史),与会话结束后沉淀的跨会话记忆是两层(4.1),别混。

三、怎么召回:量、位置与格式

何时召回——两个时机,够用且别多:会话开始时按用户 ID 一次性召回;会话中用户提及新实体 / 新话题时增量召回("我是不是说过我常用杭州仓?"——按话题补查)。反面教训是每轮全量召回:多一跳延迟,还把无关记忆反复灌进窗口(注意力稀释,1.1 节)。

召回多少——预算倒推,不是"库里有什么就带什么"。2.1 节分配表给跨会话召回留 3%(128k 窗口即约 3.8k token,示意),按每条 50~150 token 计,上限就是二三十条。相关性排序后装到预算为止,宁缺勿滥:一条无关记忆不是中性的,它在稀释真正相关的那几条。

注入哪里——专门的记忆区块,位置在系统提示之后、对话历史之前:

[系统提示 v12(指令成分)] [记忆区块] ← 跨会话记忆住这里 - (2026-08-12,偏好)回复控制在三句话内 - (2026-07-30,事实)企业账户,发票抬头:某科技公司 [对话历史 / 素材 / 本轮输入] ← 中部在后面

三个格式要点:每条带时间戳与来源——模型由此能自判新旧(见下一节的冲突处理);类型标注——偏好 / 事实 / 约定分行列出,比一大段散文可读;关键偏好末尾复述——少数红线级偏好("禁止向我推销")按 2.2 节推论一,在本轮用户输入之前再复述一次,首尾双保险。

💡 召回的记忆仍是预算恒等式里"记忆"科目的一行——它不是免费午餐。记不住这条的团队常见症状:召回额度从 3% 悄悄涨到 15%,素材被挤爆,然后回头去砍输出预留。

四、ce_memory.py:最小分层记忆示意

# ce_memory.py —— 最小跨会话记忆:写入门控与预算内召回(写法示意,以实际工程为准) import time def est_tokens(text: str) -> int: # 与 ce_budget.py 同口径 cn = sum(1 for ch in text if "\u4e00" <= ch <= "\u9fff") return cn + (len(text) - cn) // 4 RECALL_BUDGET = 3_800 # 单次召回的 token 上限(示意:128k 窗口 × 3%) MAX_AGE_DAYS = 180 # 条目过期年龄(示意:偏好类长期,状态类应另设短 TTL) def worth_writing(item: dict) -> bool: """写入门槛三问,一票否决:不稳定 / 下次没用 / 无法溯源的都不进库。""" return bool(item.get("stable") and item.get("useful_next") and item.get("source")) def write(store: dict, item: dict) -> bool: """写入即合并:同键新事实覆盖旧事实,时间戳取新。返回是否真的写入。""" if not worth_writing(item): return False # 拒收:门槛三问未过 key = item["key"] # 如 ("偏好", "回复长度") store[key] = {**item, "ts": time.time()} # 冲突策略:新覆旧 return True def recall(store: dict, query: str, top_k: int = 20) -> list[dict]: """召回:过期过滤 → 相关性粗排 → 装到预算为止。""" now = time.time() items = [v for v in store.values() if now - v["ts"] < MAX_AGE_DAYS * 86_400] scored = sorted(items, key=lambda v: -overlap(query, v["text"]))[:top_k] out, used = [], 0 for v in scored: # 召回也过预算恒等式 cost = est_tokens(v["text"]) if used + cost > RECALL_BUDGET: break out.append(v); used += cost return out def overlap(a: str, b: str) -> float: """相关性粗排的占位实现:字符二元组重合度。生产应换向量检索。""" grams = lambda s: {s[i:i + 2] for i in range(len(s) - 1)} ga, gb = grams(a), grams(b) return len(ga & gb) / max(1, len(ga | gb))

三个实现要点:门控在写入侧——worth_writing 是三问的代码化,脏数据进不来比召回侧过滤便宜一个量级;召回带预算——RECALL_BUDGET 对应分配表的记忆-召回行,与 ce_budget.pyaudit() 口径一致;粗排是占位——overlap 只保证教学可跑,生产的检索(向量、混合)属于实现层,深潜见 《腾讯 Agent Memory 记忆系统》与《memU 记忆框架》教程。

五、记忆卫生:过期、冲突与遗忘

记忆不是只进不出的收藏夹,三件卫生事:

  1. 过期:给条目设 TTL。偏好类长(MAX_AGE_DAYS = 180,示意),状态类短或干脆不进库(4.1 节事故三)。会员等级这类"会变的事实",TTL 到期或来源事件出现(用户升级)时刷新。
  2. 冲突:新事实覆盖旧事实(write 的策略),并保留时间戳——召回时把新旧都带上的"带时间戳让模型自裁"是另一派做法,适合事实类;偏好类直接新覆旧更干净。
  3. 遗忘:容量上限与长期未命中淘汰。记忆库的价值在命中率,不在条数——一年没被任何召回命中的条目,多半是当年写入门槛太松的欠账。

⚠️ 隐私是跨会话记忆的合规红线:入库内容是最小必要(只要影响交互的事实,不要对话原文全存)、可导出(用户行使"查看我的数据"权利)、可删除(用户说"忘了我说的"必须能物理删除)。本节只做工程层提示,合规评估请在部署前完成(0.2 节约定)。

本节要点回顾

  1. 写入门槛三问:下次还成立吗 / 影响未来交互吗 / 能溯源吗——一票否决;一次性事实、易变状态、可重取数据、会话过程不进库。
  2. 三种写入时机:显式信号立刻写、轮末评估择优写、会话结束批量写;形态三档:原文 / 抽取事实 / 结构化笔记。
  3. 召回三件事:会话开始 + 实体触及两个时机;预算倒推、宁缺勿滥;注入系统提示后的记忆区块,带时间戳与来源,红线级偏好末尾复述。
  4. ce_memory.py:门控在写入侧、召回带预算、粗排是占位——决策层自建,实现层外委。
  5. 记忆卫生:过期(TTL)、冲突(新覆旧 + 时间戳)、遗忘(未命中淘汰);隐私三要求:最小必要、可导出、可删除。
  6. write / select 的落地:本节的写入与召回,就是 LangChain 四操作中 write 与 select 在记忆成分上的具体形态(7.1 节映射到框架组件)。

记忆成分到此完整:三层地图(4.1)加两端管道(4.2)。动态层还剩另一半——素材:总量最大、增长最快、时效最短的成分。它的供给哲学与记忆相反:不是"沉淀下来反复使用",而是"用时才取、用完即走"。下一章讲按需供给的两种形态与取回之后的组装手艺。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U