CMDC.Agent.Compactor (cmdc v0.4.0)

Copy Markdown View Source

上下文压缩引擎 — 对标 DeepAgents SummarizationMiddleware

职责

  • 监控上下文 token 使用量,在超过阈值时自动压缩旧消息
  • 将被驱逐的消息 offload 到文件,保留完整历史
  • ContextOverflow 时作为 fallback 强制压缩
  • 生成摘要消息替换旧历史

Token 计数策略

采用 Provider usage 为主 + 字符估算 fallback

  1. 优先使用 State.token_usage.total_tokens(Provider 返回的真实值)
  2. Fallback:消息文本 byte_size / 4 粗估

触发条件(二选一)

  • :token 模式 — total_tokens >= trigger_tokens(默认 170_000)
  • :fraction 模式 — total_tokens >= context_window * trigger_fraction(默认 0.85)

保留策略

  • :messages 模式 — 保留最近 N 条消息(默认 6)
  • :fraction 模式 — 保留最近占 context_window 的 fraction

使用方式

不直接调用,由 Agent run_turnbefore_request 后自动检查:

case Compactor.maybe_compact(state) do
  {:compacted, state} -> run_turn_with(state)
  {:skip, state} -> run_turn_with(state)
end

或在 ContextOverflow 时强制调用:

{:compacted, state} = Compactor.force_compact(state)

Summary

Types

压缩配置。

消息保留配置。

压缩触发配置。

Functions

读取压缩配置。从 state.config 中获取,缺省使用默认值。

估算当前上下文 token 数量。

从消息列表估算 token 数(字符数 / 4 粗估)。

强制执行压缩(ContextOverflow fallback)。

检查是否需要压缩,需要时自动执行。

仅检查是否达到压缩阈值(不执行压缩)。

Types

compact_opts()

@type compact_opts() :: %{
  trigger: trigger(),
  keep: keep(),
  offload_dir: String.t(),
  summary_prompt: String.t()
}

压缩配置。

keep()

@type keep() :: {:messages, pos_integer()} | {:fraction, float()}

消息保留配置。

trigger()

@type trigger() :: {:tokens, pos_integer()} | {:fraction, float()}

压缩触发配置。

Functions

compact_config(state)

@spec compact_config(CMDC.Agent.State.t()) :: compact_opts()

读取压缩配置。从 state.config 中获取,缺省使用默认值。

支持的 config 键:

  • :compact_trigger{:tokens, n}{:fraction, f}
  • :compact_keep{:messages, n}{:fraction, f}
  • :compact_offload_dir — offload 文件目录前缀
  • :compact_summary_prompt — 摘要生成提示词

estimate_tokens(state)

@spec estimate_tokens(CMDC.Agent.State.t()) :: non_neg_integer()

估算当前上下文 token 数量。

优先使用 Provider 返回的 usage,fallback 到字符估算。

estimate_tokens_from_messages(messages)

@spec estimate_tokens_from_messages([CMDC.Message.t()]) :: non_neg_integer()

从消息列表估算 token 数(字符数 / 4 粗估)。

force_compact(state)

@spec force_compact(CMDC.Agent.State.t()) ::
  {:compacted, CMDC.Agent.State.t()} | {:skip, CMDC.Agent.State.t()}

强制执行压缩(ContextOverflow fallback)。

忽略阈值检查,直接压缩。如果消息太少无法分割,返回原 state。

maybe_compact(state)

@spec maybe_compact(CMDC.Agent.State.t()) ::
  {:compacted, CMDC.Agent.State.t()} | {:skip, CMDC.Agent.State.t()}

检查是否需要压缩,需要时自动执行。

返回:

  • {:compacted, state} — 已执行压缩,state 中消息已替换
  • {:skip, state} — 未达到阈值,不需要压缩

should_compact?(state)

@spec should_compact?(CMDC.Agent.State.t()) :: boolean()

仅检查是否达到压缩阈值(不执行压缩)。

供 Agent 层在 :before_compact Plugin Pipeline 之前判断是否触发。