上下文压缩

会话逼近模型上下文窗口时,compaction 插件先做确定性的 tool-result 剪裁,不够再用一次模型摘要把较早的 surface 换成一条 checkpoint。 对应实现:src/Tether.Compaction/;对照 dsh compaction-basic 与 compaction-tool-result-pruner(锚点 ddefc45f)。

三个入口

入口触发阈值失败时
步间压力agent/pre-step,auto 开启时(缺省开)超过压力阈值才动告警后照常进入本 step;同一路由目标的配置失败只告警一次
溢出恢复agent/request-error 收到 CONTEXT_WINDOW_EXCEEDED,auto 开启时绕过阈值,强制一次有用的缩减告警并保留原请求错误;取消优先
/compact人工命令,只在 Agent idle 时可用绕过阈值命令报错

auto: false 同时卸下前两个监听器,只留 /compact。告警走 contained internal/error(dsh ctx.logger.warn 的对位通道),宿主的 lifecycle supervisor 把它记成一条 degraded incident。

步间压力

每个 step 进入前,插件按会话最近一次 durable request/header 的 provider/model 评估压力:

  1. 没有路由面(会话从未发过请求)就跳过。
  2. 窗口 W 取自 ILlmModelCatalog。目录不知道该模型的窗口时抛 TargetPressureConfigException:告警一次,不静默退回某个绝对阈值。
  3. 估算低于阈值就结束。
  4. 超过阈值时先落确定性剪裁并重新计量;剪裁已经足够就不调用摘要模型。
  5. 仍超阈值才摘要,保留尾部按逐节点定价从末尾回积到保留预算;每次摘要后重新计量,最多 1 + compactionRetries 次,之后仍超阈值即失败(告警后继续 turn)。

阈值与保留预算的公式见下文登记的偏离:Tether 已按 v0.22 目标扣除输出预留与 headroom。

溢出恢复

provider 确认上下文溢出时,监听器先剪裁、再强制一次摘要(保留 retainedTailNodes 个尾部节点),只要有一个 durable surface 替换落地就让同一请求重试——单独的剪裁也算。其余规则:

  • 恢复本身抛错时,已落地的剪裁仍作为重试依据;没有任何进展就告警,并把原请求错误交给下游 listener。恢复异常不会逃出 agent/request-error waterfall。
  • 请求已取消时不重试,即使剪裁已经落地。
  • 会话没有 durable 路由面、或失败码不是 CONTEXT_WINDOW_EXCEEDED 时直接交给下游。
  • 预算 overflowRetriesPerRequest(缺省 1,0 关闭溢出恢复)按请求序列计:一次成功响应(Append 形态的 assistant/message)或 Agent 离开 running 都开启新序列。compaction 自己以 Replace 落地的 summary 不算响应。

什么算溢出由适配器决定:DeepSeek 适配器与通用 OpenAI / Anthropic wire 都用 LlmErrorCodes.IsContextWindowExceeded 判定错误信封(code、type、message)。只是偶然提到 “context” 的 400(字段校验、context_management 之类)仍是 INVALID_REQUEST,不会触发无意义的压缩。

确定性剪裁

pruner 只处理当前 surface 上结果为字符串且超过 toolResultPruneThresholdChars 的 tool/result:保留 head/tail 各至多 toolResultPruneKeepChars 个字符,中段换成带计数的省略标记,然后以 Replace(N,N) 落地。

  • 已被替换出 surface 的节点(包括先前剪裁掉的原始结果)不再入选,所以重复剪裁只处理新出现的超限结果。
  • head/tail 边界落在代理对中间时向内收缩,不产生孤立代理项。
  • 选项校验要求 2 × keep + 标记 ≤ threshold,剪裁产物因此不会再次超限。
  • 替换只改 result 值:失败标记与 durable error 原样保留,失败结果剪裁后仍显示为失败。

事务与锁

一次摘要是一个带 log-only 锁的事务:

  1. compaction/start 经 AppendIfAsync 与锁判定原子提交;锁被占用时本次调用 no-op。
  2. 选出保持 tool call/result 配平的 surface 段,调用摘要模型,以一条 assistant/message 的 Replace 落地 checkpoint。
  3. compaction/end 闭锁。start 之后的任何失败(包括取消)都恰好追加一次 end,取消记为 failed;只有 end 本身追加失败才会留下未闭合的 start。

锁有效的判定是:compaction/start、compaction/end、session/end-seed 三者中最新的一个是 start。resume 与 fork 构造时追加的 session/end-seed 标出新的会话生命周期,崩溃遗留的 start 因此不会永久阻塞后续压缩。

进程内的剪裁与摘要按 exact Session 串行,不同 Session 互不阻塞;跨实例、跨进程的互斥由 durable 锁裁决。

summary 请求发往会话自己的路由——最近一次 request/header 的 provider(tether:provider)与 model——而不是默认 route;compaction/start 记录这对路由。从未路由过的会话才落到 client 默认。

配置

base.yaml 的 compaction 行接受 CompactionOptions:

键缺省含义
autotrue安装步间压力与溢出恢复两个自动监听器
pressureRatio0.8压力阈值占窗口的比例,(0, 1]
headroomTokens65536输出预留之外的额外压力余量
retainRatio0.16逐字保留的近期对话占消息预算的比例,必须小于 pressureRatio
summaryMaxTokens跟随 headroomTokenssummary 请求的输出上限
compactionRetries1压力路径首次摘要后的额外摘要次数
overflowRetriesPerRequest1每个请求序列的溢出恢复重试次数,0 关闭
retainedTailNodes4溢出恢复与 /compact 保留的尾部节点数
toolResultPruneThresholdChars20000单个 tool 结果超过该字符数才剪裁
toolResultPruneKeepChars4000剪裁保留的 head/tail 字符数

与 dsh 锚点的偏离

按对齐制度登记,每条写明 dsh 语义、Tether 映射、差异后果与验收证据。

压力预算与 summary 输出上限

  • dsh 语义(锚点 ddefc45f):threshold = floor(W × thresholdRatio),retain = floor(W × retainRatio),summary maxTokens 缺省 8192,没有 headroomTokens。
  • Tether 映射:#365 提前实现 v0.22 目标 c36a83ff(dsh-v0.1.7-alpha.1)的公式。输出预留 O 取 request/header 的 maxOutputTokens,缺席时取 provider 目录的模型输出上限,再缺席为 0;threshold = floor(min(W × pressureRatio, W − O − headroomTokens)),retain = floor((W − O) × retainRatio);summary 上限缺省等于 headroomTokens(65536);W − O ≤ 0 或 W − O − headroomTokens ≤ 0 时 fail-fast。
  • 差异后果:输出预留大的路由更早触发压力;窗口小的路由在锚点公式下可用的配置,可能因 headroom 被 TargetPressureConfigException 拒绝;summary 允许更长的输出,而 summary 请求发往会话模型,上限高于该模型输出上限时由 provider 拒绝(v0.22 目标同样如此)。
  • 验收证据:tests/Tether.Compaction.Tests/CompactionServiceTests.cs 的 Output_reservation_pulls_the_pressure_threshold_earlier、Catalog_output_cap_is_the_fallback_output_reservation、Insufficient_message_or_pressure_budget_fails_fast_with_target_key、Ratio_parameters_reproduce_the_absolute_96000_trigger、Summary_cap_defaults_to_headroom_and_rejects_zero。
  • 重评条件:锚点迁移到 c36a83ff 时本条转为 implemented 并从本节删除。
在 GitHub 上编辑此页