204 lines
6.0 KiB
Python
204 lines
6.0 KiB
Python
"""智能路由模块
|
||
|
||
评估任务复杂度,决定处理方式
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
from typing import Any
|
||
|
||
from minenasai.core import get_logger
|
||
from minenasai.gateway.protocol import TaskComplexity
|
||
|
||
logger = get_logger(__name__)
|
||
|
||
# 复杂任务关键词
|
||
COMPLEX_KEYWORDS = [
|
||
# 编程相关
|
||
"实现", "开发", "编写", "重构", "优化", "调试", "修复bug",
|
||
"创建项目", "搭建", "部署", "迁移",
|
||
# 文件操作
|
||
"批量", "遍历", "递归", "所有文件",
|
||
# 分析
|
||
"分析代码", "审查", "review", "架构设计",
|
||
]
|
||
|
||
# 简单任务关键词
|
||
SIMPLE_KEYWORDS = [
|
||
# 查询
|
||
"是什么", "什么是", "解释", "说明", "介绍",
|
||
"几点", "天气", "日期", "时间",
|
||
# 状态
|
||
"状态", "运行情况", "磁盘", "内存", "CPU",
|
||
# 简单操作
|
||
"打开", "关闭", "启动", "停止",
|
||
]
|
||
|
||
# 需要工具的关键词
|
||
TOOL_KEYWORDS = [
|
||
"查看", "读取", "列出", "搜索", "查找",
|
||
"执行", "运行", "计算",
|
||
"文件", "目录", "路径",
|
||
]
|
||
|
||
# 命令前缀
|
||
COMMAND_PREFIXES = {
|
||
"/快速": TaskComplexity.SIMPLE,
|
||
"/简单": TaskComplexity.SIMPLE,
|
||
"/深度": TaskComplexity.COMPLEX,
|
||
"/复杂": TaskComplexity.COMPLEX,
|
||
"/tui": TaskComplexity.COMPLEX,
|
||
"/TUI": TaskComplexity.COMPLEX,
|
||
}
|
||
|
||
|
||
class SmartRouter:
|
||
"""智能路由器
|
||
|
||
基于启发式规则评估任务复杂度
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
simple_max_length: int = 100,
|
||
complex_min_length: int = 500,
|
||
) -> None:
|
||
"""初始化路由器
|
||
|
||
Args:
|
||
simple_max_length: 简单任务的最大长度
|
||
complex_min_length: 复杂任务的最小长度
|
||
"""
|
||
self.simple_max_length = simple_max_length
|
||
self.complex_min_length = complex_min_length
|
||
|
||
def evaluate(self, content: str, metadata: dict[str, Any] | None = None) -> dict[str, Any]:
|
||
"""评估任务复杂度
|
||
|
||
Args:
|
||
content: 用户输入内容
|
||
metadata: 额外元数据(如历史上下文)
|
||
|
||
Returns:
|
||
评估结果,包含 complexity, confidence, reason, suggested_handler
|
||
"""
|
||
content = content.strip()
|
||
metadata = metadata or {}
|
||
|
||
# 检查命令前缀覆盖
|
||
for prefix, complexity in COMMAND_PREFIXES.items():
|
||
if content.startswith(prefix):
|
||
return {
|
||
"complexity": complexity,
|
||
"confidence": 1.0,
|
||
"reason": f"用户指定 {prefix}",
|
||
"suggested_handler": self._get_handler(complexity),
|
||
"content": content[len(prefix):].strip(),
|
||
}
|
||
|
||
# 计算各项得分
|
||
scores = {
|
||
"simple": 0.0,
|
||
"medium": 0.0,
|
||
"complex": 0.0,
|
||
}
|
||
|
||
# 长度评估
|
||
length = len(content)
|
||
if length <= self.simple_max_length:
|
||
scores["simple"] += 0.3
|
||
elif length >= self.complex_min_length:
|
||
scores["complex"] += 0.3
|
||
else:
|
||
scores["medium"] += 0.2
|
||
|
||
# 关键词评估
|
||
content_lower = content.lower()
|
||
|
||
simple_matches = sum(1 for kw in SIMPLE_KEYWORDS if kw in content_lower)
|
||
complex_matches = sum(1 for kw in COMPLEX_KEYWORDS if kw in content_lower)
|
||
tool_matches = sum(1 for kw in TOOL_KEYWORDS if kw in content_lower)
|
||
|
||
if simple_matches > 0:
|
||
scores["simple"] += min(0.4, simple_matches * 0.15)
|
||
if complex_matches > 0:
|
||
scores["complex"] += min(0.5, complex_matches * 0.2)
|
||
if tool_matches > 0:
|
||
scores["medium"] += min(0.3, tool_matches * 0.1)
|
||
|
||
# 问号检测(通常是简单问题)
|
||
if content.endswith("?") or content.endswith("?"):
|
||
scores["simple"] += 0.1
|
||
|
||
# 代码块检测
|
||
if "```" in content or re.search(r"def\s+\w+|class\s+\w+|function\s+\w+", content):
|
||
scores["complex"] += 0.3
|
||
|
||
# 多步骤检测
|
||
if re.search(r"\d+\.\s|第[一二三四五六七八九十]+步|首先.*然后|step\s*\d+", content_lower):
|
||
scores["complex"] += 0.2
|
||
|
||
# 确定复杂度
|
||
max_score = max(scores.values())
|
||
if scores["complex"] == max_score and scores["complex"] >= 0.3:
|
||
complexity = TaskComplexity.COMPLEX
|
||
elif scores["simple"] == max_score and scores["simple"] >= 0.3:
|
||
complexity = TaskComplexity.SIMPLE
|
||
else:
|
||
complexity = TaskComplexity.MEDIUM
|
||
|
||
# 计算置信度
|
||
total = sum(scores.values())
|
||
confidence = max_score / total if total > 0 else 0.5
|
||
|
||
# 生成原因
|
||
reasons = []
|
||
if length <= self.simple_max_length:
|
||
reasons.append("短文本")
|
||
elif length >= self.complex_min_length:
|
||
reasons.append("长文本")
|
||
if simple_matches:
|
||
reasons.append(f"简单关键词x{simple_matches}")
|
||
if complex_matches:
|
||
reasons.append(f"复杂关键词x{complex_matches}")
|
||
if tool_matches:
|
||
reasons.append(f"工具关键词x{tool_matches}")
|
||
|
||
return {
|
||
"complexity": complexity,
|
||
"confidence": round(confidence, 2),
|
||
"reason": ", ".join(reasons) if reasons else "综合评估",
|
||
"suggested_handler": self._get_handler(complexity),
|
||
"scores": scores,
|
||
"content": content,
|
||
}
|
||
|
||
def _get_handler(self, complexity: TaskComplexity) -> str:
|
||
"""获取建议的处理器
|
||
|
||
Args:
|
||
complexity: 任务复杂度
|
||
|
||
Returns:
|
||
处理器名称
|
||
"""
|
||
handlers = {
|
||
TaskComplexity.SIMPLE: "quick_response",
|
||
TaskComplexity.MEDIUM: "agent_execute",
|
||
TaskComplexity.COMPLEX: "webtui_redirect",
|
||
}
|
||
return handlers.get(complexity, "agent_execute")
|
||
|
||
|
||
# 全局路由器实例
|
||
_router: SmartRouter | None = None
|
||
|
||
|
||
def get_router() -> SmartRouter:
|
||
"""获取全局路由器实例"""
|
||
global _router
|
||
if _router is None:
|
||
_router = SmartRouter()
|
||
return _router
|