qinghuan
← 让长任务能暂停和恢复 / 全部笔记

单元 24 / 让长任务能暂停和恢复

P0 · 必会主线L2 · 进阶

分开保存历史、工作记忆与长期偏好

把历史、当前任务信息和长期记忆分开保存,让对话接得上,也给眼前的问题留够空间。

本篇目录 · 按需要跳转

这篇重点学什么

本篇重点:记录记忆中的事实、出处和权限;以完整记忆组为单位选取内容,并检查是否超出上下文预算。

开始读正文 ↓
学过相近内容?查看哪些可以跳过

两条路线有些基础相同。已经学会的部分可以跳过,另一条路线只用来补你当前需要的内容。

检索与记忆

共同基础检索、证据和上下文选择相通;使用检索器与训练检索器有不同验收目标。

另一条路线补充什么?

分别为查询和文档生成向量(双编码器),用负样本和对比损失学习区分相关资料,再检查内容选择策略及对新数据的效果。

读完这篇,你能做什么

能压缩长对话并核对关键事实出处,验证账号隔离和实际存储的消息类型。

学习理由、准备要求与知识点

为什么学它

每次模型调用能读的内容有限。把完整历史、当前任务信息和长期偏好分开保存,能减少压缩丢条件或混入其他用户资料的问题。

先读这些内容

知识点清单

  • 完整历史与工作记忆
  • 长期偏好
  • 消息条数与 Token 预算
  • 摘要有损性
  • 来源消息标识
  • 结构化关键状态
  • 会话身份隔离
  • 存储工具消息的限制

运行前先确认完整算法使用 Java 17 标准库;JDK 源码基线为 OpenJDK 17 GA。示例是内存中的机制模型,外部服务接入需要另外配置和验证。

01先弄懂它是什么

对话越来越长时,既要接得上前文,也要避免把所有旧内容反复发送。完整历史用于回看,工作记忆是当前调用实际使用的内容,长期记忆则保存有来源、经过确认的偏好或事实。全部历史都塞进去,会浪费用量,也可能让旧要求干扰当前任务;只剩一份摘要,又可能丢掉关键条件。

摘要能缩短文字,但不能保证每个细节都留下。比如“不要删除”里的否定、某个版本号、尚未完成的操作,都可能在概括时丢失。因此任务状态、权限范围、确认记录和操作 ID 应单独保存成字段,不能全靠一段摘要。压缩后的内容也应能找到原消息或原文,发现疑点时才有办法核对。

消息条数上限与Token预算不同。一条巨大工具结果可能超过许多短对话总量,完整工具请求与结果还应成组保留。选择记忆时先留必须状态,再分配可选信息预算;本篇用整数背包说明完整证据组的选择,而不把价值分数当作客观语义真值。

文中这几个词,先认一认

工作记忆
当前这次任务或模型调用能直接读取的一组有限信息。
有损摘要
缩短文字时可能舍去部分细节的概括,需要保留来源,并把关键条件另存为明确字段。
不可拆组
需要一起保留才有完整含义的信息,例如一条工具请求和它对应的结果。

还有陌生词?到术语小抄里看一个具体例子 ↗

02看看它怎么工作

把可选记忆组抽象为成本和价值。成本是外部计数器给出的Token预算,价值是应用为练习设定的非负整数。预算五、组成本三和二、价值四和三,可以同时保留得七;若另一组成本五价值六,最优仍是前两组。每组只能选择一次,保持工具交换完整。

可以画一张表逐组决定选不选。dp[i][b] 表示只考虑前 i 组、预算最多 b 时,能得到的最大总价值。对第 i 组,先看“不选它”的结果;若预算够,再看“给它留出成本后,前 i-1 组还能贡献多少,加上它本身的价值”,取较大者。两种情况都读取上一行,保证当前这一组最多选一次。最后从表的末尾倒着检查哪些选择形成了结果,就能找回实际要放入上下文的组 ID。

算法仅对给定价值函数最优,不保证回答质量最优。真实记忆价值依赖当前问题、来源可信度、时效和组合关系,可能不可相加。任何选择后还需检查必须状态、来源和最终Token;被选摘要也不能获得高于原始资料的可信等级。

正在加载流程图…

图中状态只描述本篇可执行机制;业务调用仍需由外层应用负责。
查看流程图源码(Mermaid)
flowchart LR
  H["完整历史与来源"] --> K["结构化必须状态"]
  H --> G["可选完整记忆组"]
  K --> B["剩余 Token 预算"]
  G --> D["0/1选择或摘要"]
  B --> D
  D --> V["关键事实与最终计量核对"]

