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:
314
backend/routers/agents.py
Normal file
314
backend/routers/agents.py
Normal file
@@ -0,0 +1,314 @@
|
||||
"""
|
||||
Agent管理路由
|
||||
"""
|
||||
from typing import List, Optional, Dict, Any
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from loguru import logger
|
||||
|
||||
from services.agent_service import AgentService, AGENT_TEMPLATES
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# ============ 请求/响应模型 ============
|
||||
|
||||
class CapabilitiesModel(BaseModel):
|
||||
"""能力配置模型"""
|
||||
memory_enabled: bool = False
|
||||
mcp_tools: List[str] = []
|
||||
skills: List[str] = []
|
||||
multimodal: bool = False
|
||||
|
||||
|
||||
class BehaviorModel(BaseModel):
|
||||
"""行为配置模型"""
|
||||
speak_threshold: float = 0.5
|
||||
max_speak_per_round: int = 2
|
||||
speak_style: str = "balanced"
|
||||
|
||||
|
||||
class AgentCreateRequest(BaseModel):
|
||||
"""创建Agent请求"""
|
||||
name: str = Field(..., description="Agent名称")
|
||||
role: str = Field(..., description="角色定义")
|
||||
system_prompt: str = Field(..., description="系统提示词")
|
||||
provider_id: str = Field(..., description="使用的AI接口ID")
|
||||
temperature: float = Field(default=0.7, ge=0, le=2, description="温度参数")
|
||||
max_tokens: int = Field(default=2000, gt=0, description="最大token数")
|
||||
capabilities: Optional[CapabilitiesModel] = None
|
||||
behavior: Optional[BehaviorModel] = None
|
||||
avatar: Optional[str] = None
|
||||
color: str = "#1890ff"
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"name": "产品经理",
|
||||
"role": "产品规划和需求分析专家",
|
||||
"system_prompt": "你是一位经验丰富的产品经理...",
|
||||
"provider_id": "openrouter-abc123",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 2000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AgentUpdateRequest(BaseModel):
|
||||
"""更新Agent请求"""
|
||||
name: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
system_prompt: Optional[str] = None
|
||||
provider_id: Optional[str] = None
|
||||
temperature: Optional[float] = Field(default=None, ge=0, le=2)
|
||||
max_tokens: Optional[int] = Field(default=None, gt=0)
|
||||
capabilities: Optional[CapabilitiesModel] = None
|
||||
behavior: Optional[BehaviorModel] = None
|
||||
avatar: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
enabled: Optional[bool] = None
|
||||
|
||||
|
||||
class AgentResponse(BaseModel):
|
||||
"""Agent响应"""
|
||||
agent_id: str
|
||||
name: str
|
||||
role: str
|
||||
system_prompt: str
|
||||
provider_id: str
|
||||
temperature: float
|
||||
max_tokens: int
|
||||
capabilities: Dict[str, Any]
|
||||
behavior: Dict[str, Any]
|
||||
avatar: Optional[str]
|
||||
color: str
|
||||
enabled: bool
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
class AgentTestRequest(BaseModel):
|
||||
"""Agent测试请求"""
|
||||
message: str = "你好,请简单介绍一下你自己。"
|
||||
|
||||
|
||||
class AgentTestResponse(BaseModel):
|
||||
"""Agent测试响应"""
|
||||
success: bool
|
||||
message: str
|
||||
response: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
tokens: Optional[int] = None
|
||||
latency_ms: Optional[float] = None
|
||||
|
||||
|
||||
class TemplateResponse(BaseModel):
|
||||
"""模板响应"""
|
||||
template_id: str
|
||||
name: str
|
||||
role: str
|
||||
system_prompt: str
|
||||
color: str
|
||||
|
||||
|
||||
class GeneratePromptRequest(BaseModel):
|
||||
"""生成提示词请求"""
|
||||
provider_id: str = Field(..., description="使用的AI接口ID")
|
||||
name: str = Field(..., description="Agent名称")
|
||||
role: str = Field(..., description="角色定位")
|
||||
description: Optional[str] = Field(None, description="额外描述(可选)")
|
||||
|
||||
|
||||
class GeneratePromptResponse(BaseModel):
|
||||
"""生成提示词响应"""
|
||||
success: bool
|
||||
message: Optional[str] = None
|
||||
prompt: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
tokens: Optional[int] = None
|
||||
|
||||
|
||||
# ============ 路由处理 ============
|
||||
|
||||
@router.post("", response_model=AgentResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_agent(request: AgentCreateRequest):
|
||||
"""
|
||||
创建新的Agent
|
||||
"""
|
||||
try:
|
||||
agent = await AgentService.create_agent(
|
||||
name=request.name,
|
||||
role=request.role,
|
||||
system_prompt=request.system_prompt,
|
||||
provider_id=request.provider_id,
|
||||
temperature=request.temperature,
|
||||
max_tokens=request.max_tokens,
|
||||
capabilities=request.capabilities.dict() if request.capabilities else None,
|
||||
behavior=request.behavior.dict() if request.behavior else None,
|
||||
avatar=request.avatar,
|
||||
color=request.color
|
||||
)
|
||||
|
||||
return _to_response(agent)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"创建Agent失败: {e}")
|
||||
raise HTTPException(status_code=500, detail="创建失败")
|
||||
|
||||
|
||||
@router.get("", response_model=List[AgentResponse])
|
||||
async def list_agents(enabled_only: bool = False):
|
||||
"""
|
||||
获取所有Agent
|
||||
"""
|
||||
agents = await AgentService.get_all_agents(enabled_only)
|
||||
return [_to_response(a) for a in agents]
|
||||
|
||||
|
||||
@router.get("/templates", response_model=List[TemplateResponse])
|
||||
async def list_templates():
|
||||
"""
|
||||
获取Agent预设模板
|
||||
"""
|
||||
return [
|
||||
TemplateResponse(
|
||||
template_id=tid,
|
||||
name=t["name"],
|
||||
role=t["role"],
|
||||
system_prompt=t["system_prompt"],
|
||||
color=t["color"]
|
||||
)
|
||||
for tid, t in AGENT_TEMPLATES.items()
|
||||
]
|
||||
|
||||
|
||||
@router.post("/generate-prompt", response_model=GeneratePromptResponse)
|
||||
async def generate_prompt(request: GeneratePromptRequest):
|
||||
"""
|
||||
使用AI生成Agent系统提示词
|
||||
"""
|
||||
result = await AgentService.generate_system_prompt(
|
||||
provider_id=request.provider_id,
|
||||
name=request.name,
|
||||
role=request.role,
|
||||
description=request.description
|
||||
)
|
||||
return GeneratePromptResponse(**result)
|
||||
|
||||
|
||||
@router.get("/{agent_id}", response_model=AgentResponse)
|
||||
async def get_agent(agent_id: str):
|
||||
"""
|
||||
获取指定Agent
|
||||
"""
|
||||
agent = await AgentService.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent不存在")
|
||||
return _to_response(agent)
|
||||
|
||||
|
||||
@router.put("/{agent_id}", response_model=AgentResponse)
|
||||
async def update_agent(agent_id: str, request: AgentUpdateRequest):
|
||||
"""
|
||||
更新Agent配置
|
||||
"""
|
||||
update_data = request.dict(exclude_unset=True)
|
||||
|
||||
# 转换嵌套模型
|
||||
if "capabilities" in update_data and update_data["capabilities"]:
|
||||
if hasattr(update_data["capabilities"], "dict"):
|
||||
update_data["capabilities"] = update_data["capabilities"].dict()
|
||||
if "behavior" in update_data and update_data["behavior"]:
|
||||
if hasattr(update_data["behavior"], "dict"):
|
||||
update_data["behavior"] = update_data["behavior"].dict()
|
||||
|
||||
try:
|
||||
agent = await AgentService.update_agent(agent_id, **update_data)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent不存在")
|
||||
return _to_response(agent)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{agent_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_agent(agent_id: str):
|
||||
"""
|
||||
删除Agent
|
||||
"""
|
||||
success = await AgentService.delete_agent(agent_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Agent不存在")
|
||||
|
||||
|
||||
@router.post("/{agent_id}/test", response_model=AgentTestResponse)
|
||||
async def test_agent(agent_id: str, request: AgentTestRequest = None):
|
||||
"""
|
||||
测试Agent对话
|
||||
"""
|
||||
message = request.message if request else "你好,请简单介绍一下你自己。"
|
||||
result = await AgentService.test_agent(agent_id, message)
|
||||
return AgentTestResponse(**result)
|
||||
|
||||
|
||||
@router.post("/{agent_id}/duplicate", response_model=AgentResponse)
|
||||
async def duplicate_agent(agent_id: str, new_name: Optional[str] = None):
|
||||
"""
|
||||
复制Agent
|
||||
"""
|
||||
agent = await AgentService.duplicate_agent(agent_id, new_name)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="源Agent不存在")
|
||||
return _to_response(agent)
|
||||
|
||||
|
||||
@router.post("/from-template/{template_id}", response_model=AgentResponse)
|
||||
async def create_from_template(template_id: str, provider_id: str):
|
||||
"""
|
||||
从模板创建Agent
|
||||
"""
|
||||
if template_id not in AGENT_TEMPLATES:
|
||||
raise HTTPException(status_code=404, detail="模板不存在")
|
||||
|
||||
template = AGENT_TEMPLATES[template_id]
|
||||
|
||||
try:
|
||||
agent = await AgentService.create_agent(
|
||||
name=template["name"],
|
||||
role=template["role"],
|
||||
system_prompt=template["system_prompt"],
|
||||
provider_id=provider_id,
|
||||
color=template["color"]
|
||||
)
|
||||
return _to_response(agent)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
# ============ 辅助函数 ============
|
||||
|
||||
def _to_response(agent) -> AgentResponse:
|
||||
"""
|
||||
转换为响应模型
|
||||
"""
|
||||
return AgentResponse(
|
||||
agent_id=agent.agent_id,
|
||||
name=agent.name,
|
||||
role=agent.role,
|
||||
system_prompt=agent.system_prompt,
|
||||
provider_id=agent.provider_id,
|
||||
temperature=agent.temperature,
|
||||
max_tokens=agent.max_tokens,
|
||||
capabilities=agent.capabilities,
|
||||
behavior=agent.behavior,
|
||||
avatar=agent.avatar,
|
||||
color=agent.color,
|
||||
enabled=agent.enabled,
|
||||
created_at=agent.created_at.isoformat(),
|
||||
updated_at=agent.updated_at.isoformat()
|
||||
)
|
||||
Reference in New Issue
Block a user