feat: 优化飞书集成、知识库、Agent、工单管理及AI建议功能,统一前端对话字体样式并移除工单模板文件。
This commit is contained in:
@@ -6,10 +6,12 @@ TSP Agent助手 - 简化版本
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
from datetime import datetime
|
||||
from src.config.unified_config import get_config
|
||||
from src.agent.llm_client import LLMManager
|
||||
from src.web.service_manager import service_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -304,22 +306,65 @@ class TSPAgentAssistant:
|
||||
logger.error(f"获取LLM使用统计失败: {e}")
|
||||
return {}
|
||||
|
||||
def process_message_agent_sync(self, message: str, user_id: str = "admin",
|
||||
work_order_id: Optional[int] = None,
|
||||
enable_proactive: bool = True) -> Dict[str, Any]:
|
||||
"""处理消息(同步桥接)"""
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
return loop.run_until_complete(self.process_message_agent(message, user_id, work_order_id, enable_proactive))
|
||||
except Exception as e:
|
||||
logger.error(f"同步处理消息失败: {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
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]:
|
||||
"""处理消息"""
|
||||
"""处理消息 (实战化)"""
|
||||
try:
|
||||
# 简化的消息处理
|
||||
logger.info(f"Agent收到消息: {message}")
|
||||
|
||||
# 1. 识别意图和推荐工具
|
||||
prompt = f"用户消息: {message}\n请分析用户意图,并从工具列表中选择最合适的工具。工具列表: {json.dumps(self.get_available_tools())}\n请直接返回你的分析和建议响应。"
|
||||
|
||||
response_text = await self.llm_manager.generate(prompt)
|
||||
|
||||
# 2. 模拟动作生成
|
||||
actions = []
|
||||
if "工单" in message or "查询" in message:
|
||||
actions.append({"type": "tool_call", "tool": "search_work_order", "status": "suggested"})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Agent收到消息: {message}",
|
||||
"response": response_text,
|
||||
"actions": actions,
|
||||
"user_id": user_id,
|
||||
"work_order_id": work_order_id,
|
||||
"status": "completed",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"处理消息失败: {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
def execute_tool_sync(self, tool_name: str, parameters: Dict[str, Any] = None) -> Dict[str, Any]:
|
||||
"""执行工具(同步桥接)"""
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
return loop.run_until_complete(self.execute_tool(tool_name, parameters))
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
def trigger_sample_actions_sync(self) -> Dict[str, Any]:
|
||||
"""触发示例动作(同步桥接)"""
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
return loop.run_until_complete(self.trigger_sample_actions())
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
async def trigger_sample_actions(self) -> Dict[str, Any]:
|
||||
"""触发示例动作"""
|
||||
@@ -336,7 +381,7 @@ class TSPAgentAssistant:
|
||||
logger.error(f"触发示例动作失败: {e}")
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
def process_file_to_knowledge(self, file_path: str, filename: str) -> Dict[str, Any]:
|
||||
async def process_file_to_knowledge(self, file_path: str, filename: str) -> Dict[str, Any]:
|
||||
"""处理文件并生成知识库"""
|
||||
try:
|
||||
import os
|
||||
@@ -356,20 +401,39 @@ class TSPAgentAssistant:
|
||||
|
||||
logger.info(f"文件读取成功: {filename}, 字符数={len(content)}")
|
||||
|
||||
# 使用简化的知识提取
|
||||
# 使用LLM进行知识提取 (异步调用)
|
||||
logger.info(f"正在对文件内容进行 AI 知识提取...")
|
||||
knowledge_entries = self._extract_knowledge_from_content(content, filename)
|
||||
knowledge_entries = await self._extract_knowledge_from_content(content, filename)
|
||||
|
||||
logger.info(f"知识提取完成: 共提取出 {len(knowledge_entries)} 个潜在条目")
|
||||
|
||||
# 保存到知识库
|
||||
saved_count = 0
|
||||
|
||||
# 获取知识库管理器
|
||||
try:
|
||||
knowledge_manager = service_manager.get_assistant().knowledge_manager
|
||||
except Exception as e:
|
||||
logger.error(f"无法获取知识库管理器: {e}")
|
||||
knowledge_manager = None
|
||||
|
||||
for i, entry in enumerate(knowledge_entries):
|
||||
try:
|
||||
logger.info(f"正在保存知识条目 [{i+1}/{len(knowledge_entries)}]: {entry.get('question', '')[:30]}...")
|
||||
# 这里在实际项目中应当注入知识库管理器的保存逻辑
|
||||
# 但在当前简化版本中仅记录日志
|
||||
saved_count += 1
|
||||
|
||||
if knowledge_manager:
|
||||
# 实际保存到数据库
|
||||
knowledge_manager.add_knowledge_entry(
|
||||
question=entry.get('question'),
|
||||
answer=entry.get('answer'),
|
||||
category=entry.get('category', '文档导入'),
|
||||
confidence_score=entry.get('confidence_score', 0.8)
|
||||
)
|
||||
saved_count += 1
|
||||
else:
|
||||
# 如果无法获取管理器,仅记录日志(降级处理)
|
||||
logger.warning("知识库管理器不可用,跳过保存")
|
||||
|
||||
except Exception as save_error:
|
||||
logger.error(f"保存知识条目 {i+1} 时出错: {save_error}")
|
||||
|
||||
@@ -402,26 +466,71 @@ class TSPAgentAssistant:
|
||||
logger.error(f"读取文件失败: {e}")
|
||||
return ""
|
||||
|
||||
def _extract_knowledge_from_content(self, content: str, filename: str) -> List[Dict[str, Any]]:
|
||||
"""从内容中提取知识"""
|
||||
async def _extract_knowledge_from_content(self, content: str, filename: str) -> List[Dict[str, Any]]:
|
||||
"""从内容中提取知识 - 使用LLM"""
|
||||
try:
|
||||
# 简化的知识提取逻辑
|
||||
entries = []
|
||||
|
||||
# 按段落分割内容
|
||||
paragraphs = content.split('\n\n')
|
||||
|
||||
for i, paragraph in enumerate(paragraphs[:5]): # 最多提取5个
|
||||
if len(paragraph.strip()) > 20: # 过滤太短的段落
|
||||
entries.append({
|
||||
"question": f"关于{filename}的问题{i+1}",
|
||||
"answer": paragraph.strip(),
|
||||
"category": "文档知识",
|
||||
"confidence_score": 0.7
|
||||
# 限制内容长度,避免超出token限制
|
||||
# 假设每个汉字2个token,保留前8000个字符作为上下文
|
||||
truncated_content = content[:8000]
|
||||
if len(content) > 8000:
|
||||
truncated_content += "\n...(后续内容已省略)"
|
||||
|
||||
prompt = f"""
|
||||
你是一个专业的知识库构建助手。请分析以下文档内容,提取出关键的"问题"和"答案"对,用于构建知识库。
|
||||
|
||||
文档文件名:{filename}
|
||||
文档内容:
|
||||
{truncated_content}
|
||||
|
||||
要求:
|
||||
1. 提取文档中的核心知识点,转化为"问题(question)"和"答案(answer)"的形式。
|
||||
2. "问题"应该清晰明确,方便用户搜索。
|
||||
3. "答案"应该准确、完整,直接回答问题。
|
||||
4. "分类(category)"请根据内容自动归类(如:故障排查、操作指南、系统配置、业务流程等)。
|
||||
5. 输出格式必须是合法的 JSON 数组,不要包含Markdown标记。
|
||||
|
||||
JSON格式示例:
|
||||
[
|
||||
{{"question": "如何重置密码?", "answer": "请访问设置页面,点击重置密码按钮...", "category": "操作指南"}},
|
||||
{{"question": "系统支持哪些浏览器?", "answer": "支持Chrome, Edge, Firefox...", "category": "系统配置"}}
|
||||
]
|
||||
"""
|
||||
# 调用LLM生成
|
||||
logger.info("正在调用LLM进行知识提取...")
|
||||
response_text = await self.llm_manager.generate(prompt, temperature=0.3)
|
||||
|
||||
# 清理响应中的Markdown标记(如果存在)
|
||||
cleaned_text = response_text.strip()
|
||||
if cleaned_text.startswith("```json"):
|
||||
cleaned_text = cleaned_text[7:]
|
||||
if cleaned_text.startswith("```"):
|
||||
cleaned_text = cleaned_text[3:]
|
||||
if cleaned_text.endswith("```"):
|
||||
cleaned_text = cleaned_text[:-3]
|
||||
cleaned_text = cleaned_text.strip()
|
||||
|
||||
# 解析JSON
|
||||
try:
|
||||
entries = json.loads(cleaned_text)
|
||||
except json.JSONDecodeError:
|
||||
# 尝试修复常见的JSON错误
|
||||
logger.warning(f"JSON解析失败,尝试简单修复: {cleaned_text[:100]}...")
|
||||
# 这里可以添加更复杂的修复逻辑,或者直接记录错误
|
||||
return []
|
||||
|
||||
# 验证和标准化
|
||||
valid_entries = []
|
||||
for entry in entries:
|
||||
if isinstance(entry, dict) and "question" in entry and "answer" in entry:
|
||||
valid_entries.append({
|
||||
"question": entry["question"],
|
||||
"answer": entry["answer"],
|
||||
"category": entry.get("category", "文档导入"),
|
||||
"confidence_score": 0.9 # LLM生成的置信度较高
|
||||
})
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
return valid_entries
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"提取知识失败: {e}")
|
||||
return []
|
||||
|
||||
Reference in New Issue
Block a user