按顺序看,每一步做了什么

  1. 分开保存完整历史、当前工作记忆和已确认长期事实。
  2. 将权限、操作和未完成任务作为结构化必须状态。
  3. 把可选资料按完整消息组计量并估值。
  4. 在剩余预算内选择或摘要,保留来源与不确定性。
  5. 对最终上下文复算并用关键事实保持测试验收。

03对照实现代码

OpenJDK 17 BitSet 源码 (新标签页)↗

OpenJDK 17 GA,jdk-17+35 · BitSet.set / get / clone

下方为原创 Java 教学片段,调用已核验的 JDK API 说明局部机制;不是该类原样源码,也不实现神经网络。完整程序见算法模块。

核心机制代码 · java
BitSet selected = new BitSet(items.size());
selected.set(index); // 一个比特表示一个完整记忆组,不代表自然语言内容。
BitSet snapshot = (BitSet) selected.clone(); // 保存独立选择状态,避免后续修改污染快照。
if (snapshot.get(index)) includeWholeGroup(items.get(index));
// 必须状态与来源另行保存,位图不压缩原文语义。

BitSet用位表示布尔选择状态,set和get操作对应索引。它适合记录“是否选择”,但不保存文本内容、版本和来源,不能被称为语义记忆压缩器。

clone得到独立位集合,避免回溯或后续选择修改已保存方案。完整算法用DP表恢复ID列表,展示选择机制;位图是等价的方案表示选择。

Spring AI的消息窗口与存储实现有各自保留政策,不应仅凭框架接口名推断全部工具消息会被持久保存。需要按固定版本核对仓库过滤行为,并为审计另建可靠记录。

JDK源码桥梁覆盖选择状态管理,不实现摘要模型。摘要是否保留事实必须用原消息对照测试,不能通过一个位集合或消息条数证明。

代码先调用谁,再调用谁

  1. 结构化必须状态先占预算
  2. 可选完整组生成成本与价值
  3. DP计算最佳组合
  4. BitSet或ID列表保存选择结果
  5. 恢复来源并构造最终上下文

04动手写一个例子

完整记忆组的0/1预算选择

输入唯一ID、正整数成本、非负价值和预算,输出价值最大的完整组集合;同价值时优先沿用已有方案。预算上限和表大小显式限制。Java17 Main.java运行自测。

输入 1
组a成本3价值4,b成本2价值3,预算5
输出 1
价值7,a/b
输入 2
预算0
输出 2
价值0,空

dp每行只使用上一行,所以每个组最多取一次;不满足预算的组只能跳过。价值相等时不替换,给方案恢复一个固定规则。

从最后一格回溯,如果本行值不同于上一行,则该组被选中,减去成本继续;相同时按约定跳过。恢复后反转ID列表,保持原输入顺序。

预算数值进入表维度,因此O(nB)是伪多项式复杂度。预算用Token数量时可能很大,不能忽略内存;本程序限制表规模,正式系统可使用近似估值或稀疏状态。

为什么这样写是对的dp[i][b]是前i个完整组在预算b内最大可加价值,每组至多一次;回溯只从确实改善价值的转移选组,所选总成本不超过预算。

时间 O(nB)额外空间 O(nB)

n为组数,B为整数预算,完整表用于恢复方案;这是对预算数值线性的伪多项式算法,不代表输入位数意义下多项式。

保存为 Main.java,运行 javac --release 17 -encoding UTF-8 Main.java,再运行 java Main。程序包含固定输入自测,断言失败时会抛出错误。

