优化: 弱模型工具行为治理(项目/任务清单补id + 缓存命中警告 + read_symbol 提示)

This commit is contained in:
lxy
2026-08-08 18:11:21 +08:00
parent 3dfa043bb6
commit 6aa334fc9b
5 changed files with 100 additions and 45 deletions
+12 -6
View File
@@ -67,7 +67,7 @@ pub(crate) use finalize::audit_finalize;
// cache(audit/cache.rs):高危工具去重缓存 + 只读工具缓存。
// 第三批从本文件抽离,行为零变更。
mod cache;
pub(super) use cache::{find_cached_readonly_result, pending_placeholder_for};
pub(super) use cache::{cache_hit_warning, find_cached_readonly_result, pending_placeholder_for};
// data_change(audit/data_change.rs):AR-11 数据变更联动刷新。
// 第四批从本文件抽离,行为零变更。pub(crate) use 保持 emit_data_changed 对 crate 内可见
@@ -586,13 +586,17 @@ pub(crate) async fn process_tool_calls(
let mut low_risk_uncached: Vec<(ToolCallDraft, serde_json::Value, RiskLevel)> = Vec::with_capacity(low_risk.len());
for (draft, args, risk_level) in low_risk {
let cached = find_cached_readonly_result(session_arc, conv_id, &audit_repo, &draft.name, &args).await;
if let Some(cached_content) = cached {
if let Some((cached_content, hit_count)) = cached {
// 缓存命中:直接 push tool_result + 审计(decided_by=cache_hit 标记缓存来源),
// 不走真执行 + 不重emit Started/Completed(避免误导前端工具又执行了一次)。
// AC-1 根治:弱模型不知道结果来自缓存,仍死循环重调同参工具。此处给回填的
// tool_result 前置「重复调用拦截」警告头(机制化提示,LLM 能看到 tool_result),
// 命中次数递增威慑,告知勿再重复调用相同参数的工具。
let warned_content = format!("{}{}", cache_hit_warning(&draft.name, hit_count), cached_content);
// emit Completed 携带缓存结果供前端折叠卡片展示(与 find_cached_high_risk_result 一致)。
let ev = AiChatEvent::AiToolCallCompleted {
id: draft.id.clone(),
result: serde_json::Value::String(cached_content.clone()),
result: serde_json::Value::String(warned_content.clone()),
conversation_id: Some(conv_id.to_string()),
};
let _ = app_handle.emit("ai-chat-event", ev.clone());
@@ -600,18 +604,20 @@ pub(crate) async fn process_tool_calls(
// 短 lock 段:push tool_result(纯写,无 await)
{
let mut session = session_arc.lock().await;
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, &cached_content));
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, &warned_content));
}
audit_tool_call(
&audit_repo, conv_id, &draft.id, &draft.name, &draft.args,
"completed", risk_level, Some(cached_content), Some("cache_hit"),
"completed", risk_level, Some(warned_content), Some("cache_hit"),
current_message_id,
).await;
tracing::info!(
conv_id = %conv_id,
tool = %draft.name,
tc_id = %draft.id,
"[ai] 只读工具缓存命中,跳过真执行(治 LLM 死循环重调)"
hit_count,
"[ai] 只读工具缓存命中(第 {} 次),已加警告头回填,跳过真执行(治 LLM 死循环重调)",
hit_count
);
} else {
low_risk_uncached.push((draft, args, risk_level));