压缩到底必须保留什么
前两章把容量约束变成真实编码长度,也证明裁剪可能留下合法文本却丢掉答案。本章研究更早的一步:资料还没进入选择器时,可否改成更短表示。读者只需会列表、集合和字符串,新增的“保真”先定义为一组可检查的源声明完全保留,而不是任意读者的心理感受相同。最终能力是写出压缩前后对应表,指出哪些信息不可删,并在证明条件不成立时回退原文。
项目把一份文档表示为身份、版本、原始正文与摘要。facts 函数按原始行号扫描,忽略空行和左侧去空白后以井号开头的标题,把剩余每一行都当作待保留声明。这是人为定义的文档语言。它适合本课受控的短通知:标题只是标签,正文完整承载事实;如果真实材料的标题写“仅限未成年人”而正文没写,该假设不成立,必须修改语言与验证器,不能沿用本课证明声称保真。
这里需要三个不同对象。源文档是不可变文本;压缩提案是想留下的表示;用于检索的证据单元是含来源身份、原行号和逐字引文的记录。压缩器提出只保留以“- ”开头的行,验证器却遍历所有非标题行。若提案漏掉其中任何一行,验证不通过,证据单元使用全文。先有完整判据再做短提案,避免让压缩器自己定义“重要信息”并给自己打满分。
一个可推导的保真条件
定义 为文档 d 的非空、非标题原始行集合,每项同时含原行号和文本。提案 是其中以项目符号开头的子集。因为 P 从 F 筛选,天然满足 P 是 F 的子集;再检查差集 F 减 P 为空,便得到 F 等于 P。验证器不是看压缩后词数有多短,而是逐项核对这个集合等式。相同行文在不同行号仍是不同来源位置,不能因为文字重复便误删一个有独立证据身份的条目。
从集合等式可推导下游支持集合相同,但须加条件:source_claims 只按这些完整行生成事实,不跨行做语义推断;版本和日期视图相同;压缩记录仍指向原始摘要与原行号。给定这些条件,全文中每条可抽取事实在压缩单元中都有相同身份、文本和摘要,反向也没有新条目。两边逐条建立一一对应,故可抽取支持集合相同。这是当前数据语言内的精确命题,并不是自然语言摘要普遍无损的定理。
完整算例一:活动安排保真抽取
schedule 第二版原文包含标题、空行、三个项目符号事实,行号分别为三、四、五。F 含活动时间、活动时长、集合要求三项;P 也含这三项,差集为空。提案正文去掉标题与空行,冻结 BPE 计数从七十三降到五十七,减少十六,正文层压缩比例为五十七除七十三约零点七八。这一比例只是文档文本,不含每个证据单元的来源字段;不要直接拿它宣称整个 JSON 上下文省百分之二十二。
原文行号三的“活动时间:周四16:30。”生成身份 schedule@2:3。抽取后即使它成了压缩表示的第一条,也仍用原行号三。原 SHA 指向整份源文件,不能换成缩短后正文的摘要却继续声称同一源身份。检查时从源版本取第三行,与 quote 逐字比较;读者由引用回到原文件即可复核,不需要相信摘要器的解释。下一章的事件历史会决定这条身份此刻能否使用。
from context import compress_document,sha
text='# 安排\n\n- 时间:16:30。\n- 地点:B室。\n'
row={'doc_id':'d','version':1,'text':text,'sha256':sha(text)}
c=compress_document(row)
assert c['faithful'] and c['retained_facts']==2
assert c['lines'][0][0]==3
print(c['lines'])完整算例二:最短的一行可能最关键
access 文件两条项目符号写开放对象与开放方式,最后一行没有项目符号:“有效限制:只在本周五之前有效。”F 有三项,P 只有两项,差集恰是行号五的期限。若盲删这行,程序会把一次临时开放误表示为长期许可。实际提案从一百零四词元降为六十七,看起来更短,但验证失败,units 返回全文。报告把 faithful 标为 false 并列出漏行,使用状态写 full document fallback;没有把未采用的六十七当实际压缩收益。
这个反例同时暴露两个边界。第一,程序不懂周五是哪一天,所以事件元数据还要给明确的日期区间,第四章再计算。第二,保留原行不等于选入模型窗口:第二章的预算器仍可能不选 access 全文。压缩前后源事实集合相等只控制第一种损失,选择后的可见集合检查控制第二种损失。如果把两个阶段合在一个“摘要质量分”里,就难以定位究竟是资料被压坏,还是好资料没装进去。
再考虑一份条件句跨行书写的通知:“可借用相机”下一行“仅限老师确认后”。本课验证器会把两行都视作事实并保留,但下游按字段抽取可能无法理解条件依附关系。因此本课数据约定每行是一条完整、带限定的字段声明,源文档由作者按此约定编写。真实文档迁移应在单元形成时保留完整句群或依赖边,不是只扩大上下文就默认逻辑条件自动关联。
from context import compress_document,sha
text='# 临时通知\n\n- 开放对象:成员。\n有效限制:仅今天。\n'
c=compress_document({'doc_id':'a','version':1,'text':text,'sha256':sha(text)})
assert not c['faithful']
assert c['missing']==[{'line':4,'quote':'有效限制:仅今天。'}]
print('fallback required',c['missing'])从同一原文独立检查两种表示
独立检查不复用压缩器的 faithful 布尔值作为答案。测试分别调用 units 的全文模式和压缩模式,经 source_claims 构造三元组集合:来源身份、逐字引文、原文摘要,再比较相等。若压缩器错报成功却漏行,两个集合会不同;若只改原行号或摘要也会失败。这比“函数返回 true”多检查了表示到实际引用的整条路径,但仍共享 facts 的文档语言定义,所以不是对任意语义的独立裁判。
复杂度按本课成本模型计:N 为文档 Unicode 字符数,L 为非标题行数,splitlines 与逐行筛选扫描 字符,保存源行与缺失列表占 空间。实际上下文打包会重复 JSON 序列化和 BPE 编码,其成本单独计算,不能把压缩器线性复杂度误写成全管线线性。我们的受控短材料很小,优先选择容易审计的实现;长材料需要缓存不可变片段、增量索引和重新证明失效规则。
如果把 extractive 替换成 LLM 摘要,应保留提案/验证分离的接口。让模型生成短文本只是新提案机制;还要问每条期限、否定、条件、数值和出处是否存在对应支持。逐字集合相等会过于保守,语义蕴含判据又依赖模型与评估,需要新的正负对照,不能借用这里的集合证明。工程文章中 compaction 的建议是动机输入,本章只对已定义的行式语言给出精确局部保证。
从这一章开始,读者应保留每个失败的最早位置。若候选构造后事实已缺,错误归压缩;若完整候选存在而 pack 没选,归选择;若选中了却答案漏引,归生成或引用校验。阶段分开不是为了给系统找借口,而是让一次改动可以对一个机制提出可证伪的预测。最终评测会保存每个阶段的身份列表,而非只留下漂亮的回答。
证据粒度与排列不是同一保真命题
集合保真有意忽略顺序,因此只能支持本课按字段独立抽取的机制。若资料说“先登记再取走器材”,把两条短句颠倒可能改变执行流程,原集合虽然相同也不能保证行动等价。我们的受控通知把顺序条件写在同一完整原行,不从条目排列推导额外约束。迁移到流程文档时,应把顺序边、条件作用域与否定范围纳入待保留对象,重新定义F,而不是复用一个只验集合的函数。
另一差异是存储保真与呈现保真。源文件不变,抽取后证据单元含逐字quote,源内容可回查;但模型看到的排列、来源头部和重复开销可能变了。因此本课保真压缩不是保证视觉页面毫无变化,也不是保证LLM输出分布不变。它精确保证的是特定抽取关系下支持集合不丢不增。实际选择效果已经单列比较,head在主任务中的失败正提醒我们:一个局部正确性命题不能自动升级成端到端质量提升。
对任意新增正文行,最保守的行为是完整保存并让新模板经过检查。验证器拒绝并不意味着原文不可用,而是当前压缩提案不足以证明可用,所以返回全文。程序宁可在预算阶段明确拒绝装入,也不静默删掉未理解的条件。若未来增加可靠的结构解析器,应同时构造有条件与无条件、否定与肯定、数值改动等成对反例,让“保留同一事实”成为可测试对象,而不是用摘要读起来顺畅当证据。
TRY IT YOURSELF
基础:集合证明
F 有三条原行,P 从中筛出两条。P⊆F 能证明保真吗?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
进阶:压缩比例
正文73→57词元,能否宣称全 wire 同比缩短?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
挑战:标题带限制
标题写“仅限周五”,正文两行都保留。当前事实集合检查通过,能否保证真实语义保真?