Main.java · 完整可运行程序 · Java
import java.util.*;
public class Main {
    record Item(String id,int cost,long value){} record Choice(long value,List<String> ids){}
    static Choice choose(List<Item> items,int budget){
        if(budget<0||budget>10000||(long)(items.size()+1)*(budget+1)>2000000)throw new IllegalArgumentException("table budget");
        Set<String> ids=new HashSet<>();for(Item x:items)if(x.id()==null||!ids.add(x.id())||x.cost()<=0||x.value()<0)throw new IllegalArgumentException("item");
        long[][] dp=new long[items.size()+1][budget+1];
        for(int i=1;i<=items.size();i++){Item x=items.get(i-1);
            for(int b=0;b<=budget;b++){
                dp[i][b]=dp[i-1][b]; // 不选当前组,先沿用旧方案。
                if(x.cost()<=b){long take=Math.addExact(dp[i-1][b-x.cost()],x.value());if(take>dp[i][b])dp[i][b]=take;} // 只读上一行,禁止重复选择。
            }
        }
        List<String> selected=new ArrayList<>();int b=budget;
        for(int i=items.size();i>0;i--)if(dp[i][b]!=dp[i-1][b]){Item x=items.get(i-1);selected.add(x.id());b-=x.cost();}
        Collections.reverse(selected);return new Choice(dp[items.size()][budget],selected); // 恢复完整组ID。
    }
    static void eq(Choice e,Choice a){if(!e.equals(a))throw new AssertionError(a);}
    public static void main(String[] args){
        List<Item> x=List.of(new Item("a",3,4),new Item("b",2,3),new Item("c",5,6));
        eq(new Choice(7,List.of("a","b")),choose(x,5));
        eq(new Choice(0,List.of()),choose(x,0));eq(new Choice(0,List.of()),choose(List.of(),5));
        eq(new Choice(4,List.of("a")),choose(List.of(new Item("a",2,4),new Item("b",2,4)),2));
        eq(new Choice(0,List.of()),choose(List.of(new Item("large",9,100)),2));
        try{choose(List.of(new Item("bad",0,1)),2);throw new AssertionError();}catch(IllegalArgumentException expected){}
        System.out.println("PASS 6 tests");
    }
}

这些特殊情况也要试一试

  • 成本必须为正,预算为零合法。
  • 价值相同按固定不替换规则,避免方案随遍历细节漂移。
  • 巨大预算触发表规模限制,不能失控申请内存。
进阶选读 · 后续再读:相关性、多样性与互斥记忆

场景两段记忆高度重复,简单相加价值高估收益;新旧偏好互相冲突。

做法把来源时效、互斥组与冗余惩罚纳入约束,先解决事实冲突再选上下文;必要时用贪心近似或整数规划,并人工核对关键状态。

复杂度带一般交互和约束的组合优化可能NP-hard,精确搜索最坏指数级;背包模型不能覆盖所有语义关系。

好处与代价复杂评分更贴近实际却难校准,必须项结构化与简单可审计选择常是更可靠基线。

05项目里怎么用

压缩测试使用关键事实清单:用户明确否定的事项、当前版本、操作ID、未完成步骤与权限范围。把摘要与原消息逐项对照,发现遗漏就调整结构化字段或摘要策略。只看摘要读起来通顺无法证明关键状态保留。

完整历史与工作记忆可以采用不同保留期限和访问范围,避免把所有原始内容永久复制到长期存储。摘要和向量索引同样可能含敏感信息,用户撤回或资料过期时需要同步处理派生数据,不能只删除可见聊天文本。

会话身份应使用可信用户和会话组合,跨会话偏好须有明确确认与来源。临时要求只对当前任务生效时,不应被自动提升为长期习惯。模型提炼的推测先标记未确认,不能与用户明确声明的事实混在一起。

容易踩的坑

  • 按消息条数估算Token而不看工具结果大小。
  • 摘要覆盖权限、确认与操作ID等关键结构状态。
  • 拆开工具请求和结果以便凑预算。
  • 把背包价值最优称为答案质量最优。

几种做法,怎么选

表格有四列,窄屏可左右滑动查看代价和适用条件。

方案优势代价与限制适用条件
完整历史追溯信息充分存储与上下文成本高审计与故障复现
结构化关键状态准确保留控制事实需要字段设计与迁移权限、操作和任务进度
来源摘要与选择降低当前输入成本有损并依赖估值长期对话工作上下文

06检验是否读懂了

先自己想、自己写,再展开答案核对。场景题是假设的练习情境;遇到还没学过的内容,可以做完基础后再回来。

先用自己的话解释

01工作记忆与长期记忆区别是什么?

展开参考答案与推导

工作记忆服务当前调用预算,长期记忆保存经确认且有来源的持续事实;不能把当前上下文所有内容自动长期化。

02为什么背包必须读取上一行?

展开参考答案与推导

上一行只包含前i-1组,保证当前组至多使用一次;错误地正向读写同一行会变成可重复选择。

03摘要流畅能证明压缩正确吗?

展开参考答案与推导

不能,需核对否定、数字、版本和未完成操作等关键事实,并保留原始来源。

换个情况,还会处理吗

01摘要把“不要发送”改成“发送”,怎样防止?

展开参考答案与推导

