大改,未验证

This commit is contained in:
2026-03-20 16:50:26 +08:00
parent c7ee292c4f
commit e14e3ee7a5
36 changed files with 1419 additions and 4805 deletions

12
.env
View File

@@ -48,7 +48,7 @@ LLM_API_KEY=sk-Gce85QLROESeOWf3icd2mQnYHOrmMYojwVPQ0AubMjGQ5ZE2
LLM_BASE_URL=https://gemini.jeason.online/v1
# The specific model to use, e.g., "qwen-plus-latest", "gpt-3.5-turbo", "claude-3-sonnet-20240229"
LLM_MODEL=gemini-2.5-flash
LLM_MODEL=mimo-v2-flash
# The temperature for the model's responses (0.0 to 2.0).
LLM_TEMPERATURE=0.7
@@ -123,3 +123,13 @@ REDIS_DEFAULT_TTL=3600
# Enable Redis cache (set to False to disable caching)
REDIS_ENABLED=True
# ============================================================================
# EMBEDDING CONFIGURATION (知识库向量检索 - 本地模型)
# ============================================================================
# 暂时禁用,等有合适的 embedding API 或服务器资源时再启用
EMBEDDING_ENABLED=False
EMBEDDING_MODEL=BAAI/bge-small-zh-v1.5
EMBEDDING_DIMENSION=512
EMBEDDING_SIMILARITY_THRESHOLD=0.5

View File

@@ -124,3 +124,26 @@ REDIS_DEFAULT_TTL=3600
# Enable Redis cache (set to False to disable caching)
REDIS_ENABLED=True
# ============================================================================
# EMBEDDING CONFIGURATION (知识库向量检索 - 本地模型)
# ============================================================================
# 启用 Embedding 语义检索(禁用则降级为关键词匹配)
EMBEDDING_ENABLED=True
# 本地 embedding 模型名称(首次运行自动从 HuggingFace 下载)
# 推荐模型:
# BAAI/bge-small-zh-v1.5 (~95MB, 512维, 中文效果好, 内存占用~150MB)
# BAAI/bge-base-zh-v1.5 (~400MB, 768维, 中文效果更好)
# shibing624/text2vec-base-chinese (~400MB, 768维, 中文专优)
EMBEDDING_MODEL=BAAI/bge-small-zh-v1.5
# 向量维度(需与模型匹配)
EMBEDDING_DIMENSION=512
# 语义搜索相似度阈值0.0-1.0,越高越严格)
EMBEDDING_SIMILARITY_THRESHOLD=0.5
# Embedding 缓存过期时间(秒),默认 1 天
EMBEDDING_CACHE_TTL=86400

Binary file not shown.

View File

@@ -20,7 +20,7 @@ from src.utils.helpers import setup_logging
from src.core.database import db_manager
from src.core.models import (
Base, WorkOrder, KnowledgeEntry, Conversation, Analytics, Alert, VehicleData,
WorkOrderSuggestion, WorkOrderProcessHistory, User
WorkOrderSuggestion, WorkOrderProcessHistory, User, ChatSession
)
class DatabaseInitializer:
@@ -197,7 +197,8 @@ class DatabaseInitializer:
self._migrate_workorder_dispatch_fields,
self._migrate_workorder_process_history_table,
self._migrate_analytics_enhancements,
self._migrate_system_optimization_fields
self._migrate_system_optimization_fields,
self._migrate_chat_sessions_table,
]
success_count = 0
@@ -445,6 +446,37 @@ class DatabaseInitializer:
return success
def _migrate_chat_sessions_table(self) -> bool:
"""迁移:创建 chat_sessions 表并为 conversations 添加 session_id 字段"""
print(" 检查会话管理表...")
try:
inspector = inspect(db_manager.engine)
# 1. 创建 chat_sessions 表
if 'chat_sessions' not in inspector.get_table_names():
print(" 创建 chat_sessions 表...")
ChatSession.__table__.create(db_manager.engine, checkfirst=True)
print(" chat_sessions 表创建成功")
else:
print(" chat_sessions 表已存在")
# 2. 为 conversations 表添加 session_id 字段
if not self._column_exists('conversations', 'session_id'):
print(" 添加 conversations.session_id 字段...")
self._add_table_columns('conversations', [
('session_id', 'VARCHAR(100)')
])
print(" session_id 字段添加成功")
else:
print(" conversations.session_id 字段已存在")
return True
except Exception as e:
print(f" 会话管理表迁移失败: {e}")
return False
def _add_table_columns(self, table_name: str, fields: List[tuple]) -> bool:
"""为表添加字段"""
try:

View File

