Files

315 lines
9.2 KiB
Python
Raw Permalink Normal View History

"""
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()
)