修复: 上下文流式与工具签名域清债
- tool_signature 归一化补参,合法换参不再误触探索熔断 - SSE 超限截头改对齐事件边界保尾,流不再永久破损 - content_filter 纳入终态判定,无 DONE 流也收敛 - sanitize 占位补头前缀短路只吞 orphan 的盲区消除 - intent 关键词加词边界,history 不再误判 - 恢复重放后重置话题锚点,URL 图 token 地板不被稀释
This commit is contained in:
@@ -420,7 +420,7 @@ fn best_in_group(message: &str, group: &[IntentGroup]) -> Option<(Intent, f32)>
|
||||
for rule in cand.rules.iter() {
|
||||
// 英文关键词用小写匹配;中文不受 to_lowercase 影响(no-op)。
|
||||
let needle = rule.kw.to_lowercase();
|
||||
if lower.contains(&needle) {
|
||||
if kw_matches(&lower, &needle) {
|
||||
score += rule.weight;
|
||||
matched = true;
|
||||
}
|
||||
@@ -437,6 +437,26 @@ fn best_in_group(message: &str, group: &[IntentGroup]) -> Option<(Intent, f32)>
|
||||
best
|
||||
}
|
||||
|
||||
/// 关键词命中判定:ASCII 关键词要求两侧词边界(词字符 = ASCII 字母数字 + 下划线,与正则
|
||||
/// `\b` 语义一致),防子串误判——"history" 不命中 "hi"(误判 Chat)、"rapid" 不命中
|
||||
/// "api"(误判 Http)。非 ASCII(中文)关键词保持子串语义:中文无词边界概念,直接 contains。
|
||||
fn kw_matches(haystack: &str, needle: &str) -> bool {
|
||||
if !needle.is_ascii() {
|
||||
return haystack.contains(needle);
|
||||
}
|
||||
let is_word_char = |c: char| c.is_ascii_alphanumeric() || c == '_';
|
||||
haystack.match_indices(needle).any(|(pos, m)| {
|
||||
haystack[..pos]
|
||||
.chars()
|
||||
.next_back()
|
||||
.map_or(true, |c| !is_word_char(c))
|
||||
&& haystack[pos + m.len()..]
|
||||
.chars()
|
||||
.next()
|
||||
.map_or(true, |c| !is_word_char(c))
|
||||
})
|
||||
}
|
||||
|
||||
// ---- Intent → 工具子集映射 --------------------------------------------------
|
||||
|
||||
/// 按 Intent 返回工具名子集。
|
||||
@@ -854,6 +874,38 @@ mod tests {
|
||||
assert_eq!(i, Intent::Http);
|
||||
}
|
||||
|
||||
// --- ASCII 关键词词边界(防子串误判) ---
|
||||
|
||||
#[test]
|
||||
fn word_boundary_history_not_chat() {
|
||||
// "history" 内嵌 "hi" 不再判 Chat(无其他关键词 → Unknown)
|
||||
let (i, c) = IntentRecognizer::recognize("show me the history");
|
||||
assert_eq!(i, Intent::Unknown, "history 不应命中 hi, 实际 conf={}", c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn word_boundary_rapid_not_http() {
|
||||
// "rapid" 内嵌 "api" 不再判 Http
|
||||
let (i, c) = IntentRecognizer::recognize("rapid growth");
|
||||
assert_eq!(i, Intent::Unknown, "rapid 不应命中 api, 实际 conf={}", c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standalone_english_keywords_still_hit() {
|
||||
// 词边界不误伤独立词命中
|
||||
let (i, _) = IntentRecognizer::recognize("call the api");
|
||||
assert_eq!(i, Intent::Http);
|
||||
let (i, _) = IntentRecognizer::recognize("hi");
|
||||
assert_eq!(i, Intent::Chat);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cjk_adjacent_ascii_keyword_still_hits() {
|
||||
// 中文紧邻 ASCII 关键词:非 ASCII 字符算边界,不破坏中文场景命中
|
||||
let (i, _) = IntentRecognizer::recognize("调用这个api");
|
||||
assert_eq!(i, Intent::Http);
|
||||
}
|
||||
|
||||
// --- tool_subset_for ---
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user