← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

增量上下文打包(Context Pack)

为 LLM / Agent 上下文管线实现增量上下文传输(Context Pack 协议)。把每次 prepare 产出的完整正文切成带 SHA-256 校验的确定性分块并打成 pack,后续请求只发送"保留前 N 块 + 新增后缀"的 delta,接收端仅凭已有的 base pack 与收到的 delta 就能校验并逐字节重建出与完整正文一致的上下文。当需要降低多轮长上下文的传输量、复用客户端已持有的上一轮内容、做条件请求/缓存协商(304 风格),或给任意检索型 prepare 接口加一层增量复用时使用。

personAuthor: nxxnl123hubOpenAPI
<!-- OB-S:dzN-nb3iLbKH76FJbTuvcg -->

增量上下文打包(Context Pack)

这个 Skill 解决什么问题

多轮对话 / 会议纪要 / 检索式问答里,服务端每轮都会返回一份完整的 prepare 正文。客户端上一轮已经拿到过同样的内容,如果每轮都把整份再传一遍,代价随轮次线性累积。

Context Pack 把完整正文表示成可校验的分块包(pack),增量则只携带保留的前缀 + 新增后缀(delta):

  • 首次请求:发送完整 pack;
  • 后续请求:发送 delta("我留了前 N 块,你再补上这些块");
  • 接收端:拿手上已有的 base pack + delta → 校验 → 重建出与完整正文逐字节一致的结果。

关键点是重建只依赖序列化数据,不依赖发送端的进程内缓存、不共享任何 Python 对象,因此可以跨进程、跨语言、跨网络实现。

适用场景

| 场景 | 收益来源 | | --- | --- | | 会议纪要 / 长对话逐轮追加 | 前面轮次的内容字节完全不变,直接复用 | | 检索式 prepare:引用顺序变化、正文尾部追加 | 中间内容不变时只重发尾部 | | 客户端已缓存整份正文(304 风格协商) | 用摘要判断是否变化,变化时才走增量 | | 弱网 / 计费敏感的网关转发 | 同样的语义,少传很多字节 |

快速开始

本 Skill 自带一份零依赖的参考实现 scripts/ctxpack.py(Python 3.9+,只用标准库)。

# 0) 先跑一遍内置自检,确认环境正常
python scripts/ctxpack.py selftest

# 1) 把正文打成完整 pack
python scripts/ctxpack.py pack --input body.txt --out pack.json

# 2) 下一轮正文变了,算出增量(base = 上一轮 pack,target = 本轮 pack)
python scripts/ctxpack.py pack --input body2.txt --out pack2.json
python scripts/ctxpack.py delta --base pack.json --target pack2.json --out delta.json

# 3) 接收端:只凭 base + delta 重建,并和期望正文逐字节比对
python scripts/ctxpack.py apply --base pack.json --delta delta.json --out rebuilt.json --check body2.txt

# 4) 校验任意一个包的摘要与字节数
python scripts/ctxpack.py verify --pack pack.json

作为库使用:

from ctxpack import ContextPack, ContextPackDelta, apply_delta

base = ContextPack.from_content(previous_text)              # 默认每块上限 512 字节
target = ContextPack.from_content(current_text)

delta = ContextPackDelta.between(base, target)               # 只带差异
wire = delta.to_bytes()                                      # 规范 JSON,可直接发网络

# 接收端:手上只有 base 和 wire
rebuilt = apply_delta(base, ContextPackDelta.from_bytes(wire))
assert rebuilt.content == current_text                      # 与完整 prepare 完全一致

工作原理

分块:以行为锚点

split_content() 把正文按行边界贪心聚合成块,单块不超过 max_chunk_bytes(默认 512)字节;超长单行退化为按字符边界切分。

  • 每块都是合法 UTF-8,单独解码也不会乱码;
  • 切分点永远落在字符边界上;
  • 同一输入永远得到同一组分块(确定性);
  • 因为锚在行边界上,正文只在尾部追加时,前面各块的字节保持不变 —— 这正是前缀能复用的原因。若按固定容量切块,追加内容会改动最后一块并连带打乱边界,收益会明显变差。

