fix(compaction): 自动压缩触发线单位对齐、pin 上限与紧急恢复迟滞 - #36
Closed
h3c-hexin wants to merge 2 commits into
Closed
Conversation
added 2 commits
September 1, 2026 09:58
长会话诊断出三层叠加缺陷,压缩退化为「每步触发、每次只前删几条最旧 消息」的锯齿(351→348 条、~247K→~244K token 反复越线): 1. 单位错配:should_compact 用原始口径估算(chars/4)与 token_threshold 比较,而阈值派生自保守口径预算(percent × input_budget_ceiling,×3/2 缩放)。默认 75%/80% 触发线折算后高于预检预算线(需 <2/3 才可达), 自动压缩在紧急通道之前数学上不可达,全部溢出都走 preflight 紧急 恢复;TUI 页脚的 will_auto_compact 却按保守口径对比,向用户预告了 实际不会发生的自动压缩。修复:pinned/summarizable 双侧估算统一 ×3/2 保守缩放,与阈值、预检、页脚同一单位。 2. pin 溢出:working-set 路径提及 + error/patch 标记 + 外部 pin 在 debug 会话里几乎 pin 住全部消息,summarize_indices 为空使 compact_messages 原样返回,LLM 摘要整体空转,只剩前删一条路。 修复:大会话(原始估算 ≥16K token)pin 份额上限 1/2,超限从最旧 开始释放;尾部与保留的 user query 永不逐出,逐出 call 连带其 result,避免保留孤儿 result。 3. 无迟滞:trim_oldest_messages_to_budget 删到刚好低于预算即停,下一 步新增输出立刻再次越线,每步一次紧急压缩。修复:紧急 trim 目标 降到预算的 9/10(emergency_trim_budget)。 Signed-off-by: pinvou3-dev <dev@pinvou3.local>
Warn 与 Stop 之间护栏恰好返回一次 None(repeats_after_warn_to_stop 先计 1 再计 2),该步对 no_progress_warning_started_at 的重置把告警 时钟清掉,Stop 时 get_or_insert_with 重新取当前时间,elapsed 恒报 0s。改为 Warn 覆盖写入时钟、去掉 None 步重置,Stop 汇报真实的 Warn→Stop 时长;Warn 覆盖同时保证新告警回合不沿用旧回合的时钟。 Signed-off-by: pinvou3-dev <dev@pinvou3.local>
Author
|
错误目标:此修复属上游原生缺陷(相对 Hmbown/CodeWhale v0.9.5 逐字节验证),按 fork 政策应从最新 upstream main 提 Hmbown/CodeWhale,由后续上游 release 同步回流 fork。将关闭并在上游重提。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
长会话(~351 条消息、保守估算 ~247K token、预算 ~245K)观察到压缩退化为锯齿:每步都触发
Emergency context compaction started (preflight token budget),每次只前删 3 条最旧消息(351 → 348, ~247,159 → ~244,269 tokens, trimmed 3 oldest)就宣布恢复,下一步立刻再次越线。同时全程从未出现Auto context compaction started。另有伴随症状:no-progress 停止消息恒报elapsed 0s。根因
三层叠加缺陷 + 一个显示 bug:
should_compact用原始口径(chars/4)的估算与token_threshold比较,而阈值派生自保守口径预算(percent × input_budget_ceiling,即 ×3/2 缩放体系,与预检estimate_input_tokens_conservative同单位)。默认 75%/80% 触发线折算后高于预检预算线(需 <2/3 才可能先于预检),自动压缩数学上永远不可达,全部溢出都走 100% 线的紧急通道。TUI 页脚will_auto_compact却按保守口径对比,向用户预告了实际不会发生的自动压缩。should_pin_message(working-set 路径提及 +error:/failed/panic/diff 标记)+ 外部working_set.pinned_message_indices在 debug 会话里几乎 pin 住全部消息 →summarize_indices为空 →compact_messages原样返回(完成文案无 retries、无 API pass failed 与此吻合),唯一剩下的手段就是无脑前删。trim_oldest_messages_to_budget删到刚好低于预算即停,下一步新增输出(assistant + tool call + tool result,数千 token)立刻再次越线。每轮还静默吃掉最旧历史并使供应商 KV prefix cache 全量失效(观察到 42 次执行累计输入 4.4M token)。None(repeats_after_warn_to_stop先计 1 再计 2),该步把no_progress_warning_started_at重置为 None,Stop 时get_or_insert_with(Instant::now)现取时间 → 恒报 0s。修复
should_compact:pinned/summarizable 双侧估算统一 ×3/2 保守缩放,与阈值、预检、页脚同一单位;token_threshold字段补充单位契约文档。派生值、route_budget、UI 均不动(它们本来就是保守口径,改消费端影响面最小且不改变既有用户可配置行为)。plan_compaction:新增cap_pinned_token_share—— 大会话(原始估算 ≥16K token)pin 份额上限 1/2,超限从最旧开始释放;keep-recent 尾部与保留的 user query 永不逐出;逐出 call 连带其 pinned result(保留孤儿 result 会被 OpenAI 系后端拒绝)。小会话低于门槛完全不受影响,保留原启发式行为。emergency_trim_budget),一次恢复买到数步余量。测试
新增 7 个回归测试:
should_compact_threshold_compares_in_conservative_units:阈值落在两口径之间必须触发(旧实现永不触发)。should_compact_fires_below_the_preflight_budget_for_route:按 Kimi 路由真实预算/阈值构造「高于 80% 触发线、仍低于预算上限」的会话,断言自动压缩先于预检触发(原 bug 的端到端复现)。plan_compaction_caps_pinned_token_share_for_large_sessions/plan_compaction_keeps_small_sessions_pin_heuristics/pinned_token_cap_evicts_call_and_result_pairs_together(含配对连带逐出与防双重记账)。emergency_trim_budget_leaves_a_hysteresis_margin。验证与披露
cargo test -p codewhale-tui --lib -- compaction:: core::engine:: core::route_budget:582 通过。cargo test --workspace --all-features --locked:除 5 个与本次无关的既有失败(config 命令 4 个 + skill 卸载 1 个)外全绿;这 5 个在干净基线上以相同方式失败(本地环境相关),已逐一对照验证。question_mark、collapsible_match),stash 对照确认非本次引入,未在 PR 中顺手修改。cargo fmt --all -- --check干净。影响面
CompactionConfig::default()的 800K 兜底阈值语义变为保守口径(直接构造配置的路径触发提前 ~1/3),route 派生路径与用户可配置项(auto_compact_threshold_percent)不受影响。