439 lines
12 KiB
Python
439 lines
12 KiB
Python
|
|
"""
|
|||
|
|
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"
|
|||
|
|
}
|
|||
|
|
}
|