摘要与字节数

  • digest = 对 {"chunk_bytes": [...], "schema": "ctxpack.pack.v1"} 的规范 JSON 求 SHA-256,写成 sha256:<hex>;摘要只覆盖正文内容,不覆盖自身。
  • byte_count = 序列化结果的真实字节数,包含该字段自身(用不动点迭代算出),因此拿到包就知道线上要传多少字节。

增量

ContextPackDelta.between(base, target) 求两块之间最长公共分块前缀:

{
  "base_digest":   "sha256:...",
  "kept_chunks":   12,
  "new_chunks":    ["BASE64", "..."],
  "schema":        "ctxpack.delta.v1",
  "target_digest": "sha256:..."
}

接收端 apply_delta(base, delta) 的校验顺序:

  1. delta.base_digest 必须等于 base.digest(防止用错 base);
  2. delta.kept_chunks 不得超过 base 的块数;
  3. 重建后摘要必须等于 delta.target_digest(防止传输损坏或伪造)。

任何一步不通过都抛 ContextPackError,不会返回一个"看起来能用"的结果。

协议速查

| 对象 | 字段 | 说明 | | --- | --- | --- | | Pack | schema | 固定 ctxpack.pack.v1 | | | chunk_bytes | Base64 字符串数组,内存中是 bytes 元组 | | | digest | sha256:<hex>,对 {schema, chunk_bytes} 的规范 JSON 求 SHA-256 | | | total_bytes | 正文原始字节数(不含协议开销) | | | byte_count | 序列化后真实字节数,含该字段自身 | | Delta | schema | 固定 ctxpack.delta.v1 | | | base_digest / target_digest | 增量两端的内容摘要 | | | kept_chunks | 接收端保留 base 前缀的块数(非负整数) | | | new_chunks | 追加的目标后缀块 |

JSON 一律 UTF-8、键排序、分隔符 (',', ':')、无多余空白。完整字段定义与字节级示例见 references/protocol.md。

校验规则与失败处理

ContextPack.from_bytes() / ContextPackDelta.from_bytes() 会拒绝以下输入:

  • 缺少字段或多出字段(字段集合必须精确匹配);
  • schema 不匹配;
  • Base64 非法或不是标准规范编码;
  • 摘要格式错误,或重算摘要与携带摘要不一致(篡改检测);
  • byte_count / total_bytes 与实际不一致;
  • JSON 不是规范形式(键未排序或有多余空白),可用 strict=False 放宽。

什么时候不值得用增量

  • 正文很小(几百字节以内):delta 的两个摘要字段本身就有固定开销,此时直接发完整正文更省;
  • 每一轮正文都被完全重写(例如每轮换检索词导致正文整体重排):公共前缀为空,增量反而比完整正文大;
  • gzip / brotli 已经在链路上压缩过:增量解决的是"重复内容",压缩解决的是"冗余编码",两者可叠加但别指望叠加后还有同等比例的收益。

实测参考(本 Skill 自带 measure 命令,40 轮追加式会议记录,每轮追加一段发言):

| 指标 | 字节数 | 相对原始正文 | | --- | --- | --- | | 原始正文累计 | 114,652 | — | | 每轮都发完整 pack | 160,550 | -40.0% | | 增量协议(首次 pack + 后续 delta) | 24,454 | +78.7% | | gzip(9) 逐轮压缩对照 | 12,735 | +88.9% |

可以看到:增量协议明显优于"每轮重发完整正文",但仍弱于 gzip —— 因为两者解决的问题不同(重复内容 vs 冗余编码)。如果链路已经全局 gzip,直接上 gzip 即可;增量协议的价值在于"客户端已经持有上一轮"这一前提。

参考资料

  • references/protocol.md —— 字节级协议定义、字段表、错误码、兼容性说明
  • references/integration.md —— HTTP / 缓存协商 / 存储选型等接入配方
  • scripts/ctxpack.py —— 参考实现(零依赖,含 selftest)

许可

MIT,见 LICENSE。