优化上下文窗口
当你需要控制运行时如何管理会话历史,以避免超过模型上下文上限时,使用本页。
- 已添加
awaken - 已有一个
AgentSpec
ContextWindowPolicy
Section titled “ContextWindowPolicy”每个 agent 都可以配置 ContextWindowPolicy:
use awaken::ContextWindowPolicy;
let policy = ContextWindowPolicy { max_context_tokens: 200_000, max_output_tokens: 16_384, min_recent_messages: 10, enable_prompt_cache: true, autocompact_threshold: Some(100_000), compaction_mode: ContextCompactionMode::KeepRecentRawSuffix, compaction_raw_suffix_messages: 2,};| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
max_context_tokens | usize | 200_000 | 模型上下文总窗口(token 数) |
max_output_tokens | usize | 16_384 | 为模型输出预留的 token |
min_recent_messages | usize | 10 | 始终保留的最近消息数,即使超出预算 |
enable_prompt_cache | bool | true | 是否启用 prompt cache |
autocompact_threshold | Option<usize> | None | 达到该 token 数时触发自动压缩,None 表示禁用 |
compaction_mode | ContextCompactionMode | KeepRecentRawSuffix | 自动压缩策略 |
compaction_raw_suffix_messages | usize | 2 | 后缀压缩模式下保留的原始消息数 |
截断(Truncation)
Section titled “截断(Truncation)”当消息总量超过预算时,运行时会自动丢弃最旧消息。预算大致为:
available = max_context_tokens - max_output_tokens - tool_schema_tokens截断时会保留什么
Section titled “截断时会保留什么”- 所有 system messages
- 至少
min_recent_messages条最近消息 - 成对的 tool call / tool result
- 不会留下悬挂的 tool calls
Artifact 压缩
Section titled “Artifact 压缩”在真正截断前,过大的 tool result 会先被压缩成 preview,以减少 token 占用。system / user / assistant 普通消息不会做这种压缩。
压缩(Compaction)
Section titled “压缩(Compaction)”压缩不会简单丢消息,而是把更早的历史总结成一条摘要消息。
启用自动压缩
Section titled “启用自动压缩”let policy = ContextWindowPolicy { autocompact_threshold: Some(100_000), compaction_mode: ContextCompactionMode::KeepRecentRawSuffix, compaction_raw_suffix_messages: 4, ..Default::default()};ContextCompactionMode
Section titled “ContextCompactionMode”KeepRecentRawSuffix:保留最近 N 条原始消息,其余压缩CompactToSafeFrontier:压缩到安全边界为止
安全边界的含义是:不会把某条 tool call 和它对应的结果拆开。
CompactionConfig
Section titled “CompactionConfig”压缩子系统通过 CompactionConfig 配置:
use awaken::CompactionConfig;
let config = CompactionConfig { execution_mode: CompactionExecutionMode::Background, summarizer_system_prompt: "You are a conversation summarizer. \ Preserve all key facts, decisions, tool results, and action items. \ Be concise but complete.".into(), summarizer_user_prompt: "Update the cumulative conversation summary.\n\n\ <existing-summary>\n{previous_summary}\n</existing-summary>\n\n\ <new-conversation>\n{messages}\n</new-conversation>".into(), summary_max_tokens: Some(1024), summary_model: Some("claude-3-haiku".into()), min_savings_ratio: 0.3, raw_retention: CompactionRawRetention::PreserveDurable,};| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
mode | CompactionExecutionMode | background | background 异步执行摘要;off 即使设置阈值也不自动压缩 |
summarizer_system_prompt | String | 内置摘要 prompt | 摘要 LLM 的 system prompt |
summarizer_user_prompt | String | 累积摘要 prompt | 摘要用户 prompt 模板;{messages} 会被替换为对话记录,{previous_summary} 会在已有摘要时替换为上一次累积摘要 |
summary_max_tokens | Option<u32> | None | 摘要响应的最大 token 数 |
summary_model | Option<String> | None | 同一已解析 provider/executor 上的上游模型覆盖。若该值匹配 registry model id,则必须与 agent 模型属于同一 provider,并会在解析时规范化为该模型的 upstream name |
min_savings_ratio | f64 | 0.3 | 接受一次压缩所需的最低 token 节省比例(0.0-1.0) |
raw_retention | CompactionRawRetention | preserve_durable | 压缩只改写运行时 prompt 窗口,原始用户消息仍保留在线程/运行历史中 |
DefaultSummarizer
Section titled “DefaultSummarizer”内置 DefaultSummarizer 会读取 CompactionConfig,并支持“在已有摘要上继续增量总结”。初次压缩和增量压缩都会使用同一个 summarizer_user_prompt 模板;如果希望 prompt 带上已有累积摘要,请在模板中包含 {previous_summary}。
压缩不会阻塞推理 phase。条件满足时,maybe_spawn_compaction 会先确定边
界、把 CompactionInFlight 标记写进 CompactionStateKey,再通过 agent 的
BackgroundTaskManager 把摘要 LLM 调用 spawn 到后台。完成事件经由 owner inbox
返回,由 try_consume_compaction_event 消费;如果边界依然存在,
apply_summary 会把摘要 swap 到消息日志里。
实践上需要知道两件事:
- 同一 agent 上的压缩是单飞(single-flight)的。
CompactionState::is_compacting为真时,下一轮推理不会再规划新的压缩,直接以未压缩的历史继续;swap 完成后 下一轮才会基于新的摘要前缀继续。 - config-driven 本地运行在设置了
autocompact_threshold且mode为background时,会自动挂接内置 summarizer 和每次运行的BackgroundTaskManager。直接构造ResolvedAgent的自定义 runtime 需要自行提供 两者;缺少任意一个,maybe_spawn_compaction会 no-op,runtime 退回到 truncation。 - 最新用户消息始终以原文保留在 prompt 窗口。更早的用户消息可以进入摘要,但 durable thread/run history 会保留原文。
KeepRecentRawSuffix保留尾部compaction_raw_suffix_messages条原始消息。CompactToSafeFrontier会滚动到最新安全边界,并遵守min_recent_messages。 两种模式都不会切断 tool call/result 对。
压缩结果会被保存成带 <conversation-summary> 标签的内部 system message。重新加载时,历史中较早的已摘要部分不会再被重新放回上下文窗口。
如果 LLM 因 MaxTokens 截断,而且已经产生部分文本或生成到一半的 tool call 参数不完整,运行时可以自动注入 continuation prompt 并重试,直到达到最大重试次数。
crates/awaken-runtime-contract/src/contract/inference.rscrates/awaken-runtime/src/context/transform/mod.rscrates/awaken-runtime/src/context/transform/compaction.rscrates/awaken-runtime/src/context/compaction.rscrates/awaken-runtime/src/context/summarizer.rscrates/awaken-runtime/src/context/plugin.rscrates/awaken-runtime/src/context/truncation.rs