diff --git a/src/ai/client.py b/src/ai/client.py index 5e4be00..44d2cc0 100644 --- a/src/ai/client.py +++ b/src/ai/client.py @@ -493,6 +493,11 @@ class AIClient: return None return min(limit, 5000) + @staticmethod + def _compact_identifier(text: str) -> str: + """Compact identifier for fuzzy matching (e.g. humanizer_zh -> humanizerzh).""" + return re.sub(r"[^a-z0-9]+", "", (text or "").lower()) + @staticmethod def _extract_forced_tool_name( user_message: str, available_tool_names: List[str] @@ -500,7 +505,16 @@ class AIClient: if not user_message or not available_tool_names: return None - triggers = ["调用工具", "使用工具", "只调用", "务必调用", "必须调用", "tool"] + triggers = [ + "调用工具", + "使用工具", + "只调用", + "务必调用", + "必须调用", + "调用", + "使用", + "tool", + ] if not any(trigger in user_message for trigger in triggers): return None @@ -537,6 +551,38 @@ class AIClient: if len(prefix_tools) == 1: return prefix_tools[0] + # 模糊匹配:支持省略下划线/点号的写法(如 humanizerzh)。 + compact_message = AIClient._compact_identifier(user_message) + if compact_message: + compact_full_matches = [] + for tool_name in available_tool_names: + compact_tool_name = AIClient._compact_identifier(tool_name) + if compact_tool_name and compact_tool_name in compact_message: + compact_full_matches.append(tool_name) + + if len(compact_full_matches) == 1: + return compact_full_matches[0] + if len(compact_full_matches) > 1: + return None + + compact_prefix_map: Dict[str, List[str]] = {} + for tool_name in available_tool_names: + prefix = tool_name.split(".", 1)[0] + compact_prefix = AIClient._compact_identifier(prefix) + if not compact_prefix: + continue + compact_prefix_map.setdefault(compact_prefix, []).append(tool_name) + + compact_prefix_matches = [ + compact_prefix + for compact_prefix in compact_prefix_map + if compact_prefix in compact_message + ] + if len(compact_prefix_matches) == 1: + matched_tools = compact_prefix_map[compact_prefix_matches[0]] + if len(matched_tools) == 1: + return matched_tools[0] + return None def set_personality(self, personality_name: str) -> bool: diff --git a/tests/test_ai_client_forced_tool.py b/tests/test_ai_client_forced_tool.py index 07ad623..cb2ac85 100644 --- a/tests/test_ai_client_forced_tool.py +++ b/tests/test_ai_client_forced_tool.py @@ -27,6 +27,18 @@ def test_extract_forced_tool_name_unique_prefix(): assert forced == "humanizer_zh.read_skill_doc" +def test_extract_forced_tool_name_compact_prefix_without_underscore(): + tools = [ + "humanizer_zh.read_skill_doc", + "skills_creator.create_skill", + ] + message = "调用humanizerzh人性化处理以下文本" + + forced = AIClient._extract_forced_tool_name(message, tools) + + assert forced == "humanizer_zh.read_skill_doc" + + def test_extract_forced_tool_name_ambiguous_prefix_returns_none(): tools = [ "skills_creator.create_skill",