大改,未验证
This commit is contained in:
12
.env
12
.env
@@ -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
|
||||
|
||||
23
.env.example
23
.env.example
@@ -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.
@@ -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:
|
||||
|
||||
@@ -68,4 +68,7 @@ pydantic==2.9.2
|
||||
marshmallow==3.23.3
|
||||
|
||||
# 飞书官方 SDK(事件订阅 2.0 - 长连接模式)
|
||||
lark-oapi==1.3.5
|
||||
lark-oapi==1.3.5
|
||||
|
||||
# 本地 Embedding 模型(可选,EMBEDDING_ENABLED=True 时需要)
|
||||
# pip install sentence-transformers torch
|
||||
81
scripts/migrate_embeddings.py
Normal file
81
scripts/migrate_embeddings.py
Normal 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()
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)}
|
||||
@@ -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状态已重置")
|
||||
@@ -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 []
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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": "用户已通知"}
|
||||
@@ -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
345
src/agent/react_agent.py
Normal 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,
|
||||
}
|
||||
@@ -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("推理历史已清空")
|
||||
@@ -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
|
||||
@@ -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)}
|
||||
|
||||
@@ -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())
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
# --- 全局单例模式 ---
|
||||
|
||||
152
src/core/embedding_client.py
Normal file
152
src/core/embedding_client.py
Normal 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}"
|
||||
@@ -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):
|
||||
"""知识库条目模型"""
|
||||
|
||||
@@ -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
164
src/core/vector_store.py
Normal 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()
|
||||
@@ -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
|
||||
|
||||
@@ -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__)
|
||||
@@ -54,6 +54,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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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():
|
||||
"""清空错误日志"""
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
BIN
tsp_assistant.db
BIN
tsp_assistant.db
Binary file not shown.
Reference in New Issue
Block a user