大改,未验证
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
|
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"
|
# 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).
|
# The temperature for the model's responses (0.0 to 2.0).
|
||||||
LLM_TEMPERATURE=0.7
|
LLM_TEMPERATURE=0.7
|
||||||
@@ -123,3 +123,13 @@ REDIS_DEFAULT_TTL=3600
|
|||||||
|
|
||||||
# Enable Redis cache (set to False to disable caching)
|
# Enable Redis cache (set to False to disable caching)
|
||||||
REDIS_ENABLED=True
|
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)
|
# Enable Redis cache (set to False to disable caching)
|
||||||
REDIS_ENABLED=True
|
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.database import db_manager
|
||||||
from src.core.models import (
|
from src.core.models import (
|
||||||
Base, WorkOrder, KnowledgeEntry, Conversation, Analytics, Alert, VehicleData,
|
Base, WorkOrder, KnowledgeEntry, Conversation, Analytics, Alert, VehicleData,
|
||||||
WorkOrderSuggestion, WorkOrderProcessHistory, User
|
WorkOrderSuggestion, WorkOrderProcessHistory, User, ChatSession
|
||||||
)
|
)
|
||||||
|
|
||||||
class DatabaseInitializer:
|
class DatabaseInitializer:
|
||||||
@@ -197,7 +197,8 @@ class DatabaseInitializer:
|
|||||||
self._migrate_workorder_dispatch_fields,
|
self._migrate_workorder_dispatch_fields,
|
||||||
self._migrate_workorder_process_history_table,
|
self._migrate_workorder_process_history_table,
|
||||||
self._migrate_analytics_enhancements,
|
self._migrate_analytics_enhancements,
|
||||||
self._migrate_system_optimization_fields
|
self._migrate_system_optimization_fields,
|
||||||
|
self._migrate_chat_sessions_table,
|
||||||
]
|
]
|
||||||
|
|
||||||
success_count = 0
|
success_count = 0
|
||||||
@@ -445,6 +446,37 @@ class DatabaseInitializer:
|
|||||||
|
|
||||||
return success
|
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:
|
def _add_table_columns(self, table_name: str, fields: List[tuple]) -> bool:
|
||||||
"""为表添加字段"""
|
"""为表添加字段"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -68,4 +68,7 @@ pydantic==2.9.2
|
|||||||
marshmallow==3.23.3
|
marshmallow==3.23.3
|
||||||
|
|
||||||
# 飞书官方 SDK(事件订阅 2.0 - 长连接模式)
|
# 飞书官方 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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Agent模块初始化文件
|
Agent模块
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .agent_core import AgentCore, AgentState
|
from .react_agent import ReactAgent
|
||||||
from .planner import TaskPlanner
|
|
||||||
from .executor import TaskExecutor
|
|
||||||
from .tool_manager import ToolManager
|
|
||||||
from .reasoning_engine import ReasoningEngine
|
|
||||||
from .goal_manager import GoalManager
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ['ReactAgent']
|
||||||
'AgentCore',
|
|
||||||
'AgentState',
|
|
||||||
'TaskPlanner',
|
|
||||||
'TaskExecutor',
|
|
||||||
'ToolManager',
|
|
||||||
'ReasoningEngine',
|
|
||||||
'GoalManager'
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -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的主动调用功能
|
实现Agent的主动调用功能
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio跳过系统检查,直接启动服务...
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -22,7 +22,7 @@ class AutoMonitorService:
|
|||||||
self.agent_assistant = agent_assistant
|
self.agent_assistant = agent_assistant
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
self.monitor_thread = None
|
self.monitor_thread = None
|
||||||
self.check_interval = 300 # 5分钟检查一次
|
self.check_interval = 900 # 5分钟检查一次
|
||||||
self.last_check_time = None
|
self.last_check_time = None
|
||||||
self.monitoring_stats = {
|
self.monitoring_stats = {
|
||||||
"total_checks": 0,
|
"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.config.unified_config import get_config
|
||||||
from src.agent.llm_client import LLMManager
|
from src.agent.llm_client import LLMManager
|
||||||
from src.web.service_manager import service_manager
|
from src.web.service_manager import service_manager
|
||||||
|
from src.agent.react_agent import ReactAgent
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -25,7 +26,10 @@ class TSPAgentAssistant:
|
|||||||
self.is_agent_mode = True
|
self.is_agent_mode = True
|
||||||
self.execution_history = []
|
self.execution_history = []
|
||||||
|
|
||||||
# 工具注册表
|
# ReAct Agent(核心)
|
||||||
|
self.react_agent = ReactAgent()
|
||||||
|
|
||||||
|
# 工具注册表(保留兼容旧 API)
|
||||||
self.tools = {}
|
self.tools = {}
|
||||||
self.tool_performance = {}
|
self.tool_performance = {}
|
||||||
|
|
||||||
@@ -194,13 +198,15 @@ class TSPAgentAssistant:
|
|||||||
def get_agent_status(self) -> Dict[str, Any]:
|
def get_agent_status(self) -> Dict[str, Any]:
|
||||||
"""获取Agent状态"""
|
"""获取Agent状态"""
|
||||||
try:
|
try:
|
||||||
|
react_status = self.react_agent.get_status()
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"is_active": self.is_agent_mode,
|
"is_active": self.is_agent_mode,
|
||||||
"ai_monitoring_active": self.ai_monitoring_active,
|
"ai_monitoring_active": self.ai_monitoring_active,
|
||||||
"total_tools": len(self.tools),
|
"total_tools": react_status["tool_count"],
|
||||||
"total_executions": len(self.execution_history),
|
"available_tools": react_status["available_tools"],
|
||||||
"tools": self.get_available_tools(),
|
"total_executions": len(self.execution_history) + react_status["history_count"],
|
||||||
|
"react_agent": react_status,
|
||||||
"performance": self.get_tool_performance_report()
|
"performance": self.get_tool_performance_report()
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -321,29 +327,23 @@ class TSPAgentAssistant:
|
|||||||
async def process_message_agent(self, message: str, user_id: str = "admin",
|
async def process_message_agent(self, message: str, user_id: str = "admin",
|
||||||
work_order_id: Optional[int] = None,
|
work_order_id: Optional[int] = None,
|
||||||
enable_proactive: bool = True) -> Dict[str, Any]:
|
enable_proactive: bool = True) -> Dict[str, Any]:
|
||||||
"""处理消息 (实战化)"""
|
"""处理消息 - 使用 ReAct Agent"""
|
||||||
try:
|
try:
|
||||||
logger.info(f"Agent收到消息: {message}")
|
logger.info(f"Agent收到消息: {message}")
|
||||||
|
result = await self.react_agent.chat(
|
||||||
# 1. 识别意图和推荐工具
|
message=message,
|
||||||
prompt = f"用户消息: {message}\n请分析用户意图,并从工具列表中选择最合适的工具。工具列表: {json.dumps(self.get_available_tools())}\n请直接返回你的分析和建议响应。"
|
user_id=user_id,
|
||||||
|
)
|
||||||
response_text = await self.llm_manager.generate(prompt)
|
result["user_id"] = user_id
|
||||||
|
result["work_order_id"] = work_order_id
|
||||||
# 2. 模拟动作生成
|
result["status"] = "completed" if result.get("success") else "error"
|
||||||
actions = []
|
result["timestamp"] = datetime.now().isoformat()
|
||||||
if "工单" in message or "查询" in message:
|
# 兼容旧字段
|
||||||
actions.append({"type": "tool_call", "tool": "search_work_order", "status": "suggested"})
|
result["actions"] = [
|
||||||
|
{"type": "tool_call", "tool": tc["tool"], "status": "executed"}
|
||||||
return {
|
for tc in result.get("tool_calls", [])
|
||||||
"success": True,
|
]
|
||||||
"response": response_text,
|
return result
|
||||||
"actions": actions,
|
|
||||||
"user_id": user_id,
|
|
||||||
"work_order_id": work_order_id,
|
|
||||||
"status": "completed",
|
|
||||||
"timestamp": datetime.now().isoformat()
|
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"处理消息失败: {e}")
|
logger.error(f"处理消息失败: {e}")
|
||||||
return {"error": str(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
|
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
|
@dataclass
|
||||||
class RedisConfig:
|
class RedisConfig:
|
||||||
"""Redis缓存配置"""
|
"""Redis缓存配置"""
|
||||||
@@ -99,6 +112,7 @@ class UnifiedConfig:
|
|||||||
self.feishu = self._load_feishu_from_env()
|
self.feishu = self._load_feishu_from_env()
|
||||||
self.ai_accuracy = self._load_ai_accuracy_from_env()
|
self.ai_accuracy = self._load_ai_accuracy_from_env()
|
||||||
self.redis = self._load_redis_from_env()
|
self.redis = self._load_redis_from_env()
|
||||||
|
self.embedding = self._load_embedding_from_env()
|
||||||
self.validate_config()
|
self.validate_config()
|
||||||
|
|
||||||
def _load_database_from_env(self) -> DatabaseConfig:
|
def _load_database_from_env(self) -> DatabaseConfig:
|
||||||
@@ -172,6 +186,18 @@ class UnifiedConfig:
|
|||||||
logger.info("Redis config loaded.")
|
logger.info("Redis config loaded.")
|
||||||
return config
|
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):
|
def validate_config(self):
|
||||||
"""在启动时验证关键配置"""
|
"""在启动时验证关键配置"""
|
||||||
if not self.database.url:
|
if not self.database.url:
|
||||||
@@ -193,6 +219,7 @@ class UnifiedConfig:
|
|||||||
'feishu': asdict(self.feishu),
|
'feishu': asdict(self.feishu),
|
||||||
'ai_accuracy': asdict(self.ai_accuracy),
|
'ai_accuracy': asdict(self.ai_accuracy),
|
||||||
'redis': asdict(self.redis),
|
'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")
|
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):
|
class Conversation(Base):
|
||||||
"""对话记录模型"""
|
"""对话记录模型"""
|
||||||
__tablename__ = "conversations"
|
__tablename__ = "conversations"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
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"))
|
work_order_id = Column(Integer, ForeignKey("work_orders.id"))
|
||||||
user_message = Column(Text, nullable=False)
|
user_message = Column(Text, nullable=False)
|
||||||
assistant_response = Column(Text, nullable=False)
|
assistant_response = Column(Text, nullable=False)
|
||||||
@@ -79,6 +117,7 @@ class Conversation(Base):
|
|||||||
cpu_usage = Column(Float) # CPU使用率
|
cpu_usage = Column(Float) # CPU使用率
|
||||||
|
|
||||||
work_order = relationship("WorkOrder", back_populates="conversations")
|
work_order = relationship("WorkOrder", back_populates="conversations")
|
||||||
|
chat_session = relationship("ChatSession", back_populates="messages")
|
||||||
|
|
||||||
class KnowledgeEntry(Base):
|
class KnowledgeEntry(Base):
|
||||||
"""知识库条目模型"""
|
"""知识库条目模型"""
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class QueryOptimizer:
|
|||||||
for conv in conversations:
|
for conv in conversations:
|
||||||
conversation_list.append({
|
conversation_list.append({
|
||||||
'id': conv.id,
|
'id': conv.id,
|
||||||
|
'session_id': conv.session_id,
|
||||||
'user_message': conv.user_message,
|
'user_message': conv.user_message,
|
||||||
'assistant_response': conv.assistant_response,
|
'assistant_response': conv.assistant_response,
|
||||||
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,
|
'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 sqlalchemy.orm import Session
|
||||||
|
|
||||||
from ..core.database import db_manager
|
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 ..core.redis_manager import redis_manager
|
||||||
from src.config.unified_config import get_config
|
from src.config.unified_config import get_config
|
||||||
from sqlalchemy import and_, or_, desc
|
from sqlalchemy import and_, or_, desc
|
||||||
@@ -45,7 +45,8 @@ class ConversationHistoryManager:
|
|||||||
response_time: Optional[float] = None,
|
response_time: Optional[float] = None,
|
||||||
knowledge_used: Optional[List[int]] = None,
|
knowledge_used: Optional[List[int]] = None,
|
||||||
ip_address: Optional[str] = None,
|
ip_address: Optional[str] = None,
|
||||||
invocation_method: Optional[str] = None
|
invocation_method: Optional[str] = None,
|
||||||
|
session_id: Optional[str] = None
|
||||||
) -> int:
|
) -> int:
|
||||||
"""保存对话记录到数据库和Redis"""
|
"""保存对话记录到数据库和Redis"""
|
||||||
conversation_id = 0
|
conversation_id = 0
|
||||||
@@ -54,6 +55,7 @@ class ConversationHistoryManager:
|
|||||||
# 保存到数据库
|
# 保存到数据库
|
||||||
with db_manager.get_session() as session:
|
with db_manager.get_session() as session:
|
||||||
conversation = Conversation(
|
conversation = Conversation(
|
||||||
|
session_id=session_id,
|
||||||
work_order_id=work_order_id,
|
work_order_id=work_order_id,
|
||||||
user_message=user_message,
|
user_message=user_message,
|
||||||
assistant_response=assistant_response,
|
assistant_response=assistant_response,
|
||||||
@@ -715,3 +717,130 @@ class ConversationHistoryManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取对话分析数据失败: {e}")
|
logger.error(f"获取对话分析数据失败: {e}")
|
||||||
return {}
|
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 ..core.llm_client import QwenClient
|
||||||
from ..knowledge_base.knowledge_manager import KnowledgeManager
|
from ..knowledge_base.knowledge_manager import KnowledgeManager
|
||||||
from ..core.database import db_manager
|
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
|
from ..vehicle.vehicle_data_manager import VehicleDataManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -54,6 +54,21 @@ class RealtimeChatManager:
|
|||||||
|
|
||||||
self.active_sessions[session_id] = session_data
|
self.active_sessions[session_id] = session_data
|
||||||
self.message_history[session_id] = []
|
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}")
|
logger.info(f"创建新会话: {session_id}")
|
||||||
return session_id
|
return session_id
|
||||||
@@ -356,7 +371,7 @@ class RealtimeChatManager:
|
|||||||
"""保存对话到数据库"""
|
"""保存对话到数据库"""
|
||||||
try:
|
try:
|
||||||
with db_manager.get_session() as session:
|
with db_manager.get_session() as session:
|
||||||
# 统一为一条记录:包含用户消息与助手回复
|
# 计算响应时间
|
||||||
try:
|
try:
|
||||||
response_time = None
|
response_time = None
|
||||||
if assistant_msg.timestamp and user_msg.timestamp:
|
if assistant_msg.timestamp and user_msg.timestamp:
|
||||||
@@ -364,26 +379,36 @@ class RealtimeChatManager:
|
|||||||
except Exception:
|
except Exception:
|
||||||
response_time = None
|
response_time = None
|
||||||
|
|
||||||
# 在知识字段中打上会话标记,便于结束时合并清理
|
# 保存知识库使用记录(不再塞 session_marker)
|
||||||
marked_knowledge = assistant_msg.knowledge_used or []
|
knowledge_data = assistant_msg.knowledge_used or []
|
||||||
try:
|
|
||||||
marked_knowledge = list(marked_knowledge)
|
|
||||||
marked_knowledge.append({"session_id": session_id, "type": "session_marker"})
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
conversation = Conversation(
|
conversation = Conversation(
|
||||||
|
session_id=session_id,
|
||||||
work_order_id=assistant_msg.work_order_id or user_msg.work_order_id,
|
work_order_id=assistant_msg.work_order_id or user_msg.work_order_id,
|
||||||
user_message=user_msg.content or "",
|
user_message=user_msg.content or "",
|
||||||
assistant_response=assistant_msg.content or "",
|
assistant_response=assistant_msg.content or "",
|
||||||
timestamp=assistant_msg.timestamp or user_msg.timestamp,
|
timestamp=assistant_msg.timestamp or user_msg.timestamp,
|
||||||
confidence_score=assistant_msg.confidence_score,
|
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,
|
response_time=response_time,
|
||||||
ip_address=ip_address,
|
ip_address=ip_address,
|
||||||
invocation_method=invocation_method
|
invocation_method=invocation_method
|
||||||
)
|
)
|
||||||
session.add(conversation)
|
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()
|
session.commit()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -470,57 +495,21 @@ class RealtimeChatManager:
|
|||||||
def end_session(self, session_id: str) -> bool:
|
def end_session(self, session_id: str) -> bool:
|
||||||
"""结束会话"""
|
"""结束会话"""
|
||||||
try:
|
try:
|
||||||
if session_id in self.active_sessions:
|
# 更新数据库中的会话状态
|
||||||
session_meta = self.active_sessions[session_id]
|
try:
|
||||||
# 汇总本会话为一条记录
|
with db_manager.get_session() as dbs:
|
||||||
history = self.message_history.get(session_id, [])
|
chat_session = dbs.query(ChatSession).filter(
|
||||||
if history:
|
ChatSession.session_id == session_id
|
||||||
user_parts = []
|
).first()
|
||||||
assistant_parts = []
|
if chat_session:
|
||||||
response_times = []
|
chat_session.status = "ended"
|
||||||
first_ts = None
|
chat_session.ended_at = datetime.now()
|
||||||
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
|
|
||||||
dbs.commit()
|
dbs.commit()
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"更新会话状态失败: {e}")
|
||||||
|
|
||||||
|
# 清理内存
|
||||||
|
if session_id in self.active_sessions:
|
||||||
del self.active_sessions[session_id]
|
del self.active_sessions[session_id]
|
||||||
|
|
||||||
if session_id in self.message_history:
|
if session_id in self.message_history:
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ from sqlalchemy import func
|
|||||||
from ..core.database import db_manager
|
from ..core.database import db_manager
|
||||||
from ..core.models import KnowledgeEntry, WorkOrder, Conversation
|
from ..core.models import KnowledgeEntry, WorkOrder, Conversation
|
||||||
from ..core.llm_client import QwenClient
|
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__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -18,12 +21,18 @@ class KnowledgeManager:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.llm_client = QwenClient()
|
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(
|
self.vectorizer = TfidfVectorizer(
|
||||||
max_features=1000,
|
max_features=1000,
|
||||||
stop_words=None, # 不使用英文停用词,因为数据是中文
|
stop_words=None, # 不使用英文停用词,因为数据是中文
|
||||||
ngram_range=(1, 2)
|
ngram_range=(1, 2)
|
||||||
)
|
)
|
||||||
self._load_vectorizer()
|
self._load_vectorizer()
|
||||||
|
# 加载向量索引(embedding 模式)
|
||||||
|
if self.embedding_enabled:
|
||||||
|
vector_store.load_from_db()
|
||||||
|
|
||||||
def _load_vectorizer(self):
|
def _load_vectorizer(self):
|
||||||
"""加载向量化器"""
|
"""加载向量化器"""
|
||||||
@@ -71,17 +80,34 @@ class KnowledgeManager:
|
|||||||
existing_entry.updated_at = datetime.now()
|
existing_entry.updated_at = datetime.now()
|
||||||
if work_order.satisfaction_score:
|
if work_order.satisfaction_score:
|
||||||
existing_entry.confidence_score = 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:
|
else:
|
||||||
# 创建新条目
|
# 创建新条目
|
||||||
logger.info(f"未发现相似条目,正在为工单 {work_order_id} 创建新知识点")
|
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(
|
new_entry = KnowledgeEntry(
|
||||||
question=question,
|
question=question,
|
||||||
answer=answer,
|
answer=answer,
|
||||||
category=work_order.category,
|
category=work_order.category,
|
||||||
confidence_score=work_order.satisfaction_score or 0.5,
|
confidence_score=work_order.satisfaction_score or 0.5,
|
||||||
usage_count=1
|
usage_count=1,
|
||||||
|
vector_embedding=embedding_json
|
||||||
)
|
)
|
||||||
session.add(new_entry)
|
session.add(new_entry)
|
||||||
|
session.flush() # 获取 ID
|
||||||
|
if vec and new_entry.id:
|
||||||
|
vector_store.add(new_entry.id, vec)
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
logger.info(f"从工单 {work_order_id} 学习知识成功")
|
logger.info(f"从工单 {work_order_id} 学习知识成功")
|
||||||
@@ -94,6 +120,22 @@ class KnowledgeManager:
|
|||||||
def _find_similar_entry(self, question: str, session) -> Optional[KnowledgeEntry]:
|
def _find_similar_entry(self, question: str, session) -> Optional[KnowledgeEntry]:
|
||||||
"""查找相似的知识库条目"""
|
"""查找相似的知识库条目"""
|
||||||
try:
|
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(
|
entries = session.query(KnowledgeEntry).filter(
|
||||||
KnowledgeEntry.is_active == True
|
KnowledgeEntry.is_active == True
|
||||||
).all()
|
).all()
|
||||||
@@ -101,7 +143,6 @@ class KnowledgeManager:
|
|||||||
if not entries:
|
if not entries:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 计算相似度
|
|
||||||
texts = [entry.question for entry in entries]
|
texts = [entry.question for entry in entries]
|
||||||
question_vector = self.vectorizer.transform([question])
|
question_vector = self.vectorizer.transform([question])
|
||||||
entry_vectors = self.vectorizer.transform(texts)
|
entry_vectors = self.vectorizer.transform(texts)
|
||||||
@@ -110,13 +151,11 @@ class KnowledgeManager:
|
|||||||
max_similarity_idx = np.argmax(similarities)
|
max_similarity_idx = np.argmax(similarities)
|
||||||
max_score = similarities[max_similarity_idx]
|
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: # 相似度阈值
|
if max_score > 0.8:
|
||||||
logger.info(f"匹配成功: 相似度 {max_score:.4f} 超过阈值 0.8")
|
|
||||||
return entries[max_similarity_idx]
|
return entries[max_similarity_idx]
|
||||||
|
|
||||||
logger.debug(f"匹配跳过: 相似度 {max_score:.4f} 未达到阈值 0.8")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -124,7 +163,85 @@ class KnowledgeManager:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def search_knowledge(self, query: str, top_k: int = 3, verified_only: bool = True) -> List[Dict[str, Any]]:
|
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:
|
try:
|
||||||
with db_manager.get_session() as session:
|
with db_manager.get_session() as session:
|
||||||
# 构建查询条件
|
# 构建查询条件
|
||||||
@@ -221,6 +338,14 @@ class KnowledgeManager:
|
|||||||
) -> bool:
|
) -> bool:
|
||||||
"""添加知识库条目"""
|
"""添加知识库条目"""
|
||||||
try:
|
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:
|
with db_manager.get_session() as session:
|
||||||
entry = KnowledgeEntry(
|
entry = KnowledgeEntry(
|
||||||
question=question,
|
question=question,
|
||||||
@@ -228,12 +353,18 @@ class KnowledgeManager:
|
|||||||
category=category,
|
category=category,
|
||||||
confidence_score=confidence_score,
|
confidence_score=confidence_score,
|
||||||
usage_count=0,
|
usage_count=0,
|
||||||
is_verified=is_verified
|
is_verified=is_verified,
|
||||||
|
vector_embedding=embedding_json
|
||||||
)
|
)
|
||||||
session.add(entry)
|
session.add(entry)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
entry_id = entry.id
|
||||||
|
|
||||||
# 重新训练向量化器
|
# 更新向量索引
|
||||||
|
if vec and entry_id:
|
||||||
|
vector_store.add(entry_id, vec)
|
||||||
|
|
||||||
|
# 重新训练 TF-IDF 向量化器
|
||||||
self._load_vectorizer()
|
self._load_vectorizer()
|
||||||
|
|
||||||
logger.info(f"添加知识库条目成功: {question[:50]}...")
|
logger.info(f"添加知识库条目成功: {question[:50]}...")
|
||||||
@@ -261,15 +392,26 @@ class KnowledgeManager:
|
|||||||
if not entry:
|
if not entry:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
content_changed = False
|
||||||
if question:
|
if question:
|
||||||
entry.question = question
|
entry.question = question
|
||||||
|
content_changed = True
|
||||||
if answer:
|
if answer:
|
||||||
entry.answer = answer
|
entry.answer = answer
|
||||||
|
content_changed = True
|
||||||
if category:
|
if category:
|
||||||
entry.category = category
|
entry.category = category
|
||||||
if confidence_score is not None:
|
if confidence_score is not None:
|
||||||
entry.confidence_score = confidence_score
|
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()
|
entry.updated_at = datetime.now()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@@ -383,12 +525,14 @@ class KnowledgeManager:
|
|||||||
entry.is_active = False
|
entry.is_active = False
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
# 从向量索引中移除
|
||||||
|
vector_store.remove(entry_id)
|
||||||
|
|
||||||
# 重新训练向量化器(如果还有活跃条目)
|
# 重新训练向量化器(如果还有活跃条目)
|
||||||
try:
|
try:
|
||||||
self._load_vectorizer()
|
self._load_vectorizer()
|
||||||
except Exception as vectorizer_error:
|
except Exception as vectorizer_error:
|
||||||
logger.warning(f"重新加载向量化器失败: {vectorizer_error}")
|
logger.warning(f"重新加载向量化器失败: {vectorizer_error}")
|
||||||
# 即使向量化器加载失败,删除操作仍然成功
|
|
||||||
|
|
||||||
logger.info(f"删除知识库条目成功: {entry_id}")
|
logger.info(f"删除知识库条目成功: {entry_id}")
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -185,20 +185,20 @@ def get_agent_tools_stats():
|
|||||||
try:
|
try:
|
||||||
from src.web.service_manager import service_manager
|
from src.web.service_manager import service_manager
|
||||||
agent_assistant = service_manager.get_agent_assistant()
|
agent_assistant = service_manager.get_agent_assistant()
|
||||||
tools = agent_assistant.agent_core.tool_manager.get_available_tools()
|
react_status = agent_assistant.react_agent.get_status()
|
||||||
performance = agent_assistant.agent_core.tool_manager.get_tool_performance_report()
|
tools = agent_assistant.react_agent.get_tool_definitions()
|
||||||
|
history = agent_assistant.react_agent.get_execution_history(20)
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"tools": tools,
|
"tools": tools,
|
||||||
"performance": performance
|
"status": react_status,
|
||||||
|
"recent_history": history
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 返回默认工具列表,避免500错误
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": False,
|
"success": False,
|
||||||
"tools": [],
|
"tools": [],
|
||||||
"performance": {},
|
"error": str(e)
|
||||||
"error": "工具统计暂时不可用"
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -213,15 +213,23 @@ def execute_agent_tool():
|
|||||||
if not tool_name:
|
if not tool_name:
|
||||||
return jsonify({"error": "缺少工具名称tool"}), 400
|
return jsonify({"error": "缺少工具名称tool"}), 400
|
||||||
|
|
||||||
result = service_manager.get_agent_assistant().agent_core.tool_manager.execute_tool_sync(tool_name, parameters)
|
agent = service_manager.get_agent_assistant()
|
||||||
return jsonify(result)
|
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:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
@agent_bp.route('/tools/register', methods=['POST'])
|
@agent_bp.route('/tools/register', methods=['POST'])
|
||||||
def register_custom_tool():
|
def register_custom_tool():
|
||||||
"""注册自定义工具(仅登记元数据,函数为占位符)"""
|
"""注册自定义工具(仅登记元数据)"""
|
||||||
try:
|
try:
|
||||||
from src.web.service_manager import service_manager
|
from src.web.service_manager import service_manager
|
||||||
data = request.get_json() or {}
|
data = request.get_json() or {}
|
||||||
@@ -230,14 +238,9 @@ def register_custom_tool():
|
|||||||
if not name:
|
if not name:
|
||||||
return jsonify({"error": "缺少工具名称"}), 400
|
return jsonify({"error": "缺少工具名称"}), 400
|
||||||
|
|
||||||
def _placeholder_tool(**kwargs):
|
agent = service_manager.get_agent_assistant()
|
||||||
return {"message": f"自定义工具 {name} 已登记(占位),当前不可执行", "params": kwargs}
|
agent.register_tool(name, lambda **kw: {"message": f"自定义工具 {name} 占位", "params": kw},
|
||||||
|
metadata={"description": description, "custom": True})
|
||||||
service_manager.get_agent_assistant().agent_core.tool_manager.register_tool(
|
|
||||||
name,
|
|
||||||
_placeholder_tool,
|
|
||||||
metadata={"description": description, "custom": True}
|
|
||||||
)
|
|
||||||
return jsonify({"success": True, "message": "工具已注册"})
|
return jsonify({"success": True, "message": "工具已注册"})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
@@ -248,7 +251,7 @@ def unregister_custom_tool(name):
|
|||||||
"""注销自定义工具"""
|
"""注销自定义工具"""
|
||||||
try:
|
try:
|
||||||
from src.web.service_manager import service_manager
|
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})
|
return jsonify({"success": success})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|||||||
@@ -349,3 +349,68 @@ def get_conversation_analytics():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取对话分析数据失败: {e}")
|
logger.error(f"获取对话分析数据失败: {e}")
|
||||||
return jsonify({"error": str(e)}), 500
|
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()
|
).limit(50).all()
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
error_id = 1
|
|
||||||
|
|
||||||
for conv in conversations:
|
for conv in conversations:
|
||||||
error_type = None
|
error_type = None
|
||||||
@@ -460,14 +459,17 @@ def get_error_log():
|
|||||||
# 只记录有错误的对话
|
# 只记录有错误的对话
|
||||||
if error_type:
|
if error_type:
|
||||||
errors.append({
|
errors.append({
|
||||||
'id': error_id,
|
'id': conv.id,
|
||||||
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,
|
'timestamp': conv.timestamp.isoformat() if conv.timestamp else None,
|
||||||
'error_type': error_type,
|
'error_type': error_type,
|
||||||
'error_message': error_message,
|
'error_message': error_message,
|
||||||
'model': 'qwen-turbo', # 实际使用的模型
|
'model': 'qwen-turbo',
|
||||||
'user_id': f'user_{conv.id}'
|
'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({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
@@ -476,6 +478,31 @@ def get_error_log():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
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'])
|
@monitoring_bp.route('/ai-monitor/error-log', methods=['DELETE'])
|
||||||
def clear_error_log():
|
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() {
|
async loadSystemOptimizer() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -2469,6 +2469,24 @@
|
|||||||
<!-- 通知容器 -->
|
<!-- 通知容器 -->
|
||||||
<div id="notificationContainer" class="position-fixed top-0 end-0 p-3" style="z-index: 1050;"></div>
|
<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/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>
|
<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