feat: AI聊天室多Agent协作讨论平台
- 实现Agent管理,支持AI辅助生成系统提示词 - 支持多个AI提供商(OpenRouter、智谱、MiniMax等) - 实现聊天室和讨论引擎 - WebSocket实时消息推送 - 前端使用React + Ant Design - 后端使用FastAPI + MongoDB Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
438
backend/services/agent_service.py
Normal file
438
backend/services/agent_service.py
Normal file
@@ -0,0 +1,438 @@
|
||||
"""
|
||||
Agent服务
|
||||
管理AI代理的配置
|
||||
"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Any, Optional
|
||||
from loguru import logger
|
||||
|
||||
from models.agent import Agent
|
||||
from services.ai_provider_service import AIProviderService
|
||||
|
||||
|
||||
class AgentService:
|
||||
"""
|
||||
Agent服务类
|
||||
负责Agent的CRUD操作
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
async def create_agent(
|
||||
cls,
|
||||
name: str,
|
||||
role: str,
|
||||
system_prompt: str,
|
||||
provider_id: str,
|
||||
temperature: float = 0.7,
|
||||
max_tokens: int = 2000,
|
||||
capabilities: Optional[Dict[str, Any]] = None,
|
||||
behavior: Optional[Dict[str, Any]] = None,
|
||||
avatar: Optional[str] = None,
|
||||
color: str = "#1890ff"
|
||||
) -> Agent:
|
||||
"""
|
||||
创建新的Agent
|
||||
|
||||
Args:
|
||||
name: Agent名称
|
||||
role: 角色定义
|
||||
system_prompt: 系统提示词
|
||||
provider_id: 使用的AI接口ID
|
||||
temperature: 温度参数
|
||||
max_tokens: 最大token数
|
||||
capabilities: 能力配置
|
||||
behavior: 行为配置
|
||||
avatar: 头像URL
|
||||
color: 代表颜色
|
||||
|
||||
Returns:
|
||||
创建的Agent文档
|
||||
"""
|
||||
# 验证AI接口存在
|
||||
provider = await AIProviderService.get_provider(provider_id)
|
||||
if not provider:
|
||||
raise ValueError(f"AI接口不存在: {provider_id}")
|
||||
|
||||
# 生成唯一ID
|
||||
agent_id = f"agent-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
# 默认能力配置
|
||||
default_capabilities = {
|
||||
"memory_enabled": False,
|
||||
"mcp_tools": [],
|
||||
"skills": [],
|
||||
"multimodal": False
|
||||
}
|
||||
if capabilities:
|
||||
default_capabilities.update(capabilities)
|
||||
|
||||
# 默认行为配置
|
||||
default_behavior = {
|
||||
"speak_threshold": 0.5,
|
||||
"max_speak_per_round": 2,
|
||||
"speak_style": "balanced"
|
||||
}
|
||||
if behavior:
|
||||
default_behavior.update(behavior)
|
||||
|
||||
# 创建文档
|
||||
agent = Agent(
|
||||
agent_id=agent_id,
|
||||
name=name,
|
||||
role=role,
|
||||
system_prompt=system_prompt,
|
||||
provider_id=provider_id,
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
capabilities=default_capabilities,
|
||||
behavior=default_behavior,
|
||||
avatar=avatar,
|
||||
color=color,
|
||||
enabled=True,
|
||||
created_at=datetime.utcnow(),
|
||||
updated_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
await agent.insert()
|
||||
|
||||
logger.info(f"创建Agent: {agent_id} ({name})")
|
||||
return agent
|
||||
|
||||
@classmethod
|
||||
async def get_agent(cls, agent_id: str) -> Optional[Agent]:
|
||||
"""
|
||||
获取指定Agent
|
||||
|
||||
Args:
|
||||
agent_id: Agent ID
|
||||
|
||||
Returns:
|
||||
Agent文档或None
|
||||
"""
|
||||
return await Agent.find_one(Agent.agent_id == agent_id)
|
||||
|
||||
@classmethod
|
||||
async def get_all_agents(
|
||||
cls,
|
||||
enabled_only: bool = False
|
||||
) -> List[Agent]:
|
||||
"""
|
||||
获取所有Agent
|
||||
|
||||
Args:
|
||||
enabled_only: 是否只返回启用的Agent
|
||||
|
||||
Returns:
|
||||
Agent列表
|
||||
"""
|
||||
if enabled_only:
|
||||
return await Agent.find(Agent.enabled == True).to_list()
|
||||
return await Agent.find_all().to_list()
|
||||
|
||||
@classmethod
|
||||
async def get_agents_by_ids(
|
||||
cls,
|
||||
agent_ids: List[str]
|
||||
) -> List[Agent]:
|
||||
"""
|
||||
根据ID列表获取多个Agent
|
||||
|
||||
Args:
|
||||
agent_ids: Agent ID列表
|
||||
|
||||
Returns:
|
||||
Agent列表
|
||||
"""
|
||||
return await Agent.find(
|
||||
{"agent_id": {"$in": agent_ids}}
|
||||
).to_list()
|
||||
|
||||
@classmethod
|
||||
async def update_agent(
|
||||
cls,
|
||||
agent_id: str,
|
||||
**kwargs
|
||||
) -> Optional[Agent]:
|
||||
"""
|
||||
更新Agent配置
|
||||
|
||||
Args:
|
||||
agent_id: Agent ID
|
||||
**kwargs: 要更新的字段
|
||||
|
||||
Returns:
|
||||
更新后的Agent或None
|
||||
"""
|
||||
agent = await cls.get_agent(agent_id)
|
||||
if not agent:
|
||||
return None
|
||||
|
||||
# 如果更新了provider_id,验证其存在
|
||||
if "provider_id" in kwargs:
|
||||
provider = await AIProviderService.get_provider(kwargs["provider_id"])
|
||||
if not provider:
|
||||
raise ValueError(f"AI接口不存在: {kwargs['provider_id']}")
|
||||
|
||||
# 更新字段
|
||||
kwargs["updated_at"] = datetime.utcnow()
|
||||
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(agent, key):
|
||||
setattr(agent, key, value)
|
||||
|
||||
await agent.save()
|
||||
|
||||
logger.info(f"更新Agent: {agent_id}")
|
||||
return agent
|
||||
|
||||
@classmethod
|
||||
async def delete_agent(cls, agent_id: str) -> bool:
|
||||
"""
|
||||
删除Agent
|
||||
|
||||
Args:
|
||||
agent_id: Agent ID
|
||||
|
||||
Returns:
|
||||
是否删除成功
|
||||
"""
|
||||
agent = await cls.get_agent(agent_id)
|
||||
if not agent:
|
||||
return False
|
||||
|
||||
await agent.delete()
|
||||
|
||||
logger.info(f"删除Agent: {agent_id}")
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def test_agent(
|
||||
cls,
|
||||
agent_id: str,
|
||||
test_message: str = "你好,请简单介绍一下你自己。"
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
测试Agent对话
|
||||
|
||||
Args:
|
||||
agent_id: Agent ID
|
||||
test_message: 测试消息
|
||||
|
||||
Returns:
|
||||
测试结果
|
||||
"""
|
||||
agent = await cls.get_agent(agent_id)
|
||||
if not agent:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Agent不存在: {agent_id}"
|
||||
}
|
||||
|
||||
if not agent.enabled:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Agent已禁用"
|
||||
}
|
||||
|
||||
# 构建消息
|
||||
messages = [
|
||||
{"role": "system", "content": agent.system_prompt},
|
||||
{"role": "user", "content": test_message}
|
||||
]
|
||||
|
||||
# 调用AI接口
|
||||
response = await AIProviderService.chat(
|
||||
provider_id=agent.provider_id,
|
||||
messages=messages,
|
||||
temperature=agent.temperature,
|
||||
max_tokens=agent.max_tokens
|
||||
)
|
||||
|
||||
if response.success:
|
||||
return {
|
||||
"success": True,
|
||||
"message": "测试成功",
|
||||
"response": response.content,
|
||||
"model": response.model,
|
||||
"tokens": response.total_tokens,
|
||||
"latency_ms": response.latency_ms
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": response.error
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def duplicate_agent(
|
||||
cls,
|
||||
agent_id: str,
|
||||
new_name: Optional[str] = None
|
||||
) -> Optional[Agent]:
|
||||
"""
|
||||
复制Agent
|
||||
|
||||
Args:
|
||||
agent_id: 源Agent ID
|
||||
new_name: 新Agent名称
|
||||
|
||||
Returns:
|
||||
新创建的Agent或None
|
||||
"""
|
||||
source_agent = await cls.get_agent(agent_id)
|
||||
if not source_agent:
|
||||
return None
|
||||
|
||||
return await cls.create_agent(
|
||||
name=new_name or f"{source_agent.name} (副本)",
|
||||
role=source_agent.role,
|
||||
system_prompt=source_agent.system_prompt,
|
||||
provider_id=source_agent.provider_id,
|
||||
temperature=source_agent.temperature,
|
||||
max_tokens=source_agent.max_tokens,
|
||||
capabilities=source_agent.capabilities,
|
||||
behavior=source_agent.behavior,
|
||||
avatar=source_agent.avatar,
|
||||
color=source_agent.color
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def generate_system_prompt(
|
||||
cls,
|
||||
provider_id: str,
|
||||
name: str,
|
||||
role: str,
|
||||
description: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
使用AI生成Agent系统提示词
|
||||
|
||||
Args:
|
||||
provider_id: AI接口ID
|
||||
name: Agent名称
|
||||
role: 角色定位
|
||||
description: 额外描述(可选)
|
||||
|
||||
Returns:
|
||||
生成结果,包含success和生成的prompt
|
||||
"""
|
||||
# 验证AI接口存在
|
||||
provider = await AIProviderService.get_provider(provider_id)
|
||||
if not provider:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"AI接口不存在: {provider_id}"
|
||||
}
|
||||
|
||||
# 构建生成提示词的请求
|
||||
generate_prompt = f"""请为一个AI Agent编写系统提示词(system prompt)。
|
||||
|
||||
Agent名称:{name}
|
||||
角色定位:{role}
|
||||
{f'补充说明:{description}' if description else ''}
|
||||
|
||||
要求:
|
||||
1. 提示词应简洁专业,控制在200字以内
|
||||
2. 明确该Agent的核心职责和专业领域
|
||||
3. 说明在多Agent讨论中应该关注什么
|
||||
4. 使用中文编写
|
||||
5. 不要包含任何问候语或开场白,直接给出提示词内容
|
||||
|
||||
请直接输出系统提示词,不要有任何额外的解释或包装。"""
|
||||
|
||||
try:
|
||||
messages = [{"role": "user", "content": generate_prompt}]
|
||||
|
||||
response = await AIProviderService.chat(
|
||||
provider_id=provider_id,
|
||||
messages=messages,
|
||||
temperature=0.7,
|
||||
max_tokens=1000
|
||||
)
|
||||
|
||||
if response.success:
|
||||
# 清理可能的包装文本
|
||||
content = response.content.strip()
|
||||
# 移除可能的markdown代码块标记
|
||||
if content.startswith("```"):
|
||||
lines = content.split("\n")
|
||||
content = "\n".join(lines[1:])
|
||||
if content.endswith("```"):
|
||||
content = content[:-3]
|
||||
content = content.strip()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"prompt": content,
|
||||
"model": response.model,
|
||||
"tokens": response.total_tokens
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": response.error or "生成失败"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"生成系统提示词失败: {e}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"生成失败: {str(e)}"
|
||||
}
|
||||
|
||||
|
||||
# Agent预设模板
|
||||
AGENT_TEMPLATES = {
|
||||
"product_manager": {
|
||||
"name": "产品经理",
|
||||
"role": "产品规划和需求分析专家",
|
||||
"system_prompt": """你是一位经验丰富的产品经理,擅长:
|
||||
- 分析用户需求和痛点
|
||||
- 制定产品策略和路线图
|
||||
- 平衡业务目标和用户体验
|
||||
- 与团队协作推进产品迭代
|
||||
|
||||
在讨论中,你需要从产品角度出发,关注用户价值、商业可行性和优先级排序。
|
||||
请用专业但易懂的语言表达观点。""",
|
||||
"color": "#1890ff"
|
||||
},
|
||||
"developer": {
|
||||
"name": "开发工程师",
|
||||
"role": "技术实现和架构设计专家",
|
||||
"system_prompt": """你是一位资深的软件开发工程师,擅长:
|
||||
- 系统架构设计
|
||||
- 代码实现和优化
|
||||
- 技术方案评估
|
||||
- 性能和安全考量
|
||||
|
||||
在讨论中,你需要从技术角度出发,关注实现可行性、技术债务和最佳实践。
|
||||
请提供具体的技术建议和潜在风险评估。""",
|
||||
"color": "#52c41a"
|
||||
},
|
||||
"designer": {
|
||||
"name": "设计师",
|
||||
"role": "用户体验和界面设计专家",
|
||||
"system_prompt": """你是一位专业的UI/UX设计师,擅长:
|
||||
- 用户体验设计
|
||||
- 界面视觉设计
|
||||
- 交互流程优化
|
||||
- 设计系统构建
|
||||
|
||||
在讨论中,你需要从设计角度出发,关注用户体验、视觉美感和交互流畅性。
|
||||
请提供设计建议并考虑可用性和一致性。""",
|
||||
"color": "#eb2f96"
|
||||
},
|
||||
"moderator": {
|
||||
"name": "主持人",
|
||||
"role": "讨论主持和共识判断专家",
|
||||
"system_prompt": """你是讨论的主持人,负责:
|
||||
- 引导讨论方向
|
||||
- 总结各方观点
|
||||
- 判断是否达成共识
|
||||
- 提炼行动要点
|
||||
|
||||
在讨论中,你需要保持中立,促进有效沟通,并在适当时机总结讨论成果。
|
||||
当各方观点趋于一致时,请明确指出并总结共识内容。""",
|
||||
"color": "#722ed1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user