mcpField
S
smart-compaction

smart-compaction

github.com/openduoAgent 工作流1089 次安装4 天前更新
代码仓库

关于 smart-compaction

用于配置 duoduo 会话空闲压缩的技能。它指导 Agent 根据实测会话统计、后端缓存行为和安全规则调整阈值。

主要功能

  1. 01按空闲时间和上下文大小触发
  2. 02按会话或类型设置参数
  3. 03提供压缩统计与校准指导
  4. 04依据实测数据分析盈亏平衡
  5. 05避免无效压缩的保护规则

适用场景

  1. 01降低会话空闲后的上下文成本
  2. 02调整会话或运行时类型的压缩阈值
  3. 03为需保留上下文的对话关闭压缩

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/openduo/duoduo --skill smart-compaction

安装后在 Claude Code 中输入/smart-compaction确认已加载。

详细介绍

智能压缩 — 空闲时的自动压缩管理

这是什么(一段话)

频道会话会不断累积上下文;空闲时间超过提示词缓存 TTL 后,下一条消息会以更高价格将整个上下文重新写入缓存。守护进程内置了一个确定性扫描器:当一个 LIVE 会话的空闲时间达到 auto_compact_idle_minutes,且上下文超过 auto_compact_min_context_tokens 时,它会静默运行 /compact。此功能在所有地方都默认关闭;你(Agent)是策略层,负责按对话启用并调整它。Claude 会在实时流式子进程中就地运行 /compact。Grok 使用相同的参数,但执行 _x.ai/compact_conversation(静默执行,不向频道发送确认)。Pi 也使用相同的两个参数,而且 Pi 的压缩采用双层机制:Pi 自带的原生阈值压缩保持开启(继承用户的 Pi 设置),同时运行 duoduo 的空闲自动压缩——两层按设计共存。Codex 仍是唯一不支持的运行时。Grok 压缩不会返回 Token 数,因此在仅使用 Grok 的会话中,熔断器和压缩通知都不会自动校准——不要把 Grok 首次空闲压缩当作校准测量值。Pi 也一样:其压缩结果只会报告压缩前的大小(压缩后 Pi 暂时无法测量新的常驻上下文),因此在仅使用 Pi 的会话中,熔断器也不会自动校准。不过,最坏情况下 Pi 的成本更低——如果会话没有值得压缩的内容,它会免费返回无操作结果,而不是付费执行无收益的压缩。

参数(按实例、按类型)

duoduo session config <session|alias> get            # merged view + per-key source + measured stats
duoduo session config <session|alias> set auto_compact_idle_minutes=50 auto_compact_min_context_tokens=100000
duoduo session config <session|alias> unset auto_compact_idle_minutes   # back to kind default
duoduo session config --kind <kind> set ...          # kind-wide default (ONLY when the user explicitly says "kind"/"所有会话")
  • 建议的初始值(适用于订阅制/缓存 TTL 为 1 小时的后端): idle_minutes=50(在 1 小时缓存 TTL 内触发 → 压缩读取成本降低到 1/10),min_context_tokens=100000(约为实测压缩后下限的 2 倍)。
  • 关闭 = set auto_compact_idle_minutes=0。这会保留已校准的阈值——开关和校准值是两个独立字段(恒温器规则:关闭开关不会忘记设定值)。如需从头开始,请显式执行 unset。
  • 作用范围原则:默认仅对当前实例进行操作。只有用户明确扩大作用范围时,才使用 --kind。
  • set/unset 会在会话的下一次 drain 或下次 60 秒扫描时生效——无需重启。get 不会修改任何内容。

查看统计数据——切勿自行心算内核已预先计算的数据

每次压缩后,session config get 都会输出会话的 compact_stats(无论来源是手动、自动还是模型自身的响应式压缩):

字段含义
post_total实测的 S_total:压缩无法低于的下限(提示链 + 摘要)
history_post压缩后的历史大小——这是摘要的输出成本(公式中的 O)
p_estimate固定的提示链开销(压缩无法回收这部分)
suggested_min_context_tokens内核计算的 2 × post_total——默认重新调整目标
g_gt1h_since_prev_compact上两次压缩之间超过 1 小时空档后的返回次数——实测的 G
g_5m1h_since_prev_compact中等空档后的返回次数——在缓存 TTL 为 5 分钟的后端上也会变为冷启动
idle_ms自动触发时会话已空闲的时长(手动触发时不存在)
threshold_at_fire自动触发时生效的 min_context_tokens(手动/响应式压缩时不存在)

精简通知(内核 → 你)

