优化: 缓存命中字段解析与提示词前缀稳定化
- openai 兼容口径补解析嵌套 cached_tokens - cache 显示区分无数据与真零,估算轮不渲染 - 轨迹展开折叠空过程记录行降噪 - token 统计行恒完整可见不截断 - openai_compat 纳入 system 稳定易变拆分 - 系统警示与主题标记改尾部注入不位移前缀 - 工具结果视图压缩按入库时刻冻结 - 会话内工具集冻结仅增不减 - anthropic 缓存补消息级断点,设置页加开关 - 补 intent 测试对 Agent domain 覆盖
This commit is contained in:
@@ -680,22 +680,66 @@ pub(crate) async fn run_agentic_loop(
|
||||
// 分离:即使将来 PLANNING_ENABLED 翻 true,plan_hint 内部 PLAN_HINT_ENABLED 关闭时
|
||||
// filter_tool_defs_planned 仍退扁平(双层开关,任一关闭均退旧行为)。
|
||||
let tool_defs: Vec<df_ai::provider::ToolDefinition> = if pure_greeting {
|
||||
Vec::new() // 纯问候 → 空工具集(tools=None,强制纯文本回复)
|
||||
} else if conf >= INTENT_CONF_THRESHOLD {
|
||||
let filtered = if df_ai::planner::PLANNING_ENABLED {
|
||||
// Phase 1:plan_hint 编排排序。intent_label 供 plan_hint 备用(当前规则纯关键词驱动)。
|
||||
filter_tool_defs_planned(&all_defs, &intent, intent.as_str(), &user_text)
|
||||
} else {
|
||||
// 旧行为:intent 收敛扁平子集(零行为变更,flag 默认关走此路)。
|
||||
filter_tool_defs(&all_defs, &intent)
|
||||
};
|
||||
if filtered.len() < 3 {
|
||||
all_defs // 兜底:过滤<3(漂移/误收敛)回全量
|
||||
} else {
|
||||
filtered
|
||||
}
|
||||
Vec::new() // 纯问候 → 空工具集(tools=None,强制纯文本回复;仅作用当轮,不写冻结集)
|
||||
} else {
|
||||
all_defs // 低置信 fallback 全量
|
||||
let computed: Vec<df_ai::provider::ToolDefinition> = if conf >= INTENT_CONF_THRESHOLD {
|
||||
let filtered = if df_ai::planner::PLANNING_ENABLED {
|
||||
// Phase 1:plan_hint 编排排序。intent_label 供 plan_hint 备用(当前规则纯关键词驱动)。
|
||||
filter_tool_defs_planned(&all_defs, &intent, intent.as_str(), &user_text)
|
||||
} else {
|
||||
// 旧行为:intent 收敛扁平子集(零行为变更,flag 默认关走此路)。
|
||||
filter_tool_defs(&all_defs, &intent)
|
||||
};
|
||||
if filtered.len() < 3 {
|
||||
all_defs.clone() // 兜底:过滤<3(漂移/误收敛)回全量
|
||||
} else {
|
||||
filtered
|
||||
}
|
||||
} else {
|
||||
all_defs.clone() // 低置信 fallback 全量
|
||||
};
|
||||
// 跨轮工具集冻结(前缀稳定):tools 数组在请求中位于 system 之后、消息之前,
|
||||
// 每轮按末条 user 消息重新裁剪会让数组跨轮变化 → 前缀字节断,自动前缀缓存
|
||||
// (DeepSeek/GLM/Qwen)与 Anthropic 显式缓存全部失效。改按会话冻结:首次裁剪结果
|
||||
// 入冻结集,后续轮只增不减(新意图带来的工具并入,已并入的不移除)。
|
||||
// 顺序稳定:冻结集是 all_defs 的子集过滤,all_defs 顺序恒定 → 数组字节只增不改位。
|
||||
let mut frozen_names = {
|
||||
let session = session_arc.lock().await;
|
||||
session
|
||||
.conv_read(&conv_id)
|
||||
.and_then(|c| c.frozen_tool_names.clone())
|
||||
};
|
||||
let mut changed = false;
|
||||
match frozen_names.as_mut() {
|
||||
Some(prev) => {
|
||||
for d in &computed {
|
||||
if !prev.contains(&d.function.name) {
|
||||
prev.push(d.function.name.clone());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if !computed.is_empty() {
|
||||
frozen_names = Some(computed.iter().map(|d| d.function.name.clone()).collect());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
let mut session = session_arc.lock().await;
|
||||
// contains_key 守卫防 conv() 惰性建(循环入口已桥接,正常恒存在,防御性保留)。
|
||||
if session.per_conv.contains_key(&conv_id) {
|
||||
session.conv(&conv_id).frozen_tool_names = frozen_names.clone();
|
||||
}
|
||||
}
|
||||
match &frozen_names {
|
||||
Some(names) => all_defs
|
||||
.into_iter()
|
||||
.filter(|d| names.contains(&d.function.name))
|
||||
.collect(),
|
||||
None => computed,
|
||||
}
|
||||
};
|
||||
tracing::info!(
|
||||
conv_id = %conv_id,
|
||||
@@ -1294,10 +1338,12 @@ async fn prepare_round_inputs(
|
||||
"── 用户已切换话题(从「{}」到「{}」),请以新话题为准 ──",
|
||||
old_topic, new_topic
|
||||
);
|
||||
// 尾部追加而非 insert_at(0):头部插入位移整条前缀破坏 prompt 缓存,
|
||||
// 语义「提示当前轮」放末尾同样生效(紧邻本轮内容,LLM 必见)。
|
||||
let mut session = session_arc.lock().await;
|
||||
if session.per_conv.contains_key(conv_id) {
|
||||
let conv = session.conv(conv_id);
|
||||
conv.messages.insert_at(0, ChatMessage::system(&marker_text));
|
||||
conv.messages.push(ChatMessage::system(&marker_text));
|
||||
tracing::info!(
|
||||
conv_id = %conv_id,
|
||||
iteration,
|
||||
@@ -1429,15 +1475,26 @@ async fn prepare_round_inputs(
|
||||
// 故即使摘要有误/过度压缩,下次 build_for_request 仍从 DB 全量重建,可自愈。
|
||||
//
|
||||
// TOOL_RESULT_COMPRESS_ENABLED=false(常量开关)→ 跳过(原样送 LLM,排障/对比用)。
|
||||
// 压缩决策经 per_conv.tool_view_decisions 冻结:首次判定后沿用,不再随阈值翻转
|
||||
// (防同一条历史跨轮在全文/摘要间翻转致前缀断)。写回仅在 conv 存活时做(防惰性建)。
|
||||
let messages: Vec<ChatMessage> = if TOOL_RESULT_COMPRESS_ENABLED {
|
||||
let history_tokens_snapshot: u32 = {
|
||||
let (history_tokens_snapshot, mut view_decisions) = {
|
||||
let session = session_arc.lock().await;
|
||||
session
|
||||
.conv_read(conv_id)
|
||||
.map(|c| c.messages.history_tokens())
|
||||
.unwrap_or(0)
|
||||
let conv = session.conv_read(conv_id);
|
||||
(
|
||||
conv.map(|c| c.messages.history_tokens()).unwrap_or(0),
|
||||
conv.map(|c| c.tool_view_decisions.clone()).unwrap_or_default(),
|
||||
)
|
||||
};
|
||||
summarize_tool_results(messages, history_tokens_snapshot, conv_id, iteration)
|
||||
let messages =
|
||||
summarize_tool_results(messages, history_tokens_snapshot, &mut view_decisions, conv_id, iteration);
|
||||
if !view_decisions.is_empty() {
|
||||
let mut session = session_arc.lock().await;
|
||||
if session.per_conv.contains_key(conv_id) {
|
||||
session.conv(conv_id).tool_view_decisions = view_decisions;
|
||||
}
|
||||
}
|
||||
messages
|
||||
} else {
|
||||
messages
|
||||
};
|
||||
@@ -1767,7 +1824,7 @@ async fn heartbeat_loop(
|
||||
/// 注入目标验证续轮 nudge(强制续轮,非软提示)。
|
||||
///
|
||||
/// 文案随 goal_verify_rounds 递进:第 1 次请验证,第 2 次(将达上限)明确最后机会。
|
||||
/// 复用 insert_stall_warning 的 insert_at(0, system) 范式 + fetch_goal_summary 拼目标。
|
||||
/// 复用 insert_stall_warning 的尾部追加 system 范式 + fetch_goal_summary 拼目标。
|
||||
async fn insert_goal_verify_nudge(
|
||||
session_arc: &Arc<Mutex<AiSession>>,
|
||||
conv_id: &str,
|
||||
@@ -1789,7 +1846,9 @@ async fn insert_goal_verify_nudge(
|
||||
let mut session = session_arc.lock().await;
|
||||
if session.per_conv.contains_key(conv_id) {
|
||||
let conv = session.conv(conv_id);
|
||||
conv.messages.insert_at(0, ChatMessage::system(&nudge_text));
|
||||
// 尾部追加而非 insert_at(0):nudge 紧邻本轮内容语义不变,且不位移既有前缀字节
|
||||
// (insert_at(0) 会把整条历史后移,自动前缀缓存/Anthropic 显式缓存全失效)。
|
||||
conv.messages.push(ChatMessage::system(&nudge_text));
|
||||
tracing::info!(
|
||||
conv_id = %conv_id, iteration, verify_rounds,
|
||||
"[GOAL-VERIFY] 目标未验证,注入续轮 nudge(强制续轮)"
|
||||
|
||||
Reference in New Issue
Block a user