优化: aichat效率批(save无变化捷径/断路器尾窗/system缓存指纹/会话列表刷新收敛) + 新增 LLM prompt caching(cache_control开关默认关/system稳定段易变段分离治缓存命中率) + 销账
This commit is contained in:
@@ -263,6 +263,15 @@ pub const CIRCUIT_BREAKER_THRESHOLD: u32 = 3;
|
||||
/// 单轮并行失败爆发,又足够长以容忍偶发抖动。
|
||||
pub const CIRCUIT_BREAKER_WINDOW: usize = 20;
|
||||
|
||||
/// BE2(AC-EFF-R2-1):断路器/探索熔断读消息的尾部窗口大小。
|
||||
///
|
||||
/// count_recent_failures / check_stall_breaker 只关心最近若干条消息(末尾工具结果 + 其前驱
|
||||
/// assistant tool_calls / 最近几轮工具签名),用 ContextManager::recent_messages 只 clone 尾部
|
||||
/// 切片,避免 all_messages_clone 每轮全量深克隆(长对话每轮 O(n) clone 浪费)。
|
||||
/// 40:同轮工具回填通常 1~5 条,富余覆盖其定义调用与最近多轮;超窗工具映射退化为
|
||||
/// unknown_tool(仅失败分组更粗)/ 签名样本截断(仍达 STALL_BREAKER_SAMPLE_SIZE=12),不误熔断。
|
||||
pub const BREAKER_TAIL_N: usize = 40;
|
||||
|
||||
/// L1 断路器总开关(默认 true)。false → 跳过断路器检查,降级为纯 max_iterations
|
||||
/// 旧行为(排障/对比/临时关闭用)。机制优先 prompt 说教,每改配开关 + 兜底(关降级旧行为)。
|
||||
pub const CIRCUIT_BREAKER_ENABLED: bool = true;
|
||||
@@ -598,6 +607,25 @@ async fn emit_retry_attempt(
|
||||
tokio::time::sleep(delay).await;
|
||||
}
|
||||
|
||||
/// 把 Anthropic prompt caching 易变尾段追加到请求消息流**末尾**(一条 user 消息)。
|
||||
///
|
||||
/// 多场景命中率设计要点:
|
||||
/// - **放消息流末尾而非 system**:任何位于 system 之后的消息级缓存断点(含未来「多轮对话缓存」
|
||||
/// 在末条 user 上打断点)都在易变段之前——易变内容(日期/清单/augmentation/知识)每日/每请求
|
||||
/// 变化时,只影响其自身及之后(无),不失效已缓存的 system/历史前缀。若放首条 user,跨天日期
|
||||
/// 变化会失效其后全部历史缓存。
|
||||
/// - **用 user 角色而非 system**:anthropic_compat::convert_request 会把 System-role 消息抽到
|
||||
/// 顶层 system(受 cache_control 缓存),易变段若为 system 会随请求变化失效整段 system 缓存。
|
||||
/// 必须 user 承载,convert_request 对连续 user 做 merge_consecutive_users,追加安全。
|
||||
/// - **不持久化**:仅注入本轮请求的 messages clone,per_conv.messages 不含易变段 → 每轮重建
|
||||
/// 恰好一条,无重复。
|
||||
fn merge_volatile_tail(messages: &mut Vec<ChatMessage>, tail: &str) {
|
||||
if tail.is_empty() {
|
||||
return;
|
||||
}
|
||||
messages.push(ChatMessage::user(tail));
|
||||
}
|
||||
|
||||
/// Agentic 循环:流式接收 → 工具执行 → 结果回传 LLM → 循环
|
||||
///
|
||||
/// 退出条件:
|
||||
@@ -611,6 +639,9 @@ pub(crate) async fn run_agentic_loop(
|
||||
app_handle: AppHandle,
|
||||
provider_config: AiProviderRecord,
|
||||
system_prompt: String,
|
||||
// Anthropic prompt caching 易变尾段(缓存模式:日期/清单/augmentation/知识,追加到消息流末尾;
|
||||
// None = 开关关,保持现状行为)。
|
||||
volatile_tail: Option<String>,
|
||||
conv_id: String,
|
||||
knowledge_config: crate::state::KnowledgeConfig,
|
||||
llm_concurrency: LlmConcurrency,
|
||||
@@ -1523,6 +1554,11 @@ pub(crate) async fn run_agentic_loop(
|
||||
}
|
||||
let mut msgs = vec![ChatMessage::system(&system_prompt)];
|
||||
msgs.extend(history_msgs);
|
||||
// Anthropic prompt caching:把易变尾段(日期/清单/augmentation/知识)追加到消息流末尾。
|
||||
// 放末尾而非 system:易变内容不进缓存前缀,每日/每请求变化不失效 system 缓存(跨天仍命中)。
|
||||
if let Some(tail) = &volatile_tail {
|
||||
merge_volatile_tail(&mut msgs, tail);
|
||||
}
|
||||
msgs
|
||||
};
|
||||
|
||||
@@ -2188,10 +2224,13 @@ async fn count_recent_failures(
|
||||
conv_id: &str,
|
||||
fail_window: &mut std::collections::VecDeque<String>,
|
||||
) -> (u32, String) {
|
||||
// BE2(AC-EFF-R2-1):只克隆尾部 BREAKER_TAIL_N 条,避免 all_messages_clone 全量深克隆
|
||||
// (长对话每轮 O(n) clone 浪费)。窗口覆盖末尾 Tool 结果与其前驱 assistant tool_calls
|
||||
// (同轮工具回填通常 1~5 条,40 足富余;超窗工具映射退化为 unknown_tool,仅失败分组更粗,不误熔断)。
|
||||
let messages = {
|
||||
let session = session_arc.lock().await;
|
||||
match session.conv_read(conv_id) {
|
||||
Some(conv) => conv.messages.all_messages_clone(),
|
||||
Some(conv) => conv.messages.recent_messages(BREAKER_TAIL_N),
|
||||
None => Vec::new(),
|
||||
}
|
||||
};
|
||||
@@ -2424,8 +2463,10 @@ async fn check_stall_breaker(
|
||||
// arguments 非合法 JSON 时 to_string 兜底(签名仍可比,只是兜底全量)。
|
||||
let signatures: Vec<String> = {
|
||||
let session = session_arc.lock().await;
|
||||
// BE2(AC-EFF-R2-1):只取尾部 BREAKER_TAIL_N 条(签名抽取只需最近几轮工具调用,
|
||||
// 全量 clone 纯浪费;STALL_BREAKER_SAMPLE_SIZE=12 ≪ 40,样本充足)。
|
||||
let messages = match session.conv_read(conv_id) {
|
||||
Some(conv) => conv.messages.all_messages_clone(),
|
||||
Some(conv) => conv.messages.recent_messages(BREAKER_TAIL_N),
|
||||
None => Vec::new(),
|
||||
};
|
||||
let mut sigs: Vec<String> = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user