压缩、摘要失真与缓存
正在读取学习记录…
上下文压缩是把需要交给模型的信息整理得更短。删去重复段落、选取相关句子、把长记录整理成摘要,都可以减少请求中的文字。上一节先选出需要的资料;资料选对之后,还可以进一步缩短,但要保留回答所需的条件。
摘要像做会议纪要:大家寒暄了十分钟,可以缩成一句;“谁负责、何时完成、哪些情况例外”需要写清楚。省下的文字越多,越要留意是否连着事实一起省掉了。
先看一个容易失真的规则
原始资料写着:
已发货订单在签收7天内可退货,生鲜商品除外。申请时请填写订单编号,客服将在工作时间处理。
客户问“签收第10天还能退货吗”,摘要至少需要保留期限。如果只留下“订单可退货”,阅读的人可能以为任何订单、任何时间都能申请。
| 要素 | 原规则 | 过度简写后的缺口 |
|---|---|---|
| 期限 | 签收7天内 | 缺少时间限制 |
| 适用条件 | 已发货订单 | 范围变成所有订单 |
| 例外 | 生鲜商品除外 | 商品限制消失 |
| 来源版本 | v1 | 保留版本便于核对更新 |
句子变短只是长度变化。判断摘要是否有用,要对照当前问题,检查作答需要的事实和条件是否还在。
运行一次压缩与缓存演示
缓存是保存已经计算过的结果,下次输入相同就直接取出,减少重复工作。它适合保存经常读取、变化较少的资料摘要。
先在 PowerShell 创建并进入学习目录:
mkdir "F:\学习\l5-compression" -Force
cd "F:\学习\l5-compression"保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。
新建 F:\学习\l5-compression,保存下面完整代码为 compression_demo.py。它先检查一个过度简写的摘要,然后依次读取旧规则、重复读取和更新后的规则。
先在 PowerShell 创建并进入学习目录:
mkdir "F:\学习\l5-compression" -Force
cd "F:\学习\l5-compression"保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。
"""保留规则中的条件,并观察资料更新后的摘要缓存。"""
from dataclasses import dataclass
@dataclass(frozen=True)
class Policy:
version: str
deadline_days: int
condition: str
exception: str
@dataclass(frozen=True)
class Summary:
text: str
version: str
deadline_days: int
condition: str
exception: str
def summarize(policy):
# 提取期限、适用条件和例外,组合为短句。
text = (f"{policy.condition}在签收{policy.deadline_days}天内可退货,"
f"{policy.exception}除外。")
return Summary(text, policy.version, policy.deadline_days,
policy.condition, policy.exception)
def inspect(summary, policy):
issues = []
# 比较可明确核对的字段,指出摘要丢失或改动了哪项规则。
for field in ("version", "deadline_days", "condition", "exception"):
if getattr(summary, field) != getattr(policy, field):
issues.append(field)
return issues
class SummaryCache:
def __init__(self):
self.values = {}
def get(self, policy, scope, strategy="extract-v1"):
# 资料内容、可见范围和摘要策略共同决定缓存是否可复用。
key = (policy, scope, strategy)
hit = key in self.values
if not hit:
self.values[key] = summarize(policy)
return self.values[key], hit
if __name__ == "__main__":
original = Policy("v1", 7, "已发货订单", "生鲜商品")
bad = Summary("订单可退货。", "v1", 0, "订单", "")
print("过度简写丢失:" + "、".join(inspect(bad, original)))
cache = SummaryCache()
for label, policy in (
("首次读取", original),
("再次读取", original),
("规则更新", Policy("v2", 14, "已发货订单", "生鲜商品")),
):
result, hit = cache.get(policy, scope="公开规则")
print(f"{label}:命中={hit};{result.text}")在 PowerShell 运行:
cd "F:\学习\l5-compression"
ls
python -X utf8 compression_demo.py程序输出:
过度简写丢失:deadline_days、condition、exception
首次读取:命中=False;已发货订单在签收7天内可退货,生鲜商品除外。
再次读取:命中=True;已发货订单在签收7天内可退货,生鲜商品除外。
规则更新:命中=False;已发货订单在签收14天内可退货,生鲜商品除外。deadline_days 是期限天数,condition 是适用条件,exception 是例外。第一行指出简写摘要改动了这三项。
接下来三行观察缓存。False 表示尚未找到相同输入的摘要,需要生成;True 表示已经保存过,可以复用。规则改成14天后,缓存重新生成,因此最终句子也改为14天。
摘要怎样生成,怎样检查
Policy 保存原始规则的结构化字段,Summary 保存摘要及其对应字段。summarize 读取期限、条件和例外,组合成短句。这是一种提取式整理:保留资料中的字段,再删去当前回答用不到的操作说明。
实际资料通常是长文本。可以先选取相关原句,也可以让模型改写成摘要。选取原句容易对照来源;改写可以合并重复内容,但还需要检查是否改动了数字、主体或条件。
inspect 比较明确的字段,逐项列出差异。例子里的坏摘要把期限写成0,把“已发货订单”改成“订单”,还丢掉生鲜例外,因此得到三项差异。实际改写后,也可以先做这类可自动检查的字段对照,再检查完整句子的含义。
里面的 getattr(policy, field) 表示按名字取出对象属性。例如 field='deadline_days' 时,取到的是 policy.deadline_days。循环逐个取出原文与摘要的相同字段,再比较两个值。
摘要应怎样适应问题
对于“第10天能否退货”,期限和商品例外很重要;对于“怎样填写申请”,订单编号和处理步骤更重要。压缩前先明确本次问题,再选择保留内容。
如果把一份很短的摘要用于所有问题,读者可能在需要操作步骤时只得到期限。更合适的做法是保留原始资料,按问题提取相关内容;常用摘要用于快速定位,需要细节时继续读取原文。
缓存如何识别“相同输入”
key = (policy, scope, strategy) 是缓存键,相当于存放摘要的抽屉标签:
policy包含资料版本与规则内容。scope表示这份资料的可见范围。strategy表示使用哪套摘要规则。
三项都相同,才取出已有摘要。Policy 使用 frozen=True,实例创建后字段保持固定,便于作为字典键使用。可见范围本身仍需由资料访问逻辑确认;这里将已确认的范围传入缓存。
把内容也放进键,是为了覆盖“资料已经改了,但版本号没更新”的情况。只有版本号的键会继续找到旧摘要;包含内容后,规则由7天改成14天,即使仍叫v1,也会得到新结果。
大文档通常会计算内容摘要值作为键的一部分,不必把整段原文塞进键。摘要策略、模型配置变化时也应调整对应版本;不同策略可能产生不同长度和不同表述。
缓存保存在哪里
例子把缓存放在当前进程的字典里。关闭程序后字典消失,再次启动会从首次生成开始。需要跨进程复用时,可以写入数据库或缓存服务,并设置保留时间和失效条件。
缓存占空间,也需要清理。文件数量增加后,可以限制条目数、删除长期未用条目,或在资料更新时移除旧版本。频繁变化的订单状态通常需要短保留时间;稳定公开规则可以保存更久。
对已有摘要再摘要,会把前一次丢失的细节永久带到后续结果中。更新摘要时优先回到原始资料,重新提取;保留来源标识,便于遇到问题时查原句。
跟着固定改法检查更新
将主程序“规则更新”中的14改成30,再执行同一命令。最后一行会显示“签收30天内”,前两行仍显示7天。恢复14即可回到上面的输出。
再将更新样本里的 "v2" 改为 "v1",保留14,运行 python -X utf8 compression_demo.py。最后一行仍是 命中=False,因为规则内容不同。这能直接观察到缓存键同时比较版本和内容。恢复更新样本为v2、14天后重跑。
检查七种情况
将测试保存为 test_compression_demo.py,覆盖正常摘要、条件失真、重复命中、资料更新、同版本内容变更、范围变更与策略变更。
测试代码:test_compression_demo.py
"""检查摘要规则字段及缓存复用条件。"""
import unittest
from compression_demo import Policy, Summary, SummaryCache, inspect, summarize
class CompressionTests(unittest.TestCase):
def setUp(self):
self.policy = Policy("v1", 7, "已发货订单", "生鲜商品")
def test_preserved_fields(self):
result = summarize(self.policy)
self.assertEqual(inspect(result, self.policy), [])
self.assertEqual(result.text, "已发货订单在签收7天内可退货,生鲜商品除外。")
def test_missing_conditions(self):
bad = Summary("订单可退货。", "v1", 0, "订单", "")
self.assertEqual(inspect(bad, self.policy),
["deadline_days", "condition", "exception"])
def test_repeated_read_hits(self):
cache = SummaryCache()
self.assertFalse(cache.get(self.policy, "公开")[1])
self.assertTrue(cache.get(self.policy, "公开")[1])
def test_document_update_misses(self):
cache = SummaryCache()
cache.get(self.policy, "公开")
updated = Policy("v2", 14, "已发货订单", "生鲜商品")
result, hit = cache.get(updated, "公开")
self.assertFalse(hit)
self.assertEqual(result.deadline_days, 14)
def test_content_change_same_version_misses(self):
cache = SummaryCache()
cache.get(self.policy, "公开")
changed = Policy("v1", 14, "已发货订单", "生鲜商品")
self.assertFalse(cache.get(changed, "公开")[1])
def test_other_scope_misses(self):
cache = SummaryCache()
cache.get(self.policy, "公开")
self.assertFalse(cache.get(self.policy, "内部")[1])
def test_changed_strategy_misses(self):
cache = SummaryCache()
cache.get(self.policy, "公开")
self.assertFalse(cache.get(self.policy, "公开", "extract-v2")[1])
if __name__ == "__main__":
unittest.main()cd "F:\学习\l5-compression"
ls
python -X utf8 -m unittest -v test_compression_demo应显示7项通过。
| 现象 | 优先检查 |
|---|---|
| 摘要中数字与原文不同 | 期限、金额等字段的提取与改写 |
| 更新后仍显示旧规则 | 缓存键是否包含变化后的内容 |
| 每次运行都未命中 | 是否重启了程序、输入或策略是否变化 |
| 缩短后答复缺少细节 | 当前问题需要的条件是否被删去 |
聊天历史也可以按最近消息、重要事实和历史摘要整理,具体接口可查阅 LangChain 短期记忆文档。下一篇上下文隔离、污染与可信来源会进一步解释:这些内容进入同一次请求时,怎样保持来源和职责清楚。
课后练习展开习题收起习题
正在读取本地记录…
不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。
选择题 · 先判断边界
关于“压缩、摘要失真与缓存”,哪种做法更稳妥?
对应知识点:L5-compression
简答题 · 解释失败
写出一个失败输入并说明记录字段。
对应知识点:L5-compression
代码题 · 边界测试
补充正常、边界、失败三组输入和预期结果。
对应知识点:L5-compression
场景题 · 结果未知
证据不足时如何设计状态和人工接管?
对应知识点:L5-compression
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。