在启用了智能压缩的会话中(且仅限此类会话——未启用该功能的会话不会注入通知),每次压缩后的第一个实际轮次都会附带一个 <smart-compact-notice> 块:

  • 数据行 — compacted <ts>: ctx <pre>→<post>, history <pre>→<post>。 post 是测得的下限;基础数据无需查询统计信息。
  • 不匹配行(仅在校准不准时出现)— threshold <T> < suggested <S> — re-calibrate via smart-compaction skill。这是重新调校信号:立即应用防护规则 4。这也表示内核 FUSE 现已启用:当阈值小于或等于测得的下限时,自动压缩会拒绝再次触发(在此阈值下触发不可能低于阈值——只会形成纯粹无收益的循环),因此重新调校才能重新启用自动压缩。
  • 转录文件行 — 磁盘上完整的压缩前转录文件路径。压缩会总结你的上下文,但不会删除任何内容:如需找回丢失的近期细节,请启动一个成本较低的子 Agent(haiku/sonnet)搜索该文件——不要把整个文件读入刚精简过的上下文。记忆/档案比实时聊天滞后数小时;它们属于长期记忆层,而非近期回忆层。

盈亏平衡算法(仅用于处理算术无法判断的情况)

C* = (5·O + 1.25·G·S) / (1.25·G − w)
  • S ← compact_stats.post_total(本次会话的实测值——绝不凭空假设)
  • O ← 总结输出的大小,即压缩摘要本身消耗的 token 数:compact_stats.history_post(压缩后的历史记录——通常约为 4K)。不要使用历史记录的缩减量(history_pre − history_post,可能约为 50K);那是被移除的内容,不是摘要的开销,使用它会使 C* 增大一个数量级。
  • G ← g_gt1h_since_prev_compact(如果后端 TTL 属于 5 分钟级别,也加上 g_5m1h)。这些值由内核根据账本测量——读取它们。
  • w ← 触发温度:如果后端缓存 TTL 超过 idle_minutes,则为 0.1(订阅 = 1 小时 TTL);否则为 1.0(按量计费 API 默认值、Bedrock、Vertex)

适用范围:仅当 1.25·G > w 时,该公式才有效。当 1.25·G ≤ w 时,分母为零或负数——每个周期内的冷返回次数太少,无法让压缩在任何上下文大小下都实现成本回收;此区域由防护规则 2 管理(提高阈值或禁用),而非由 C* 管理。

上下文高于 C* 的会话可以从压缩中获益;低于 C* 时,压缩会增加成本。TTL 是你必须了解或询问的后端事实——内核有意不提供此信息。

G 是反馈变量,而非固定输入。 你设置的阈值决定会话压缩的频率,进而决定每个压缩周期的长度,并改变周期内冷返回的次数——也就是你下次将测量的 G。每次重新调校都应视为循环中的一步:设置 → 观察下一次 compact_stats(新的 G)→ 重新评估。不要根据单个周期的 G 过度拟合;应观察几次压缩后的趋势。

防护规则(硬性规则)

  1. 绝不能将阈值设为低于实测的 post_total 的 1.2 倍——低于物理下限时,压缩只会造成无意义的反复操作和保真度损失。
  2. 按量计费/TTL 较短的后端:只有在实测 G ≥ 2 时才保留 100000。对于 G≈1 的会话(一个繁重任务,隔夜后返回,次日再次膨胀),冷启动盈亏平衡点约为 305K——应将阈值调高到该数值,或禁用压缩。
  3. 重新调优 = 先执行,再告知:应用更改后,用一行话告知所有者更改了什么以及原因(例如:“已把这个会话的压缩阈值从 100K 调到 76K — 实测压缩地板是 38K”)。绝不能默不作声,也绝不能长篇大论。
  4. 首次自动压缩就是校准(Claude 会写入 compact_stats):收到首次压缩通知时,读取 suggested_min_context_tokens,并据此重新调优该实例。新类型无需预先校准。Grok 不会发出该通知,因此在 grok 上跳过此步骤。Pi 也不会发出该通知(其压缩结果没有压缩后的总量)——在 pi 上也跳过此步骤,仅依据盈亏平衡公式调整阈值。
  5. 当所有者表示某个对话很珍贵(“这个会话的上下文别动”)时,将该实例的 auto_compact_idle_minutes=0,并确认已设置。
  6. 任何压缩之后,如果不确定之前的某个细节:对于近期的具体信息,让一个低成本子 Agent 搜索通知中提供的转录文件路径;对于长期知识,查阅记忆/档案。绝不能只根据摘要进行还原。
  7. 安装某个类型的通道后,再配置该类型。 对尚未安装通道的类型使用 --kind <kind> 会创建该类型的配置文件;之后安装通道时会跳过其默认配置(因为该文件已存在),导致通道启动时没有随附的默认配置。除非有意进行全类型推广,否则优先使用实例级配置(config <session>)。

兼容无缓存后端

如果会话运行在完全不支持提示词缓存的端点上,每一轮都会按整个上下文的完整输入价格计费——压缩在这种情况下更有用,而非更无用。使用相同的旋钮和公式,令 w=1,并将缓存溢价按普通输入成本计算。

评论

支持 Markdown