把禁止动作和确认状态结构化保存,摘要不能覆盖控制字段;加入否定事实保持测试并阻止未确认执行。

02一条工具消息超窗口,按条数截取为何无效?

展开参考答案与推导

消息长度差异很大,需实际Token计量与完整组策略;对超长结果做受控分页或摘要。

03框架保存了聊天但审计缺工具结果,怎么办?

展开参考答案与推导

核对具体仓库版本的过滤政策,建立独立运行事件审计;ChatMemory接口名称不保证完整轨迹。

写代码试一试

01同一高价值组能选两次吗?

输入 / 条件
成本2价值4,预算4
输出 / 预期
只选一次价值4

提示 这是0/1而非完全背包。

展开参考答案与推导

转移只读上一行,当前组没有机会再次贡献;测试可以发现错误的一维正向循环。

02同价值方案如何稳定?

输入 / 条件
a和b均成本2价值4,预算2
输出 / 预期
选a

提示 相等时不替换。

展开参考答案与推导

先处理a得到四,处理b候选也是四,不更新,回溯按约定保留先前方案。

03O(nB)为什么称伪多项式?

输入 / 条件
B用二进制输入
输出 / 预期
复杂度依B数值而非log B

提示 区分数值与编码长度。

展开参考答案与推导

预算翻倍会使表规模翻倍,但输入只多约一位;因此不能称为一般背包的输入长度多项式算法。

读完之后,独立完成

课后作业:自己做一遍

本篇共 12 道作业,先完成 9 道基础与综合任务,再按前置知识挑战进阶题。其中包含 2 道思维拓展,试着换个条件,看看原来的办法是否还管用。不附参考答案。

这次练什么

能压缩长对话并核对关键事实出处,验证账号隔离和实际存储的消息类型。

本篇重点加练

摘要可能丢失条件,关键结构化状态需要独立维护并在压缩后核验。

  • 摘要有损性
  • 结构化关键状态

重点内容会多练几次。先说清楚怎么做,再试试空数据、出错或条件改变时会发生什么。

先自己做,卡住时记下问题,再回来查。问答题写清“为什么、什么时候适用”;动手题留下输入、输出和运行步骤,方便下次重做。

基础必做

  1. 作业 01原理问答

    将“用户偏好中文、今天想练集合、工具报错日志、去年聊天记录”分配到你设计的记忆层,并说明保存依据与生命周期。

    提交内容
    一份独立书面回答或标注图,包含自造例子、概念边界及判断依据。
    怎样算完成
    • 逐项回应题目要求,区分事实、假设与个人判断。
    • 能用自己的例子解释适用条件,记录尚未弄懂的点。

    练到的知识点完整历史与工作记忆 · 长期偏好

  2. 作业 02代码推演

    给六条长短不同的消息设置总预算,分别按条数截断和摘要压缩;比较被保留的信息,逐项列出不可默默丢弃的关键事实。

    提交内容
    手工推演记录,写明输入约定、中间状态、最终判断;可运行时附程序对照记录。
    怎样算完成
    • 推演包含中间过程,数据形状、单位、顺序或状态前后一致。
    • 主动检查至少一个边界或异常条件,能解释手算与运行差异。

    练到的知识点消息条数与 Token 预算 · 摘要有损性

  3. 作业 03原理问答

    为“用户只在周末允许自动调整计划”设计文字摘要与结构化状态的并行表达,指出需要显式保存的限定条件及冲突检查项。

    提交内容
    概念或合同说明、关系图与自造案例,明确事实、假设和适用条件。
    怎样算完成
    • 关键概念有明确边界,能用案例检验声明。
    • 未获证据支持的假设单独标注。

    练到的知识点摘要有损性 · 结构化关键状态

