03 跨压缩边界的约束 本节摘要:压缩看起来是「智能摘要 + 近期保留」,但有个硬约束不能违反——厂商原生消息不能被切割。带签名的助手消息、加密的推理内容,一旦跨越压缩边界就会失效(签名校验失败、推理链断裂)。本节讲清这个约束的根因、违反了会怎样、以及 OpenCode 如何在压缩时保证不切割。这是压缩机制里最容易被忽视、却最不能出错的部分。 一、什么是「厂商原生消息」 先澄清概念。
本节摘要:压缩看起来是「智能摘要 + 近期保留」,但有个硬约束不能违反——厂商原生消息不能被切割。带签名的助手消息、加密的推理内容,一旦跨越压缩边界就会失效(签名校验失败、推理链断裂)。本节讲清这个约束的根因、违反了会怎样、以及 OpenCode 如何在压缩时保证不切割。这是压缩机制里最容易被忽视、却最不能出错的部分。
先澄清概念。不同厂商的流式响应里,有些消息是「原生」的——它们带厂商特定的元数据或加密内容:
| 类型 | 特点 |
|---|---|
| 带签名的助手消息 | 某些厂商给助手回复签名,防篡改 |
| 加密的推理(reasoning)内容 | 思维链等推理过程可能加密传输,客户端不解密 |
| 工具结果(特定厂商格式) | 某些厂商工具结果有特殊格式/校验 |
这些「原生消息」的共同点是:它们必须作为整体被保留或丢弃,不能被切割。
切割会失效,根因是签名和加密:
带签名的助手消息,签名是针对「完整消息内容」算的。如果压缩把消息切成两半,只留一半,签名就对不上了——厂商校验签名失败,拒绝处理:
原始助手消息:「A完整的回复内容B」+ 签名S(对整段算的) │ ▼ 压缩切成两半,留「A完整的」 │ ▼ 下次发给模型:「A完整的」+ 签名S │ ▼ 厂商校验:签名S 是对完整消息算的,「A完整的」不匹配 ──► 失败
加密的推理内容,加密是针对「完整推理块」的。切割会让加密块残缺,无法解密:
原始推理块(加密):[加密块X] │ ▼ 压缩切割,留半个加密块 │ ▼ 下次解密:残缺的加密块无法解密 ──► 推理链断裂
如果压缩不小心切割了原生消息,后果:
这些后果都是「硬故障」——不是性能下降,而是会话出错甚至中断。所以跨边界约束是绝对不能违反的硬规则。
OpenCode 在压缩时如何保证不切割?核心原则是:原生消息要么完整保留在近期上下文里,要么完全进入摘要,绝不留在「切割边界」上。
压缩时,对于每条原生消息: │ ├─ 如果它在「近期保留范围」内 ──► 完整保留(不动) │ └─ 如果它在「被压缩范围」内 ──► 整条进入摘要(不切割)
也就是说,压缩的「切割点」永远落在非原生消息之间——比如普通用户消息之间、或工具结果与下一条消息之间,而不会落在一条原生消息中间。
💡 保证机制:压缩算法在选择「保留哪些、摘要哪些」时,会把原生消息视为「不可分割的原子单元」——它要么整体在保留区,要么整体在摘要区,不存在「半个」状态。
这个约束对「近期上下文保留」有个影响:有时为了不切割原生消息,近期保留会比预期多保留一点。
考虑:近期预算快满了,但下一条要被切掉的是原生消息。为了不切割,算法会把它整体纳入近期保留(即使略超预算),而不是切割它。
近期预算:8000 token 已保留:7800 token(还剩 200) 下一条原生消息:500 token │ ▼ 切了会破坏签名/推理 │ ▼ 选择:整体保留(虽略超预算,到 8300) 而不是:切割留 200
这种「宁可略超预算也不切割」的取舍,是因为切割的代价(签名失败/推理断裂)远大于略超预算(多用一点 token)。
这个约束和第 8 章 Context Epoch 有呼应——压缩时不仅不能切割原生消息,还会开启新纪元(下一节详讲)。因为压缩重写了历史(旧对话变摘要),基准前缀变了,旧纪元的缓存失效,必须开新纪元重建缓存。
所以压缩涉及两个「不能违反」:
边界约束讲清了,下一节讲压缩与新纪元的衔接——压缩完成为何开启新纪元。