现象
一个连续运行 21 天的 hub 会话(glm-5.3,limit=1M,v1.14.x),Tier-2 蒸馏 21 天只发生 3 次,压缩锚点(compress anchor)常驻上下文 ~45K(57 个活跃块),是会话上下文底部单调上升(35K→252K)的主要成分之一。
对 session state(storage/plugin/acp/<session>.json,417 个块:414 T1 + 3 T2,360 个已失活 T1 中 157 个是被其他 T1 消费的、203 个被 3 个 T2 消费)做时间轴重建,发现两类问题:
问题 1:T2 触发被系统性推迟("应该触发而迟迟不触发")
tier-1 活跃摘要质量共 4 次越过 50K 阈值,其中两次 T2 滞后 12~22 小时才触发,期间 tier-1 质量持续 ≥50K:
| 越过 50K |
T2 实际触发 |
滞后 |
期间发生的 T1 compress |
| 08-20 01:40 |
08-20 23:51 |
22h |
23 次 |
| 08-29 15:08 |
08-30 03:31 |
12h |
25 次 |
根因在 lib/messages/inject/inject.ts:
- :126-127 — 每次 compress(任意 tier)都重置 T2 cadence 水位线:
state.nudges.lastTier2NudgeTokens = currentTokens
state.nudges.lastTier3NudgeTokens = currentTokens
(该重置的本意是避免"蒸馏→基线清空→立刻再触发"的循环,但它对普通 T1 compress 同样生效。)
- T2 触发要求
currentTokens - lastTier2NudgeTokens >= growthFloor(1M 模型 = max(5K, 0.45×50K) = 22.5K)。每次 T1 compress 把水位线抬到当前值,上下文必须再净涨 22.5K,T2 的闸门才打开;而在压缩活跃的会话里,涨到 50K 时 T1 nudge 先触发并再次压缩、再次重置——T2 只能在"两次 T1 compress 之间恰好净涨 22.5K"的缝隙里溜进来。
:387 的 if (suffixMessage && !shouldInject) 在 T1 nudge 触发的轮次完全跳过 T2/T3 检查,进一步压缩了触发窗口。
问题 2:阈值随模型容量缩放,与锚点的绝对上下文成本失配
resolveAdaptiveNudgeGrowth = min(50K, max(6K, limit×5%))(context-compress-algorithms,chunk-BZYW3CH5.js)。T2 触发条件 tierUsage.tier1Tokens >= nudgeGrowthTokens(inject.ts:395-396)直接复用该值:
- 1M 模型 → 阈值 50K:需要 ~55 个活跃锚点(均重 ~0.9K)、上下文已经烧掉 ~50K 才允许回收;
- 200K 模型 → 阈值 10K:~13 个锚点即蒸馏。
锚点占用的上下文是绝对成本,不随模型容量缩放;结果是大上下文模型的蒸馏周期反而被拉长到 67 天(实测:08-23 蒸馏后,tier-1 质量在 4649K 徘徊了近 6 天才凑够 50K)。另外 T1 compress 互噬老锚点会把 tier-1 质量反复剃回阈值以下,让"T2 攒质量"更慢——两层回收在竞争同一个质量池。
建议修复
- T2 触发与 nudgeGrowthTokens 解耦:改用绝对阈值(如 15~20K)或活跃锚点计数(≥12 个即蒸馏),或双阈值取先到;
- :126 的水位线重置只针对真实 T2/T3 蒸馏生效,普通 T1 compress 不重置
lastTier2NudgeTokens(或重置为 currentTokens - growthFloor/2,保留半窗);
- T1 nudge 触发的轮次不整体跳过 tier 检查——可在 T1 nudge 文本后附带 T2 trigger 指令;
- (可选)被 T2 消费后的锚点 summary 参数缩略为指针,decompress 仍可回源,进一步降低锚点常驻成本。
数据来源
21 天 hub 会话 state 文件时间轴重建(块创建/消费事件模拟,终态与文件 ground truth 一致:54 个活跃 T1 = 36,189 tok);两次饥饿窗口内 T1 compress 创建次数直接取自块的 createdAt。自 08-30 最后一次蒸馏以来 tier-1 峰值仅 36.2K(<50K),按规则未漏触发——本文报告的是阈值达到后的 12~22h 触发延迟,以及阈值/重置机制造成的系统性蒸馏饥饿。
现象
一个连续运行 21 天的 hub 会话(glm-5.3,limit=1M,v1.14.x),Tier-2 蒸馏 21 天只发生 3 次,压缩锚点(compress anchor)常驻上下文 ~45K(57 个活跃块),是会话上下文底部单调上升(35K→252K)的主要成分之一。
对 session state(
storage/plugin/acp/<session>.json,417 个块:414 T1 + 3 T2,360 个已失活 T1 中 157 个是被其他 T1 消费的、203 个被 3 个 T2 消费)做时间轴重建,发现两类问题:问题 1:T2 触发被系统性推迟("应该触发而迟迟不触发")
tier-1 活跃摘要质量共 4 次越过 50K 阈值,其中两次 T2 滞后 12~22 小时才触发,期间 tier-1 质量持续 ≥50K:
根因在
lib/messages/inject/inject.ts:currentTokens - lastTier2NudgeTokens >= growthFloor(1M 模型 = max(5K, 0.45×50K) = 22.5K)。每次 T1 compress 把水位线抬到当前值,上下文必须再净涨 22.5K,T2 的闸门才打开;而在压缩活跃的会话里,涨到 50K 时 T1 nudge 先触发并再次压缩、再次重置——T2 只能在"两次 T1 compress 之间恰好净涨 22.5K"的缝隙里溜进来。:387的if (suffixMessage && !shouldInject)在 T1 nudge 触发的轮次完全跳过 T2/T3 检查,进一步压缩了触发窗口。问题 2:阈值随模型容量缩放,与锚点的绝对上下文成本失配
resolveAdaptiveNudgeGrowth = min(50K, max(6K, limit×5%))(context-compress-algorithms,chunk-BZYW3CH5.js)。T2 触发条件tierUsage.tier1Tokens >= nudgeGrowthTokens(inject.ts:395-396)直接复用该值:锚点占用的上下文是绝对成本,不随模型容量缩放;结果是大上下文模型的蒸馏周期反而被拉长到 6
7 天(实测:08-23 蒸馏后,tier-1 质量在 4649K 徘徊了近 6 天才凑够 50K)。另外 T1 compress 互噬老锚点会把 tier-1 质量反复剃回阈值以下,让"T2 攒质量"更慢——两层回收在竞争同一个质量池。建议修复
lastTier2NudgeTokens(或重置为currentTokens - growthFloor/2,保留半窗);数据来源
21 天 hub 会话 state 文件时间轴重建(块创建/消费事件模拟,终态与文件 ground truth 一致:54 个活跃 T1 = 36,189 tok);两次饥饿窗口内 T1 compress 创建次数直接取自块的
createdAt。自 08-30 最后一次蒸馏以来 tier-1 峰值仅 36.2K(<50K),按规则未漏触发——本文报告的是阈值达到后的 12~22h 触发延迟,以及阈值/重置机制造成的系统性蒸馏饥饿。