综合应用

  1. 作业 04面试场景

    摘要写“用户已确认删除”,原消息却是“先不要删除”。设计可回到来源的结构和校验过程,并说明状态冲突如何呈现给操作者。

    提交内容
    场景分析与决策记录,包含信息缺口、约束、备选方案和验证计划。
    怎样算完成
    • 方案回应给定约束,列出至少一种替代方案及代价。
    • 每项关键结论说明所需证据,不能核实的部分明确标注。

    练到的知识点来源消息标识 · 结构化关键状态

  2. 作业 05编程实践

    用两个用户和两个会话实现记忆读取测试,加入未配对工具消息、过期工具结果与错误会话ID;保存输入、读取记录和异常分类。

    提交内容
    可复现的最小程序或实验材料、自写测试、环境说明与运行记录;题目允许纸面实验时提交完整案例表。
    怎样算完成
    • 提交物按说明可以重现;测试覆盖正常、边界与失败场景。
    • 运行证据与断言能核验声明的行为,注明模拟与真实执行范围。

    练到的知识点会话身份隔离 · 存储工具消息的限制

  3. 作业 06排错实验

    连续压缩同一段对话三次,再与原始消息比较,定义可量化的遗漏与错误归因标准,提交至少两个自行发现的失真样本。

    提交内容
    最小故障输入、复现步骤、观测记录、定位依据及回归用例。
    怎样算完成
    • 其他人可按记录复现故障,并区分现象与已验证原因。
    • 定位过程有观测依据,回归用例可以再次暴露原问题。

    练到的知识点完整历史与工作记忆 · 摘要有损性 · 来源消息标识

  4. 作业 07编程实践

    实现一个纯本地记忆验收器,输入原消息、候选摘要和关键状态。自行定义三条业务不变量,用包含否定、条件和修订的对话检查压缩产物。

    提交内容
    可复现的小程序或题目允许的离线实验、自写测试、输入和运行记录。
    怎样算完成
    • 输入、环境和运行过程可重现,测试覆盖声明的重点条件。
    • 验证目标由合同确定,模拟结果不冒充真实服务证据。

    练到的知识点摘要有损性 · 结构化关键状态

  5. 作业 08排错实验

    把同一对话按不同分段顺序生成手工摘要,再合并为上下文。比较关键状态是否一致,并记录何种信息丢失使后续无法恢复。

    提交内容
    最小故障序列、观测记录、原因核对与可再次触发原问题的测试。
    怎样算完成
    • 故障可以稳定重现,现象与已验证原因分开。
    • 观测记录足以判断声明的合同是否被违反。

    练到的知识点摘要有损性 · 结构化关键状态

  6. 作业 09面试场景

    审计要求保留可追溯历史,但模型上下文仅有很小预算。提出查询历史、摘要缓存和关键状态的职责安排,并给出失效与重建用例。

    提交内容
    场景评审记录,包含约束、备选方案、未决信息和验证计划。
    怎样算完成
    • 方案回应题目约束,取舍能对应到可核验的事实。
    • 给出失败或条件变化时的检查方式。

    练到的知识点摘要有损性 · 结构化关键状态

进阶挑战 · 掌握前置后选做

  1. 作业 10设计评审

    在已掌握持久化基础后,设计跨设备更新偏好的协议,给出并发冲突、用户撤回和会话隔离的验证计划。

    提交内容
    设计评审文档或对照实验报告,包含前置条件、方案取舍、验收证据与尚未验证的范围。
    怎样算完成
    • 比较使用一致条件与事先声明的标准,记录失败与未知结果。
    • 说明方案的适用前提、未覆盖风险及后续验证方法。

    练到的知识点长期偏好 · 结构化关键状态 · 会话身份隔离

思维拓展

先写出你的猜想,再用例子或实验验证。答案可以不同,但要说清依据、适用情况,以及还有什么没弄懂。

  1. 作业 11思维拓展 · 反例构造

    审阅“摘要覆盖全部关键词就足以保留用户意图”。构造关键词相同而条件或否定关系不同的两段对话,设计可区分它们的检查。

    提交内容
    具体反例、原主张的适用前提、复现或逻辑证明及结论边界。
    怎样算完成
    • 反例满足原主张所声称的前提,确实针对其结论。
    • 说明一个反例能推翻什么、不能进一步证明什么。

    练到的知识点摘要有损性 · 结构化关键状态

  2. 作业 12思维拓展 · 条件变化

    如果后续任务从“给学习建议”变为“自动修改计划”,重新审查原记忆压缩政策;列出需要提高保证强度的状态及验证成本。

    提交内容
    变更前后条件表、重新评审的方案、检验用例与新增代价。
    怎样算完成
    • 只改变明确列出的条件,比较口径保持一致。
    • 修改方案说明收益、代价与仍未验证的范围。

    练到的知识点摘要有损性 · 结构化关键状态

完成后,再检验一次

给每题标记“独立完成 / 查阅后完成 / 尚未完成”。查过资料或没做出的题,记下卡在哪里。隔一天换一组输入再试,能解释结果和出错原因,再把这个知识点标为掌握。

继续阅读

先看能帮你完成当前练习的部分。例子跑通后,再读更深入的解释。

打开资料库,找下一份学习材料 ↗