@@ -69,3 +69,6 @@ marshmallow==3.23.3
# 飞书官方 SDK事件订阅 2.0 - 长连接模式)
lark-oapi==1.3.5
# 本地 Embedding 模型可选EMBEDDING_ENABLED=True 时需要)
# pip install sentence-transformers torch

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
批量为已有知识库条目生成 Embedding 向量(本地模型)
运行方式: python scripts/migrate_embeddings.py
首次运行会自动下载模型(~95MB之后走本地缓存
"""
import sys
import os
import json
import logging
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.config.unified_config import get_config
from src.core.database import db_manager
from src.core.models import KnowledgeEntry
from src.core.embedding_client import EmbeddingClient
from src.core.vector_store import vector_store
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def migrate():
config = get_config()
if not config.embedding.enabled:
logger.warning("Embedding 功能未启用,请在 .env 中设置 EMBEDDING_ENABLED=True")
return
client = EmbeddingClient()
# 测试模型加载
logger.info("正在加载本地 embedding 模型(首次运行需下载)...")
if not client.test_connection():
logger.error("Embedding 模型加载失败,请检查 sentence-transformers 是否安装")
return
logger.info("模型加载成功")
# 获取所有需要生成 embedding 的条目
with db_manager.get_session() as session:
entries = session.query(KnowledgeEntry).filter(
KnowledgeEntry.is_active == True
).all()
# 筛选出没有 embedding 的条目
to_process = []
for entry in entries:
if not entry.vector_embedding or entry.vector_embedding.strip() == '':
to_process.append(entry)
logger.info(f"{len(entries)} 条活跃知识,{len(to_process)} 条需要生成 embedding")
if not to_process:
logger.info("所有条目已有 embedding无需迁移")
return
# 批量生成
texts = [e.question + " " + e.answer for e in to_process]
logger.info(f"开始批量生成 embedding...")
vectors = client.embed_batch(texts)
success_count = 0
for i, entry in enumerate(to_process):
vec = vectors[i]
if vec:
entry.vector_embedding = json.dumps(vec)
success_count += 1
session.commit()
logger.info(f"Embedding 生成完成: 成功 {success_count}/{len(to_process)}")
# 重建向量索引
vector_store.load_from_db()
logger.info(f"向量索引重建完成: {vector_store.size}")
if __name__ == "__main__":
migrate()

View File

@@ -1,22 +1,8 @@
# -*- coding: utf-8 -*-
"""
Agent模块初始化文件
Agent模块
"""
from .agent_core import AgentCore, AgentState
from .planner import TaskPlanner
from .executor import TaskExecutor
from .tool_manager import ToolManager
from .reasoning_engine import ReasoningEngine
from .goal_manager import GoalManager
from .react_agent import ReactAgent
__all__ = [
'AgentCore',
'AgentState',
'TaskPlanner',
'TaskExecutor',
'ToolManager',
'ReasoningEngine',
'GoalManager'
]
__all__ = ['ReactAgent']

View File

@@ -1,255 +0,0 @@
# -*- coding: utf-8 -*-
"""
Agent动作执行器 - 执行具体的Agent动作
"""
import logging
import asyncio
from typing import Dict, Any, List, Optional
from datetime import datetime
import json
from .intelligent_agent import AgentAction, ActionType, AlertContext, KnowledgeContext
logger = logging.getLogger(__name__)
class ActionExecutor:
"""动作执行器"""
def __init__(self, tsp_assistant=None):
self.tsp_assistant = tsp_assistant
self.execution_history = []
self.action_handlers = {
ActionType.ALERT_RESPONSE: self._handle_alert_response,
ActionType.KNOWLEDGE_UPDATE: self._handle_knowledge_update,
ActionType.WORKORDER_CREATE: self._handle_workorder_create,
ActionType.SYSTEM_OPTIMIZE: self._handle_system_optimize,
ActionType.USER_NOTIFY: self._handle_user_notify
}
async def execute_action(self, action: AgentAction) -> Dict[str, Any]:
"""执行动作"""
try:
logger.info(f"开始执行动作: {action.action_type.value}")
start_time = datetime.now()
# 获取处理器
handler = self.action_handlers.get(action.action_type)
if not handler:
return {"success": False, "error": f"未找到动作处理器: {action.action_type}"}
# 执行动作
result = await handler(action)
# 记录执行历史
execution_record = {
"action_id": f"{action.action_type.value}_{datetime.now().timestamp()}",
"action_type": action.action_type.value,
"description": action.description,
"priority": action.priority,
"confidence": action.confidence,
"start_time": start_time.isoformat(),
"end_time": datetime.now().isoformat(),
"success": result.get("success", False),
"result": result
}
self.execution_history.append(execution_record)
logger.info(f"动作执行完成: {action.action_type.value}, 结果: {result.get('success', False)}")
return result
except Exception as e:
logger.error(f"执行动作失败: {e}")
return {"success": False, "error": str(e)}
async def _handle_alert_response(self, action: AgentAction) -> Dict[str, Any]:
"""处理预警响应"""
try:
alert_id = action.parameters.get("alert_id")
service = action.parameters.get("service")
# 根据动作描述执行具体操作
if "重启" in action.description:
return await self._restart_service(service)
elif "检查" in action.description:
return await self._check_system_status(alert_id)
elif "通知" in action.description:
return await self._notify_alert(alert_id, action.description)
else:
return await self._generic_alert_response(action)
except Exception as e:
logger.error(f"处理预警响应失败: {e}")
return {"success": False, "error": str(e)}
async def _handle_knowledge_update(self, action: AgentAction) -> Dict[str, Any]:
"""处理知识库更新"""
try:
question = action.parameters.get("question")
enhanced_answer = action.parameters.get("enhanced_answer")
if enhanced_answer:
# 更新知识库条目
if self.tsp_assistant:
# 这里调用TSP助手的知识库更新方法
result = await self._update_knowledge_entry(question, enhanced_answer)
return result
else:
return {"success": True, "message": "知识库条目已标记更新"}
else:
# 标记低置信度条目
return await self._mark_low_confidence_knowledge(question)
except Exception as e:
logger.error(f"处理知识库更新失败: {e}")
return {"success": False, "error": str(e)}
async def _handle_workorder_create(self, action: AgentAction) -> Dict[str, Any]:
"""处理工单创建"""
try:
title = action.parameters.get("title", "Agent自动创建工单")
description = action.description
category = action.parameters.get("category", "系统问题")
priority = action.parameters.get("priority", "medium")
if self.tsp_assistant:
# 调用TSP助手创建工单
workorder = self.tsp_assistant.create_work_order(
title=title,
description=description,
category=category,
priority=priority
)
return {"success": True, "workorder": workorder}
else:
return {"success": True, "message": "工单创建请求已记录"}
except Exception as e:
logger.error(f"处理工单创建失败: {e}")
return {"success": False, "error": str(e)}
async def _handle_system_optimize(self, action: AgentAction) -> Dict[str, Any]:
"""处理系统优化"""
try:
optimization_type = action.parameters.get("type", "general")
if optimization_type == "performance":
return await self._optimize_performance(action)
elif optimization_type == "memory":
return await self._optimize_memory(action)
elif optimization_type == "database":
return await self._optimize_database(action)
else:
return await self._general_optimization(action)
except Exception as e:
logger.error(f"处理系统优化失败: {e}")
return {"success": False, "error": str(e)}
async def _handle_user_notify(self, action: AgentAction) -> Dict[str, Any]:
"""处理用户通知"""
try:
message = action.description
user_id = action.parameters.get("user_id", "admin")
notification_type = action.parameters.get("type", "info")
# 这里实现具体的通知逻辑
# 可以是邮件、短信、系统通知等
return await self._send_notification(user_id, message, notification_type)
except Exception as e:
logger.error(f"处理用户通知失败: {e}")
return {"success": False, "error": str(e)}
# 具体实现方法
async def _restart_service(self, service: str) -> Dict[str, Any]:
"""重启服务"""
logger.info(f"重启服务: {service}")
# 这里实现具体的服务重启逻辑
await asyncio.sleep(2) # 模拟重启时间
return {"success": True, "message": f"服务 {service} 已重启"}
async def _check_system_status(self, alert_id: str) -> Dict[str, Any]:
"""检查系统状态"""
logger.info(f"检查系统状态: {alert_id}")
# 这里实现具体的系统检查逻辑
await asyncio.sleep(1)
return {"success": True, "status": "正常", "alert_id": alert_id}
async def _notify_alert(self, alert_id: str, message: str) -> Dict[str, Any]:
"""通知预警"""
logger.info(f"通知预警: {alert_id} - {message}")
# 这里实现具体的通知逻辑
return {"success": True, "message": "预警通知已发送"}
async def _generic_alert_response(self, action: AgentAction) -> Dict[str, Any]:
"""通用预警响应"""
logger.info(f"执行通用预警响应: {action.description}")
return {"success": True, "message": "预警响应已执行"}
async def _update_knowledge_entry(self, question: str, enhanced_answer: str) -> Dict[str, Any]:
"""更新知识库条目"""
logger.info(f"更新知识库条目: {question}")
# 这里实现具体的知识库更新逻辑
return {"success": True, "message": "知识库条目已更新"}
async def _mark_low_confidence_knowledge(self, question: str) -> Dict[str, Any]:
"""标记低置信度知识"""
logger.info(f"标记低置信度知识: {question}")
# 这里实现具体的标记逻辑
return {"success": True, "message": "低置信度知识已标记"}
async def _optimize_performance(self, action: AgentAction) -> Dict[str, Any]:
"""性能优化"""
logger.info("执行性能优化")
# 这里实现具体的性能优化逻辑
return {"success": True, "message": "性能优化已执行"}
async def _optimize_memory(self, action: AgentAction) -> Dict[str, Any]:
"""内存优化"""
logger.info("执行内存优化")
# 这里实现具体的内存优化逻辑
return {"success": True, "message": "内存优化已执行"}
async def _optimize_database(self, action: AgentAction) -> Dict[str, Any]:
"""数据库优化"""
logger.info("执行数据库优化")
# 这里实现具体的数据库优化逻辑
return {"success": True, "message": "数据库优化已执行"}
async def _general_optimization(self, action: AgentAction) -> Dict[str, Any]:
"""通用优化"""
logger.info(f"执行通用优化: {action.description}")
return {"success": True, "message": "系统优化已执行"}
async def _send_notification(self, user_id: str, message: str, notification_type: str) -> Dict[str, Any]:
"""发送通知"""
logger.info(f"发送通知给 {user_id}: {message}")
# 这里实现具体的通知发送逻辑
return {"success": True, "message": "通知已发送"}
def get_execution_history(self, limit: int = 100) -> List[Dict[str, Any]]:
"""获取执行历史"""
return self.execution_history[-limit:]
def get_action_statistics(self) -> Dict[str, Any]:
"""获取动作统计"""
total_actions = len(self.execution_history)
successful_actions = sum(1 for record in self.execution_history if record["success"])
action_types = {}
for record in self.execution_history:
action_type = record["action_type"]
if action_type not in action_types:
action_types[action_type] = {"total": 0, "successful": 0}
action_types[action_type]["total"] += 1
if record["success"]:
action_types[action_type]["successful"] += 1
return {
"total_actions": total_actions,
"successful_actions": successful_actions,
"success_rate": successful_actions / total_actions if total_actions > 0 else 0,
"action_types": action_types
}

View File

@@ -1,268 +0,0 @@
# -*- coding: utf-8 -*-
"""
TSP Agent助手核心模块
包含Agent助手的核心功能和基础类
"""
import logging
import asyncio
from typing import Dict, Any, List, Optional
from datetime import datetime
import json
from src.main import TSPAssistant
from src.agent import AgentCore, AgentState
from src.agent.auto_monitor import AutoMonitorService
from src.agent.intelligent_agent import IntelligentAgent, AlertContext, KnowledgeContext
from src.agent.llm_client import LLMManager, LLMConfig
from src.agent.action_executor import ActionExecutor
logger = logging.getLogger(__name__)
class TSPAgentAssistantCore(TSPAssistant):
"""TSP Agent助手核心 - 基础功能"""
def __init__(self, llm_config: Optional[LLMConfig] = None):
# 初始化基础TSP助手
super().__init__()
# 初始化Agent核心
self.agent_core = AgentCore()
# 初始化自动监控服务
self.auto_monitor = AutoMonitorService(self)
# 初始化LLM客户端
self._init_llm_manager(llm_config)
# 初始化智能Agent
self.intelligent_agent = IntelligentAgent(
llm_client=self.llm_manager
)
# 初始化动作执行器
self.action_executor = ActionExecutor(self)
# Agent状态
self.agent_state = AgentState.IDLE
self.is_agent_mode = True
self.proactive_monitoring_enabled = False
# 执行历史
self.execution_history = []
self.max_history_size = 1000
logger.info("TSP Agent助手核心初始化完成")
def _init_llm_manager(self, llm_config: Optional[LLMConfig] = None):
"""初始化LLM管理器"""
if llm_config:
self.llm_manager = LLMManager(llm_config)
else:
# 从统一配置管理器获取LLM配置
try:
from src.config.unified_config import get_config
unified_llm = get_config().llm
# 将统一配置的LLMConfig转换为agent需要的LLMConfig
agent_llm_config = LLMConfig(
provider=unified_llm.provider,
api_key=unified_llm.api_key,
base_url=unified_llm.base_url,
model=unified_llm.model,
temperature=unified_llm.temperature,
max_tokens=unified_llm.max_tokens
)
self.llm_manager = LLMManager(agent_llm_config)
except Exception as e:
logger.warning(f"无法从统一配置加载LLM配置使用config/llm_config.py: {e}")
try:
from config.llm_config import DEFAULT_CONFIG
self.llm_manager = LLMManager(DEFAULT_CONFIG)
except ImportError:
# 最后的fallback
default_config = LLMConfig(
provider="qwen",
api_key="",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-turbo",
temperature=0.7,
max_tokens=2000
)
self.llm_manager = LLMManager(default_config)
def get_agent_status(self) -> Dict[str, Any]:
"""获取Agent状态"""
return {
"agent_state": self.agent_state.value,
"is_agent_mode": self.is_agent_mode,
"proactive_monitoring": self.proactive_monitoring_enabled,
"execution_count": len(self.execution_history),
"llm_status": self.llm_manager.get_status(),
"agent_core_status": self.agent_core.get_status(),
"last_activity": self.execution_history[-1]["timestamp"] if self.execution_history else None
}
def toggle_agent_mode(self, enabled: bool) -> bool:
"""切换Agent模式"""
try:
self.is_agent_mode = enabled
if enabled:
self.agent_state = AgentState.IDLE
logger.info("Agent模式已启用")
else:
self.agent_state = AgentState.DISABLED
logger.info("Agent模式已禁用")
return True
except Exception as e:
logger.error(f"切换Agent模式失败: {e}")
return False
def start_proactive_monitoring(self) -> bool:
"""启动主动监控"""
try:
if not self.proactive_monitoring_enabled:
self.proactive_monitoring_enabled = True
self.auto_monitor.start_monitoring()
logger.info("主动监控已启动")
return True
return False
except Exception as e:
logger.error(f"启动主动监控失败: {e}")
return False
def stop_proactive_monitoring(self) -> bool:
"""停止主动监控"""
try:
if self.proactive_monitoring_enabled:
self.proactive_monitoring_enabled = False
self.auto_monitor.stop_monitoring()
logger.info("主动监控已停止")
return True
return False
except Exception as e:
logger.error(f"停止主动监控失败: {e}")
return False
def run_proactive_monitoring(self) -> Dict[str, Any]:
"""运行主动监控检查"""
try:
if not self.proactive_monitoring_enabled:
return {"success": False, "message": "主动监控未启用"}
# 获取系统状态
system_health = self.get_system_health()
# 检查预警
alerts = self.check_alerts()
# 检查工单状态
workorders_status = self._check_workorders_status()
# 运行智能分析
analysis = self.intelligent_agent.analyze_system_state(
system_health=system_health,
alerts=alerts,
workorders=workorders_status
)
# 执行建议的动作
actions_taken = []
if analysis.get("recommended_actions"):
for action in analysis["recommended_actions"]:
result = self.action_executor.execute_action(action)
actions_taken.append(result)
return {
"success": True,
"analysis": analysis,
"actions_taken": actions_taken,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"主动监控检查失败: {e}")
return {"success": False, "error": str(e)}
def _check_workorders_status(self) -> Dict[str, Any]:
"""检查工单状态"""
try:
from src.core.database import db_manager
from src.core.models import WorkOrder
with db_manager.get_session() as session:
total_workorders = session.query(WorkOrder).count()
open_workorders = session.query(WorkOrder).filter(WorkOrder.status == 'open').count()
resolved_workorders = session.query(WorkOrder).filter(WorkOrder.status == 'resolved').count()
return {
"total": total_workorders,
"open": open_workorders,
"resolved": resolved_workorders,
"resolution_rate": resolved_workorders / total_workorders if total_workorders > 0 else 0
}
except Exception as e:
logger.error(f"检查工单状态失败: {e}")
return {"error": str(e)}
def run_intelligent_analysis(self) -> Dict[str, Any]:
"""运行智能分析"""
try:
# 获取系统数据
system_health = self.get_system_health()
alerts = self.check_alerts()
workorders = self._check_workorders_status()
# 创建分析上下文
context = {
"system_health": system_health,
"alerts": alerts,
"workorders": workorders,
"timestamp": datetime.now().isoformat()
}
# 运行智能分析
analysis = self.intelligent_agent.comprehensive_analysis(context)
# 记录分析结果
self._record_execution("intelligent_analysis", analysis)
return analysis
except Exception as e:
logger.error(f"智能分析失败: {e}")
return {"error": str(e)}
def _record_execution(self, action_type: str, result: Any):
"""记录执行历史"""
execution_record = {
"timestamp": datetime.now().isoformat(),
"action_type": action_type,
"result": result,
"agent_state": self.agent_state.value
}
self.execution_history.append(execution_record)
# 保持历史记录大小限制
if len(self.execution_history) > self.max_history_size:
self.execution_history = self.execution_history[-self.max_history_size:]
def get_action_history(self, limit: int = 50) -> List[Dict[str, Any]]:
"""获取动作执行历史"""
return self.execution_history[-limit:] if self.execution_history else []
def clear_execution_history(self) -> Dict[str, Any]:
"""清空执行历史"""
try:
self.execution_history.clear()
logger.info("执行历史已清空")
return {"success": True, "message": "执行历史已清空"}
except Exception as e:
logger.error(f"清空执行历史失败: {e}")
return {"success": False, "error": str(e)}
def get_llm_usage_stats(self) -> Dict[str, Any]:
"""获取LLM使用统计"""
try:
return self.llm_manager.get_usage_stats()
except Exception as e:
logger.error(f"获取LLM使用统计失败: {e}")
return {"error": str(e)}

View File

@@ -1,313 +0,0 @@
# -*- coding: utf-8 -*-
"""
Agent核心模块
实现智能体的核心逻辑和决策机制
"""
import logging
import asyncio
from typing import Dict, List, Any, Optional, Callable
from datetime import datetime
from enum import Enum
import json
from ..core.database import db_manager
from ..core.llm_client import QwenClient
from .planner import TaskPlanner
from .executor import TaskExecutor
from .tool_manager import ToolManager
from .reasoning_engine import ReasoningEngine
from .goal_manager import GoalManager
logger = logging.getLogger(__name__)
class AgentState(Enum):
"""Agent状态枚举"""
IDLE = "idle"
THINKING = "thinking"
PLANNING = "planning"
EXECUTING = "executing"
LEARNING = "learning"
PROCESSING = "processing"
ERROR = "error"
class AgentCore:
"""Agent核心类"""
def __init__(self):
self.state = AgentState.IDLE
self.llm_client = QwenClient()
self.planner = TaskPlanner()
self.executor = TaskExecutor()
self.tool_manager = ToolManager()
self.reasoning_engine = ReasoningEngine()
self.goal_manager = GoalManager()
# Agent记忆和上下文
self.memory = {}
self.current_goal = None
self.active_tasks = []
self.execution_history = []
# 配置参数
self.max_iterations = 10
self.confidence_threshold = 0.7
logger.info("Agent核心初始化完成")
async def process_request(self, request: Dict[str, Any]) -> Dict[str, Any]:
"""处理用户请求的主入口"""
try:
self.state = AgentState.THINKING
# 1. 理解用户意图
intent = await self._understand_intent(request)
# 2. 设定目标
goal = await self._set_goal(intent, request)
# 3. 制定计划
plan = await self._create_plan(goal)
# 4. 执行计划
result = await self._execute_plan(plan)
# 5. 学习和反思
await self._learn_from_execution(result)
self.state = AgentState.IDLE
return result
except Exception as e:
logger.error(f"处理请求失败: {e}")
self.state = AgentState.ERROR
return {"error": f"处理失败: {str(e)}"}
async def _understand_intent(self, request: Dict[str, Any]) -> Dict[str, Any]:
"""理解用户意图"""
user_message = request.get("message", "")
context = request.get("context", {})
# 使用推理引擎分析意图
intent_analysis = await self.reasoning_engine.analyze_intent(
message=user_message,
context=context,
history=self.execution_history[-5:] # 最近5次执行历史
)
return intent_analysis
async def _set_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""设定目标"""
goal = await self.goal_manager.create_goal(
intent=intent,
request=request,
current_state=self.state
)
self.current_goal = goal
return goal
async def _create_plan(self, goal: Dict[str, Any]) -> List[Dict[str, Any]]:
"""制定执行计划"""
self.state = AgentState.PLANNING
plan = await self.planner.create_plan(
goal=goal,
available_tools=self.tool_manager.get_available_tools(),
constraints=self._get_constraints()
)
return plan
async def _execute_plan(self, plan: List[Dict[str, Any]]) -> Dict[str, Any]:
"""执行计划"""
self.state = AgentState.EXECUTING
execution_result = await self.executor.execute_plan(
plan=plan,
tool_manager=self.tool_manager,
context=self.memory
)
# 记录执行历史
self.execution_history.append({
"timestamp": datetime.now().isoformat(),
"plan": plan,
"result": execution_result
})
return execution_result
async def _learn_from_execution(self, result: Dict[str, Any]):
"""从执行结果中学习"""
self.state = AgentState.LEARNING
# 分析执行效果
learning_insights = await self.reasoning_engine.extract_insights(
execution_result=result,
goal=self.current_goal
)
# 更新记忆
self._update_memory(learning_insights)
# 更新工具使用统计
self.tool_manager.update_usage_stats(result.get("tool_usage", []))
def _get_constraints(self) -> Dict[str, Any]:
"""获取执行约束"""
return {
"max_iterations": self.max_iterations,
"confidence_threshold": self.confidence_threshold,
"timeout": 300, # 5分钟超时
"memory_limit": 1000 # 内存限制
}
def _update_memory(self, insights: Dict[str, Any]):
"""更新Agent记忆"""
timestamp = datetime.now().isoformat()
# 更新成功模式
if insights.get("success_patterns"):
if "success_patterns" not in self.memory:
self.memory["success_patterns"] = []
self.memory["success_patterns"].extend(insights["success_patterns"])
# 更新失败模式
if insights.get("failure_patterns"):
if "failure_patterns" not in self.memory:
self.memory["failure_patterns"] = []
self.memory["failure_patterns"].extend(insights["failure_patterns"])
# 更新知识
if insights.get("new_knowledge"):
if "knowledge" not in self.memory:
self.memory["knowledge"] = []
self.memory["knowledge"].extend(insights["new_knowledge"])
# 限制记忆大小
for key in self.memory:
if isinstance(self.memory[key], list) and len(self.memory[key]) > 100:
self.memory[key] = self.memory[key][-100:]
async def proactive_action(self) -> Optional[Dict[str, Any]]:
"""主动行动 - Agent主动发起的行为"""
try:
# 检查是否有需要主动处理的任务
proactive_tasks = await self._identify_proactive_tasks()
if proactive_tasks:
# 选择最重要的任务
priority_task = max(proactive_tasks, key=lambda x: x.get("priority", 0))
# 执行主动任务
result = await self.process_request(priority_task)
return result
return None
except Exception as e:
logger.error(f"主动行动失败: {e}")
return None
async def _identify_proactive_tasks(self) -> List[Dict[str, Any]]:
"""识别需要主动处理的任务"""
tasks = []
# 检查预警系统
alerts = await self._check_alerts()
if alerts:
tasks.extend([{
"type": "alert_response",
"message": f"处理预警: {alert['message']}",
"priority": self._calculate_alert_priority(alert),
"context": {"alert": alert}
} for alert in alerts])
# 检查知识库更新需求
knowledge_gaps = await self._identify_knowledge_gaps()
if knowledge_gaps:
tasks.append({
"type": "knowledge_update",
"message": "更新知识库",
"priority": 0.6,
"context": {"gaps": knowledge_gaps}
})
# 检查系统健康状态
health_issues = await self._check_system_health()
if health_issues:
tasks.append({
"type": "system_maintenance",
"message": "系统维护",
"priority": 0.8,
"context": {"issues": health_issues}
})
return tasks
async def _check_alerts(self) -> List[Dict[str, Any]]:
"""检查预警"""
# 这里可以调用现有的预警系统
from ..analytics.alert_system import AlertSystem
alert_system = AlertSystem()
return alert_system.get_active_alerts()
def _calculate_alert_priority(self, alert: Dict[str, Any]) -> float:
"""计算预警优先级"""
severity_map = {
"low": 0.3,
"medium": 0.6,
"high": 0.8,
"critical": 1.0
}
return severity_map.get(alert.get("severity", "medium"), 0.5)
async def _identify_knowledge_gaps(self) -> List[Dict[str, Any]]:
"""识别知识库缺口"""
# 分析未解决的问题,识别知识缺口
gaps = []
# 这里可以实现具体的知识缺口识别逻辑
# 例如:分析低置信度的回复、未解决的问题等
return gaps
async def _check_system_health(self) -> List[Dict[str, Any]]:
"""检查系统健康状态"""
issues = []
# 检查各个组件的健康状态
if not self.llm_client.test_connection():
issues.append({"component": "llm_client", "issue": "连接失败"})
# 检查内存使用
import psutil
memory_percent = psutil.virtual_memory().percent
if memory_percent > 80:
issues.append({"component": "memory", "issue": f"内存使用率过高: {memory_percent}%"})
return issues
def get_status(self) -> Dict[str, Any]:
"""获取Agent状态"""
return {
"state": self.state.value,
"current_goal": self.current_goal,
"active_tasks": len(self.active_tasks),
"execution_history_count": len(self.execution_history),
"memory_size": len(str(self.memory)),
"available_tools": len(self.tool_manager.get_available_tools()),
"timestamp": datetime.now().isoformat()
}
def reset(self):
"""重置Agent状态"""
self.state = AgentState.IDLE
self.current_goal = None
self.active_tasks = []
self.execution_history = []
self.memory = {}
logger.info("Agent状态已重置")

View File

@@ -1,243 +0,0 @@
# -*- coding: utf-8 -*-
"""
TSP Agent消息处理模块
处理Agent的消息处理和对话功能
"""
import logging
import asyncio
from typing import Dict, Any, List, Optional
from datetime import datetime
from .agent_assistant_core import TSPAgentAssistantCore
from .intelligent_agent import IntelligentAgent
logger = logging.getLogger(__name__)
class AgentMessageHandler:
"""Agent消息处理器"""
def __init__(self, agent_core: TSPAgentAssistantCore):
self.agent_core = agent_core
self.intelligent_agent = agent_core.intelligent_agent
self.action_executor = agent_core.action_executor
async def process_message_agent(self, message: str, user_id: str = "admin",
work_order_id: Optional[int] = None,
enable_proactive: bool = True) -> Dict[str, Any]:
"""使用Agent处理消息"""
try:
# 更新Agent状态
self.agent_core.agent_state = self.agent_core.agent_core.AgentState.PROCESSING
# 创建对话上下文
context = {
"message": message,
"user_id": user_id,
"work_order_id": work_order_id,
"timestamp": datetime.now().isoformat(),
"enable_proactive": enable_proactive
}
# 使用智能Agent处理消息
agent_response = await self.intelligent_agent.process_message(context)
# 执行建议的动作
actions_taken = []
if agent_response.get("recommended_actions"):
for action in agent_response["recommended_actions"]:
action_result = self.action_executor.execute_action(action)
actions_taken.append(action_result)
# 生成响应
response = {
"response": agent_response.get("response", "Agent已处理您的请求"),
"actions": actions_taken,
"status": "completed",
"confidence": agent_response.get("confidence", 0.8),
"context": context
}
# 记录执行历史
self.agent_core._record_execution("message_processing", response)
# 更新Agent状态
self.agent_core.agent_state = self.agent_core.agent_core.AgentState.IDLE
return response
except Exception as e:
logger.error(f"Agent消息处理失败: {e}")
self.agent_core.agent_state = self.agent_core.agent_core.AgentState.ERROR
return {
"response": f"处理消息时发生错误: {str(e)}",
"actions": [],
"status": "error",
"error": str(e)
}
async def process_conversation_agent(self, conversation_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理对话"""
try:
# 提取对话信息
user_message = conversation_data.get("message", "")
user_id = conversation_data.get("user_id", "anonymous")
session_id = conversation_data.get("session_id")
# 创建对话上下文
context = {
"message": user_message,
"user_id": user_id,
"session_id": session_id,
"conversation_history": conversation_data.get("history", []),
"timestamp": datetime.now().isoformat()
}
# 使用智能Agent处理对话
agent_response = await self.intelligent_agent.process_conversation(context)
# 执行建议的动作
actions_taken = []
if agent_response.get("recommended_actions"):
for action in agent_response["recommended_actions"]:
action_result = self.action_executor.execute_action(action)
actions_taken.append(action_result)
# 生成响应
response = {
"response": agent_response.get("response", "Agent已处理您的对话"),
"actions": actions_taken,
"status": "completed",
"confidence": agent_response.get("confidence", 0.8),
"context": context,
"session_id": session_id
}
# 记录执行历史
self.agent_core._record_execution("conversation_processing", response)
return response
except Exception as e:
logger.error(f"Agent对话处理失败: {e}")
return {
"response": f"处理对话时发生错误: {str(e)}",
"actions": [],
"status": "error",
"error": str(e)
}
async def process_workorder_agent(self, workorder_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理工单"""
try:
# 提取工单信息
workorder_id = workorder_data.get("workorder_id")
action_type = workorder_data.get("action_type", "analyze")
# 创建工单上下文
context = {
"workorder_id": workorder_id,
"action_type": action_type,
"workorder_data": workorder_data,
"timestamp": datetime.now().isoformat()
}
# 使用智能Agent处理工单
agent_response = await self.intelligent_agent.process_workorder(context)
# 执行建议的动作
actions_taken = []
if agent_response.get("recommended_actions"):
for action in agent_response["recommended_actions"]:
action_result = self.action_executor.execute_action(action)
actions_taken.append(action_result)
# 生成响应
response = {
"response": agent_response.get("response", "Agent已处理工单"),
"actions": actions_taken,
"status": "completed",
"confidence": agent_response.get("confidence", 0.8),
"context": context
}
# 记录执行历史
self.agent_core._record_execution("workorder_processing", response)
return response
except Exception as e:
logger.error(f"Agent工单处理失败: {e}")
return {
"response": f"处理工单时发生错误: {str(e)}",
"actions": [],
"status": "error",
"error": str(e)
}
async def process_alert_agent(self, alert_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理预警"""
try:
# 创建预警上下文
context = {
"alert_data": alert_data,
"timestamp": datetime.now().isoformat()
}
# 使用智能Agent处理预警
agent_response = await self.intelligent_agent.process_alert(context)
# 执行建议的动作
actions_taken = []
if agent_response.get("recommended_actions"):
for action in agent_response["recommended_actions"]:
action_result = self.action_executor.execute_action(action)
actions_taken.append(action_result)
# 生成响应
response = {
"response": agent_response.get("response", "Agent已处理预警"),
"actions": actions_taken,
"status": "completed",
"confidence": agent_response.get("confidence", 0.8),
"context": context
}
# 记录执行历史
self.agent_core._record_execution("alert_processing", response)
return response
except Exception as e:
logger.error(f"Agent预警处理失败: {e}")
return {
"response": f"处理预警时发生错误: {str(e)}",
"actions": [],
"status": "error",
"error": str(e)
}
def get_conversation_suggestions(self, context: Dict[str, Any]) -> List[str]:
"""获取对话建议"""
try:
return self.intelligent_agent.get_conversation_suggestions(context)
except Exception as e:
logger.error(f"获取对话建议失败: {e}")
return []
def get_workorder_suggestions(self, workorder_data: Dict[str, Any]) -> List[str]:
"""获取工单建议"""
try:
return self.intelligent_agent.get_workorder_suggestions(workorder_data)
except Exception as e:
logger.error(f"获取工单建议失败: {e}")
return []
def get_alert_suggestions(self, alert_data: Dict[str, Any]) -> List[str]:
"""获取预警建议"""
try:
return self.intelligent_agent.get_alert_suggestions(alert_data)
except Exception as e:
logger.error(f"获取预警建议失败: {e}")
return []

View File

@@ -1,405 +0,0 @@
# -*- coding: utf-8 -*-
"""
TSP Agent示例动作模块
包含Agent的示例动作和测试功能
"""
import logging
import asyncio
from typing import Dict, Any, List
from datetime import datetime, timedelta
from .agent_assistant_core import TSPAgentAssistantCore
logger = logging.getLogger(__name__)
class AgentSampleActions:
"""Agent示例动作处理器"""
def __init__(self, agent_core: TSPAgentAssistantCore):
self.agent_core = agent_core
async def trigger_sample_actions(self) -> Dict[str, Any]:
"""触发示例动作"""
try:
logger.info("开始执行示例动作")
# 执行多个示例动作
actions_results = []
# 1. 系统健康检查
health_result = await self._sample_health_check()
actions_results.append(health_result)
# 2. 预警分析
alert_result = await self._sample_alert_analysis()
actions_results.append(alert_result)
# 3. 工单处理
workorder_result = await self._sample_workorder_processing()
actions_results.append(workorder_result)
# 4. 知识库更新
knowledge_result = await self._sample_knowledge_update()
actions_results.append(knowledge_result)
# 5. 性能优化
optimization_result = await self._sample_performance_optimization()
actions_results.append(optimization_result)
# 记录执行历史
self.agent_core._record_execution("sample_actions", {
"actions_count": len(actions_results),
"results": actions_results
})
return {
"success": True,
"message": f"成功执行 {len(actions_results)} 个示例动作",
"actions_results": actions_results,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"执行示例动作失败: {e}")
return {
"success": False,
"error": str(e),
"timestamp": datetime.now().isoformat()
}
async def _sample_health_check(self) -> Dict[str, Any]:
"""示例:系统健康检查"""
try:
# 获取系统健康状态
health_data = self.agent_core.get_system_health()
# 模拟健康检查逻辑
health_score = health_data.get("health_score", 0)
if health_score > 80:
status = "excellent"
message = "系统运行状态良好"
elif health_score > 60:
status = "good"
message = "系统运行状态正常"
elif health_score > 40:
status = "fair"
message = "系统运行状态一般,建议关注"
else:
status = "poor"
message = "系统运行状态较差,需要优化"
return {
"action_type": "health_check",
"status": status,
"message": message,
"health_score": health_score,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"健康检查失败: {e}")
return {
"action_type": "health_check",
"status": "error",
"error": str(e)
}
async def _sample_alert_analysis(self) -> Dict[str, Any]:
"""示例:预警分析"""
try:
# 获取预警数据
alerts = self.agent_core.check_alerts()
# 分析预警
alert_count = len(alerts)
critical_alerts = [a for a in alerts if a.get("level") == "critical"]
warning_alerts = [a for a in alerts if a.get("level") == "warning"]
# 生成分析结果
if alert_count == 0:
status = "no_alerts"
message = "当前无活跃预警"
elif len(critical_alerts) > 0:
status = "critical"
message = f"发现 {len(critical_alerts)} 个严重预警,需要立即处理"
elif len(warning_alerts) > 0:
status = "warning"
message = f"发现 {len(warning_alerts)} 个警告预警,建议关注"
else:
status = "info"
message = f"发现 {alert_count} 个信息预警"
return {
"action_type": "alert_analysis",
"status": status,
"message": message,
"alert_count": alert_count,
"critical_count": len(critical_alerts),
"warning_count": len(warning_alerts),
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"预警分析失败: {e}")
return {
"action_type": "alert_analysis",
"status": "error",
"error": str(e)
}
async def _sample_workorder_processing(self) -> Dict[str, Any]:
"""示例:工单处理"""
try:
# 获取工单状态
workorders_status = self.agent_core._check_workorders_status()
total = workorders_status.get("total", 0)
open_count = workorders_status.get("open", 0)
resolved_count = workorders_status.get("resolved", 0)
resolution_rate = workorders_status.get("resolution_rate", 0)
# 分析工单状态
if total == 0:
status = "no_workorders"
message = "当前无工单"
elif open_count > 10:
status = "high_backlog"
message = f"工单积压严重,有 {open_count} 个待处理工单"
elif resolution_rate > 0.8:
status = "good_resolution"
message = f"工单处理效率良好,解决率 {resolution_rate:.1%}"
else:
status = "normal"
message = f"工单处理状态正常,待处理 {open_count}"
return {
"action_type": "workorder_processing",
"status": status,
"message": message,
"total_workorders": total,
"open_workorders": open_count,
"resolved_workorders": resolved_count,
"resolution_rate": resolution_rate,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"工单处理分析失败: {e}")
return {
"action_type": "workorder_processing",
"status": "error",
"error": str(e)
}
async def _sample_knowledge_update(self) -> Dict[str, Any]:
"""示例:知识库更新"""
try:
from src.core.database import db_manager
from src.core.models import KnowledgeEntry
with db_manager.get_session() as session:
# 获取知识库统计
total_knowledge = session.query(KnowledgeEntry).count()
verified_knowledge = session.query(KnowledgeEntry).filter(
KnowledgeEntry.is_verified == True
).count()
unverified_knowledge = total_knowledge - verified_knowledge
# 分析知识库状态
if total_knowledge == 0:
status = "empty"
message = "知识库为空,建议添加知识条目"
elif unverified_knowledge > 0:
status = "needs_verification"
message = f"{unverified_knowledge} 个知识条目需要验证"
else:
status = "up_to_date"
message = "知识库状态良好,所有条目已验证"
return {
"action_type": "knowledge_update",
"status": status,
"message": message,
"total_knowledge": total_knowledge,
"verified_knowledge": verified_knowledge,
"unverified_knowledge": unverified_knowledge,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"知识库更新分析失败: {e}")
return {
"action_type": "knowledge_update",
"status": "error",
"error": str(e)
}
async def _sample_performance_optimization(self) -> Dict[str, Any]:
"""示例:性能优化"""
try:
# 获取系统性能数据
system_health = self.agent_core.get_system_health()
# 分析性能指标
cpu_usage = system_health.get("cpu_usage", 0)
memory_usage = system_health.get("memory_usage", 0)
disk_usage = system_health.get("disk_usage", 0)
# 生成优化建议
optimization_suggestions = []
if cpu_usage > 80:
optimization_suggestions.append("CPU使用率过高建议优化计算密集型任务")
if memory_usage > 80:
optimization_suggestions.append("内存使用率过高,建议清理缓存或增加内存")
if disk_usage > 90:
optimization_suggestions.append("磁盘空间不足,建议清理日志文件或扩容")
if not optimization_suggestions:
status = "optimal"
message = "系统性能良好,无需优化"
else:
status = "needs_optimization"
message = f"发现 {len(optimization_suggestions)} 个性能优化点"
return {
"action_type": "performance_optimization",
"status": status,
"message": message,
"cpu_usage": cpu_usage,
"memory_usage": memory_usage,
"disk_usage": disk_usage,
"optimization_suggestions": optimization_suggestions,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"性能优化分析失败: {e}")
return {
"action_type": "performance_optimization",
"status": "error",
"error": str(e)
}
async def run_performance_test(self) -> Dict[str, Any]:
"""运行性能测试"""
try:
start_time = datetime.now()
# 执行多个测试
test_results = []
# 1. 响应时间测试
response_time = await self._test_response_time()
test_results.append(response_time)
# 2. 并发处理测试
concurrency_test = await self._test_concurrency()
test_results.append(concurrency_test)
# 3. 内存使用测试
memory_test = await self._test_memory_usage()
test_results.append(memory_test)
end_time = datetime.now()
total_time = (end_time - start_time).total_seconds()
return {
"success": True,
"message": "性能测试完成",
"total_time": total_time,
"test_results": test_results,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"性能测试失败: {e}")
return {
"success": False,
"error": str(e),
"timestamp": datetime.now().isoformat()
}
async def _test_response_time(self) -> Dict[str, Any]:
"""测试响应时间"""
start_time = datetime.now()
# 模拟处理任务
await asyncio.sleep(0.1)
end_time = datetime.now()
response_time = (end_time - start_time).total_seconds()
return {
"test_type": "response_time",
"response_time": response_time,
"status": "good" if response_time < 0.5 else "slow"
}
async def _test_concurrency(self) -> Dict[str, Any]:
"""测试并发处理"""
try:
# 创建多个并发任务
tasks = []
for i in range(5):
task = asyncio.create_task(self._simulate_task(i))
tasks.append(task)
# 等待所有任务完成
results = await asyncio.gather(*tasks)
return {
"test_type": "concurrency",
"concurrent_tasks": len(tasks),
"successful_tasks": len([r for r in results if r.get("success")]),
"status": "good"
}
except Exception as e:
return {
"test_type": "concurrency",
"status": "error",
"error": str(e)
}
async def _simulate_task(self, task_id: int) -> Dict[str, Any]:
"""模拟任务"""
try:
await asyncio.sleep(0.05) # 模拟处理时间
return {
"task_id": task_id,
"success": True,
"result": f"Task {task_id} completed"
}
except Exception as e:
return {
"task_id": task_id,
"success": False,
"error": str(e)
}
async def _test_memory_usage(self) -> Dict[str, Any]:
"""测试内存使用"""
try:
import psutil
# 获取当前内存使用情况
memory_info = psutil.virtual_memory()
return {
"test_type": "memory_usage",
"total_memory": memory_info.total,
"available_memory": memory_info.available,
"used_memory": memory_info.used,
"memory_percentage": memory_info.percent,
"status": "good" if memory_info.percent < 80 else "high"
}
except Exception as e:
return {
"test_type": "memory_usage",
"status": "error",
"error": str(e)
}

View File

@@ -5,7 +5,7 @@
实现Agent的主动调用功能
"""
import asyncio跳过系统检查直接启动服务...
import asyncio
import logging
import threading
import time
@@ -22,7 +22,7 @@ class AutoMonitorService:
self.agent_assistant = agent_assistant
self.is_running = False
self.monitor_thread = None
self.check_interval = 300 # 5分钟检查一次
self.check_interval = 900 # 5分钟检查一次
self.last_check_time = None
self.monitoring_stats = {
"total_checks": 0,

View File

@@ -1,589 +0,0 @@
# -*- coding: utf-8 -*-
"""
任务执行器
负责执行计划中的具体任务
"""
import logging
import asyncio
from typing import Dict, List, Any, Optional
from datetime import datetime
import json
logger = logging.getLogger(__name__)
class TaskExecutor:
"""任务执行器"""
def __init__(self):
self.execution_strategies = {
"sequential": self._execute_sequential,
"parallel": self._execute_parallel,
"conditional": self._execute_conditional,
"iterative": self._execute_iterative
}
self.active_executions = {}
async def execute_plan(
self,
plan: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行计划"""
try:
execution_id = f"exec_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
self.active_executions[execution_id] = {
"start_time": datetime.now(),
"status": "running",
"plan": plan
}
# 根据计划类型选择执行策略
execution_strategy = self._determine_execution_strategy(plan)
# 执行计划
result = await self.execution_strategies[execution_strategy](
plan=plan,
tool_manager=tool_manager,
context=context,
execution_id=execution_id
)
# 更新执行状态
self.active_executions[execution_id]["status"] = "completed"
self.active_executions[execution_id]["end_time"] = datetime.now()
self.active_executions[execution_id]["result"] = result
logger.info(f"计划执行完成: {execution_id}")
return result
except Exception as e:
logger.error(f"执行计划失败: {e}")
if execution_id in self.active_executions:
self.active_executions[execution_id]["status"] = "failed"
self.active_executions[execution_id]["error"] = str(e)
return {
"success": False,
"error": str(e),
"execution_id": execution_id
}
def _determine_execution_strategy(self, plan: List[Dict[str, Any]]) -> str:
"""确定执行策略"""
if not plan:
return "sequential"
# 检查计划类型
plan_types = [task.get("type") for task in plan]
if "parallel_group" in plan_types:
return "parallel"
elif "condition" in plan_types or "branch" in plan_types:
return "conditional"
elif "iteration_control" in plan_types:
return "iterative"
else:
return "sequential"
async def _execute_sequential(
self,
plan: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any],
execution_id: str
) -> Dict[str, Any]:
"""顺序执行计划"""
results = []
execution_log = []
for i, task in enumerate(plan):
try:
logger.info(f"执行任务 {i+1}/{len(plan)}: {task.get('id', 'unknown')}")
# 检查任务依赖
if not await self._check_dependencies(task, results):
logger.warning(f"任务 {task.get('id')} 的依赖未满足,跳过执行")
continue
# 执行任务
task_result = await self._execute_single_task(task, tool_manager, context)
results.append({
"task_id": task.get("id"),
"result": task_result,
"timestamp": datetime.now().isoformat()
})
execution_log.append({
"task_id": task.get("id"),
"status": "completed",
"duration": task_result.get("duration", 0)
})
# 检查是否满足成功条件
if not self._check_success_criteria(task, task_result):
logger.warning(f"任务 {task.get('id')} 未满足成功条件")
except Exception as e:
logger.error(f"执行任务 {task.get('id')} 失败: {e}")
execution_log.append({
"task_id": task.get("id"),
"status": "failed",
"error": str(e)
})
# 根据任务重要性决定是否继续
if task.get("critical", False):
return {
"success": False,
"error": f"关键任务失败: {task.get('id')}",
"results": results,
"execution_log": execution_log
}
return {
"success": True,
"results": results,
"execution_log": execution_log,
"execution_id": execution_id
}
async def _execute_parallel(
self,
plan: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any],
execution_id: str
) -> Dict[str, Any]:
"""并行执行计划"""
results = []
execution_log = []
# 将计划分组
parallel_groups = self._group_tasks_for_parallel_execution(plan)
for group in parallel_groups:
if group["execution_mode"] == "parallel":
# 并行执行组内任务
group_results = await self._execute_tasks_parallel(
group["tasks"], tool_manager, context
)
results.extend(group_results)
else:
# 顺序执行组内任务
for task in group["tasks"]:
task_result = await self._execute_single_task(task, tool_manager, context)
results.append({
"task_id": task.get("id"),
"result": task_result,
"timestamp": datetime.now().isoformat()
})
return {
"success": True,
"results": results,
"execution_log": execution_log,
"execution_id": execution_id
}
async def _execute_conditional(
self,
plan: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any],
execution_id: str
) -> Dict[str, Any]:
"""条件执行计划"""
results = []
execution_log = []
# 找到条件检查任务
condition_task = None
branch_tasks = []
for task in plan:
if task.get("type") == "condition":
condition_task = task
elif task.get("type") == "branch":
branch_tasks.append(task)
if not condition_task:
logger.error("条件计划中缺少条件检查任务")
return {"success": False, "error": "缺少条件检查任务"}
# 执行条件检查
condition_result = await self._execute_single_task(condition_task, tool_manager, context)
results.append({
"task_id": condition_task.get("id"),
"result": condition_result,
"timestamp": datetime.now().isoformat()
})
# 根据条件结果选择分支
selected_branch = self._select_branch(condition_result, branch_tasks)
if selected_branch:
# 执行选中的分支
branch_result = await self._execute_sequential(
selected_branch.get("tasks", []),
tool_manager,
context,
execution_id
)
results.extend(branch_result.get("results", []))
execution_log.extend(branch_result.get("execution_log", []))
return {
"success": True,
"results": results,
"execution_log": execution_log,
"execution_id": execution_id,
"selected_branch": selected_branch.get("id") if selected_branch else None
}
async def _execute_iterative(
self,
plan: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any],
execution_id: str
) -> Dict[str, Any]:
"""迭代执行计划"""
# 找到迭代控制任务
iteration_task = None
for task in plan:
if task.get("type") == "iteration_control":
iteration_task = task
break
if not iteration_task:
logger.error("迭代计划中缺少迭代控制任务")
return {"success": False, "error": "缺少迭代控制任务"}
max_iterations = iteration_task.get("max_iterations", 10)
convergence_criteria = iteration_task.get("convergence_criteria", {})
tasks = iteration_task.get("tasks", [])
results = []
execution_log = []
iteration_count = 0
while iteration_count < max_iterations:
iteration_count += 1
logger.info(f"执行第 {iteration_count} 次迭代")
# 执行迭代任务
iteration_result = await self._execute_sequential(
tasks, tool_manager, context, f"{execution_id}_iter_{iteration_count}"
)
results.append({
"iteration": iteration_count,
"result": iteration_result,
"timestamp": datetime.now().isoformat()
})
# 检查收敛条件
if self._check_convergence(iteration_result, convergence_criteria):
logger.info(f"迭代在第 {iteration_count} 次收敛")
break
return {
"success": True,
"results": results,
"execution_log": execution_log,
"execution_id": execution_id,
"iterations": iteration_count,
"converged": iteration_count < max_iterations
}
async def _execute_single_task(
self,
task: Dict[str, Any],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行单个任务"""
start_time = datetime.now()
try:
task_id = task.get("id", "unknown")
task_type = task.get("type", "action")
tool_name = task.get("tool", "")
parameters = task.get("parameters", {})
logger.info(f"执行任务: {task_id}, 类型: {task_type}, 工具: {tool_name}")
# 根据任务类型执行
if task_type == "action":
result = await self._execute_action_task(task, tool_manager, context)
elif task_type == "condition":
result = await self._execute_condition_task(task, tool_manager, context)
elif task_type == "control":
result = await self._execute_control_task(task, tool_manager, context)
else:
result = await self._execute_general_task(task, tool_manager, context)
duration = (datetime.now() - start_time).total_seconds()
result["duration"] = duration
logger.info(f"任务 {task_id} 执行完成,耗时: {duration:.2f}")
return result
except Exception as e:
logger.error(f"执行任务失败: {e}")
return {
"success": False,
"error": str(e),
"duration": (datetime.now() - start_time).total_seconds()
}
async def _execute_action_task(
self,
task: Dict[str, Any],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行动作任务"""
tool_name = task.get("tool", "")
parameters = task.get("parameters", {})
# 合并上下文参数
full_parameters = {**parameters, **context}
# 调用工具
result = await tool_manager.execute_tool(tool_name, full_parameters)
return {
"success": True,
"tool": tool_name,
"parameters": full_parameters,
"result": result
}
async def _execute_condition_task(
self,
task: Dict[str, Any],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行条件任务"""
condition = task.get("condition", "")
branches = task.get("branches", {})
# 评估条件
condition_result = await self._evaluate_condition(condition, context)
return {
"success": True,
"condition": condition,
"result": condition_result,
"available_branches": list(branches.keys())
}
async def _execute_control_task(
self,
task: Dict[str, Any],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行控制任务"""
control_type = task.get("control_type", "general")
if control_type == "iteration":
return await self._execute_iteration_control(task, context)
elif control_type == "loop":
return await self._execute_loop_control(task, context)
else:
return {
"success": True,
"control_type": control_type,
"message": "控制任务执行完成"
}
async def _execute_general_task(
self,
task: Dict[str, Any],
tool_manager: Any,
context: Dict[str, Any]
) -> Dict[str, Any]:
"""执行通用任务"""
description = task.get("description", "")
# 这里可以实现通用的任务执行逻辑
# 例如调用LLM生成响应、执行数据库操作等
return {
"success": True,
"description": description,
"message": "通用任务执行完成"
}
async def _execute_tasks_parallel(
self,
tasks: List[Dict[str, Any]],
tool_manager: Any,
context: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""并行执行多个任务"""
async def execute_task(task):
return await self._execute_single_task(task, tool_manager, context)
# 创建并行任务
parallel_tasks = [execute_task(task) for task in tasks]
# 等待所有任务完成
results = await asyncio.gather(*parallel_tasks, return_exceptions=True)
# 处理结果
processed_results = []
for i, result in enumerate(results):
if isinstance(result, Exception):
processed_results.append({
"task_id": tasks[i].get("id"),
"result": {"success": False, "error": str(result)},
"timestamp": datetime.now().isoformat()
})
else:
processed_results.append({
"task_id": tasks[i].get("id"),
"result": result,
"timestamp": datetime.now().isoformat()
})
return processed_results
def _group_tasks_for_parallel_execution(self, plan: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""将任务分组以便并行执行"""
groups = []
current_group = []
for task in plan:
if task.get("type") == "parallel_group":
if current_group:
groups.append({
"execution_mode": "sequential",
"tasks": current_group
})
current_group = []
groups.append(task)
else:
current_group.append(task)
if current_group:
groups.append({
"execution_mode": "sequential",
"tasks": current_group
})
return groups
async def _check_dependencies(self, task: Dict[str, Any], results: List[Dict[str, Any]]) -> bool:
"""检查任务依赖是否满足"""
dependencies = task.get("dependencies", [])
if not dependencies:
return True
# 检查所有依赖是否已完成
completed_task_ids = [r["task_id"] for r in results if r["result"].get("success", False)]
for dep in dependencies:
if dep not in completed_task_ids:
return False
return True
def _check_success_criteria(self, task: Dict[str, Any], result: Dict[str, Any]) -> bool:
"""检查任务是否满足成功条件"""
success_criteria = task.get("success_criteria", {})
if not success_criteria:
return result.get("success", False)
# 检查每个成功条件
for criterion, expected_value in success_criteria.items():
actual_value = result.get(criterion)
if actual_value != expected_value:
return False
return True
def _select_branch(self, condition_result: Dict[str, Any], branch_tasks: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""根据条件结果选择分支"""
condition_value = condition_result.get("result", "")
for branch_task in branch_tasks:
branch_condition = branch_task.get("condition", "")
if branch_condition == condition_value:
return branch_task
return None
def _check_convergence(self, iteration_result: Dict[str, Any], convergence_criteria: Dict[str, Any]) -> bool:
"""检查迭代是否收敛"""
if not convergence_criteria:
return False
# 检查收敛条件
for criterion, threshold in convergence_criteria.items():
actual_value = iteration_result.get(criterion)
if actual_value is None:
continue
# 这里可以实现更复杂的收敛判断逻辑
if isinstance(threshold, dict):
if threshold.get("type") == "less_than":
if actual_value >= threshold.get("value"):
return False
elif threshold.get("type") == "greater_than":
if actual_value <= threshold.get("value"):
return False
return True
async def _evaluate_condition(self, condition: str, context: Dict[str, Any]) -> str:
"""评估条件表达式"""
# 这里可以实现条件评估逻辑
# 例如:解析条件表达式、查询上下文等
# 简单的条件评估示例
if "satisfaction" in condition:
return "high" if context.get("satisfaction_score", 0) > 0.7 else "low"
elif "priority" in condition:
return context.get("priority", "medium")
else:
return "default"
async def _execute_iteration_control(self, task: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
"""执行迭代控制"""
max_iterations = task.get("max_iterations", 10)
current_iteration = context.get("current_iteration", 0)
return {
"success": True,
"max_iterations": max_iterations,
"current_iteration": current_iteration,
"continue": current_iteration < max_iterations
}
async def _execute_loop_control(self, task: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
"""执行循环控制"""
loop_condition = task.get("loop_condition", "")
return {
"success": True,
"loop_condition": loop_condition,
"continue": True # 这里应该根据实际条件判断
}
def get_execution_status(self, execution_id: str) -> Optional[Dict[str, Any]]:
"""获取执行状态"""
return self.active_executions.get(execution_id)
def get_all_executions(self) -> Dict[str, Any]:
"""获取所有执行记录"""
return self.active_executions

View File

@@ -1,573 +0,0 @@
# -*- coding: utf-8 -*-
"""
目标管理器
负责目标设定、跟踪和评估
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
import json
from ..core.llm_client import QwenClient
logger = logging.getLogger(__name__)
class GoalManager:
"""目标管理器"""
def __init__(self):
self.llm_client = QwenClient()
self.active_goals = {}
self.goal_history = []
self.goal_templates = {
"problem_solving": self._create_problem_solving_goal,
"information_gathering": self._create_information_gathering_goal,
"task_execution": self._create_task_execution_goal,
"analysis": self._create_analysis_goal,
"communication": self._create_communication_goal
}
async def create_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建目标"""
try:
goal_type = self._determine_goal_type(intent, request)
if goal_type in self.goal_templates:
goal = await self.goal_templates[goal_type](intent, request, current_state)
else:
goal = await self._create_general_goal(intent, request, current_state)
# 生成唯一目标ID
goal_id = f"goal_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
goal["id"] = goal_id
goal["created_at"] = datetime.now().isoformat()
goal["status"] = "active"
# 添加到活跃目标
self.active_goals[goal_id] = goal
logger.info(f"创建目标: {goal_id}, 类型: {goal_type}")
return goal
except Exception as e:
logger.error(f"创建目标失败: {e}")
return self._create_fallback_goal(intent, request)
def _determine_goal_type(self, intent: Dict[str, Any], request: Dict[str, Any]) -> str:
"""确定目标类型"""
main_intent = intent.get("main_intent", "general_query")
goal_type_mapping = {
"problem_solving": ["problem_consultation", "issue_resolution", "troubleshooting"],
"information_gathering": ["information_query", "data_collection", "research"],
"task_execution": ["work_order_creation", "task_assignment", "action_request"],
"analysis": ["data_analysis", "report_generation", "performance_review"],
"communication": ["notification", "message_delivery", "user_interaction"]
}
for goal_type, intents in goal_type_mapping.items():
if main_intent in intents:
return goal_type
return "general"
async def _create_problem_solving_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建问题解决目标"""
prompt = f"""
请为以下问题解决请求创建目标:
用户意图: {json.dumps(intent, ensure_ascii=False)}
请求内容: {json.dumps(request, ensure_ascii=False)}
请定义:
1. 目标描述
2. 成功标准
3. 所需步骤
4. 预期结果
5. 时间限制
6. 资源需求
请以JSON格式返回目标定义。
"""
messages = [
{"role": "system", "content": "你是一个目标设定专家,擅长为问题解决任务设定清晰的目标。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_default_problem_solving_goal(intent, request)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
goal_data = json.loads(json_match.group())
goal_data["type"] = "problem_solving"
return goal_data
else:
return self._create_default_problem_solving_goal(intent, request)
async def _create_information_gathering_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建信息收集目标"""
prompt = f"""
请为以下信息收集请求创建目标:
用户意图: {json.dumps(intent, ensure_ascii=False)}
请求内容: {json.dumps(request, ensure_ascii=False)}
请定义:
1. 信息收集范围
2. 信息质量要求
3. 收集方法
4. 验证标准
5. 整理格式
请以JSON格式返回目标定义。
"""
messages = [
{"role": "system", "content": "你是一个信息收集专家,擅长设定信息收集目标。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_default_information_goal(intent, request)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
goal_data = json.loads(json_match.group())
goal_data["type"] = "information_gathering"
return goal_data
else:
return self._create_default_information_goal(intent, request)
async def _create_task_execution_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建任务执行目标"""
prompt = f"""
请为以下任务执行请求创建目标:
用户意图: {json.dumps(intent, ensure_ascii=False)}
请求内容: {json.dumps(request, ensure_ascii=False)}
请定义:
1. 任务描述
2. 执行步骤
3. 完成标准
4. 质量要求
5. 时间安排
请以JSON格式返回目标定义。
"""
messages = [
{"role": "system", "content": "你是一个任务执行专家,擅长设定任务执行目标。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_default_task_goal(intent, request)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
goal_data = json.loads(json_match.group())
goal_data["type"] = "task_execution"
return goal_data
else:
return self._create_default_task_goal(intent, request)
async def _create_analysis_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建分析目标"""
prompt = f"""
请为以下分析请求创建目标:
用户意图: {json.dumps(intent, ensure_ascii=False)}
请求内容: {json.dumps(request, ensure_ascii=False)}
请定义:
1. 分析范围
2. 分析方法
3. 分析深度
4. 输出格式
5. 质量指标
请以JSON格式返回目标定义。
"""
messages = [
{"role": "system", "content": "你是一个分析专家,擅长设定分析目标。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_default_analysis_goal(intent, request)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
goal_data = json.loads(json_match.group())
goal_data["type"] = "analysis"
return goal_data
else:
return self._create_default_analysis_goal(intent, request)
async def _create_communication_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建沟通目标"""
prompt = f"""
请为以下沟通请求创建目标:
用户意图: {json.dumps(intent, ensure_ascii=False)}
请求内容: {json.dumps(request, ensure_ascii=False)}
请定义:
1. 沟通对象
2. 沟通内容
3. 沟通方式
4. 预期效果
5. 反馈机制
请以JSON格式返回目标定义。
"""
messages = [
{"role": "system", "content": "你是一个沟通专家,擅长设定沟通目标。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_default_communication_goal(intent, request)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
goal_data = json.loads(json_match.group())
goal_data["type"] = "communication"
return goal_data
else:
return self._create_default_communication_goal(intent, request)
async def _create_general_goal(
self,
intent: Dict[str, Any],
request: Dict[str, Any],
current_state: Any
) -> Dict[str, Any]:
"""创建通用目标"""
return {
"type": "general",
"description": intent.get("main_intent", "处理用户请求"),
"success_criteria": {
"completion": True,
"user_satisfaction": 0.7
},
"steps": ["理解请求", "执行任务", "返回结果"],
"expected_result": "用户需求得到满足",
"time_limit": 300, # 5分钟
"resource_requirements": ["llm_client", "knowledge_base"]
}
def _create_default_problem_solving_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建默认问题解决目标"""
return {
"type": "problem_solving",
"description": "解决用户问题",
"success_criteria": {
"problem_identified": True,
"solution_provided": True,
"user_satisfaction": 0.7
},
"steps": ["分析问题", "寻找解决方案", "提供建议", "验证效果"],
"expected_result": "问题得到解决或提供有效建议",
"time_limit": 300,
"resource_requirements": ["knowledge_base", "llm_client"]
}
def _create_default_information_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建默认信息收集目标"""
return {
"type": "information_gathering",
"description": "收集相关信息",
"success_criteria": {
"information_complete": True,
"information_accurate": True,
"information_relevant": True
},
"steps": ["确定信息需求", "搜索信息源", "收集信息", "整理信息"],
"expected_result": "提供准确、完整、相关的信息",
"time_limit": 180,
"resource_requirements": ["knowledge_base", "search_tools"]
}
def _create_default_task_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建默认任务执行目标"""
return {
"type": "task_execution",
"description": "执行指定任务",
"success_criteria": {
"task_completed": True,
"quality_met": True,
"time_met": True
},
"steps": ["理解任务", "制定计划", "执行任务", "验证结果"],
"expected_result": "任务成功完成",
"time_limit": 600,
"resource_requirements": ["task_tools", "monitoring"]
}
def _create_default_analysis_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建默认分析目标"""
return {
"type": "analysis",
"description": "执行数据分析",
"success_criteria": {
"analysis_complete": True,
"insights_meaningful": True,
"report_clear": True
},
"steps": ["收集数据", "分析数据", "提取洞察", "生成报告"],
"expected_result": "提供有价值的分析报告",
"time_limit": 900,
"resource_requirements": ["analytics_tools", "data_sources"]
}
def _create_default_communication_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建默认沟通目标"""
return {
"type": "communication",
"description": "与用户沟通",
"success_criteria": {
"message_delivered": True,
"response_received": True,
"understanding_achieved": True
},
"steps": ["准备消息", "发送消息", "等待响应", "确认理解"],
"expected_result": "成功沟通并达成理解",
"time_limit": 120,
"resource_requirements": ["communication_tools"]
}
def _create_fallback_goal(self, intent: Dict[str, Any], request: Dict[str, Any]) -> Dict[str, Any]:
"""创建备用目标"""
return {
"type": "fallback",
"description": "处理用户请求",
"success_criteria": {"completion": True},
"steps": ["处理请求"],
"expected_result": "返回响应",
"time_limit": 60,
"resource_requirements": ["basic_tools"]
}
async def update_goal_progress(self, goal_id: str, progress_data: Dict[str, Any]) -> bool:
"""更新目标进度"""
try:
if goal_id not in self.active_goals:
return False
goal = self.active_goals[goal_id]
goal["progress"] = progress_data
goal["updated_at"] = datetime.now().isoformat()
# 检查是否完成
if self._check_goal_completion(goal):
goal["status"] = "completed"
goal["completed_at"] = datetime.now().isoformat()
# 移动到历史记录
self.goal_history.append(goal)
del self.active_goals[goal_id]
logger.info(f"目标 {goal_id} 已完成")
return True
except Exception as e:
logger.error(f"更新目标进度失败: {e}")
return False
def _check_goal_completion(self, goal: Dict[str, Any]) -> bool:
"""检查目标是否完成"""
success_criteria = goal.get("success_criteria", {})
if not success_criteria:
return True
progress = goal.get("progress", {})
# 检查每个成功标准
for criterion, required_value in success_criteria.items():
actual_value = progress.get(criterion)
if actual_value != required_value:
return False
return True
async def evaluate_goal_performance(self, goal_id: str) -> Dict[str, Any]:
"""评估目标性能"""
try:
if goal_id in self.active_goals:
goal = self.active_goals[goal_id]
elif goal_id in [g["id"] for g in self.goal_history]:
goal = next(g for g in self.goal_history if g["id"] == goal_id)
else:
return {"error": "目标不存在"}
evaluation = {
"goal_id": goal_id,
"type": goal.get("type"),
"status": goal.get("status"),
"created_at": goal.get("created_at"),
"completed_at": goal.get("completed_at"),
"duration": self._calculate_goal_duration(goal),
"success_rate": self._calculate_success_rate(goal),
"efficiency": self._calculate_efficiency(goal),
"quality_score": self._calculate_quality_score(goal)
}
return evaluation
except Exception as e:
logger.error(f"评估目标性能失败: {e}")
return {"error": str(e)}
def _calculate_goal_duration(self, goal: Dict[str, Any]) -> float:
"""计算目标持续时间"""
created_at = datetime.fromisoformat(goal.get("created_at", datetime.now().isoformat()))
if goal.get("completed_at"):
completed_at = datetime.fromisoformat(goal["completed_at"])
return (completed_at - created_at).total_seconds()
else:
return (datetime.now() - created_at).total_seconds()
def _calculate_success_rate(self, goal: Dict[str, Any]) -> float:
"""计算成功率"""
if goal.get("status") == "completed":
return 1.0
elif goal.get("status") == "failed":
return 0.0
else:
# 根据进度计算部分成功率
progress = goal.get("progress", {})
success_criteria = goal.get("success_criteria", {})
if not success_criteria:
return 0.5
completed_criteria = 0
for criterion in success_criteria:
if progress.get(criterion) == success_criteria[criterion]:
completed_criteria += 1
return completed_criteria / len(success_criteria)
def _calculate_efficiency(self, goal: Dict[str, Any]) -> float:
"""计算效率"""
duration = self._calculate_goal_duration(goal)
time_limit = goal.get("time_limit", 300)
if duration <= time_limit:
return 1.0
else:
# 超时惩罚
return max(0.0, 1.0 - (duration - time_limit) / time_limit)
def _calculate_quality_score(self, goal: Dict[str, Any]) -> float:
"""计算质量分数"""
# 这里可以根据具体的目标类型和质量指标计算
# 暂时返回一个基于成功率的简单计算
success_rate = self._calculate_success_rate(goal)
efficiency = self._calculate_efficiency(goal)
return (success_rate + efficiency) / 2
def get_active_goals(self) -> List[Dict[str, Any]]:
"""获取活跃目标"""
return list(self.active_goals.values())
def get_goal_history(self, limit: int = 10) -> List[Dict[str, Any]]:
"""获取目标历史"""
return self.goal_history[-limit:] if self.goal_history else []
def get_goal_statistics(self) -> Dict[str, Any]:
"""获取目标统计"""
total_goals = len(self.active_goals) + len(self.goal_history)
completed_goals = len([g for g in self.goal_history if g.get("status") == "completed"])
active_goals = len(self.active_goals)
return {
"total_goals": total_goals,
"active_goals": active_goals,
"completed_goals": completed_goals,
"completion_rate": completed_goals / total_goals if total_goals > 0 else 0,
"goal_types": self._get_goal_type_distribution()
}
def _get_goal_type_distribution(self) -> Dict[str, int]:
"""获取目标类型分布"""
distribution = {}
# 统计活跃目标
for goal in self.active_goals.values():
goal_type = goal.get("type", "unknown")
distribution[goal_type] = distribution.get(goal_type, 0) + 1
# 统计历史目标
for goal in self.goal_history:
goal_type = goal.get("type", "unknown")
distribution[goal_type] = distribution.get(goal_type, 0) + 1
return distribution

View File

@@ -1,371 +0,0 @@
# -*- coding: utf-8 -*-
"""
智能Agent核心 - 集成大模型和智能决策
高效实现Agent的智能处理能力
"""
import logging
import asyncio
import json
from typing import Dict, Any, List, Optional, Tuple
from datetime import datetime
from dataclasses import dataclass
from enum import Enum
logger = logging.getLogger(__name__)
class ActionType(Enum):
"""动作类型枚举"""
ALERT_RESPONSE = "alert_response"
KNOWLEDGE_UPDATE = "knowledge_update"
WORKORDER_CREATE = "workorder_create"
SYSTEM_OPTIMIZE = "system_optimize"
USER_NOTIFY = "user_notify"
class ConfidenceLevel(Enum):
"""置信度等级"""
HIGH = "high" # 高置信度 (>0.8)
MEDIUM = "medium" # 中等置信度 (0.5-0.8)
LOW = "low" # 低置信度 (<0.5)
@dataclass
class AgentAction:
"""Agent动作"""
action_type: ActionType
description: str
priority: int # 1-5, 5最高
confidence: float # 0-1
parameters: Dict[str, Any]
estimated_time: int # 预计执行时间(秒)
@dataclass
class AlertContext:
"""预警上下文"""
alert_id: str
alert_type: str
severity: str
description: str
affected_systems: List[str]
metrics: Dict[str, Any]
@dataclass
class KnowledgeContext:
"""知识库上下文"""
question: str
answer: str
confidence: float
source: str
category: str
class IntelligentAgent:
"""智能Agent核心"""
def __init__(self, llm_client=None):
self.llm_client = llm_client
self.action_history = []
self.learning_data = {}
self.confidence_thresholds = {
'high': 0.8,
'medium': 0.5,
'low': 0.3
}
async def process_alert(self, alert_context: AlertContext) -> List[AgentAction]:
"""处理预警信息,生成智能动作"""
try:
# 构建预警分析提示
prompt = self._build_alert_analysis_prompt(alert_context)
# 调用大模型分析
analysis = await self._call_llm(prompt)
# 解析动作
actions = self._parse_alert_actions(analysis, alert_context)
# 按优先级排序
actions.sort(key=lambda x: x.priority, reverse=True)
return actions
except Exception as e:
logger.error(f"处理预警失败: {e}")
return [self._create_default_alert_action(alert_context)]
async def process_knowledge_confidence(self, knowledge_context: KnowledgeContext) -> List[AgentAction]:
"""处理知识库置信度问题"""
try:
if knowledge_context.confidence >= self.confidence_thresholds['high']:
return [] # 高置信度,无需处理
# 构建知识增强提示
prompt = self._build_knowledge_enhancement_prompt(knowledge_context)
# 调用大模型增强知识
enhancement = await self._call_llm(prompt)
# 生成增强动作
actions = self._parse_knowledge_actions(enhancement, knowledge_context)
return actions
except Exception as e:
logger.error(f"处理知识库置信度失败: {e}")
return [self._create_default_knowledge_action(knowledge_context)]
async def execute_action(self, action: AgentAction) -> Dict[str, Any]:
"""执行Agent动作"""
try:
logger.info(f"执行Agent动作: {action.action_type.value} - {action.description}")
if action.action_type == ActionType.ALERT_RESPONSE:
return await self._execute_alert_response(action)
elif action.action_type == ActionType.KNOWLEDGE_UPDATE:
return await self._execute_knowledge_update(action)
elif action.action_type == ActionType.WORKORDER_CREATE:
return await self._execute_workorder_create(action)
elif action.action_type == ActionType.SYSTEM_OPTIMIZE:
return await self._execute_system_optimize(action)
elif action.action_type == ActionType.USER_NOTIFY:
return await self._execute_user_notify(action)
else:
return {"success": False, "error": "未知动作类型"}
except Exception as e:
logger.error(f"执行动作失败: {e}")
return {"success": False, "error": str(e)}
def _build_alert_analysis_prompt(self, alert_context: AlertContext) -> str:
"""构建预警分析提示"""
return f"""
作为TSP智能助手请分析以下预警信息并提供处理建议
预警信息:
- 类型: {alert_context.alert_type}
- 严重程度: {alert_context.severity}
- 描述: {alert_context.description}
- 影响系统: {', '.join(alert_context.affected_systems)}
- 指标数据: {json.dumps(alert_context.metrics, ensure_ascii=False)}
请提供以下格式的JSON响应
{{
"analysis": "预警原因分析",
"immediate_actions": [
{{
"action": "立即执行的动作",
"priority": 5,
"confidence": 0.9,
"parameters": {{"key": "value"}}
}}
],
"follow_up_actions": [
{{
"action": "后续跟进动作",
"priority": 3,
"confidence": 0.7,
"parameters": {{"key": "value"}}
}}
],
"prevention_measures": [
"预防措施1",
"预防措施2"
]
}}
"""
def _build_knowledge_enhancement_prompt(self, knowledge_context: KnowledgeContext) -> str:
"""构建知识增强提示"""
return f"""
作为TSP智能助手请分析以下知识库条目并提供增强建议
知识条目:
- 问题: {knowledge_context.question}
- 答案: {knowledge_context.answer}
- 置信度: {knowledge_context.confidence}
- 来源: {knowledge_context.source}
- 分类: {knowledge_context.category}
请提供以下格式的JSON响应
{{
"confidence_analysis": "置信度分析",
"enhancement_suggestions": [
"增强建议1",
"增强建议2"
],
"actions": [
{{
"action": "知识更新动作",
"priority": 4,
"confidence": 0.8,
"parameters": {{"enhanced_answer": "增强后的答案"}}
}}
],
"learning_opportunities": [
"学习机会1",
"学习机会2"
]
}}
"""
async def _call_llm(self, prompt: str) -> Dict[str, Any]:
"""调用大模型"""
try:
if self.llm_client:
# 使用真实的大模型客户端
response = await self.llm_client.generate(prompt)
return json.loads(response)
else:
# 模拟大模型响应
return self._simulate_llm_response(prompt)
except Exception as e:
logger.error(f"调用大模型失败: {e}")
return self._simulate_llm_response(prompt)
def _simulate_llm_response(self, prompt: str) -> Dict[str, Any]:
"""模拟大模型响应 - 千问模型风格"""
if "预警信息" in prompt:
return {
"analysis": "【千问分析】系统性能下降,需要立即处理。根据历史数据分析,这可能是由于资源不足或配置问题导致的。",
"immediate_actions": [
{
"action": "重启相关服务",
"priority": 5,
"confidence": 0.9,
"parameters": {"service": "main_service", "reason": "服务响应超时"}
}
],
"follow_up_actions": [
{
"action": "检查系统日志",
"priority": 3,
"confidence": 0.7,
"parameters": {"log_level": "error", "time_range": "last_hour"}
}
],
"prevention_measures": [
"增加监控频率,提前发现问题",
"优化系统配置,提升性能",
"建立预警机制,减少故障影响"
]
}
else:
return {
"confidence_analysis": "【千问分析】当前答案置信度较低,需要更多上下文信息。建议结合用户反馈和历史工单数据来提升答案质量。",
"enhancement_suggestions": [
"添加更多实际案例和操作步骤",
"提供详细的故障排除指南",
"结合系统架构图进行说明"
],
"actions": [
{
"action": "更新知识库条目",
"priority": 4,
"confidence": 0.8,
"parameters": {"enhanced_answer": "基于千问模型分析的增强答案"}
}
],
"learning_opportunities": [
"收集用户反馈,持续优化答案",
"分析相似问题,建立知识关联",
"利用千问模型的学习能力,提升知识质量"
]
}
def _parse_alert_actions(self, analysis: Dict[str, Any], alert_context: AlertContext) -> List[AgentAction]:
"""解析预警动作"""
actions = []
# 立即动作
for action_data in analysis.get("immediate_actions", []):
action = AgentAction(
action_type=ActionType.ALERT_RESPONSE,
description=action_data["action"],
priority=action_data["priority"],
confidence=action_data["confidence"],
parameters=action_data["parameters"],
estimated_time=30
)
actions.append(action)
# 后续动作
for action_data in analysis.get("follow_up_actions", []):
action = AgentAction(
action_type=ActionType.SYSTEM_OPTIMIZE,
description=action_data["action"],
priority=action_data["priority"],
confidence=action_data["confidence"],
parameters=action_data["parameters"],
estimated_time=300
)
actions.append(action)
return actions
def _parse_knowledge_actions(self, enhancement: Dict[str, Any], knowledge_context: KnowledgeContext) -> List[AgentAction]:
"""解析知识库动作"""
actions = []
for action_data in enhancement.get("actions", []):
action = AgentAction(
action_type=ActionType.KNOWLEDGE_UPDATE,
description=action_data["action"],
priority=action_data["priority"],
confidence=action_data["confidence"],
parameters=action_data["parameters"],
estimated_time=60
)
actions.append(action)
return actions
def _create_default_alert_action(self, alert_context: AlertContext) -> AgentAction:
"""创建默认预警动作"""
return AgentAction(
action_type=ActionType.USER_NOTIFY,
description=f"通知管理员处理{alert_context.alert_type}预警",
priority=3,
confidence=0.5,
parameters={"alert_id": alert_context.alert_id},
estimated_time=10
)
def _create_default_knowledge_action(self, knowledge_context: KnowledgeContext) -> AgentAction:
"""创建默认知识库动作"""
return AgentAction(
action_type=ActionType.KNOWLEDGE_UPDATE,
description="标记低置信度知识条目,等待人工审核",
priority=2,
confidence=0.3,
parameters={"question": knowledge_context.question},
estimated_time=5
)
async def _execute_alert_response(self, action: AgentAction) -> Dict[str, Any]:
"""执行预警响应动作"""
# 这里实现具体的预警响应逻辑
logger.info(f"执行预警响应: {action.description}")
return {"success": True, "message": "预警响应已执行"}
async def _execute_knowledge_update(self, action: AgentAction) -> Dict[str, Any]:
"""执行知识库更新动作"""
# 这里实现具体的知识库更新逻辑
logger.info(f"执行知识库更新: {action.description}")
return {"success": True, "message": "知识库已更新"}
async def _execute_workorder_create(self, action: AgentAction) -> Dict[str, Any]:
"""执行工单创建动作"""
# 这里实现具体的工单创建逻辑
logger.info(f"执行工单创建: {action.description}")
return {"success": True, "message": "工单已创建"}
async def _execute_system_optimize(self, action: AgentAction) -> Dict[str, Any]:
"""执行系统优化动作"""
# 这里实现具体的系统优化逻辑
logger.info(f"执行系统优化: {action.description}")
return {"success": True, "message": "系统优化已执行"}
async def _execute_user_notify(self, action: AgentAction) -> Dict[str, Any]:
"""执行用户通知动作"""
# 这里实现具体的用户通知逻辑
logger.info(f"执行用户通知: {action.description}")
return {"success": True, "message": "用户已通知"}

View File

@@ -1,409 +0,0 @@
# -*- coding: utf-8 -*-
"""
任务规划器
负责制定执行计划和任务分解
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
import json
from ..core.llm_client import QwenClient
logger = logging.getLogger(__name__)
class TaskPlanner:
"""任务规划器"""
def __init__(self):
self.llm_client = QwenClient()
self.planning_strategies = {
"sequential": self._create_sequential_plan,
"parallel": self._create_parallel_plan,
"conditional": self._create_conditional_plan,
"iterative": self._create_iterative_plan
}
async def create_plan(
self,
goal: Dict[str, Any],
available_tools: List[Dict[str, Any]],
constraints: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""创建执行计划"""
try:
# 1. 分析目标复杂度
complexity = await self._analyze_goal_complexity(goal)
# 2. 选择规划策略
strategy = self._select_planning_strategy(complexity, goal)
# 3. 生成计划
plan = await self.planning_strategies[strategy](goal, available_tools, constraints)
# 4. 优化计划
optimized_plan = await self._optimize_plan(plan, constraints)
logger.info(f"创建计划成功,包含 {len(optimized_plan)} 个任务")
return optimized_plan
except Exception as e:
logger.error(f"创建计划失败: {e}")
return []
async def _analyze_goal_complexity(self, goal: Dict[str, Any]) -> Dict[str, Any]:
"""分析目标复杂度"""
prompt = f"""
请分析以下目标的复杂度:
目标: {goal.get('description', '')}
类型: {goal.get('type', '')}
上下文: {goal.get('context', {})}
请从以下维度评估复杂度1-10分
1. 任务数量
2. 依赖关系复杂度
3. 所需工具数量
4. 时间要求
5. 资源需求
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个任务规划专家,擅长分析任务复杂度。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"complexity_score": 5, "strategy": "sequential"}
try:
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
analysis = json.loads(json_match.group())
return analysis
else:
return {"complexity_score": 5, "strategy": "sequential"}
except Exception as e:
logger.error(f"解析复杂度分析失败: {e}")
return {"complexity_score": 5, "strategy": "sequential"}
def _select_planning_strategy(self, complexity: Dict[str, Any], goal: Dict[str, Any]) -> str:
"""选择规划策略"""
complexity_score = complexity.get("complexity_score", 5)
goal_type = goal.get("type", "general")
if complexity_score <= 3:
return "sequential"
elif complexity_score <= 6:
if goal_type in ["analysis", "monitoring"]:
return "parallel"
else:
return "conditional"
else:
return "iterative"
async def _create_sequential_plan(
self,
goal: Dict[str, Any],
available_tools: List[Dict[str, Any]],
constraints: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""创建顺序执行计划"""
prompt = f"""
请为以下目标创建一个顺序执行计划:
目标: {goal.get('description', '')}
可用工具: {[tool.get('name', '') for tool in available_tools]}
请将目标分解为具体的执行步骤,每个步骤包含:
1. 任务描述
2. 所需工具
3. 输入参数
4. 预期输出
5. 成功条件
请以JSON数组格式返回计划。
"""
messages = [
{"role": "system", "content": "你是一个任务规划专家,擅长创建顺序执行计划。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_fallback_plan(goal)
try:
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\[.*\]', response_content, re.DOTALL)
if json_match:
plan = json.loads(json_match.group())
return self._format_plan_tasks(plan)
else:
return self._create_fallback_plan(goal)
except Exception as e:
logger.error(f"解析顺序计划失败: {e}")
return self._create_fallback_plan(goal)
async def _create_parallel_plan(
self,
goal: Dict[str, Any],
available_tools: List[Dict[str, Any]],
constraints: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""创建并行执行计划"""
# 先创建基础任务
base_tasks = await self._create_sequential_plan(goal, available_tools, constraints)
# 分析任务间的依赖关系
parallel_groups = self._group_parallel_tasks(base_tasks)
return parallel_groups
async def _create_conditional_plan(
self,
goal: Dict[str, Any],
available_tools: List[Dict[str, Any]],
constraints: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""创建条件执行计划"""
prompt = f"""
请为以下目标创建一个条件执行计划:
目标: {goal.get('description', '')}
上下文: {goal.get('context', {})}
计划应该包含:
1. 初始条件检查
2. 分支逻辑
3. 每个分支的具体任务
4. 合并条件
请以JSON格式返回计划。
"""
messages = [
{"role": "system", "content": "你是一个任务规划专家,擅长创建条件执行计划。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return await self._create_sequential_plan(goal, available_tools, constraints)
try:
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
plan = json.loads(json_match.group())
return self._format_conditional_plan(plan)
else:
return await self._create_sequential_plan(goal, available_tools, constraints)
except Exception as e:
logger.error(f"解析条件计划失败: {e}")
return await self._create_sequential_plan(goal, available_tools, constraints)
async def _create_iterative_plan(
self,
goal: Dict[str, Any],
available_tools: List[Dict[str, Any]],
constraints: Dict[str, Any]
) -> List[Dict[str, Any]]:
"""创建迭代执行计划"""
# 创建基础计划
base_plan = await self._create_sequential_plan(goal, available_tools, constraints)
# 添加迭代控制任务
iteration_control = {
"id": "iteration_control",
"type": "control",
"description": "迭代控制",
"max_iterations": constraints.get("max_iterations", 10),
"convergence_criteria": goal.get("success_criteria", {}),
"tasks": base_plan
}
return [iteration_control]
def _group_parallel_tasks(self, tasks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""将任务分组为可并行执行的任务组"""
groups = []
current_group = []
for task in tasks:
# 简单的分组逻辑:相同类型的任务可以并行
if not current_group or current_group[0].get("type") == task.get("type"):
current_group.append(task)
else:
if current_group:
groups.append({
"type": "parallel_group",
"tasks": current_group,
"execution_mode": "parallel"
})
current_group = [task]
if current_group:
groups.append({
"type": "parallel_group",
"tasks": current_group,
"execution_mode": "parallel"
})
return groups
def _format_plan_tasks(self, raw_plan: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""格式化计划任务"""
formatted_tasks = []
for i, task in enumerate(raw_plan):
formatted_task = {
"id": f"task_{i+1}",
"type": task.get("type", "action"),
"description": task.get("description", ""),
"tool": task.get("tool", ""),
"parameters": task.get("parameters", {}),
"expected_output": task.get("expected_output", ""),
"success_criteria": task.get("success_criteria", {}),
"dependencies": task.get("dependencies", []),
"priority": task.get("priority", 0.5),
"timeout": task.get("timeout", 60)
}
formatted_tasks.append(formatted_task)
return formatted_tasks
def _format_conditional_plan(self, raw_plan: Dict[str, Any]) -> List[Dict[str, Any]]:
"""格式化条件计划"""
formatted_tasks = []
# 添加条件检查任务
condition_task = {
"id": "condition_check",
"type": "condition",
"description": "条件检查",
"condition": raw_plan.get("condition", ""),
"branches": raw_plan.get("branches", {})
}
formatted_tasks.append(condition_task)
# 添加分支任务
for branch_name, branch_tasks in raw_plan.get("branches", {}).items():
branch_task = {
"id": f"branch_{branch_name}",
"type": "branch",
"description": f"执行分支: {branch_name}",
"condition": branch_name,
"tasks": self._format_plan_tasks(branch_tasks)
}
formatted_tasks.append(branch_task)
return formatted_tasks
async def _optimize_plan(self, plan: List[Dict[str, Any]], constraints: Dict[str, Any]) -> List[Dict[str, Any]]:
"""优化计划"""
optimized_plan = []
for task in plan:
# 检查时间约束
if task.get("timeout", 60) > constraints.get("timeout", 300):
task["timeout"] = constraints.get("timeout", 300)
# 检查资源约束
if task.get("resource_usage", 0) > constraints.get("memory_limit", 1000):
# 分解大任务
subtasks = await self._decompose_task(task)
optimized_plan.extend(subtasks)
else:
optimized_plan.append(task)
return optimized_plan
async def _decompose_task(self, task: Dict[str, Any]) -> List[Dict[str, Any]]:
"""分解大任务为小任务"""
prompt = f"""
请将以下大任务分解为更小的子任务:
任务: {task.get('description', '')}
类型: {task.get('type', '')}
参数: {task.get('parameters', {})}
请返回分解后的子任务列表,每个子任务应该是独立的、可执行的。
"""
messages = [
{"role": "system", "content": "你是一个任务分解专家,擅长将复杂任务分解为简单任务。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return [task] # 如果分解失败,返回原任务
try:
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\[.*\]', response_content, re.DOTALL)
if json_match:
subtasks = json.loads(json_match.group())
return self._format_plan_tasks(subtasks)
else:
return [task]
except Exception as e:
logger.error(f"任务分解失败: {e}")
return [task]
def _create_fallback_plan(self, goal: Dict[str, Any]) -> List[Dict[str, Any]]:
"""创建备用计划"""
return [{
"id": "fallback_task",
"type": "action",
"description": goal.get("description", "执行目标"),
"tool": "general_response",
"parameters": {"goal": goal},
"expected_output": "目标完成",
"success_criteria": {"completion": True},
"priority": 0.5,
"timeout": 60
}]
def validate_plan(self, plan: List[Dict[str, Any]]) -> Dict[str, Any]:
"""验证计划的有效性"""
validation_result = {
"valid": True,
"issues": [],
"warnings": []
}
for task in plan:
# 检查必要字段
if not task.get("id"):
validation_result["issues"].append("任务缺少ID")
validation_result["valid"] = False
if not task.get("description"):
validation_result["warnings"].append(f"任务 {task.get('id', 'unknown')} 缺少描述")
# 检查依赖关系
dependencies = task.get("dependencies", [])
task_ids = [t.get("id") for t in plan]
for dep in dependencies:
if dep not in task_ids:
validation_result["issues"].append(f"任务 {task.get('id')} 的依赖 {dep} 不存在")
validation_result["valid"] = False
return validation_result

345
src/agent/react_agent.py Normal file
View File

@@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
"""
ReAct Agent - 基于 ReAct 模式的智能代理
用单次 LLM 调用 + 工具循环替代原有的多步流水线
"""
import logging
import json
import re
from typing import Dict, Any, List, Optional
from datetime import datetime
from src.agent.llm_client import LLMManager
from src.config.unified_config import get_config
logger = logging.getLogger(__name__)
# ── 工具定义(供 LLM 理解可用能力) ──────────────────────────
TOOL_DEFINITIONS = [
{
"name": "search_knowledge",
"description": "搜索知识库,根据关键词查找相关的问题和答案",
"parameters": {
"query": {"type": "string", "description": "搜索关键词", "required": True},
"top_k": {"type": "integer", "description": "返回结果数量默认3", "required": False}
}
},
{
"name": "add_knowledge",
"description": "向知识库添加新的问答条目",
"parameters": {
"question": {"type": "string", "description": "问题", "required": True},
"answer": {"type": "string", "description": "答案", "required": True},
"category": {"type": "string", "description": "分类", "required": False}
}
},
{
"name": "query_vehicle",
"description": "查询车辆信息支持按VIN码或车牌号查询",
"parameters": {
"vin": {"type": "string", "description": "VIN码", "required": False},
"plate_number": {"type": "string", "description": "车牌号", "required": False}
}
},
{
"name": "get_analytics",
"description": "获取系统数据分析报告,如每日统计、分类统计等",
"parameters": {
"report_type": {
"type": "string",
"description": "报告类型: daily_analytics / summary / category_performance",
"required": True
}
}
},
{
"name": "send_feishu_message",
"description": "通过飞书发送消息通知",
"parameters": {
"message": {"type": "string", "description": "消息内容", "required": True},
"chat_id": {"type": "string", "description": "飞书群聊ID可选", "required": False}
}
},
]
def _build_tools_prompt() -> str:
"""构建工具描述文本供 system prompt 使用"""
lines = []
for t in TOOL_DEFINITIONS:
params_desc = []
for pname, pinfo in t["parameters"].items():
req = "必填" if pinfo.get("required") else "可选"
params_desc.append(f" - {pname} ({pinfo['type']}, {req}): {pinfo['description']}")
lines.append(f"- {t['name']}: {t['description']}\n 参数:\n" + "\n".join(params_desc))
return "\n".join(lines)
SYSTEM_PROMPT = f"""你是 TSP 智能客服助手,帮助用户解决车辆售后问题、查询知识库、管理客诉信息。
你可以使用以下工具来完成任务:
{_build_tools_prompt()}
## 回复规则
1. 如果你需要使用工具,请严格按以下 JSON 格式回复(不要包含其他内容):
```json
{{"tool": "工具名", "parameters": {{"参数名": "参数值"}}}}
```
2. 如果你不需要使用工具,可以直接用自然语言回复用户。
3. 每次只调用一个工具。
4. 根据工具返回的结果,综合生成最终回复。
5. 回复要简洁专业,使用中文。
"""
class ReactAgent:
"""基于 ReAct 模式的 Agent"""
MAX_TOOL_ROUNDS = 5 # 最多工具调用轮次,防止死循环
def __init__(self):
config = get_config()
self.llm = LLMManager(config.llm)
self._tool_handlers = self._register_tool_handlers()
self.execution_history: List[Dict[str, Any]] = []
logger.info("ReactAgent 初始化完成")
# ── 工具处理器注册 ──────────────────────────────────────
def _register_tool_handlers(self) -> Dict[str, Any]:
return {
"search_knowledge": self._tool_search_knowledge,
"add_knowledge": self._tool_add_knowledge,
"query_vehicle": self._tool_query_vehicle,
"get_analytics": self._tool_get_analytics,
"send_feishu_message": self._tool_send_feishu_message,
}
# ── 主处理入口 ──────────────────────────────────────────
async def chat(
self,
message: str,
user_id: str = "anonymous",
conversation_history: Optional[List[Dict[str, str]]] = None,
) -> Dict[str, Any]:
"""处理用户消息,返回最终回复"""
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# 加入历史对话(最近 10 轮)
if conversation_history:
messages.extend(conversation_history[-10:])
messages.append({"role": "user", "content": message})
tool_calls_log = []
for round_idx in range(self.MAX_TOOL_ROUNDS):
# 调用 LLM
try:
response_text = await self.llm.chat(messages, temperature=0.3, max_tokens=2000)
except Exception as e:
logger.error(f"LLM 调用失败: {e}")
return self._error_response(str(e))
# 尝试解析工具调用
tool_call = self._parse_tool_call(response_text)
if tool_call is None:
# 没有工具调用 → 这是最终回复
self._record_execution(message, user_id, tool_calls_log, response_text)
return {
"success": True,
"response": response_text,
"tool_calls": tool_calls_log,
"rounds": round_idx + 1,
}
# 执行工具
tool_name = tool_call["tool"]
tool_params = tool_call.get("parameters", {})
logger.info(f"[Round {round_idx+1}] 调用工具: {tool_name}, 参数: {tool_params}")
tool_result = await self._execute_tool(tool_name, tool_params)
tool_calls_log.append({
"tool": tool_name,
"parameters": tool_params,
"result": tool_result,
"round": round_idx + 1,
})
# 把工具调用和结果加入对话上下文
messages.append({"role": "assistant", "content": response_text})
messages.append({
"role": "user",
"content": f"工具 `{tool_name}` 返回结果:\n```json\n{json.dumps(tool_result, ensure_ascii=False, default=str)}\n```\n请根据以上结果回复用户。"
})
# 超过最大轮次
self._record_execution(message, user_id, tool_calls_log, "[达到最大工具调用轮次]")
return {
"success": True,
"response": "抱歉,处理过程较复杂,请稍后重试或换个方式描述您的问题。",
"tool_calls": tool_calls_log,
"rounds": self.MAX_TOOL_ROUNDS,
}
# ── 工具调用解析 ──────────────────────────────────────
def _parse_tool_call(self, text: str) -> Optional[Dict[str, Any]]:
"""从 LLM 回复中解析工具调用 JSON"""
if not text:
return None
# 尝试从 ```json ... ``` 代码块中提取
code_block = re.search(r'```json\s*(\{.*?\})\s*```', text, re.DOTALL)
if code_block:
try:
data = json.loads(code_block.group(1))
if "tool" in data:
return data
except json.JSONDecodeError:
pass
# 尝试直接解析整段文本为 JSON
try:
data = json.loads(text.strip())
if isinstance(data, dict) and "tool" in data:
return data
except json.JSONDecodeError:
pass
# 尝试从文本中找到第一个 JSON 对象
json_match = re.search(r'\{[^{}]*"tool"\s*:\s*"[^"]+?"[^{}]*\}', text, re.DOTALL)
if json_match:
try:
data = json.loads(json_match.group())
if "tool" in data:
return data
except json.JSONDecodeError:
pass
return None
# ── 工具执行 ──────────────────────────────────────────
async def _execute_tool(self, tool_name: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""执行指定工具"""
handler = self._tool_handlers.get(tool_name)
if not handler:
return {"error": f"未知工具: {tool_name}"}
try:
return await handler(**params)
except Exception as e:
logger.error(f"工具 {tool_name} 执行失败: {e}")
return {"error": str(e)}
# ── 具体工具实现 ──────────────────────────────────────
async def _tool_search_knowledge(self, query: str, top_k: int = 3, **kw) -> Dict[str, Any]:
"""搜索知识库"""
try:
from src.knowledge_base.knowledge_manager import KnowledgeManager
km = KnowledgeManager()
results = km.search_knowledge(query, top_k)
return {"results": results, "count": len(results)}
except Exception as e:
return {"error": str(e)}
async def _tool_add_knowledge(self, question: str, answer: str, category: str = "通用", **kw) -> Dict[str, Any]:
"""添加知识库条目"""
try:
from src.knowledge_base.knowledge_manager import KnowledgeManager
km = KnowledgeManager()
success = km.add_knowledge_entry(question=question, answer=answer, category=category)
return {"success": success}
except Exception as e:
return {"error": str(e)}
async def _tool_query_vehicle(self, vin: str = None, plate_number: str = None, **kw) -> Dict[str, Any]:
"""查询车辆信息"""
try:
from src.vehicle.vehicle_data_manager import VehicleDataManager
vm = VehicleDataManager()
if vin:
result = vm.get_latest_vehicle_data_by_vin(vin)
return {"vehicle_data": result} if result else {"error": "未找到该VIN的车辆数据"}
elif plate_number:
return {"error": "暂不支持按车牌号查询请使用VIN码"}
else:
return {"error": "请提供 VIN 码"}
except Exception as e:
return {"error": str(e)}
async def _tool_get_analytics(self, report_type: str = "summary", **kw) -> Dict[str, Any]:
"""获取分析报告"""
try:
from src.analytics.analytics_manager import AnalyticsManager
am = AnalyticsManager()
if report_type == "daily_analytics":
return am.generate_daily_analytics()
elif report_type == "summary":
return am.get_analytics_summary()
elif report_type == "category_performance":
return am.get_category_performance()
else:
return {"error": f"不支持的报告类型: {report_type}"}
except Exception as e:
return {"error": str(e)}
async def _tool_send_feishu_message(self, message: str, chat_id: str = None, **kw) -> Dict[str, Any]:
"""发送飞书消息"""
try:
from src.integrations.feishu_service import FeishuService
fs = FeishuService()
if not chat_id:
return {"error": "请提供飞书群聊 chat_id"}
success = fs.send_message(receive_id=chat_id, content=message, receive_id_type="chat_id")
return {"success": success}
except Exception as e:
return {"error": str(e)}
# ── 辅助方法 ──────────────────────────────────────────
def _record_execution(self, message: str, user_id: str, tool_calls: list, response: str):
"""记录执行历史"""
record = {
"timestamp": datetime.now().isoformat(),
"user_id": user_id,
"message": message,
"tool_calls": tool_calls,
"response": response[:500],
}
self.execution_history.append(record)
if len(self.execution_history) > 500:
self.execution_history = self.execution_history[-500:]
def _error_response(self, error_msg: str) -> Dict[str, Any]:
return {
"success": False,
"response": "抱歉,系统处理出现问题,请稍后重试。",
"error": error_msg,
"tool_calls": [],
"rounds": 0,
}
def get_tool_definitions(self) -> List[Dict[str, Any]]:
"""返回工具定义列表(供 API 展示)"""
return TOOL_DEFINITIONS
def get_execution_history(self, limit: int = 50) -> List[Dict[str, Any]]:
"""获取执行历史"""
return self.execution_history[-limit:]
def get_status(self) -> Dict[str, Any]:
"""获取 Agent 状态"""
return {
"status": "active",
"available_tools": [t["name"] for t in TOOL_DEFINITIONS],
"tool_count": len(TOOL_DEFINITIONS),
"history_count": len(self.execution_history),
"max_tool_rounds": self.MAX_TOOL_ROUNDS,
}

View File

@@ -1,479 +0,0 @@
# -*- coding: utf-8 -*-
"""
推理引擎
负责逻辑推理和决策制定
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
import json
from ..core.llm_client import QwenClient
logger = logging.getLogger(__name__)
class ReasoningEngine:
"""推理引擎"""
def __init__(self):
self.llm_client = QwenClient()
self.reasoning_patterns = {
"causal": self._causal_reasoning,
"deductive": self._deductive_reasoning,
"inductive": self._inductive_reasoning,
"abductive": self._abductive_reasoning,
"analogical": self._analogical_reasoning
}
self.reasoning_history = []
async def analyze_intent(
self,
message: str,
context: Dict[str, Any],
history: List[Dict[str, Any]]
) -> Dict[str, Any]:
"""分析用户意图"""
try:
prompt = f"""
请分析以下用户消息的意图:
用户消息: {message}
上下文: {json.dumps(context, ensure_ascii=False)}
历史记录: {json.dumps(history, ensure_ascii=False)}
请从以下维度分析:
1. 主要意图(问题咨询、工单创建、系统查询等)
2. 情感倾向(积极、消极、中性)
3. 紧急程度(高、中、低)
4. 所需工具类型
5. 预期响应类型
6. 关键信息提取
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个意图分析专家,擅长理解用户需求和意图。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_fallback_intent(message)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
intent_analysis = json.loads(json_match.group())
intent_analysis["timestamp"] = datetime.now().isoformat()
return intent_analysis
else:
return self._create_fallback_intent(message)
except Exception as e:
logger.error(f"意图分析失败: {e}")
return self._create_fallback_intent(message)
async def make_decision(
self,
situation: Dict[str, Any],
options: List[Dict[str, Any]],
criteria: Dict[str, Any]
) -> Dict[str, Any]:
"""制定决策"""
try:
prompt = f"""
请根据以下情况制定决策:
当前情况: {json.dumps(situation, ensure_ascii=False)}
可选方案: {json.dumps(options, ensure_ascii=False)}
决策标准: {json.dumps(criteria, ensure_ascii=False)}
请分析每个方案的优缺点,并选择最佳方案。
返回格式:
{{
"selected_option": "方案ID",
"reasoning": "选择理由",
"confidence": 0.8,
"risks": ["风险1", "风险2"],
"mitigation": "风险缓解措施"
}}
"""
messages = [
{"role": "system", "content": "你是一个决策制定专家,擅长分析情况并做出最优决策。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return self._create_fallback_decision(options)
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
decision = json.loads(json_match.group())
decision["timestamp"] = datetime.now().isoformat()
return decision
else:
return self._create_fallback_decision(options)
except Exception as e:
logger.error(f"决策制定失败: {e}")
return self._create_fallback_decision(options)
async def reason_about_problem(
self,
problem: str,
available_information: Dict[str, Any],
reasoning_type: str = "causal"
) -> Dict[str, Any]:
"""对问题进行推理"""
try:
if reasoning_type not in self.reasoning_patterns:
reasoning_type = "causal"
reasoning_func = self.reasoning_patterns[reasoning_type]
result = await reasoning_func(problem, available_information)
# 记录推理历史
self.reasoning_history.append({
"timestamp": datetime.now().isoformat(),
"problem": problem,
"reasoning_type": reasoning_type,
"result": result
})
return result
except Exception as e:
logger.error(f"问题推理失败: {e}")
return {"error": str(e)}
async def _causal_reasoning(self, problem: str, information: Dict[str, Any]) -> Dict[str, Any]:
"""因果推理"""
prompt = f"""
请使用因果推理分析以下问题:
问题: {problem}
可用信息: {json.dumps(information, ensure_ascii=False)}
请分析:
1. 问题的根本原因
2. 可能的因果关系链
3. 影响因素分析
4. 解决方案的预期效果
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个因果推理专家,擅长分析问题的因果关系。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"reasoning_type": "causal", "error": "推理失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
return json.loads(json_match.group())
else:
return {"reasoning_type": "causal", "analysis": response_content}
async def _deductive_reasoning(self, problem: str, information: Dict[str, Any]) -> Dict[str, Any]:
"""演绎推理"""
prompt = f"""
请使用演绎推理分析以下问题:
问题: {problem}
可用信息: {json.dumps(information, ensure_ascii=False)}
请分析:
1. 一般性规则或原理
2. 具体事实或条件
3. 逻辑推导过程
4. 必然结论
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个演绎推理专家,擅长从一般原理推导具体结论。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"reasoning_type": "deductive", "error": "推理失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
return json.loads(json_match.group())
else:
return {"reasoning_type": "deductive", "analysis": response_content}
async def _inductive_reasoning(self, problem: str, information: Dict[str, Any]) -> Dict[str, Any]:
"""归纳推理"""
prompt = f"""
请使用归纳推理分析以下问题:
问题: {problem}
可用信息: {json.dumps(information, ensure_ascii=False)}
请分析:
1. 观察到的具体现象
2. 寻找共同模式
3. 形成一般性假设
4. 验证假设的合理性
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个归纳推理专家,擅长从具体现象归纳一般规律。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"reasoning_type": "inductive", "error": "推理失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
return json.loads(json_match.group())
else:
return {"reasoning_type": "inductive", "analysis": response_content}
async def _abductive_reasoning(self, problem: str, information: Dict[str, Any]) -> Dict[str, Any]:
"""溯因推理"""
prompt = f"""
请使用溯因推理分析以下问题:
问题: {problem}
可用信息: {json.dumps(information, ensure_ascii=False)}
请分析:
1. 观察到的现象
2. 可能的最佳解释
3. 解释的合理性评估
4. 需要进一步验证的假设
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个溯因推理专家,擅长寻找现象的最佳解释。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"reasoning_type": "abductive", "error": "推理失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
return json.loads(json_match.group())
else:
return {"reasoning_type": "abductive", "analysis": response_content}
async def _analogical_reasoning(self, problem: str, information: Dict[str, Any]) -> Dict[str, Any]:
"""类比推理"""
prompt = f"""
请使用类比推理分析以下问题:
问题: {problem}
可用信息: {json.dumps(information, ensure_ascii=False)}
请分析:
1. 寻找相似的问题或情况
2. 识别相似性和差异性
3. 应用类比关系
4. 调整解决方案以适应当前情况
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个类比推理专家,擅长通过类比解决问题。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"reasoning_type": "analogical", "error": "推理失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
return json.loads(json_match.group())
else:
return {"reasoning_type": "analogical", "analysis": response_content}
async def extract_insights(
self,
execution_result: Dict[str, Any],
goal: Dict[str, Any]
) -> Dict[str, Any]:
"""从执行结果中提取洞察"""
try:
prompt = f"""
请从以下执行结果中提取洞察:
执行结果: {json.dumps(execution_result, ensure_ascii=False)}
目标: {json.dumps(goal, ensure_ascii=False)}
请分析:
1. 成功模式(什么导致了成功)
2. 失败模式(什么导致了失败)
3. 性能指标(效率、准确性等)
4. 改进建议
5. 新发现的知识
请以JSON格式返回分析结果。
"""
messages = [
{"role": "system", "content": "你是一个洞察提取专家,擅长从执行结果中提取有价值的洞察。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"error": "洞察提取失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
insights = json.loads(json_match.group())
insights["timestamp"] = datetime.now().isoformat()
return insights
else:
return {"analysis": response_content, "timestamp": datetime.now().isoformat()}
except Exception as e:
logger.error(f"洞察提取失败: {e}")
return {"error": str(e)}
async def evaluate_solution(
self,
problem: str,
solution: Dict[str, Any],
criteria: Dict[str, Any]
) -> Dict[str, Any]:
"""评估解决方案"""
try:
prompt = f"""
请评估以下解决方案:
问题: {problem}
解决方案: {json.dumps(solution, ensure_ascii=False)}
评估标准: {json.dumps(criteria, ensure_ascii=False)}
请从以下维度评估:
1. 有效性(是否能解决问题)
2. 效率(资源消耗和时间成本)
3. 可行性(实施难度)
4. 风险(潜在问题)
5. 创新性(新颖程度)
请以JSON格式返回评估结果。
"""
messages = [
{"role": "system", "content": "你是一个解决方案评估专家,擅长全面评估解决方案的质量。"},
{"role": "user", "content": prompt}
]
result = self.llm_client.chat_completion(messages, temperature=0.3)
if "error" in result:
return {"error": "解决方案评估失败"}
response_content = result["choices"][0]["message"]["content"]
import re
json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
if json_match:
evaluation = json.loads(json_match.group())
evaluation["timestamp"] = datetime.now().isoformat()
return evaluation
else:
return {"evaluation": response_content, "timestamp": datetime.now().isoformat()}
except Exception as e:
logger.error(f"解决方案评估失败: {e}")
return {"error": str(e)}
def _create_fallback_intent(self, message: str) -> Dict[str, Any]:
"""创建备用意图分析"""
return {
"main_intent": "general_query",
"emotion": "neutral",
"urgency": "medium",
"required_tools": ["generate_response"],
"expected_response": "text",
"key_information": {"message": message},
"confidence": 0.5,
"timestamp": datetime.now().isoformat()
}
def _create_fallback_decision(self, options: List[Dict[str, Any]]) -> Dict[str, Any]:
"""创建备用决策"""
if not options:
return {
"selected_option": None,
"reasoning": "无可用选项",
"confidence": 0.0,
"timestamp": datetime.now().isoformat()
}
# 选择第一个选项作为默认选择
return {
"selected_option": options[0].get("id", "option_1"),
"reasoning": "默认选择",
"confidence": 0.3,
"risks": ["决策质量未知"],
"mitigation": "需要进一步验证",
"timestamp": datetime.now().isoformat()
}
def get_reasoning_history(self, limit: int = 10) -> List[Dict[str, Any]]:
"""获取推理历史"""
return self.reasoning_history[-limit:] if self.reasoning_history else []
def clear_reasoning_history(self):
"""清空推理历史"""
self.reasoning_history = []
logger.info("推理历史已清空")

View File

@@ -1,435 +0,0 @@
# -*- coding: utf-8 -*-
"""
工具管理器
负责管理和执行各种工具
"""
import logging
import asyncio
from typing import Dict, List, Any, Optional, Callable
from datetime import datetime
import json
logger = logging.getLogger(__name__)
class ToolManager:
"""工具管理器"""
def __init__(self):
self.tools = {}
self.tool_usage_stats = {}
self.tool_performance = {}
self._register_default_tools()
def _register_default_tools(self):
"""注册默认工具"""
# 注册基础工具
self.register_tool("search_knowledge", self._search_knowledge_tool)
self.register_tool("create_work_order", self._create_work_order_tool)
self.register_tool("update_work_order", self._update_work_order_tool)
self.register_tool("generate_response", self._generate_response_tool)
self.register_tool("analyze_data", self._analyze_data_tool)
self.register_tool("send_notification", self._send_notification_tool)
self.register_tool("schedule_task", self._schedule_task_tool)
self.register_tool("web_search", self._web_search_tool)
self.register_tool("file_operation", self._file_operation_tool)
self.register_tool("database_query", self._database_query_tool)
logger.info(f"已注册 {len(self.tools)} 个默认工具")
def register_tool(self, name: str, func: Callable, metadata: Optional[Dict[str, Any]] = None):
"""注册工具"""
self.tools[name] = {
"function": func,
"metadata": metadata or {},
"usage_count": 0,
"last_used": None,
"success_rate": 0.0
}
logger.info(f"注册工具: {name}")
def unregister_tool(self, name: str) -> bool:
"""注销工具"""
if name in self.tools:
del self.tools[name]
logger.info(f"注销工具: {name}")
return True
return False
async def execute_tool(self, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
"""执行工具"""
if tool_name not in self.tools:
return {
"success": False,
"error": f"工具 '{tool_name}' 不存在"
}
tool = self.tools[tool_name]
start_time = datetime.now()
try:
# 更新使用统计
tool["usage_count"] += 1
tool["last_used"] = start_time
# 执行工具
if asyncio.iscoroutinefunction(tool["function"]):
result = await tool["function"](**parameters)
else:
result = tool["function"](**parameters)
# 更新性能统计
execution_time = (datetime.now() - start_time).total_seconds()
self._update_tool_performance(tool_name, True, execution_time)
logger.info(f"工具 '{tool_name}' 执行成功,耗时: {execution_time:.2f}")
return {
"success": True,
"result": result,
"execution_time": execution_time,
"tool": tool_name
}
except Exception as e:
logger.error(f"工具 '{tool_name}' 执行失败: {e}")
# 更新性能统计
execution_time = (datetime.now() - start_time).total_seconds()
self._update_tool_performance(tool_name, False, execution_time)
return {
"success": False,
"error": str(e),
"execution_time": execution_time,
"tool": tool_name
}
def _update_tool_performance(self, tool_name: str, success: bool, execution_time: float):
"""更新工具性能统计"""
if tool_name not in self.tool_performance:
self.tool_performance[tool_name] = {
"total_executions": 0,
"successful_executions": 0,
"total_time": 0.0,
"avg_execution_time": 0.0,
"success_rate": 0.0
}
perf = self.tool_performance[tool_name]
perf["total_executions"] += 1
perf["total_time"] += execution_time
perf["avg_execution_time"] = perf["total_time"] / perf["total_executions"]
if success:
perf["successful_executions"] += 1
perf["success_rate"] = perf["successful_executions"] / perf["total_executions"]
# 更新工具的成功率
self.tools[tool_name]["success_rate"] = perf["success_rate"]
def get_available_tools(self) -> List[Dict[str, Any]]:
"""获取可用工具列表"""
tools_info = []
for name, tool in self.tools.items():
tool_info = {
"name": name,
"metadata": tool["metadata"],
"usage_count": tool["usage_count"],
"last_used": tool["last_used"].isoformat() if tool["last_used"] else None,
"success_rate": tool["success_rate"]
}
# 添加性能信息
if name in self.tool_performance:
perf = self.tool_performance[name]
tool_info.update({
"avg_execution_time": perf["avg_execution_time"],
"total_executions": perf["total_executions"]
})
tools_info.append(tool_info)
return tools_info
def get_tool_info(self, tool_name: str) -> Optional[Dict[str, Any]]:
"""获取工具信息"""
if tool_name not in self.tools:
return None
tool = self.tools[tool_name]
info = {
"name": tool_name,
"metadata": tool["metadata"],
"usage_count": tool["usage_count"],
"last_used": tool["last_used"].isoformat() if tool["last_used"] else None,
"success_rate": tool["success_rate"]
}
if tool_name in self.tool_performance:
info.update(self.tool_performance[tool_name])
return info
def update_usage_stats(self, tool_usage: List[Dict[str, Any]]):
"""更新工具使用统计"""
for usage in tool_usage:
tool_name = usage.get("tool")
if tool_name in self.tools:
self.tools[tool_name]["usage_count"] += usage.get("count", 1)
# 默认工具实现
async def _search_knowledge_tool(self, query: str, top_k: int = 3, **kwargs) -> Dict[str, Any]:
"""搜索知识库工具"""
try:
from ..knowledge_base.knowledge_manager import KnowledgeManager
knowledge_manager = KnowledgeManager()
results = knowledge_manager.search_knowledge(query, top_k)
return {
"query": query,
"results": results,
"count": len(results)
}
except Exception as e:
logger.error(f"搜索知识库失败: {e}")
return {"error": str(e)}
async def _create_work_order_tool(self, title: str, description: str, category: str, priority: str = "medium", **kwargs) -> Dict[str, Any]:
"""创建工单工具"""
try:
from ..dialogue.dialogue_manager import DialogueManager
dialogue_manager = DialogueManager()
result = dialogue_manager.create_work_order(title, description, category, priority)
return result
except Exception as e:
logger.error(f"创建工单失败: {e}")
return {"error": str(e)}
async def _update_work_order_tool(self, work_order_id: int, **kwargs) -> Dict[str, Any]:
"""更新工单工具"""
try:
from ..dialogue.dialogue_manager import DialogueManager
dialogue_manager = DialogueManager()
success = dialogue_manager.update_work_order(work_order_id, **kwargs)
return {
"success": success,
"work_order_id": work_order_id,
"updated_fields": list(kwargs.keys())
}
except Exception as e:
logger.error(f"更新工单失败: {e}")
return {"error": str(e)}
async def _generate_response_tool(self, message: str, context: str = "", **kwargs) -> Dict[str, Any]:
"""生成回复工具"""
try:
from ..core.llm_client import QwenClient
llm_client = QwenClient()
result = llm_client.generate_response(message, context)
return result
except Exception as e:
logger.error(f"生成回复失败: {e}")
return {"error": str(e)}
async def _analyze_data_tool(self, data_type: str, date_range: str = "last_7_days", **kwargs) -> Dict[str, Any]:
"""数据分析工具"""
try:
from ..analytics.analytics_manager import AnalyticsManager
analytics_manager = AnalyticsManager()
if data_type == "daily_analytics":
result = analytics_manager.generate_daily_analytics()
elif data_type == "summary":
result = analytics_manager.get_analytics_summary()
elif data_type == "category_performance":
result = analytics_manager.get_category_performance()
else:
result = {"error": f"不支持的数据类型: {data_type}"}
return result
except Exception as e:
logger.error(f"数据分析失败: {e}")
return {"error": str(e)}
async def _send_notification_tool(self, message: str, recipients: List[str], notification_type: str = "info", **kwargs) -> Dict[str, Any]:
"""发送通知工具"""
try:
# 这里可以实现具体的通知逻辑
# 例如:发送邮件、短信、推送通知等
notification_data = {
"message": message,
"recipients": recipients,
"type": notification_type,
"timestamp": datetime.now().isoformat()
}
# 模拟发送通知
logger.info(f"发送通知: {message}{recipients}")
return {
"success": True,
"notification_id": f"notif_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
"data": notification_data
}
except Exception as e:
logger.error(f"发送通知失败: {e}")
return {"error": str(e)}
async def _schedule_task_tool(self, task_name: str, schedule_time: str, task_data: Dict[str, Any], **kwargs) -> Dict[str, Any]:
"""调度任务工具"""
try:
# 这里可以实现任务调度逻辑
# 例如使用APScheduler、Celery等
schedule_data = {
"task_name": task_name,
"schedule_time": schedule_time,
"task_data": task_data,
"created_at": datetime.now().isoformat()
}
logger.info(f"调度任务: {task_name}{schedule_time}")
return {
"success": True,
"schedule_id": f"schedule_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
"data": schedule_data
}
except Exception as e:
logger.error(f"调度任务失败: {e}")
return {"error": str(e)}
async def _web_search_tool(self, query: str, max_results: int = 5, **kwargs) -> Dict[str, Any]:
"""网络搜索工具"""
try:
# 这里可以实现网络搜索逻辑
# 例如使用Google Search API、Bing Search API等
search_results = [
{
"title": f"搜索结果 {i+1}",
"url": f"https://example.com/result{i+1}",
"snippet": f"这是关于 '{query}' 的搜索结果摘要 {i+1}"
}
for i in range(min(max_results, 3))
]
logger.info(f"网络搜索: {query}")
return {
"query": query,
"results": search_results,
"count": len(search_results)
}
except Exception as e:
logger.error(f"网络搜索失败: {e}")
return {"error": str(e)}
async def _file_operation_tool(self, operation: str, file_path: str, content: str = "", **kwargs) -> Dict[str, Any]:
"""文件操作工具"""
try:
import os
if operation == "read":
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
return {"success": True, "content": content, "operation": "read"}
elif operation == "write":
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
return {"success": True, "operation": "write", "file_path": file_path}
elif operation == "exists":
exists = os.path.exists(file_path)
return {"success": True, "exists": exists, "file_path": file_path}
else:
return {"error": f"不支持的文件操作: {operation}"}
except Exception as e:
logger.error(f"文件操作失败: {e}")
return {"error": str(e)}
async def _database_query_tool(self, query: str, query_type: str = "select", **kwargs) -> Dict[str, Any]:
"""数据库查询工具"""
try:
from ..core.database import db_manager
with db_manager.get_session() as session:
if query_type == "select":
result = session.execute(query).fetchall()
return {
"success": True,
"result": [dict(row) for row in result],
"count": len(result)
}
else:
session.execute(query)
session.commit()
return {"success": True, "operation": query_type}
except Exception as e:
logger.error(f"数据库查询失败: {e}")
return {"error": str(e)}
def get_tool_performance_report(self) -> Dict[str, Any]:
"""获取工具性能报告"""
report = {
"total_tools": len(self.tools),
"tool_performance": {},
"summary": {
"most_used": None,
"most_reliable": None,
"fastest": None,
"slowest": None
}
}
if not self.tool_performance:
return report
# 分析性能数据
most_used_count = 0
most_reliable_rate = 0
fastest_time = float('inf')
slowest_time = 0
for tool_name, perf in self.tool_performance.items():
report["tool_performance"][tool_name] = perf
# 找出最常用的工具
if perf["total_executions"] > most_used_count:
most_used_count = perf["total_executions"]
report["summary"]["most_used"] = tool_name
# 找出最可靠的工具
if perf["success_rate"] > most_reliable_rate:
most_reliable_rate = perf["success_rate"]
report["summary"]["most_reliable"] = tool_name
# 找出最快的工具
if perf["avg_execution_time"] < fastest_time:
fastest_time = perf["avg_execution_time"]
report["summary"]["fastest"] = tool_name
# 找出最慢的工具
if perf["avg_execution_time"] > slowest_time:
slowest_time = perf["avg_execution_time"]
report["summary"]["slowest"] = tool_name
return report

View File

@@ -12,6 +12,7 @@ from datetime import datetime
from src.config.unified_config import get_config
from src.agent.llm_client import LLMManager
from src.web.service_manager import service_manager
from src.agent.react_agent import ReactAgent
logger = logging.getLogger(__name__)
@@ -25,7 +26,10 @@ class TSPAgentAssistant:
self.is_agent_mode = True
self.execution_history = []
# 工具注册表
# ReAct Agent核心
self.react_agent = ReactAgent()
# 工具注册表(保留兼容旧 API
self.tools = {}
self.tool_performance = {}
@@ -194,13 +198,15 @@ class TSPAgentAssistant:
def get_agent_status(self) -> Dict[str, Any]:
"""获取Agent状态"""
try:
react_status = self.react_agent.get_status()
return {
"success": True,
"is_active": self.is_agent_mode,
"ai_monitoring_active": self.ai_monitoring_active,
"total_tools": len(self.tools),
"total_executions": len(self.execution_history),
"tools": self.get_available_tools(),
"total_tools": react_status["tool_count"],
"available_tools": react_status["available_tools"],
"total_executions": len(self.execution_history) + react_status["history_count"],
"react_agent": react_status,
"performance": self.get_tool_performance_report()
}
except Exception as e:
@@ -321,29 +327,23 @@ class TSPAgentAssistant:
async def process_message_agent(self, message: str, user_id: str = "admin",
work_order_id: Optional[int] = None,
enable_proactive: bool = True) -> Dict[str, Any]:
"""处理消息 (实战化)"""
"""处理消息 - 使用 ReAct Agent"""
try:
logger.info(f"Agent收到消息: {message}")
# 1. 识别意图和推荐工具
prompt = f"用户消息: {message}\n请分析用户意图,并从工具列表中选择最合适的工具。工具列表: {json.dumps(self.get_available_tools())}\n请直接返回你的分析和建议响应。"
response_text = await self.llm_manager.generate(prompt)
# 2. 模拟动作生成
actions = []
if "工单" in message or "查询" in message:
actions.append({"type": "tool_call", "tool": "search_work_order", "status": "suggested"})
return {
"success": True,
"response": response_text,
"actions": actions,
"user_id": user_id,
"work_order_id": work_order_id,
"status": "completed",
"timestamp": datetime.now().isoformat()
}
result = await self.react_agent.chat(
message=message,
user_id=user_id,
)
result["user_id"] = user_id
result["work_order_id"] = work_order_id
result["status"] = "completed" if result.get("success") else "error"
result["timestamp"] = datetime.now().isoformat()
# 兼容旧字段
result["actions"] = [
{"type": "tool_call", "tool": tc["tool"], "status": "executed"}
for tc in result.get("tool_calls", [])
]
return result
except Exception as e:
logger.error(f"处理消息失败: {e}")
return {"error": str(e)}

View File

@@ -1,322 +0,0 @@
# -*- coding: utf-8 -*-
"""
增强版TSP助手 - 集成Agent功能
重构版本:模块化设计,降低代码复杂度
"""
import logging
import asyncio
from typing import Dict, Any, List, Optional
from datetime import datetime
from src.agent.agent_assistant_core import TSPAgentAssistantCore
from src.agent.agent_message_handler import AgentMessageHandler
from src.agent.agent_sample_actions import AgentSampleActions
logger = logging.getLogger(__name__)
class TSPAgentAssistant(TSPAgentAssistantCore):
"""TSP Agent助手 - 重构版本"""
def __init__(self, llm_config=None):
# 初始化核心功能
super().__init__(llm_config)
# 初始化消息处理器
self.message_handler = AgentMessageHandler(self)
# 初始化示例动作处理器
self.sample_actions = AgentSampleActions(self)
logger.info("TSP Agent助手初始化完成重构版本")
# ==================== 消息处理功能 ====================
async def process_message_agent(self, message: str, user_id: str = "admin",
work_order_id: Optional[int] = None,
enable_proactive: bool = True) -> Dict[str, Any]:
"""使用Agent处理消息"""
return await self.message_handler.process_message_agent(
message, user_id, work_order_id, enable_proactive
)
async def process_conversation_agent(self, conversation_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理对话"""
return await self.message_handler.process_conversation_agent(conversation_data)
async def process_workorder_agent(self, workorder_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理工单"""
return await self.message_handler.process_workorder_agent(workorder_data)
async def process_alert_agent(self, alert_data: Dict[str, Any]) -> Dict[str, Any]:
"""使用Agent处理预警"""
return await self.message_handler.process_alert_agent(alert_data)
# ==================== 建议功能 ====================
def get_conversation_suggestions(self, context: Dict[str, Any]) -> List[str]:
"""获取对话建议"""
return self.message_handler.get_conversation_suggestions(context)
def get_workorder_suggestions(self, workorder_data: Dict[str, Any]) -> List[str]:
"""获取工单建议"""
return self.message_handler.get_workorder_suggestions(workorder_data)
def get_alert_suggestions(self, alert_data: Dict[str, Any]) -> List[str]:
"""获取预警建议"""
return self.message_handler.get_alert_suggestions(alert_data)
# ==================== 示例动作功能 ====================
async def trigger_sample_actions(self) -> Dict[str, Any]:
"""触发示例动作"""
return await self.sample_actions.trigger_sample_actions()
async def run_performance_test(self) -> Dict[str, Any]:
"""运行性能测试"""
return await self.sample_actions.run_performance_test()
# ==================== 兼容性方法 ====================
def get_agent_status(self) -> Dict[str, Any]:
"""获取Agent状态兼容性方法"""
return super().get_agent_status()
def toggle_agent_mode(self, enabled: bool) -> bool:
"""切换Agent模式兼容性方法"""
return super().toggle_agent_mode(enabled)
def start_proactive_monitoring(self) -> bool:
"""启动主动监控(兼容性方法)"""
return super().start_proactive_monitoring()
def stop_proactive_monitoring(self) -> bool:
"""停止主动监控(兼容性方法)"""
return super().stop_proactive_monitoring()
def run_proactive_monitoring(self) -> Dict[str, Any]:
"""运行主动监控检查(兼容性方法)"""
return super().run_proactive_monitoring()
def run_intelligent_analysis(self) -> Dict[str, Any]:
"""运行智能分析(兼容性方法)"""
return super().run_intelligent_analysis()
def get_action_history(self, limit: int = 50) -> List[Dict[str, Any]]:
"""获取动作执行历史(兼容性方法)"""
return super().get_action_history(limit)
def clear_execution_history(self) -> Dict[str, Any]:
"""清空执行历史(兼容性方法)"""
return super().clear_execution_history()
def get_llm_usage_stats(self) -> Dict[str, Any]:
"""获取LLM使用统计兼容性方法"""
return super().get_llm_usage_stats()
# ==================== 高级功能 ====================
async def comprehensive_analysis(self) -> Dict[str, Any]:
"""综合分析 - 结合多个模块的分析结果"""
try:
# 运行智能分析
intelligent_analysis = self.run_intelligent_analysis()
# 运行主动监控
proactive_monitoring = self.run_proactive_monitoring()
# 运行性能测试
performance_test = await self.run_performance_test()
# 综合结果
comprehensive_result = {
"timestamp": self.execution_history[-1]["timestamp"] if self.execution_history else None,
"intelligent_analysis": intelligent_analysis,
"proactive_monitoring": proactive_monitoring,
"performance_test": performance_test,
"overall_status": self._determine_overall_status(
intelligent_analysis, proactive_monitoring, performance_test
)
}
# 记录综合分析
self._record_execution("comprehensive_analysis", comprehensive_result)
return comprehensive_result
except Exception as e:
logger.error(f"综合分析失败: {e}")
return {"error": str(e)}
def _determine_overall_status(self, intelligent_analysis: Dict,
proactive_monitoring: Dict,
performance_test: Dict) -> str:
"""确定整体状态"""
try:
# 检查各个模块的状态
statuses = []
if intelligent_analysis.get("success"):
statuses.append("intelligent_analysis_ok")
else:
statuses.append("intelligent_analysis_error")
if proactive_monitoring.get("success"):
statuses.append("proactive_monitoring_ok")
else:
statuses.append("proactive_monitoring_error")
if performance_test.get("success"):
statuses.append("performance_test_ok")
else:
statuses.append("performance_test_error")
# 根据状态确定整体状态
if all("ok" in status for status in statuses):
return "excellent"
elif any("error" in status for status in statuses):
return "needs_attention"
else:
return "good"
except Exception:
return "unknown"
async def batch_process_requests(self, requests: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""批量处理请求"""
try:
results = []
for request in requests:
request_type = request.get("type", "message")
if request_type == "message":
result = await self.process_message_agent(
request.get("message", ""),
request.get("user_id", "admin"),
request.get("work_order_id"),
request.get("enable_proactive", True)
)
elif request_type == "conversation":
result = await self.process_conversation_agent(request)
elif request_type == "workorder":
result = await self.process_workorder_agent(request)
elif request_type == "alert":
result = await self.process_alert_agent(request)
else:
result = {"error": f"未知请求类型: {request_type}"}
results.append(result)
# 记录批量处理
self._record_execution("batch_process", {
"request_count": len(requests),
"results": results
})
return results
except Exception as e:
logger.error(f"批量处理请求失败: {e}")
return [{"error": str(e)} for _ in requests]
def get_system_summary(self) -> Dict[str, Any]:
"""获取系统摘要"""
try:
# 获取各种状态信息
agent_status = self.get_agent_status()
system_health = self.get_system_health()
workorders_status = self._check_workorders_status()
# 计算摘要指标
summary = {
"timestamp": datetime.now().isoformat(),
"agent_status": agent_status,
"system_health": system_health,
"workorders_status": workorders_status,
"execution_history_count": len(self.execution_history),
"llm_usage_stats": self.get_llm_usage_stats(),
"overall_health_score": system_health.get("health_score", 0)
}
return summary
except Exception as e:
logger.error(f"获取系统摘要失败: {e}")
return {"error": str(e)}
def export_agent_data(self) -> Dict[str, Any]:
"""导出Agent数据"""
try:
export_data = {
"export_timestamp": datetime.now().isoformat(),
"agent_status": self.get_agent_status(),
"execution_history": self.execution_history,
"llm_usage_stats": self.get_llm_usage_stats(),
"system_summary": self.get_system_summary()
}
return {
"success": True,
"data": export_data,
"message": "Agent数据导出成功"
}
except Exception as e:
logger.error(f"导出Agent数据失败: {e}")
return {
"success": False,
"error": str(e)
}
def import_agent_data(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""导入Agent数据"""
try:
# 验证数据格式
if not isinstance(data, dict):
raise ValueError("数据格式不正确")
# 导入执行历史
if "execution_history" in data:
self.execution_history = data["execution_history"]
# 其他数据的导入逻辑...
return {
"success": True,
"message": "Agent数据导入成功"
}
except Exception as e:
logger.error(f"导入Agent数据失败: {e}")
return {
"success": False,
"error": str(e)
}
# 测试函数
async def main():
"""测试函数"""
print("🚀 TSP Agent助手测试")
# 创建Agent助手实例
agent_assistant = TSPAgentAssistant()
# 测试基本功能
status = agent_assistant.get_agent_status()
print("Agent状态:", status)
# 测试消息处理
result = await agent_assistant.process_message_agent("你好,请帮我分析系统状态")
print("消息处理结果:", result)
# 测试示例动作
sample_result = await agent_assistant.trigger_sample_actions()
print("示例动作结果:", sample_result)
# 测试综合分析
analysis_result = await agent_assistant.comprehensive_analysis()
print("综合分析结果:", analysis_result)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -71,6 +71,19 @@ class AIAccuracyConfig:
human_resolution_confidence: float = 0.90
@dataclass
class EmbeddingConfig:
"""Embedding 向量配置"""
enabled: bool = True
api_key: Optional[str] = None # 本地模式不需要
base_url: Optional[str] = None # 本地模式不需要
model: str = "BAAI/bge-small-zh-v1.5" # 本地轻量中文模型
dimension: int = 512 # bge-small-zh 输出维度
batch_size: int = 32
similarity_threshold: float = 0.5 # 语义搜索相似度阈值
cache_ttl: int = 86400 # embedding 缓存过期时间(秒),默认 1 天
@dataclass
class RedisConfig:
"""Redis缓存配置"""
@@ -99,6 +112,7 @@ class UnifiedConfig:
self.feishu = self._load_feishu_from_env()
self.ai_accuracy = self._load_ai_accuracy_from_env()
self.redis = self._load_redis_from_env()
self.embedding = self._load_embedding_from_env()
self.validate_config()
def _load_database_from_env(self) -> DatabaseConfig:
@@ -172,6 +186,18 @@ class UnifiedConfig:
logger.info("Redis config loaded.")
return config
def _load_embedding_from_env(self) -> EmbeddingConfig:
config = EmbeddingConfig(
enabled=os.getenv("EMBEDDING_ENABLED", "True").lower() in ('true', '1', 't'),
model=os.getenv("EMBEDDING_MODEL", "BAAI/bge-small-zh-v1.5"),
dimension=int(os.getenv("EMBEDDING_DIMENSION", 512)),
batch_size=int(os.getenv("EMBEDDING_BATCH_SIZE", 32)),
similarity_threshold=float(os.getenv("EMBEDDING_SIMILARITY_THRESHOLD", 0.5)),
cache_ttl=int(os.getenv("EMBEDDING_CACHE_TTL", 86400)),
)
logger.info("Embedding config loaded.")
return config
def validate_config(self):
"""在启动时验证关键配置"""
if not self.database.url:
@@ -193,6 +219,7 @@ class UnifiedConfig:
'feishu': asdict(self.feishu),
'ai_accuracy': asdict(self.ai_accuracy),
'redis': asdict(self.redis),
'embedding': asdict(self.embedding),
}
# --- 全局单例模式 ---

View File

@@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
"""
Embedding 向量客户端(本地模型方案)
使用 sentence-transformers 在本地运行轻量级中文 embedding 模型
零 API 调用、零成本、低延迟
"""
import logging
import hashlib
import threading
from typing import List, Optional
from src.config.unified_config import get_config
from src.core.cache_manager import cache_manager
logger = logging.getLogger(__name__)
class EmbeddingClient:
"""本地 Embedding 向量客户端"""
def __init__(self):
config = get_config()
self.enabled = config.embedding.enabled
self.model_name = config.embedding.model
self.dimension = config.embedding.dimension
self.cache_ttl = config.embedding.cache_ttl
self._model = None
self._lock = threading.Lock()
if self.enabled:
logger.info(f"Embedding 客户端初始化: model={self.model_name} (本地模式)")
else:
logger.info("Embedding 功能已禁用,将使用关键词匹配降级")
def _get_model(self):
"""延迟加载模型(首次调用时下载并加载)"""
if self._model is not None:
return self._model
with self._lock:
if self._model is not None:
return self._model
try:
import os
# 设置 HuggingFace 镜像,解决国内下载问题
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
from sentence_transformers import SentenceTransformer
logger.info(f"正在加载 embedding 模型: {self.model_name} ...")
self._model = SentenceTransformer(self.model_name)
logger.info(f"Embedding 模型加载完成: {self.model_name}")
return self._model
except ImportError:
logger.error(
"sentence-transformers 未安装,请运行: pip install sentence-transformers"
)
self.enabled = False
return None
except Exception as e:
logger.error(f"加载 embedding 模型失败: {e}")
self.enabled = False
return None
# ------------------------------------------------------------------
# 公开接口
# ------------------------------------------------------------------
def embed_text(self, text: str) -> Optional[List[float]]:
"""对单条文本生成 embedding 向量,优先从缓存读取"""
if not self.enabled or not text.strip():
return None
cache_key = self._cache_key(text)
cached = cache_manager.get(cache_key)
if cached is not None:
return cached
model = self._get_model()
if model is None:
return None
try:
vec = model.encode(text, normalize_embeddings=True).tolist()
cache_manager.set(cache_key, vec, self.cache_ttl)
return vec
except Exception as e:
logger.error(f"Embedding 生成失败: {e}")
return None
def embed_batch(self, texts: List[str]) -> List[Optional[List[float]]]:
"""批量生成 embedding"""
if not self.enabled:
return [None] * len(texts)
results: List[Optional[List[float]]] = [None] * len(texts)
uncached_indices = []
uncached_texts = []
# 1. 先查缓存
for i, t in enumerate(texts):
if not t.strip():
continue
cached = cache_manager.get(self._cache_key(t))
if cached is not None:
results[i] = cached
else:
uncached_indices.append(i)
uncached_texts.append(t)
if not uncached_texts:
return results
# 2. 批量推理
model = self._get_model()
if model is None:
return results
try:
vectors = model.encode(
uncached_texts, normalize_embeddings=True, batch_size=32
).tolist()
for j, vec in enumerate(vectors):
idx = uncached_indices[j]
results[idx] = vec
cache_manager.set(self._cache_key(uncached_texts[j]), vec, self.cache_ttl)
except Exception as e:
logger.error(f"批量 embedding 生成失败: {e}")
return results
def test_connection(self) -> bool:
"""测试模型是否可用"""
try:
vec = self.embed_text("测试连接")
return vec is not None and len(vec) > 0
except Exception as e:
logger.error(f"Embedding 模型测试失败: {e}")
return False
# ------------------------------------------------------------------
# 内部方法
# ------------------------------------------------------------------
@staticmethod
def _cache_key(text: str) -> str:
"""生成缓存键(基于文本哈希)"""
h = hashlib.md5(text.encode("utf-8")).hexdigest()
return f"emb:{h}"

View File

@@ -58,11 +58,49 @@ class WorkOrder(Base):
# 关联处理过程记录
process_history = relationship("WorkOrderProcessHistory", back_populates="work_order", order_by="WorkOrderProcessHistory.process_time")
class ChatSession(Base):
"""对话会话模型 — 将多轮对话组织为一个会话"""
__tablename__ = "chat_sessions"
id = Column(Integer, primary_key=True)
session_id = Column(String(100), unique=True, nullable=False) # 唯一会话标识
user_id = Column(String(100), nullable=True) # 用户标识
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=True)
title = Column(String(200), nullable=True) # 会话标题(取首条消息摘要)
status = Column(String(20), default="active") # active, ended
message_count = Column(Integer, default=0) # 消息轮数
source = Column(String(50), nullable=True) # 来源websocket, api, feishu
ip_address = Column(String(45), nullable=True)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
ended_at = Column(DateTime, nullable=True)
# 关联消息
messages = relationship("Conversation", back_populates="chat_session", order_by="Conversation.timestamp")
def to_dict(self):
return {
'id': self.id,
'session_id': self.session_id,
'user_id': self.user_id,
'work_order_id': self.work_order_id,
'title': self.title,
'status': self.status,
'message_count': self.message_count,
'source': self.source,
'ip_address': self.ip_address,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
'ended_at': self.ended_at.isoformat() if self.ended_at else None,
}
class Conversation(Base):
"""对话记录模型"""
__tablename__ = "conversations"
id = Column(Integer, primary_key=True)
session_id = Column(String(100), ForeignKey("chat_sessions.session_id"), nullable=True) # 关联会话
work_order_id = Column(Integer, ForeignKey("work_orders.id"))
user_message = Column(Text, nullable=False)
assistant_response = Column(Text, nullable=False)
@@ -79,6 +117,7 @@ class Conversation(Base):
cpu_usage = Column(Float) # CPU使用率
work_order = relationship("WorkOrder", back_populates="conversations")
chat_session = relationship("ChatSession", back_populates="messages")
class KnowledgeEntry(Base):
"""知识库条目模型"""

View File

@@ -86,6 +86,7 @@ class QueryOptimizer:
for conv in conversations:
conversation_list.append({
'id': conv.id,
'session_id': conv.session_id,
'user_message': conv.user_message,
'assistant_response': conv.assistant_response,
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,

164
src/core/vector_store.py Normal file
View File

@@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
"""
向量存储与检索
使用 numpy 实现轻量级向量索引(无需额外依赖)
支持从 DB 加载已有 embedding 构建索引,增量更新
"""
import logging
import json
import threading
import numpy as np
from typing import List, Dict, Any, Optional, Tuple
from src.core.database import db_manager
from src.core.models import KnowledgeEntry
logger = logging.getLogger(__name__)
class VectorStore:
"""轻量级向量存储,基于 numpy 余弦相似度"""
def __init__(self):
self._lock = threading.RLock()
# 索引数据: entry_id -> embedding vector
self._ids: List[int] = []
self._matrix: Optional[np.ndarray] = None # shape: (n, dim)
self._loaded = False
# ------------------------------------------------------------------
# 索引管理
# ------------------------------------------------------------------
def load_from_db(self):
"""从数据库加载所有已有 embedding 构建索引"""
try:
with db_manager.get_session() as session:
entries = session.query(
KnowledgeEntry.id, KnowledgeEntry.vector_embedding
).filter(
KnowledgeEntry.is_active == True,
KnowledgeEntry.vector_embedding.isnot(None),
KnowledgeEntry.vector_embedding != ''
).all()
ids = []
vectors = []
for entry_id, vec_json in entries:
try:
vec = json.loads(vec_json)
if isinstance(vec, list) and len(vec) > 0:
ids.append(entry_id)
vectors.append(vec)
except (json.JSONDecodeError, TypeError):
continue
with self._lock:
if vectors:
self._ids = ids
self._matrix = np.array(vectors, dtype=np.float32)
# L2 归一化,方便后续用点积算余弦相似度
norms = np.linalg.norm(self._matrix, axis=1, keepdims=True)
norms[norms == 0] = 1.0
self._matrix = self._matrix / norms
else:
self._ids = []
self._matrix = None
self._loaded = True
logger.info(f"向量索引加载完成: {len(ids)} 条记录")
except Exception as e:
logger.error(f"加载向量索引失败: {e}")
self._loaded = True # 标记为已加载,避免重复尝试
def add(self, entry_id: int, vector: List[float]):
"""增量添加一条向量"""
with self._lock:
vec = np.array(vector, dtype=np.float32).reshape(1, -1)
norm = np.linalg.norm(vec)
if norm > 0:
vec = vec / norm
if self._matrix is not None:
self._ids.append(entry_id)
self._matrix = np.vstack([self._matrix, vec])
else:
self._ids = [entry_id]
self._matrix = vec
def remove(self, entry_id: int):
"""移除一条向量"""
with self._lock:
if entry_id in self._ids:
idx = self._ids.index(entry_id)
self._ids.pop(idx)
if self._matrix is not None and len(self._ids) > 0:
self._matrix = np.delete(self._matrix, idx, axis=0)
else:
self._matrix = None
def update(self, entry_id: int, vector: List[float]):
"""更新一条向量"""
self.remove(entry_id)
self.add(entry_id, vector)
# ------------------------------------------------------------------
# 检索
# ------------------------------------------------------------------
def search(
self,
query_vector: List[float],
top_k: int = 5,
threshold: float = 0.0
) -> List[Tuple[int, float]]:
"""
向量相似度检索
Returns:
[(entry_id, similarity_score), ...] 按相似度降序
"""
if not self._loaded:
self.load_from_db()
with self._lock:
if self._matrix is None or len(self._ids) == 0:
return []
q = np.array(query_vector, dtype=np.float32).reshape(1, -1)
norm = np.linalg.norm(q)
if norm > 0:
q = q / norm
# 余弦相似度 = 归一化向量的点积
similarities = (self._matrix @ q.T).flatten()
# 筛选超过阈值的
valid_mask = similarities >= threshold
valid_indices = np.where(valid_mask)[0]
if len(valid_indices) == 0:
return []
# 取 top_k
if len(valid_indices) > top_k:
top_indices = valid_indices[np.argsort(-similarities[valid_indices])[:top_k]]
else:
top_indices = valid_indices[np.argsort(-similarities[valid_indices])]
results = []
for idx in top_indices:
results.append((self._ids[idx], float(similarities[idx])))
return results
@property
def size(self) -> int:
with self._lock:
return len(self._ids)
# 全局单例
vector_store = VectorStore()

View File

@@ -11,7 +11,7 @@ from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from ..core.database import db_manager
from ..core.models import Conversation, WorkOrder, WorkOrderSuggestion, KnowledgeEntry
from ..core.models import Conversation, WorkOrder, WorkOrderSuggestion, KnowledgeEntry, ChatSession
from ..core.redis_manager import redis_manager
from src.config.unified_config import get_config
from sqlalchemy import and_, or_, desc
@@ -45,7 +45,8 @@ class ConversationHistoryManager:
response_time: Optional[float] = None,
knowledge_used: Optional[List[int]] = None,
ip_address: Optional[str] = None,
invocation_method: Optional[str] = None
invocation_method: Optional[str] = None,
session_id: Optional[str] = None
) -> int:
"""保存对话记录到数据库和Redis"""
conversation_id = 0
@@ -54,6 +55,7 @@ class ConversationHistoryManager:
# 保存到数据库
with db_manager.get_session() as session:
conversation = Conversation(
session_id=session_id,
work_order_id=work_order_id,
user_message=user_message,
assistant_response=assistant_response,
@@ -715,3 +717,130 @@ class ConversationHistoryManager:
except Exception as e:
logger.error(f"获取对话分析数据失败: {e}")
return {}
# ==================== 会话管理方法 ====================
def get_sessions_paginated(
self,
page: int = 1,
per_page: int = 20,
status: Optional[str] = None,
search: str = '',
date_filter: str = ''
) -> Dict[str, Any]:
"""分页获取会话列表"""
try:
with db_manager.get_session() as session:
query = session.query(ChatSession)
if status:
query = query.filter(ChatSession.status == status)
if search:
query = query.filter(
or_(
ChatSession.title.contains(search),
ChatSession.session_id.contains(search),
ChatSession.user_id.contains(search)
)
)
if date_filter:
now = datetime.now()
if date_filter == 'today':
start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
elif date_filter == 'week':
start_date = now - timedelta(days=7)
elif date_filter == 'month':
start_date = now - timedelta(days=30)
else:
start_date = None
if start_date:
query = query.filter(ChatSession.created_at >= start_date)
total = query.count()
sessions_list = query.order_by(
ChatSession.updated_at.desc()
).offset((page - 1) * per_page).limit(per_page).all()
result = []
for s in sessions_list:
result.append(s.to_dict())
return {
'sessions': result,
'page': page,
'per_page': per_page,
'total': total,
'total_pages': (total + per_page - 1) // per_page
}
except Exception as e:
logger.error(f"获取会话列表失败: {e}")
return {'sessions': [], 'page': page, 'per_page': per_page, 'total': 0, 'total_pages': 0}
def get_session_messages(
self,
session_id: str,
limit: int = 100,
offset: int = 0
) -> Dict[str, Any]:
"""获取某个会话的所有消息(按时间正序)"""
try:
with db_manager.get_session() as session:
# 获取会话元数据
chat_session = session.query(ChatSession).filter(
ChatSession.session_id == session_id
).first()
if not chat_session:
return {'error': '会话不存在'}
# 获取消息
messages = session.query(Conversation).filter(
Conversation.session_id == session_id
).order_by(Conversation.timestamp.asc()).offset(offset).limit(limit).all()
message_list = []
for msg in messages:
message_list.append({
'id': msg.id,
'user_message': msg.user_message,
'assistant_response': msg.assistant_response,
'timestamp': msg.timestamp.isoformat() if msg.timestamp else None,
'confidence_score': msg.confidence_score,
'response_time': msg.response_time,
'knowledge_used': json.loads(msg.knowledge_used) if msg.knowledge_used else [],
})
return {
'session': chat_session.to_dict(),
'messages': message_list,
'total': len(message_list)
}
except Exception as e:
logger.error(f"获取会话消息失败: {e}")
return {'error': str(e)}
def delete_session(self, session_id: str) -> bool:
"""删除会话及其所有消息"""
try:
with db_manager.get_session() as session:
# 删除关联消息
session.query(Conversation).filter(
Conversation.session_id == session_id
).delete(synchronize_session=False)
# 删除会话
session.query(ChatSession).filter(
ChatSession.session_id == session_id
).delete(synchronize_session=False)
session.commit()
logger.info(f"删除会话成功: {session_id}")
return True
except Exception as e:
logger.error(f"删除会话失败: {e}")
return False

View File

@@ -13,7 +13,7 @@ from dataclasses import dataclass
from ..core.llm_client import QwenClient
from ..knowledge_base.knowledge_manager import KnowledgeManager
from ..core.database import db_manager
from ..core.models import Conversation, WorkOrder
from ..core.models import Conversation, WorkOrder, ChatSession
from ..vehicle.vehicle_data_manager import VehicleDataManager
logger = logging.getLogger(__name__)
@@ -55,6 +55,21 @@ class RealtimeChatManager:
self.active_sessions[session_id] = session_data
self.message_history[session_id] = []
# 持久化会话到数据库
try:
with db_manager.get_session() as db_session:
chat_session = ChatSession(
session_id=session_id,
user_id=user_id,
work_order_id=work_order_id,
status="active",
message_count=0,
)
db_session.add(chat_session)
db_session.commit()
except Exception as e:
logger.warning(f"持久化会话记录失败(不影响使用): {e}")
logger.info(f"创建新会话: {session_id}")
return session_id
@@ -356,7 +371,7 @@ class RealtimeChatManager:
"""保存对话到数据库"""
try:
with db_manager.get_session() as session:
# 统一为一条记录:包含用户消息与助手回复
# 计算响应时间
try:
response_time = None
if assistant_msg.timestamp and user_msg.timestamp:
@@ -364,26 +379,36 @@ class RealtimeChatManager:
except Exception:
response_time = None
# 在知识字段中打上会话标记,便于结束时合并清理
marked_knowledge = assistant_msg.knowledge_used or []
try:
marked_knowledge = list(marked_knowledge)
marked_knowledge.append({"session_id": session_id, "type": "session_marker"})
except Exception:
pass
# 保存知识库使用记录(不再塞 session_marker
knowledge_data = assistant_msg.knowledge_used or []
conversation = Conversation(
session_id=session_id,
work_order_id=assistant_msg.work_order_id or user_msg.work_order_id,
user_message=user_msg.content or "",
assistant_response=assistant_msg.content or "",
timestamp=assistant_msg.timestamp or user_msg.timestamp,
confidence_score=assistant_msg.confidence_score,
knowledge_used=json.dumps(marked_knowledge, ensure_ascii=False) if marked_knowledge else None,
knowledge_used=json.dumps(knowledge_data, ensure_ascii=False) if knowledge_data else None,
response_time=response_time,
ip_address=ip_address,
invocation_method=invocation_method
)
session.add(conversation)
# 更新会话元数据
chat_session = session.query(ChatSession).filter(
ChatSession.session_id == session_id
).first()
if chat_session:
chat_session.message_count = (chat_session.message_count or 0) + 1
chat_session.updated_at = datetime.now()
chat_session.source = invocation_method
chat_session.ip_address = ip_address
# 首条消息时设置会话标题
if chat_session.message_count == 1 and user_msg.content:
chat_session.title = user_msg.content[:100]
session.commit()
except Exception as e:
@@ -470,57 +495,21 @@ class RealtimeChatManager:
def end_session(self, session_id: str) -> bool:
"""结束会话"""
try:
if session_id in self.active_sessions:
session_meta = self.active_sessions[session_id]
# 汇总本会话为一条记录
history = self.message_history.get(session_id, [])
if history:
user_parts = []
assistant_parts = []
response_times = []
first_ts = None
last_ts = None
for i in range(len(history)):
msg = history[i]
if first_ts is None:
first_ts = msg.timestamp
last_ts = msg.timestamp
if msg.role == "user":
user_parts.append(msg.content)
# 计算到下一条助手回复的间隔
if i + 1 < len(history) and history[i+1].role == "assistant":
try:
rt = max(0.0, (history[i+1].timestamp - msg.timestamp).total_seconds() * 1000.0)
response_times.append(rt)
except Exception:
pass
elif msg.role == "assistant":
assistant_parts.append(msg.content)
agg_user = "\n\n".join([p for p in user_parts if p])
agg_assistant = "\n\n".join([p for p in assistant_parts if p])
avg_rt = sum(response_times)/len(response_times) if response_times else None
from ..core.database import db_manager as _db
from ..core.models import Conversation as _Conv
import json as _json
with _db.get_session() as dbs:
agg = _Conv(
work_order_id=session_meta.get("work_order_id"),
user_message=agg_user,
assistant_response=agg_assistant,
timestamp=last_ts or first_ts,
confidence_score=None,
knowledge_used=_json.dumps({"session_id": session_id, "aggregated": True}, ensure_ascii=False),
response_time=avg_rt
)
dbs.add(agg)
# 删除本会话标记的分散记录
try:
pattern = f'%"session_id":"{session_id}"%'
dbs.query(_Conv).filter(_Conv.knowledge_used.like(pattern)).delete(synchronize_session=False)
except Exception:
pass
# 更新数据库中的会话状态
try:
with db_manager.get_session() as dbs:
chat_session = dbs.query(ChatSession).filter(
ChatSession.session_id == session_id
).first()
if chat_session:
chat_session.status = "ended"
chat_session.ended_at = datetime.now()
dbs.commit()
except Exception as e:
logger.warning(f"更新会话状态失败: {e}")
# 清理内存
if session_id in self.active_sessions:
del self.active_sessions[session_id]
if session_id in self.message_history:

View File

@@ -10,6 +10,9 @@ from sqlalchemy import func
from ..core.database import db_manager
from ..core.models import KnowledgeEntry, WorkOrder, Conversation
from ..core.llm_client import QwenClient
from ..core.embedding_client import EmbeddingClient
from ..core.vector_store import vector_store
from ..config.unified_config import get_config
logger = logging.getLogger(__name__)
@@ -18,12 +21,18 @@ class KnowledgeManager:
def __init__(self):
self.llm_client = QwenClient()
self.embedding_client = EmbeddingClient()
self.embedding_enabled = get_config().embedding.enabled
self.similarity_threshold = get_config().embedding.similarity_threshold
self.vectorizer = TfidfVectorizer(
max_features=1000,
stop_words=None, # 不使用英文停用词,因为数据是中文
ngram_range=(1, 2)
)
self._load_vectorizer()
# 加载向量索引embedding 模式)
if self.embedding_enabled:
vector_store.load_from_db()
def _load_vectorizer(self):
"""加载向量化器"""
@@ -71,17 +80,34 @@ class KnowledgeManager:
existing_entry.updated_at = datetime.now()
if work_order.satisfaction_score:
existing_entry.confidence_score = work_order.satisfaction_score
# 更新 embedding
if self.embedding_enabled:
vec = self.embedding_client.embed_text(question + " " + answer)
if vec:
existing_entry.vector_embedding = json.dumps(vec)
vector_store.update(existing_entry.id, vec)
else:
# 创建新条目
logger.info(f"未发现相似条目,正在为工单 {work_order_id} 创建新知识点")
embedding_json = None
vec = None
if self.embedding_enabled:
vec = self.embedding_client.embed_text(question + " " + answer)
if vec:
embedding_json = json.dumps(vec)
new_entry = KnowledgeEntry(
question=question,
answer=answer,
category=work_order.category,
confidence_score=work_order.satisfaction_score or 0.5,
usage_count=1
usage_count=1,
vector_embedding=embedding_json
)
session.add(new_entry)
session.flush() # 获取 ID
if vec and new_entry.id:
vector_store.add(new_entry.id, vec)
session.commit()
logger.info(f"从工单 {work_order_id} 学习知识成功")
@@ -94,6 +120,22 @@ class KnowledgeManager:
def _find_similar_entry(self, question: str, session) -> Optional[KnowledgeEntry]:
"""查找相似的知识库条目"""
try:
# 优先使用 embedding 查找
if self.embedding_enabled:
query_vec = self.embedding_client.embed_text(question)
if query_vec:
candidates = vector_store.search(query_vec, top_k=1, threshold=0.8)
if candidates:
entry_id, score = candidates[0]
entry = session.query(KnowledgeEntry).filter(
KnowledgeEntry.id == entry_id,
KnowledgeEntry.is_active == True
).first()
if entry:
logger.info(f"Embedding 匹配成功: 相似度 {score:.4f}, ID={entry_id}")
return entry
# 降级TF-IDF 匹配
entries = session.query(KnowledgeEntry).filter(
KnowledgeEntry.is_active == True
).all()
@@ -101,7 +143,6 @@ class KnowledgeManager:
if not entries:
return None
# 计算相似度
texts = [entry.question for entry in entries]
question_vector = self.vectorizer.transform([question])
entry_vectors = self.vectorizer.transform(texts)
@@ -110,13 +151,11 @@ class KnowledgeManager:
max_similarity_idx = np.argmax(similarities)
max_score = similarities[max_similarity_idx]
logger.debug(f"相似度检索完成: 最高分值={max_score:.4f}, 目标ID={entries[max_similarity_idx].id if entries else 'N/A'}")
logger.debug(f"TF-IDF 相似度检索: 最高分值={max_score:.4f}")
if max_score > 0.8: # 相似度阈值
logger.info(f"匹配成功: 相似度 {max_score:.4f} 超过阈值 0.8")
if max_score > 0.8:
return entries[max_similarity_idx]
logger.debug(f"匹配跳过: 相似度 {max_score:.4f} 未达到阈值 0.8")
return None
except Exception as e:
@@ -124,7 +163,85 @@ class KnowledgeManager:
return None
def search_knowledge(self, query: str, top_k: int = 3, verified_only: bool = True) -> List[Dict[str, Any]]:
"""搜索知识库"""
"""搜索知识库 — 优先使用 embedding 语义检索,降级为关键词匹配"""
try:
# 尝试 embedding 语义检索
if self.embedding_enabled:
results = self._search_by_embedding(query, top_k, verified_only)
if results:
return results
logger.debug("Embedding 检索无结果,降级为关键词匹配")
# 降级:关键词匹配
return self._search_by_keyword(query, top_k, verified_only)
except Exception as e:
logger.error(f"搜索知识库失败: {e}")
return []
def _search_by_embedding(self, query: str, top_k: int = 3, verified_only: bool = True) -> List[Dict[str, Any]]:
"""基于 embedding 向量的语义检索"""
try:
query_vec = self.embedding_client.embed_text(query)
if query_vec is None:
return []
# 向量检索
candidates = vector_store.search(
query_vector=query_vec,
top_k=top_k * 3, # 多取一些,后面过滤
threshold=self.similarity_threshold
)
if not candidates:
return []
# 从 DB 获取完整条目并过滤
candidate_ids = [cid for cid, _ in candidates]
score_map = {cid: score for cid, score in candidates}
with db_manager.get_session() as session:
query_filter = session.query(KnowledgeEntry).filter(
KnowledgeEntry.id.in_(candidate_ids),
KnowledgeEntry.is_active == True
)
if verified_only:
query_filter = query_filter.filter(KnowledgeEntry.is_verified == True)
entries = query_filter.all()
# 如果 verified_only 没结果,回退到全部
if not entries and verified_only:
entries = session.query(KnowledgeEntry).filter(
KnowledgeEntry.id.in_(candidate_ids),
KnowledgeEntry.is_active == True
).all()
results = []
for entry in entries:
results.append({
"id": entry.id,
"question": entry.question,
"answer": entry.answer,
"category": entry.category,
"confidence_score": entry.confidence_score,
"similarity_score": score_map.get(entry.id, 0.0),
"usage_count": entry.usage_count,
"is_verified": entry.is_verified
})
results.sort(key=lambda x: x['similarity_score'], reverse=True)
results = results[:top_k]
logger.info(f"Embedding 搜索 '{query[:30]}' 返回 {len(results)} 个结果")
return results
except Exception as e:
logger.error(f"Embedding 搜索失败: {e}")
return []
def _search_by_keyword(self, query: str, top_k: int = 3, verified_only: bool = True) -> List[Dict[str, Any]]:
"""基于关键词的搜索(降级方案)"""
try:
with db_manager.get_session() as session:
# 构建查询条件
@@ -221,6 +338,14 @@ class KnowledgeManager:
) -> bool:
"""添加知识库条目"""
try:
# 生成 embedding
embedding_json = None
text_for_embedding = question + " " + answer
if self.embedding_enabled:
vec = self.embedding_client.embed_text(text_for_embedding)
if vec:
embedding_json = json.dumps(vec)
with db_manager.get_session() as session:
entry = KnowledgeEntry(
question=question,
@@ -228,12 +353,18 @@ class KnowledgeManager:
category=category,
confidence_score=confidence_score,
usage_count=0,
is_verified=is_verified
is_verified=is_verified,
vector_embedding=embedding_json
)
session.add(entry)
session.commit()
entry_id = entry.id
# 重新训练向量化器
# 更新向量索引
if vec and entry_id:
vector_store.add(entry_id, vec)
# 重新训练 TF-IDF 向量化器
self._load_vectorizer()
logger.info(f"添加知识库条目成功: {question[:50]}...")
@@ -261,15 +392,26 @@ class KnowledgeManager:
if not entry:
return False
content_changed = False
if question:
entry.question = question
content_changed = True
if answer:
entry.answer = answer
content_changed = True
if category:
entry.category = category
if confidence_score is not None:
entry.confidence_score = confidence_score
# 内容变更时重新生成 embedding
if content_changed and self.embedding_enabled:
text_for_embedding = (question or entry.question) + " " + (answer or entry.answer)
vec = self.embedding_client.embed_text(text_for_embedding)
if vec:
entry.vector_embedding = json.dumps(vec)
vector_store.update(entry_id, vec)
entry.updated_at = datetime.now()
session.commit()
@@ -383,12 +525,14 @@ class KnowledgeManager:
entry.is_active = False
session.commit()
# 从向量索引中移除
vector_store.remove(entry_id)
# 重新训练向量化器(如果还有活跃条目)
try:
self._load_vectorizer()
except Exception as vectorizer_error:
logger.warning(f"重新加载向量化器失败: {vectorizer_error}")
# 即使向量化器加载失败,删除操作仍然成功
logger.info(f"删除知识库条目成功: {entry_id}")
return True

View File

@@ -185,20 +185,20 @@ def get_agent_tools_stats():
try:
from src.web.service_manager import service_manager
agent_assistant = service_manager.get_agent_assistant()
tools = agent_assistant.agent_core.tool_manager.get_available_tools()
performance = agent_assistant.agent_core.tool_manager.get_tool_performance_report()
react_status = agent_assistant.react_agent.get_status()
tools = agent_assistant.react_agent.get_tool_definitions()
history = agent_assistant.react_agent.get_execution_history(20)
return jsonify({
"success": True,
"tools": tools,
"performance": performance
"status": react_status,
"recent_history": history
})
except Exception as e:
# 返回默认工具列表避免500错误
return jsonify({
"success": False,
"tools": [],
"performance": {},
"error": "工具统计暂时不可用"
"error": str(e)
})
@@ -213,15 +213,23 @@ def execute_agent_tool():
if not tool_name:
return jsonify({"error": "缺少工具名称tool"}), 400
result = service_manager.get_agent_assistant().agent_core.tool_manager.execute_tool_sync(tool_name, parameters)
return jsonify(result)
agent = service_manager.get_agent_assistant()
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
result = loop.run_until_complete(
agent.react_agent._execute_tool(tool_name, parameters)
)
finally:
loop.close()
return jsonify({"success": True, "result": result})
except Exception as e:
return jsonify({"error": str(e)}), 500
@agent_bp.route('/tools/register', methods=['POST'])
def register_custom_tool():
"""注册自定义工具(仅登记元数据,函数为占位符"""
"""注册自定义工具(仅登记元数据)"""
try:
from src.web.service_manager import service_manager
data = request.get_json() or {}
@@ -230,14 +238,9 @@ def register_custom_tool():
if not name:
return jsonify({"error": "缺少工具名称"}), 400
def _placeholder_tool(**kwargs):
return {"message": f"自定义工具 {name} 已登记(占位),当前不可执行", "params": kwargs}
service_manager.get_agent_assistant().agent_core.tool_manager.register_tool(
name,
_placeholder_tool,
metadata={"description": description, "custom": True}
)
agent = service_manager.get_agent_assistant()
agent.register_tool(name, lambda **kw: {"message": f"自定义工具 {name} 占位", "params": kw},
metadata={"description": description, "custom": True})
return jsonify({"success": True, "message": "工具已注册"})
except Exception as e:
return jsonify({"error": str(e)}), 500
@@ -248,7 +251,7 @@ def unregister_custom_tool(name):
"""注销自定义工具"""
try:
from src.web.service_manager import service_manager
success = service_manager.get_agent_assistant().agent_core.tool_manager.unregister_tool(name)
success = service_manager.get_agent_assistant().unregister_tool(name)
return jsonify({"success": success})
except Exception as e:
return jsonify({"error": str(e)}), 500

View File

@@ -349,3 +349,68 @@ def get_conversation_analytics():
except Exception as e:
logger.error(f"获取对话分析数据失败: {e}")
return jsonify({"error": str(e)}), 500
# ==================== 会话管理 API ====================
@conversations_bp.route('/sessions')
def get_sessions():
"""获取会话列表(分页)"""
try:
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
status = request.args.get('status', '') # active, ended, 空=全部
search = request.args.get('search', '')
date_filter = request.args.get('date_filter', '')
result = history_manager.get_sessions_paginated(
page=page,
per_page=per_page,
status=status or None,
search=search,
date_filter=date_filter
)
return jsonify(result)
except Exception as e:
logger.error(f"获取会话列表失败: {e}")
return jsonify({"error": str(e)}), 500
@conversations_bp.route('/sessions/<session_id>')
def get_session_detail(session_id):
"""获取某个会话的完整消息列表"""
try:
limit = request.args.get('limit', 100, type=int)
offset = request.args.get('offset', 0, type=int)
result = history_manager.get_session_messages(
session_id=session_id,
limit=limit,
offset=offset
)
if 'error' in result:
return jsonify(result), 404
return jsonify({'success': True, **result})
except Exception as e:
logger.error(f"获取会话详情失败: {e}")
return jsonify({"error": str(e)}), 500
@conversations_bp.route('/sessions/<session_id>', methods=['DELETE'])
def delete_session(session_id):
"""删除会话及其所有消息"""
try:
success = history_manager.delete_session(session_id)
if success:
return jsonify({"success": True, "message": "会话已删除"})
else:
return jsonify({"error": "删除失败"}), 500
except Exception as e:
logger.error(f"删除会话失败: {e}")
return jsonify({"error": str(e)}), 500

View File

@@ -437,7 +437,6 @@ def get_error_log():
).limit(50).all()
errors = []
error_id = 1
for conv in conversations:
error_type = None
@@ -460,14 +459,17 @@ def get_error_log():
# 只记录有错误的对话
if error_type:
errors.append({
'id': error_id,
'id': conv.id,
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,
'error_type': error_type,
'error_message': error_message,
'model': 'qwen-turbo', # 实际使用的模型
'user_id': f'user_{conv.id}'
'model': 'qwen-turbo',
'user_id': f'user_{conv.id}',
'user_message': (conv.user_message or '')[:100],
'assistant_response': (conv.assistant_response or '')[:200],
'confidence_score': conv.confidence_score,
'response_time': conv.response_time,
})
error_id += 1
return jsonify({
'success': True,
@@ -476,6 +478,31 @@ def get_error_log():
except Exception as e:
return jsonify({"error": str(e)}), 500
@monitoring_bp.route('/ai-monitor/error-log/<int:conv_id>')
def get_error_detail(conv_id):
"""获取单条错误详情"""
try:
with db_manager.get_session() as session:
conv = session.query(Conversation).filter_by(id=conv_id).first()
if not conv:
return jsonify({"error": "记录不存在"}), 404
return jsonify({
'success': True,
'detail': {
'id': conv.id,
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,
'user_message': conv.user_message,
'assistant_response': conv.assistant_response,
'confidence_score': conv.confidence_score,
'response_time': conv.response_time,
'category': conv.category,
'source': conv.source,
}
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@monitoring_bp.route('/ai-monitor/error-log', methods=['DELETE'])
def clear_error_log():
"""清空错误日志"""

View File

@@ -3863,6 +3863,44 @@ class TSPDashboard {
}
}
async viewErrorDetail(convId) {
const modal = new bootstrap.Modal(document.getElementById('errorDetailModal'));
const body = document.getElementById('errorDetailBody');
body.innerHTML = '<div class="text-center text-muted"><i class="fas fa-spinner fa-spin me-2"></i>加载中...</div>';
modal.show();
try {
const response = await fetch(`/api/ai-monitor/error-log/${convId}`);
const data = await response.json();
if (data.success) {
const d = data.detail;
body.innerHTML = `
<table class="table table-bordered mb-0">
<tr><th style="width:120px">记录ID</th><td>${d.id}</td></tr>
<tr><th>时间</th><td>${d.timestamp ? new Date(d.timestamp).toLocaleString() : '-'}</td></tr>
<tr><th>分类</th><td>${d.category || '-'}</td></tr>
<tr><th>来源</th><td>${d.source || '-'}</td></tr>
<tr><th>置信度</th><td>${d.confidence_score != null ? d.confidence_score : '-'}</td></tr>
<tr><th>响应时间</th><td>${d.response_time != null ? d.response_time + ' ms' : '-'}</td></tr>
<tr><th>用户消息</th><td><pre class="mb-0" style="white-space:pre-wrap">${this.escapeHtml(d.user_message || '-')}</pre></td></tr>
<tr><th>助手回复</th><td><pre class="mb-0" style="white-space:pre-wrap">${this.escapeHtml(d.assistant_response || '-')}</pre></td></tr>
</table>
`;
} else {
body.innerHTML = `<div class="alert alert-danger">${data.error || '加载失败'}</div>`;
}
} catch (error) {
body.innerHTML = `<div class="alert alert-danger">请求失败: ${error.message}</div>`;
}
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 系统优化
async loadSystemOptimizer() {
try {

View File

@@ -2469,6 +2469,24 @@
<!-- 通知容器 -->
<div id="notificationContainer" class="position-fixed top-0 end-0 p-3" style="z-index: 1050;"></div>
<!-- 错误详情模态框 -->
<div class="modal fade" id="errorDetailModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-bug me-2"></i>错误详情</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="errorDetailBody">
<div class="text-center text-muted"><i class="fas fa-spinner fa-spin me-2"></i>加载中...</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<!-- 脚本 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>

Binary file not shown.