chore(compaction): 调整压缩阈值默认值

工程化压缩阈值 threshold_ratio: 0.7 → 0.5(50%)
LLM 压缩阈值 llm_compaction_threshold_ratio: 0.5 → 0.3(30%)

降低触发门槛使压缩更积极介入,减少上下文溢出风险。
同步更新相关注释、日志信息和前端 hint 文案。
This commit is contained in:
oudecheng 2026-08-07 11:53:54 +08:00
parent a9429a5657
commit 79d099a3bc
4 changed files with 17 additions and 17 deletions

View File

@ -781,9 +781,9 @@ pub struct AgentLoop {
/// watch::Receiver::changed() 需要 &mut self但 process() 持有 &self。 /// watch::Receiver::changed() 需要 &mut self但 process() 持有 &self。
cancel_token: Option<tokio::sync::Mutex<tokio::sync::watch::Receiver<()>>>, cancel_token: Option<tokio::sync::Mutex<tokio::sync::watch::Receiver<()>>>,
/// 上下文压缩器(可选)。配置后会在每轮工具调用完成后按双阈值执行压缩: /// 上下文压缩器(可选)。配置后会在每轮工具调用完成后按双阈值执行压缩:
/// 1) 真实 prompt_tokens > 70% context_window → 进入压缩流程 /// 1) 真实 prompt_tokens > 50% context_window → 进入压缩流程
/// 2) 工程化压缩(截断 tool 结果到 100 token仅改内存 /// 2) 工程化压缩(截断 tool 结果到 100 token仅改内存
/// 3) estimate_tokens > 50% context_window → 调 LLM 三段压缩;否则跳过 /// 3) estimate_tokens > 30% context_window → 调 LLM 三段压缩;否则跳过
compressor: Option<Arc<ContextCompressor>>, compressor: Option<Arc<ContextCompressor>>,
} }
@ -795,7 +795,7 @@ pub struct AgentProcessResult {
/// true 表示发生过 LLM 压缩compaction_sink 已被调用), /// true 表示发生过 LLM 压缩compaction_sink 已被调用),
/// 调用方据此决定是否需要刷新 DB 中的会话历史。 /// 调用方据此决定是否需要刷新 DB 中的会话历史。
pub compaction_performed: bool, pub compaction_performed: bool,
/// 本轮 process 是否触发过工程化压缩(70% 阈值命中,截断 tool 结果)。 /// 本轮 process 是否触发过工程化压缩(50% 阈值命中,截断 tool 结果)。
/// 调用方据此跳过兜底 LLM 压缩——因为 in-loop 已判断工程化压缩足够 /// 调用方据此跳过兜底 LLM 压缩——因为 in-loop 已判断工程化压缩足够
/// (或 LLM 压缩失败已降级),兜底基于未压缩历史的判断会不准确。 /// (或 LLM 压缩失败已降级),兜底基于未压缩历史的判断会不准确。
pub engineering_compaction_applied: bool, pub engineering_compaction_applied: bool,
@ -1084,7 +1084,7 @@ impl AgentLoop {
// 跟踪本轮 process 是否触发过 LLM 压缩。 // 跟踪本轮 process 是否触发过 LLM 压缩。
// 工程化压缩(仅截断内存中的 tool 结果)不算 —— 那不影响 DB 状态。 // 工程化压缩(仅截断内存中的 tool 结果)不算 —— 那不影响 DB 状态。
let mut compaction_performed = false; let mut compaction_performed = false;
// 跟踪本轮 process 是否触发过工程化压缩(70% 阈值命中)。 // 跟踪本轮 process 是否触发过工程化压缩(50% 阈值命中)。
// finalize_result 据此跳过兜底 LLM 压缩——因为 in-loop 已判断工程化压缩足够 // finalize_result 据此跳过兜底 LLM 压缩——因为 in-loop 已判断工程化压缩足够
// (或 LLM 压缩失败已降级),兜底基于未压缩历史的判断会不准确。 // (或 LLM 压缩失败已降级),兜底基于未压缩历史的判断会不准确。
let mut engineering_compaction_applied = false; let mut engineering_compaction_applied = false;
@ -1422,7 +1422,7 @@ impl AgentLoop {
// === 两阶段压缩(工具调用完成后) === // === 两阶段压缩(工具调用完成后) ===
// 仅当配置了 compressor 时执行。compaction_sink 控制是否回写 DB。 // 仅当配置了 compressor 时执行。compaction_sink 控制是否回写 DB。
if let Some(compressor) = &self.compressor { if let Some(compressor) = &self.compressor {
// 阶段 1用最近一次 LLM 调用的真实 prompt_tokens 判断 70% 触发阈值 // 阶段 1用最近一次 LLM 调用的真实 prompt_tokens 判断 50% 触发阈值
// 提取 u32Copy避免持有 messages 的不可变借用 // 提取 u32Copy避免持有 messages 的不可变借用
let last_prompt_tokens = messages let last_prompt_tokens = messages
.iter() .iter()
@ -1444,7 +1444,7 @@ impl AgentLoop {
"Engineering compaction applied (tool results truncated)" "Engineering compaction applied (tool results truncated)"
); );
// 阶段 1b重新估算判断是否需要 LLM 压缩(50% 阈值) // 阶段 1b重新估算判断是否需要 LLM 压缩(30% 阈值)
let estimated = let estimated =
crate::agent::context_compressor::estimate_tokens(&messages); crate::agent::context_compressor::estimate_tokens(&messages);
if estimated > compressor.llm_compaction_threshold() { if estimated > compressor.llm_compaction_threshold() {
@ -1452,7 +1452,7 @@ impl AgentLoop {
iteration, iteration,
estimated_tokens = estimated, estimated_tokens = estimated,
llm_threshold = compressor.llm_compaction_threshold(), llm_threshold = compressor.llm_compaction_threshold(),
"LLM compaction triggered (still above 50% after engineering compaction)" "LLM compaction triggered (still above 30% after engineering compaction)"
); );
// LLM 压缩失败时降级为仅工程化压缩,不中断 agent loop // LLM 压缩失败时降级为仅工程化压缩,不中断 agent loop
match compressor match compressor
@ -1493,7 +1493,7 @@ impl AgentLoop {
iteration, iteration,
estimated_tokens = estimated, estimated_tokens = estimated,
llm_threshold = compressor.llm_compaction_threshold(), llm_threshold = compressor.llm_compaction_threshold(),
"Engineering compaction sufficient (under 50%), skipping LLM compaction" "Engineering compaction sufficient (under 30%), skipping LLM compaction"
); );
} }
} }

View File

@ -267,7 +267,7 @@ impl Default for ContextCompressionConfig {
pub struct ContextCompressor { pub struct ContextCompressor {
config: ContextCompressionConfig, config: ContextCompressionConfig,
context_window: usize, context_window: usize,
/// Threshold ratio to trigger compression (70% of context window). /// Threshold ratio to trigger compression (50% of context window).
threshold_ratio: f64, threshold_ratio: f64,
/// LLM 压缩阈值比例(工程化压缩后仍超此比例才调 LLM /// LLM 压缩阈值比例(工程化压缩后仍超此比例才调 LLM
llm_compaction_threshold_ratio: f64, llm_compaction_threshold_ratio: f64,
@ -822,7 +822,7 @@ OLDER SEGMENT (events from earlier in the session):
} }
} }
/// Get the compression threshold in tokens (70% of context window). /// Get the compression threshold in tokens (50% of context window).
pub fn threshold(&self) -> usize { pub fn threshold(&self) -> usize {
(self.context_window as f64 * self.threshold_ratio) as usize (self.context_window as f64 * self.threshold_ratio) as usize
} }
@ -831,12 +831,12 @@ OLDER SEGMENT (events from earlier in the session):
estimate_tokens(history) > self.threshold() estimate_tokens(history) > self.threshold()
} }
/// 触发阈值(70%):用真实 prompt_tokens 判断是否进入压缩流程。 /// 触发阈值(50%):用真实 prompt_tokens 判断是否进入压缩流程。
pub fn should_compress_by_usage(&self, prompt_tokens: u32) -> bool { pub fn should_compress_by_usage(&self, prompt_tokens: u32) -> bool {
(prompt_tokens as usize) > self.threshold() (prompt_tokens as usize) > self.threshold()
} }
/// LLM 压缩阈值(50%):工程化压缩后用 estimate_tokens 判断是否需要 LLM 压缩。 /// LLM 压缩阈值(30%):工程化压缩后用 estimate_tokens 判断是否需要 LLM 压缩。
pub fn llm_compaction_threshold(&self) -> usize { pub fn llm_compaction_threshold(&self) -> usize {
(self.context_window as f64 * self.llm_compaction_threshold_ratio) as usize (self.context_window as f64 * self.llm_compaction_threshold_ratio) as usize
} }
@ -1216,7 +1216,7 @@ mod tests {
#[test] #[test]
fn test_threshold() { fn test_threshold() {
let compressor = ContextCompressor::new(128_000); let compressor = ContextCompressor::new(128_000);
assert_eq!(compressor.threshold(), 89_600); // 70% of 128_000 assert_eq!(compressor.threshold(), 64_000); // 50% of 128_000
} }
#[test] #[test]

View File

@ -99,10 +99,10 @@ pub struct CompactionConfig {
} }
fn default_threshold_ratio() -> f64 { fn default_threshold_ratio() -> f64 {
0.7 0.5
} }
fn default_llm_compaction_threshold_ratio() -> f64 { fn default_llm_compaction_threshold_ratio() -> f64 {
0.5 0.3
} }
fn default_truncate_max_tokens() -> usize { fn default_truncate_max_tokens() -> usize {
100 100

View File

@ -9,7 +9,7 @@ export function CompactionTab({ config, update }: TabProps) {
<SectionCard title="压缩触发阈值"> <SectionCard title="压缩触发阈值">
<Field <Field
label="工程化压缩阈值" label="工程化压缩阈值"
hint="当 LLM 返回的 prompt_tokens 超过 context_window × 此比例时触发压缩。默认 0.770%" hint="当 LLM 返回的 prompt_tokens 超过 context_window × 此比例时触发压缩。默认 0.550%"
> >
<input <input
type="number" type="number"
@ -28,7 +28,7 @@ export function CompactionTab({ config, update }: TabProps) {
</Field> </Field>
<Field <Field
label="LLM 压缩阈值" label="LLM 压缩阈值"
hint="工程化压缩(截断 tool 结果)后,若估算 token 仍超过此比例才调 LLM 压缩。默认 0.550%" hint="工程化压缩(截断 tool 结果)后,若估算 token 仍超过此比例才调 LLM 压缩。默认 0.330%"
> >
<input <input
type="number" type="number"