[modify] manage multi agent logic
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ import datetime
|
||||
from typing import Optional, List, Dict, Any, Union
|
||||
from pydantic import BaseModel, Field, ConfigDict, field_serializer
|
||||
|
||||
from app.schemas import ModelParameters
|
||||
|
||||
|
||||
# ==================== 子 Agent 配置 ====================
|
||||
|
||||
@@ -30,7 +32,7 @@ class ExecutionConfig(BaseModel):
|
||||
parallel_limit: int = Field(default=3, ge=1, le=10, description="并行限制")
|
||||
retry_on_failure: bool = Field(default=True, description="失败时是否重试")
|
||||
max_retries: int = Field(default=3, ge=0, le=10, description="最大重试次数")
|
||||
|
||||
|
||||
# 新增:路由模式配置
|
||||
routing_mode: str = Field(
|
||||
default="master_agent",
|
||||
@@ -41,14 +43,14 @@ class ExecutionConfig(BaseModel):
|
||||
default=True,
|
||||
description="是否启用规则快速路径(性能优化,高置信度关键词直接返回)"
|
||||
)
|
||||
|
||||
|
||||
# 新增:结果整合模式配置
|
||||
result_merge_mode: str = Field(
|
||||
default="smart",
|
||||
pattern="^(smart|master)$",
|
||||
description="结果整合模式:smart(规则去重,快速)| master(Master Agent 智能整合,连贯)"
|
||||
)
|
||||
|
||||
|
||||
# 新增:子 Agent 执行模式配置
|
||||
sub_agent_execution_mode: str = Field(
|
||||
default="parallel",
|
||||
@@ -82,6 +84,11 @@ class MultiAgentConfigUpdate(BaseModel):
|
||||
"""更新多 Agent 配置"""
|
||||
master_agent_id: Optional[uuid.UUID] = None
|
||||
master_agent_name: Optional[str] = Field(None, max_length=100, description="主 Agent 名称")
|
||||
default_model_config_id : uuid.UUID = Field(description="默认模型配置ID")
|
||||
model_parameters: ModelParameters | None = Field(
|
||||
default_factory=ModelParameters,
|
||||
description="模型参数配置(temperature、max_tokens 等)"
|
||||
)
|
||||
orchestration_mode: Optional[str] = Field(
|
||||
None,
|
||||
pattern="^(sequential|parallel|conditional|loop)$"
|
||||
@@ -99,11 +106,16 @@ class MultiAgentConfigUpdate(BaseModel):
|
||||
class MultiAgentConfigSchema(BaseModel):
|
||||
"""多 Agent 配置输出"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
id: uuid.UUID
|
||||
app_id: uuid.UUID
|
||||
master_agent_id: uuid.UUID
|
||||
master_agent_name: Optional[str]
|
||||
default_model_config_id : uuid.UUID | None = Field(description="默认模型配置ID")
|
||||
model_parameters: ModelParameters | None = Field(
|
||||
default_factory=ModelParameters,
|
||||
description="模型参数配置(temperature、max_tokens 等)"
|
||||
)
|
||||
orchestration_mode: str
|
||||
sub_agents: List[Dict[str, Any]]
|
||||
routing_rules: Optional[List[Dict[str, Any]]]
|
||||
@@ -112,11 +124,11 @@ class MultiAgentConfigSchema(BaseModel):
|
||||
is_active: bool
|
||||
created_at: datetime.datetime
|
||||
updated_at: datetime.datetime
|
||||
|
||||
|
||||
@field_serializer("created_at", when_used="json")
|
||||
def _serialize_created_at(self, dt: datetime.datetime):
|
||||
return int(dt.timestamp() * 1000) if dt else None
|
||||
|
||||
|
||||
@field_serializer("updated_at", when_used="json")
|
||||
def _serialize_updated_at(self, dt: datetime.datetime):
|
||||
return int(dt.timestamp() * 1000) if dt else None
|
||||
|
||||
@@ -5,63 +5,63 @@ import uuid
|
||||
from typing import Dict, Any, List, Optional, Tuple
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.schemas import ModelParameters
|
||||
from app.services.conversation_state_manager import ConversationStateManager
|
||||
from app.models import ModelConfig, AgentConfig
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.services.model_service import ModelApiKeyService
|
||||
|
||||
logger = get_business_logger()
|
||||
|
||||
|
||||
class MasterAgentRouter:
|
||||
"""Master Agent 路由器
|
||||
|
||||
|
||||
让 Master Agent 作为"大脑",负责:
|
||||
1. 分析用户意图
|
||||
2. 选择最合适的 Sub Agent
|
||||
3. 决定是否需要多 Agent 协作
|
||||
4. 管理会话上下文
|
||||
|
||||
|
||||
优势:
|
||||
- 更智能的决策(基于完整上下文)
|
||||
- 减少 LLM 调用次数
|
||||
- 架构更清晰(Master Agent 真正起作用)
|
||||
"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
db: Session,
|
||||
master_agent_config: AgentConfig,
|
||||
master_model_config: ModelConfig,
|
||||
model_parameters: ModelParameters,
|
||||
sub_agents: Dict[str, Any],
|
||||
state_manager: ConversationStateManager,
|
||||
enable_rule_fast_path: bool = True
|
||||
):
|
||||
"""初始化 Master Agent 路由器
|
||||
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
master_agent_config: Master Agent 配置
|
||||
master_model_config: Master Agent 使用的模型配置
|
||||
sub_agents: 子 Agent 配置字典
|
||||
state_manager: 会话状态管理器
|
||||
enable_rule_fast_path: 是否启用规则快速路径(性能优化)
|
||||
"""
|
||||
self.db = db
|
||||
self.master_agent_config = master_agent_config
|
||||
self.master_model_config = master_model_config
|
||||
self.model_parameters = model_parameters
|
||||
self.sub_agents = sub_agents
|
||||
self.state_manager = state_manager
|
||||
self.enable_rule_fast_path = enable_rule_fast_path
|
||||
|
||||
|
||||
logger.info(
|
||||
"Master Agent 路由器初始化",
|
||||
extra={
|
||||
"master_agent": master_agent_config.name,
|
||||
"sub_agent_count": len(sub_agents),
|
||||
"enable_rule_fast_path": enable_rule_fast_path
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def route(
|
||||
self,
|
||||
message: str,
|
||||
@@ -69,12 +69,12 @@ class MasterAgentRouter:
|
||||
variables: Optional[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""智能路由决策
|
||||
|
||||
|
||||
Args:
|
||||
message: 用户消息
|
||||
conversation_id: 会话 ID
|
||||
variables: 变量参数
|
||||
|
||||
|
||||
Returns:
|
||||
路由决策结果
|
||||
"""
|
||||
@@ -85,12 +85,12 @@ class MasterAgentRouter:
|
||||
"conversation_id": conversation_id
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# 1. 获取会话状态
|
||||
state = None
|
||||
if conversation_id:
|
||||
state = self.state_manager.get_state(conversation_id)
|
||||
|
||||
|
||||
# 2. 尝试规则快速路径(可选的性能优化)
|
||||
if self.enable_rule_fast_path:
|
||||
rule_result = self._try_rule_fast_path(message, state)
|
||||
@@ -102,7 +102,7 @@ class MasterAgentRouter:
|
||||
"confidence": rule_result["confidence"]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# 更新会话状态
|
||||
if conversation_id:
|
||||
self.state_manager.update_state(
|
||||
@@ -112,12 +112,12 @@ class MasterAgentRouter:
|
||||
rule_result.get("topic"),
|
||||
rule_result["confidence"]
|
||||
)
|
||||
|
||||
|
||||
return rule_result
|
||||
|
||||
|
||||
# 3. 调用 Master Agent 做决策
|
||||
decision = await self._master_agent_decide(message, state, variables)
|
||||
|
||||
|
||||
# 4. 更新会话状态
|
||||
if conversation_id:
|
||||
self.state_manager.update_state(
|
||||
@@ -127,7 +127,7 @@ class MasterAgentRouter:
|
||||
decision.get("topic"),
|
||||
decision["confidence"]
|
||||
)
|
||||
|
||||
|
||||
logger.info(
|
||||
"Master Agent 路由完成",
|
||||
extra={
|
||||
@@ -136,22 +136,22 @@ class MasterAgentRouter:
|
||||
"confidence": decision["confidence"]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return decision
|
||||
|
||||
|
||||
def _try_rule_fast_path(
|
||||
self,
|
||||
message: str,
|
||||
state: Optional[Dict[str, Any]]
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""尝试规则快速路径(性能优化)
|
||||
|
||||
|
||||
对于明确的关键词匹配,直接返回结果,不调用 Master Agent
|
||||
|
||||
|
||||
Args:
|
||||
message: 用户消息
|
||||
state: 会话状态
|
||||
|
||||
|
||||
Returns:
|
||||
如果命中规则返回决策结果,否则返回 None
|
||||
"""
|
||||
@@ -178,15 +178,15 @@ class MasterAgentRouter:
|
||||
"confidence_threshold": 0.9
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
message_lower = message.lower()
|
||||
|
||||
|
||||
for rule in high_confidence_rules:
|
||||
matched_keywords = [kw for kw in rule["keywords"] if kw in message_lower]
|
||||
|
||||
|
||||
if matched_keywords:
|
||||
confidence = len(matched_keywords) / len(rule["keywords"])
|
||||
|
||||
|
||||
if confidence >= rule["confidence_threshold"]:
|
||||
# 查找对应的 agent
|
||||
for agent_id, agent_data in self.sub_agents.items():
|
||||
@@ -201,9 +201,9 @@ class MasterAgentRouter:
|
||||
"need_collaboration": False,
|
||||
"routing_method": "rule"
|
||||
}
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
async def _master_agent_decide(
|
||||
self,
|
||||
message: str,
|
||||
@@ -211,35 +211,35 @@ class MasterAgentRouter:
|
||||
variables: Optional[Dict[str, Any]]
|
||||
) -> Dict[str, Any]:
|
||||
"""让 Master Agent 做路由决策
|
||||
|
||||
|
||||
Args:
|
||||
message: 用户消息
|
||||
state: 会话状态
|
||||
variables: 变量参数
|
||||
|
||||
|
||||
Returns:
|
||||
决策结果
|
||||
"""
|
||||
# 1. 构建决策 prompt
|
||||
prompt = self._build_decision_prompt(message, state, variables)
|
||||
|
||||
|
||||
# 2. 调用 Master Agent 的 LLM
|
||||
try:
|
||||
response = await self._call_master_agent_llm(prompt)
|
||||
|
||||
|
||||
# 3. 解析决策
|
||||
decision = self._parse_decision(response)
|
||||
|
||||
|
||||
# 4. 验证决策
|
||||
decision = self._validate_decision(decision)
|
||||
|
||||
|
||||
return decision
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Master Agent 决策失败: {str(e)}")
|
||||
# 降级到默认 agent
|
||||
return self._get_fallback_decision(message)
|
||||
|
||||
|
||||
def _build_decision_prompt(
|
||||
self,
|
||||
message: str,
|
||||
@@ -247,12 +247,12 @@ class MasterAgentRouter:
|
||||
variables: Optional[Dict[str, Any]]
|
||||
) -> str:
|
||||
"""构建 Master Agent 的决策 prompt
|
||||
|
||||
|
||||
Args:
|
||||
message: 用户消息
|
||||
state: 会话状态
|
||||
variables: 变量参数
|
||||
|
||||
|
||||
Returns:
|
||||
prompt 字符串
|
||||
"""
|
||||
@@ -260,29 +260,29 @@ class MasterAgentRouter:
|
||||
agent_descriptions = []
|
||||
for agent_id, agent_data in self.sub_agents.items():
|
||||
agent_info = agent_data.get("info", {})
|
||||
|
||||
|
||||
name = agent_info.get("name", "未命名")
|
||||
role = agent_info.get("role", "")
|
||||
capabilities = agent_info.get("capabilities", [])
|
||||
|
||||
|
||||
# 简化格式:一行描述
|
||||
desc = f"- {agent_id}: {name}"
|
||||
if role:
|
||||
desc += f" ({role})"
|
||||
if capabilities:
|
||||
desc += f" - {', '.join(capabilities[:3])}" # 只取前3个能力
|
||||
|
||||
|
||||
agent_descriptions.append(desc)
|
||||
|
||||
|
||||
agents_text = "\n".join(agent_descriptions)
|
||||
|
||||
|
||||
# 2. 构建会话上下文
|
||||
context_text = ""
|
||||
if state:
|
||||
current_agent = state.get("current_agent_id")
|
||||
last_topic = state.get("last_topic")
|
||||
same_turns = state.get("same_agent_turns", 0)
|
||||
|
||||
|
||||
if current_agent:
|
||||
context_text = f"""
|
||||
当前会话上下文:
|
||||
@@ -290,10 +290,10 @@ class MasterAgentRouter:
|
||||
- 上一个主题: {last_topic}
|
||||
- 连续使用轮数: {same_turns}
|
||||
"""
|
||||
|
||||
|
||||
# 获取第一个可用的 agent_id 作为示例
|
||||
example_agent_id = next(iter(self.sub_agents.keys())) if self.sub_agents else "agent_id"
|
||||
|
||||
|
||||
# 3. 构建完整 prompt(简化版,提升性能)
|
||||
prompt = f"""路由任务:分析问题并选择合适的 Agent。
|
||||
|
||||
@@ -331,15 +331,15 @@ class MasterAgentRouter:
|
||||
6. 只做路由决策,不要回答问题内容
|
||||
|
||||
请返回 JSON:"""
|
||||
|
||||
|
||||
return prompt
|
||||
|
||||
|
||||
async def _call_master_agent_llm(self, prompt: str) -> str:
|
||||
"""调用 Master Agent 的 LLM
|
||||
|
||||
|
||||
Args:
|
||||
prompt: 提示词
|
||||
|
||||
|
||||
Returns:
|
||||
LLM 响应
|
||||
"""
|
||||
@@ -347,16 +347,13 @@ class MasterAgentRouter:
|
||||
from app.core.models import RedBearLLM
|
||||
from app.core.models.base import RedBearModelConfig
|
||||
from app.models import ModelApiKey, ModelType
|
||||
|
||||
|
||||
# 获取 API Key 配置
|
||||
api_key_config = self.db.query(ModelApiKey).filter(
|
||||
ModelApiKey.model_config_id == self.master_model_config.id,
|
||||
ModelApiKey.is_active == True
|
||||
).first()
|
||||
|
||||
api_key_config = ModelApiKeyService.get_a_api_key(self.db, self.master_model_config.id)
|
||||
|
||||
if not api_key_config:
|
||||
raise Exception("Master Agent 模型没有可用的 API Key")
|
||||
|
||||
|
||||
logger.info(
|
||||
"调用 Master Agent LLM",
|
||||
extra={
|
||||
@@ -364,39 +361,44 @@ class MasterAgentRouter:
|
||||
"model_name": api_key_config.model_name
|
||||
}
|
||||
)
|
||||
|
||||
temperature = 0.3 # 决策任务使用较低温度
|
||||
max_tokens = 1000
|
||||
extra_params = None
|
||||
if self.model_parameters:
|
||||
extra_params = {"temperature": temperature,
|
||||
"max_tokens":max_tokens
|
||||
}
|
||||
# 创建 RedBearModelConfig
|
||||
model_config = RedBearModelConfig(
|
||||
model_name=api_key_config.model_name,
|
||||
provider=api_key_config.provider,
|
||||
api_key=api_key_config.api_key,
|
||||
base_url=api_key_config.api_base,
|
||||
temperature=0.3, # 决策任务使用较低温度
|
||||
max_tokens=1000
|
||||
extra_params = extra_params
|
||||
)
|
||||
|
||||
|
||||
# 创建 LLM 实例
|
||||
llm = RedBearLLM(model_config, type=ModelType.CHAT)
|
||||
|
||||
|
||||
# 调用模型
|
||||
response = await llm.ainvoke(prompt)
|
||||
|
||||
|
||||
# 提取响应内容
|
||||
if hasattr(response, 'content'):
|
||||
return response.content
|
||||
else:
|
||||
return str(response)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Master Agent LLM 调用失败: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
def _parse_decision(self, response: str) -> Dict[str, Any]:
|
||||
"""解析 Master Agent 的决策
|
||||
|
||||
|
||||
Args:
|
||||
response: LLM 响应
|
||||
|
||||
|
||||
Returns:
|
||||
决策字典
|
||||
"""
|
||||
@@ -405,29 +407,29 @@ class MasterAgentRouter:
|
||||
json_match = re.search(r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}', response, re.DOTALL)
|
||||
if json_match:
|
||||
decision = json.loads(json_match.group())
|
||||
|
||||
|
||||
# 添加默认值
|
||||
decision.setdefault("confidence", 0.8)
|
||||
decision.setdefault("strategy", "master_agent")
|
||||
decision.setdefault("routing_method", "master_agent")
|
||||
decision.setdefault("need_collaboration", False)
|
||||
decision.setdefault("collaboration_agents", [])
|
||||
|
||||
|
||||
return decision
|
||||
else:
|
||||
raise ValueError("无法从响应中提取 JSON")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"解析 Master Agent 决策失败: {str(e)}")
|
||||
logger.debug(f"原始响应: {response}")
|
||||
raise
|
||||
|
||||
|
||||
def _validate_decision(self, decision: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""验证决策的有效性
|
||||
|
||||
|
||||
Args:
|
||||
decision: 决策字典
|
||||
|
||||
|
||||
Returns:
|
||||
验证后的决策
|
||||
"""
|
||||
@@ -439,26 +441,26 @@ class MasterAgentRouter:
|
||||
decision["selected_agent_id"] = self._get_default_agent_id()
|
||||
decision["confidence"] = 0.5
|
||||
decision["reasoning"] = "原始选择无效,使用默认 Agent"
|
||||
|
||||
|
||||
# 验证 confidence
|
||||
confidence = decision.get("confidence", 0.8)
|
||||
if not isinstance(confidence, (int, float)) or confidence < 0 or confidence > 1:
|
||||
decision["confidence"] = 0.8
|
||||
|
||||
|
||||
# 验证协作 agents
|
||||
if decision.get("need_collaboration"):
|
||||
# 检查是否是问题拆分模式
|
||||
if decision.get("need_decomposition") or decision.get("sub_questions"):
|
||||
# 问题拆分模式
|
||||
sub_questions = decision.get("sub_questions", [])
|
||||
|
||||
|
||||
# 验证每个子问题
|
||||
valid_sub_questions = []
|
||||
for sub_q in sub_questions:
|
||||
if isinstance(sub_q, dict):
|
||||
agent_id = sub_q.get("agent_id")
|
||||
question = sub_q.get("question")
|
||||
|
||||
|
||||
if agent_id in self.sub_agents and question:
|
||||
# 确保有必要的字段
|
||||
sub_q.setdefault("order", len(valid_sub_questions) + 1)
|
||||
@@ -475,9 +477,9 @@ class MasterAgentRouter:
|
||||
"available_agents": list(self.sub_agents.keys())
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
decision["sub_questions"] = valid_sub_questions
|
||||
|
||||
|
||||
# 如果所有子问题都验证失败,降级处理
|
||||
if not valid_sub_questions and sub_questions:
|
||||
logger.warning(
|
||||
@@ -496,10 +498,10 @@ class MasterAgentRouter:
|
||||
first_agent_id = next(iter(self.sub_agents.keys()))
|
||||
decision["selected_agent_id"] = first_agent_id
|
||||
logger.info(f"降级使用默认 Agent: {first_agent_id}")
|
||||
|
||||
|
||||
# 设置协作策略为 decomposition
|
||||
decision["collaboration_strategy"] = "decomposition"
|
||||
|
||||
|
||||
logger.info(
|
||||
"问题拆分决策验证完成",
|
||||
extra={
|
||||
@@ -510,7 +512,7 @@ class MasterAgentRouter:
|
||||
else:
|
||||
# 普通协作模式
|
||||
collaboration_agents = decision.get("collaboration_agents", [])
|
||||
|
||||
|
||||
# 如果是简单列表格式,转换为详细格式
|
||||
if collaboration_agents and isinstance(collaboration_agents[0], str):
|
||||
collaboration_agents = [
|
||||
@@ -522,7 +524,7 @@ class MasterAgentRouter:
|
||||
}
|
||||
for i, agent_id in enumerate(collaboration_agents)
|
||||
]
|
||||
|
||||
|
||||
# 验证每个协作 agent
|
||||
valid_agents = []
|
||||
for agent_info in collaboration_agents:
|
||||
@@ -541,13 +543,13 @@ class MasterAgentRouter:
|
||||
"task": "协作处理",
|
||||
"order": len(valid_agents) + 1
|
||||
})
|
||||
|
||||
|
||||
decision["collaboration_agents"] = valid_agents
|
||||
|
||||
|
||||
# 设置默认协作策略
|
||||
if not decision.get("collaboration_strategy"):
|
||||
decision["collaboration_strategy"] = "sequential"
|
||||
|
||||
|
||||
logger.info(
|
||||
"协作决策验证完成",
|
||||
extra={
|
||||
@@ -555,20 +557,20 @@ class MasterAgentRouter:
|
||||
"strategy": decision.get("collaboration_strategy")
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return decision
|
||||
|
||||
|
||||
def _get_fallback_decision(self, message: str) -> Dict[str, Any]:
|
||||
"""获取降级决策(当 Master Agent 失败时)
|
||||
|
||||
|
||||
Args:
|
||||
message: 用户消息
|
||||
|
||||
|
||||
Returns:
|
||||
降级决策
|
||||
"""
|
||||
default_agent_id = self._get_default_agent_id()
|
||||
|
||||
|
||||
return {
|
||||
"selected_agent_id": default_agent_id,
|
||||
"confidence": 0.5,
|
||||
@@ -579,15 +581,15 @@ class MasterAgentRouter:
|
||||
"collaboration_agents": [],
|
||||
"routing_method": "fallback"
|
||||
}
|
||||
|
||||
|
||||
def _get_default_agent_id(self) -> str:
|
||||
"""获取默认 Agent ID
|
||||
|
||||
|
||||
Returns:
|
||||
默认 Agent ID
|
||||
"""
|
||||
if self.sub_agents:
|
||||
# 返回第一个 agent
|
||||
return next(iter(self.sub_agents.keys()))
|
||||
|
||||
|
||||
return "default-agent"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,19 @@
|
||||
"""多 Agent 配置管理服务"""
|
||||
import uuid
|
||||
from typing import Optional, List, Tuple, Any
|
||||
from typing import Optional, List, Tuple, Any, Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import select, desc
|
||||
|
||||
from app.db import get_db
|
||||
from app.models import MultiAgentConfig, App, AgentConfig
|
||||
from app.schemas.multi_agent_schema import (
|
||||
MultiAgentConfigCreate,
|
||||
MultiAgentConfigUpdate,
|
||||
MultiAgentRunRequest
|
||||
)
|
||||
from app.services.model_service import ModelApiKeyService
|
||||
from app.services.multi_agent_orchestrator import MultiAgentOrchestrator
|
||||
from app.core.exceptions import ResourceNotFoundException, BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
@@ -21,10 +25,10 @@ logger = get_business_logger()
|
||||
|
||||
def convert_uuids_to_str(obj: Any) -> Any:
|
||||
"""递归转换对象中的所有 UUID 为字符串
|
||||
|
||||
|
||||
Args:
|
||||
obj: 要转换的对象(dict, list, UUID 等)
|
||||
|
||||
|
||||
Returns:
|
||||
转换后的对象
|
||||
"""
|
||||
@@ -40,10 +44,10 @@ def convert_uuids_to_str(obj: Any) -> Any:
|
||||
|
||||
class MultiAgentService:
|
||||
"""多 Agent 配置管理服务"""
|
||||
|
||||
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
|
||||
def create_config(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
@@ -51,12 +55,12 @@ class MultiAgentService:
|
||||
created_by: uuid.UUID
|
||||
) -> MultiAgentConfig:
|
||||
"""创建多 Agent 配置
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
data: 配置数据
|
||||
created_by: 创建者 ID
|
||||
|
||||
|
||||
Returns:
|
||||
多 Agent 配置
|
||||
"""
|
||||
@@ -64,7 +68,7 @@ class MultiAgentService:
|
||||
app = self.db.get(App, app_id)
|
||||
if not app:
|
||||
raise ResourceNotFoundException("应用", str(app_id))
|
||||
|
||||
|
||||
# 2. 检查是否已有有效配置
|
||||
existing = self.db.scalars(
|
||||
select(MultiAgentConfig)
|
||||
@@ -76,22 +80,22 @@ class MultiAgentService:
|
||||
).first()
|
||||
if existing:
|
||||
raise BusinessException("应用已有多 Agent 配置", BizCode.DUPLICATE_RESOURCE)
|
||||
|
||||
|
||||
# 3. 验证主 Agent 存在
|
||||
master_agent = self.db.get(AgentConfig, data.master_agent_id)
|
||||
if not master_agent:
|
||||
raise ResourceNotFoundException("主 Agent", str(data.master_agent_id))
|
||||
|
||||
|
||||
# 4. 验证子 Agent 存在
|
||||
for sub_agent in data.sub_agents:
|
||||
agent = self.db.get(AgentConfig, sub_agent.agent_id)
|
||||
if not agent:
|
||||
raise ResourceNotFoundException("子 Agent", str(sub_agent.agent_id))
|
||||
|
||||
|
||||
# 5. 创建配置(转换 UUID 为字符串以支持 JSON 序列化)
|
||||
sub_agents_data = [convert_uuids_to_str(sub_agent.model_dump()) for sub_agent in data.sub_agents]
|
||||
routing_rules_data = [convert_uuids_to_str(rule.model_dump()) for rule in data.routing_rules] if data.routing_rules else None
|
||||
|
||||
|
||||
# 处理 execution_config(可能是 None、字典或 Pydantic 模型)
|
||||
if data.execution_config is None:
|
||||
execution_config_data = {}
|
||||
@@ -99,7 +103,7 @@ class MultiAgentService:
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config)
|
||||
else:
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config.model_dump())
|
||||
|
||||
|
||||
config = MultiAgentConfig(
|
||||
app_id=app_id,
|
||||
master_agent_id=data.master_agent_id,
|
||||
@@ -110,11 +114,11 @@ class MultiAgentService:
|
||||
execution_config=execution_config_data,
|
||||
aggregation_strategy=data.aggregation_strategy
|
||||
)
|
||||
|
||||
|
||||
self.db.add(config)
|
||||
self.db.commit()
|
||||
self.db.refresh(config)
|
||||
|
||||
|
||||
logger.info(
|
||||
"创建多 Agent 配置成功",
|
||||
extra={
|
||||
@@ -124,15 +128,15 @@ class MultiAgentService:
|
||||
"sub_agent_count": len(data.sub_agents)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def get_config(self, app_id: uuid.UUID) -> Optional[MultiAgentConfig]:
|
||||
"""获取多 Agent 配置
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
|
||||
|
||||
Returns:
|
||||
多 Agent 配置,如果不存在返回 None
|
||||
"""
|
||||
@@ -144,24 +148,25 @@ class MultiAgentService:
|
||||
)
|
||||
.order_by(MultiAgentConfig.updated_at.desc())
|
||||
).first()
|
||||
|
||||
|
||||
def get_multi_agent_configs(self, app_id: uuid.UUID) -> Optional[dict]:
|
||||
"""通过 app_id 获取最新有效的多智能体配置,并将 agent_id 转换为 app_id
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
|
||||
|
||||
Returns:
|
||||
转换后的配置字典,如果不存在返回 None
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
# 转换 master_agent_id (release_id) 为 app_id
|
||||
master_release = self.db.get(AppRelease, config.master_agent_id)
|
||||
master_app_id = master_release.app_id if master_release else config.master_agent_id
|
||||
|
||||
|
||||
#兼容代码
|
||||
if not config.default_model_config_id:
|
||||
master_release = self.db.get(AppRelease, config.master_agent_id)
|
||||
config.default_model_config_id = master_release.default_model_config_id if master_release else None
|
||||
|
||||
# 转换 sub_agents 中的 agent_id (release_id) 为 app_id
|
||||
converted_sub_agents = []
|
||||
for sub_agent in config.sub_agents:
|
||||
@@ -176,13 +181,13 @@ class MultiAgentService:
|
||||
except Exception as e:
|
||||
logger.warning(f"转换 sub_agent agent_id 失败: {release_id}, 错误: {str(e)}")
|
||||
converted_sub_agents.append(sub_agent_copy)
|
||||
|
||||
|
||||
# 构建返回的配置字典
|
||||
return {
|
||||
"id": config.id,
|
||||
"app_id": config.app_id,
|
||||
"master_agent_id": master_app_id,
|
||||
"master_agent_name": config.master_agent_name,
|
||||
"default_model_config_id": config.default_model_config_id,
|
||||
"model_parameters": config.model_parameters,
|
||||
"orchestration_mode": config.orchestration_mode,
|
||||
"sub_agents": converted_sub_agents,
|
||||
"routing_rules": config.routing_rules,
|
||||
@@ -192,133 +197,134 @@ class MultiAgentService:
|
||||
"created_at": config.created_at,
|
||||
"updated_at": config.updated_at
|
||||
}
|
||||
|
||||
|
||||
def get_published_config_by_agent_id(self, agent_id: uuid.UUID) -> Optional[dict]:
|
||||
"""通过 agent_id 获取当前发布版本的完整配置
|
||||
|
||||
|
||||
Args:
|
||||
agent_id: Agent 配置 ID
|
||||
|
||||
|
||||
Returns:
|
||||
当前发布版本的配置字典,如果没有发布版本则返回 None
|
||||
"""
|
||||
from app.models import AppRelease
|
||||
|
||||
|
||||
# 查询 Agent 配置
|
||||
agent_config = self.db.get(AgentConfig, agent_id)
|
||||
if not agent_config:
|
||||
logger.warning(f"Agent 配置不存在: {agent_id}")
|
||||
return None
|
||||
|
||||
|
||||
# 获取关联的应用
|
||||
app = self.db.get(App, agent_config.app_id)
|
||||
if not app or not app.current_release_id:
|
||||
logger.warning(f"应用未发布或不存在: app_id={agent_config.app_id}")
|
||||
return None
|
||||
|
||||
|
||||
# 获取当前发布版本
|
||||
release = self.db.get(AppRelease, app.current_release_id)
|
||||
if not release:
|
||||
logger.warning(f"发布版本不存在: release_id={app.current_release_id}")
|
||||
return None
|
||||
|
||||
|
||||
# 从发布版本的 config 中获取完整配置
|
||||
# config 是一个 JSON 对象,包含了发布时的配置快照
|
||||
config_data = release.config
|
||||
if config_data and isinstance(config_data, dict):
|
||||
return config_data
|
||||
|
||||
|
||||
return None
|
||||
|
||||
def get_published_by_agent_id(self, agent_id: uuid.UUID) -> Optional[AppRelease]:
|
||||
"""通过 agent_id 获取当前发布版本的完整配置
|
||||
|
||||
|
||||
Args:
|
||||
agent_id: Agent 配置 ID
|
||||
|
||||
|
||||
Returns:
|
||||
当前发布版本的配置字典,如果没有发布版本则返回 None
|
||||
"""
|
||||
|
||||
|
||||
# 获取关联的应用
|
||||
app = self.db.get(App, agent_id)
|
||||
if not app or not app.current_release_id:
|
||||
logger.warning(f"应用未发布或不存在: app_id={agent_id}")
|
||||
return None
|
||||
|
||||
|
||||
# 获取当前发布版本
|
||||
release = self.db.get(AppRelease, app.current_release_id)
|
||||
if not release:
|
||||
logger.warning(f"发布版本不存在: release_id={app.current_release_id}")
|
||||
return None
|
||||
return release
|
||||
|
||||
def update_config(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
data: MultiAgentConfigUpdate
|
||||
) -> MultiAgentConfig:
|
||||
"""更新多 Agent 配置
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
data: 更新数据
|
||||
|
||||
Returns:
|
||||
更新后的配置
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
# 1. 验证应用存在
|
||||
app = self.db.get(App, app_id)
|
||||
if not app:
|
||||
raise ResourceNotFoundException("应用", str(app_id))
|
||||
|
||||
# 2. 验证主 Agent 存在并获取发布版本 ID
|
||||
master_app_release = self.get_published_by_agent_id(data.master_agent_id)
|
||||
if not master_app_release:
|
||||
raise ResourceNotFoundException("主 Agent 未发布或不存在", str(data.master_agent_id))
|
||||
|
||||
# 使用发布版本 ID
|
||||
data.master_agent_id = master_app_release.id
|
||||
|
||||
# 3. 验证子 Agent 存在并获取发布版本 ID
|
||||
for sub_agent in data.sub_agents:
|
||||
agent_app_release = self.get_published_by_agent_id(sub_agent.agent_id)
|
||||
if not agent_app_release:
|
||||
raise ResourceNotFoundException("子 Agent 未发布或不存在", str(sub_agent.agent_id))
|
||||
|
||||
def check_config_data(self,app_id: uuid.UUID, data: MultiAgentConfigUpdate) -> MultiAgentConfig:
|
||||
# 1. 验证应用存在
|
||||
app = self.db.get(App, app_id)
|
||||
if not app:
|
||||
raise ResourceNotFoundException("应用", str(app_id))
|
||||
|
||||
# 2. 验证模型配置
|
||||
model_api_key = ModelApiKeyService.get_a_api_key(self.db,data.default_model_config_id)
|
||||
if not model_api_key:
|
||||
raise ResourceNotFoundException("模型配置", str(data.default_model_config_id))
|
||||
|
||||
# 3. 验证子 Agent 存在并获取发布版本 ID
|
||||
for sub_agent in data.sub_agents:
|
||||
agent_app_release = self.get_published_by_agent_id(sub_agent.agent_id)
|
||||
if not agent_app_release:
|
||||
raise ResourceNotFoundException("子 Agent 未发布或不存在", str(sub_agent.agent_id))
|
||||
|
||||
# 使用发布版本 ID
|
||||
sub_agent.agent_id = agent_app_release.id
|
||||
|
||||
|
||||
# 5. 创建配置(转换 UUID 为字符串以支持 JSON 序列化)
|
||||
sub_agents_data = [convert_uuids_to_str(sub_agent.model_dump()) for sub_agent in data.sub_agents]
|
||||
# routing_rules_data = [convert_uuids_to_str(rule.model_dump()) for rule in data.routing_rules] if data.routing_rules else None
|
||||
|
||||
# 处理 execution_config(可能是 None、字典或 Pydantic 模型)
|
||||
if data.execution_config is None:
|
||||
execution_config_data = {}
|
||||
elif isinstance(data.execution_config, dict):
|
||||
sub_agent.agent_id = agent_app_release.id
|
||||
|
||||
# 5. 创建配置(转换 UUID 为字符串以支持 JSON 序列化)
|
||||
sub_agents_data = [convert_uuids_to_str(sub_agent.model_dump()) for sub_agent in data.sub_agents]
|
||||
# routing_rules_data = [convert_uuids_to_str(rule.model_dump()) for rule in data.routing_rules] if data.routing_rules else None
|
||||
|
||||
# 处理 execution_config(可能是 None、字典或 Pydantic 模型)
|
||||
if data.execution_config is None:
|
||||
execution_config_data = {}
|
||||
elif isinstance(data.execution_config, dict):
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config)
|
||||
else:
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config.model_dump())
|
||||
|
||||
config = MultiAgentConfig(
|
||||
else:
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config.model_dump())
|
||||
|
||||
config = MultiAgentConfig(
|
||||
app_id=app_id,
|
||||
master_agent_id=data.master_agent_id,
|
||||
master_agent_name=data.master_agent_name,
|
||||
default_model_config_id=data.default_model_config_id,
|
||||
model_parameters=data.model_parameters,
|
||||
orchestration_mode=data.orchestration_mode,
|
||||
sub_agents=sub_agents_data,
|
||||
# routing_rules=routing_rules_data,
|
||||
execution_config=execution_config_data,
|
||||
aggregation_strategy=data.aggregation_strategy
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
def update_config(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
data: MultiAgentConfigUpdate
|
||||
) -> MultiAgentConfig:
|
||||
"""更新多 Agent 配置
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
data: 更新数据
|
||||
|
||||
Returns:
|
||||
更新后的配置
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
newConfig = self.check_config_data(app_id, data)
|
||||
if not config:
|
||||
config = newConfig
|
||||
self.db.add(config)
|
||||
self.db.commit()
|
||||
self.db.refresh(config)
|
||||
|
||||
logger.info(
|
||||
"创建多 Agent 配置成功",
|
||||
extra={
|
||||
@@ -329,56 +335,17 @@ class MultiAgentService:
|
||||
}
|
||||
)
|
||||
return config
|
||||
# raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
# 更新字段
|
||||
if data.master_agent_id is not None:
|
||||
# 验证主 Agent 存在
|
||||
# 3. 验证主 Agent 存在并获取发布配置
|
||||
master_app_release = self.get_published_by_agent_id(data.master_agent_id)
|
||||
if not master_app_release:
|
||||
raise ResourceNotFoundException("主 Agent 未发布或", str(data.master_agent_id))
|
||||
|
||||
config.master_agent_id = master_app_release.id
|
||||
|
||||
if data.master_agent_name is not None:
|
||||
config.master_agent_name = data.master_agent_name
|
||||
|
||||
if data.orchestration_mode is not None:
|
||||
config.orchestration_mode = data.orchestration_mode
|
||||
|
||||
if data.sub_agents is not None:
|
||||
# 验证子 Agent 存在,并获取其发布的 config_id
|
||||
updated_sub_agents = []
|
||||
for sub_agent in data.sub_agents:
|
||||
agent_app_release = self.get_published_by_agent_id(sub_agent.agent_id)
|
||||
if not agent_app_release:
|
||||
raise ResourceNotFoundException("子 Agent 未发布或", str(sub_agent.agent_id))
|
||||
sub_agent.agent_id = agent_app_release.id
|
||||
sub_agent_dict = convert_uuids_to_str(sub_agent.model_dump())
|
||||
updated_sub_agents.append(sub_agent_dict)
|
||||
|
||||
config.sub_agents = updated_sub_agents
|
||||
|
||||
# if data.routing_rules is not None:
|
||||
# config.routing_rules = [convert_uuids_to_str(rule.model_dump()) for rule in data.routing_rules] if data.routing_rules else None
|
||||
|
||||
if data.execution_config is not None:
|
||||
if isinstance(data.execution_config, dict):
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config)
|
||||
else:
|
||||
execution_config_data = convert_uuids_to_str(data.execution_config.model_dump())
|
||||
config.execution_config = execution_config_data
|
||||
|
||||
if data.aggregation_strategy is not None:
|
||||
config.aggregation_strategy = data.aggregation_strategy
|
||||
|
||||
if data.is_active is not None:
|
||||
config.is_active = data.is_active
|
||||
|
||||
config.default_model_config_id = newConfig.default_model_config_id
|
||||
config.model_parameters = newConfig.model_parameters
|
||||
config.orchestration_mode = newConfig.orchestration_mode
|
||||
config.sub_agents = newConfig.sub_agents
|
||||
config.routing_rules = newConfig.routing_rules
|
||||
config.execution_config = newConfig.execution_config
|
||||
config.aggregation_strategy = newConfig.aggregation_strategy
|
||||
self.db.commit()
|
||||
self.db.refresh(config)
|
||||
|
||||
|
||||
logger.info(
|
||||
"更新多 Agent 配置成功",
|
||||
extra={
|
||||
@@ -386,23 +353,23 @@ class MultiAgentService:
|
||||
"app_id": str(app_id)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def delete_config(self, app_id: uuid.UUID) -> None:
|
||||
"""删除多 Agent 配置
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
|
||||
# 逻辑删除多 Agent 配置
|
||||
config.is_active = False
|
||||
self.db.commit()
|
||||
|
||||
|
||||
logger.info(
|
||||
"删除多 Agent 配置成功",
|
||||
extra={
|
||||
@@ -410,18 +377,18 @@ class MultiAgentService:
|
||||
"app_id": str(app_id)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def run(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
request: MultiAgentRunRequest
|
||||
) -> dict:
|
||||
"""运行多 Agent 任务
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
request: 运行请求
|
||||
|
||||
|
||||
Returns:
|
||||
执行结果
|
||||
"""
|
||||
@@ -429,13 +396,13 @@ class MultiAgentService:
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
|
||||
if not config.is_active:
|
||||
raise BusinessException("多 Agent 配置已禁用", BizCode.RESOURCE_DISABLED)
|
||||
|
||||
|
||||
# 2. 创建编排器
|
||||
orchestrator = MultiAgentOrchestrator(self.db, config)
|
||||
|
||||
|
||||
# 3. 执行任务
|
||||
result = await orchestrator.execute(
|
||||
message=request.message,
|
||||
@@ -446,9 +413,9 @@ class MultiAgentService:
|
||||
web_search=getattr(request, 'web_search', False), # 网络搜索参数
|
||||
memory=getattr(request, 'memory', True) # 记忆功能参数
|
||||
)
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
async def run_stream(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
@@ -457,11 +424,11 @@ class MultiAgentService:
|
||||
user_rag_memory_id :str
|
||||
):
|
||||
"""运行多 Agent 任务(流式返回)
|
||||
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
request: 运行请求
|
||||
|
||||
|
||||
Yields:
|
||||
SSE 格式的事件流
|
||||
"""
|
||||
@@ -469,13 +436,13 @@ class MultiAgentService:
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
|
||||
if not config.is_active:
|
||||
raise BusinessException("多 Agent 配置已禁用", BizCode.RESOURCE_DISABLED)
|
||||
|
||||
|
||||
# 2. 创建编排器
|
||||
orchestrator = MultiAgentOrchestrator(self.db, config)
|
||||
|
||||
|
||||
# 3. 流式执行任务
|
||||
async for event in orchestrator.execute_stream(
|
||||
message=request.message,
|
||||
@@ -489,113 +456,113 @@ class MultiAgentService:
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
):
|
||||
yield event
|
||||
|
||||
def add_sub_agent(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
agent_id: uuid.UUID,
|
||||
name: str,
|
||||
role: Optional[str] = None,
|
||||
priority: int = 1,
|
||||
capabilities: Optional[List[str]] = None
|
||||
) -> MultiAgentConfig:
|
||||
"""添加子 Agent
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
agent_id: Agent ID
|
||||
name: Agent 名称
|
||||
role: 角色描述
|
||||
priority: 优先级
|
||||
capabilities: 能力列表
|
||||
|
||||
Returns:
|
||||
更新后的配置
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
# 验证 Agent 存在
|
||||
agent = self.db.get(AgentConfig, agent_id)
|
||||
if not agent:
|
||||
raise ResourceNotFoundException("Agent", str(agent_id))
|
||||
|
||||
# 检查是否已存在
|
||||
for sub_agent in config.sub_agents:
|
||||
if sub_agent["agent_id"] == str(agent_id):
|
||||
raise BusinessException("Agent 已存在于配置中", BizCode.DUPLICATE_RESOURCE)
|
||||
|
||||
# 添加子 Agent
|
||||
new_sub_agent = {
|
||||
"agent_id": str(agent_id),
|
||||
"name": name,
|
||||
"role": role,
|
||||
"priority": priority,
|
||||
"capabilities": capabilities or []
|
||||
}
|
||||
|
||||
config.sub_agents.append(new_sub_agent)
|
||||
|
||||
# 标记为已修改
|
||||
self.db.add(config)
|
||||
self.db.commit()
|
||||
self.db.refresh(config)
|
||||
|
||||
logger.info(
|
||||
"添加子 Agent 成功",
|
||||
extra={
|
||||
"config_id": str(config.id),
|
||||
"agent_id": str(agent_id),
|
||||
"agent_name": name
|
||||
}
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
def remove_sub_agent(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
agent_id: uuid.UUID
|
||||
) -> MultiAgentConfig:
|
||||
"""移除子 Agent
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
agent_id: Agent ID
|
||||
|
||||
Returns:
|
||||
更新后的配置
|
||||
"""
|
||||
config = self.get_config(app_id)
|
||||
if not config:
|
||||
raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
# 查找并移除
|
||||
original_count = len(config.sub_agents)
|
||||
config.sub_agents = [
|
||||
sub_agent for sub_agent in config.sub_agents
|
||||
if sub_agent["agent_id"] != str(agent_id)
|
||||
]
|
||||
|
||||
if len(config.sub_agents) == original_count:
|
||||
raise ResourceNotFoundException("子 Agent", str(agent_id))
|
||||
|
||||
# 标记为已修改
|
||||
self.db.add(config)
|
||||
self.db.commit()
|
||||
self.db.refresh(config)
|
||||
|
||||
logger.info(
|
||||
"移除子 Agent 成功",
|
||||
extra={
|
||||
"config_id": str(config.id),
|
||||
"agent_id": str(agent_id)
|
||||
}
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
# def add_sub_agent(
|
||||
# self,
|
||||
# app_id: uuid.UUID,
|
||||
# agent_id: uuid.UUID,
|
||||
# name: str,
|
||||
# role: Optional[str] = None,
|
||||
# priority: int = 1,
|
||||
# capabilities: Optional[List[str]] = None
|
||||
# ) -> MultiAgentConfig:
|
||||
# """添加子 Agent
|
||||
|
||||
# Args:
|
||||
# app_id: 应用 ID
|
||||
# agent_id: Agent ID
|
||||
# name: Agent 名称
|
||||
# role: 角色描述
|
||||
# priority: 优先级
|
||||
# capabilities: 能力列表
|
||||
|
||||
# Returns:
|
||||
# 更新后的配置
|
||||
# """
|
||||
# config = self.get_config(app_id)
|
||||
# if not config:
|
||||
# raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
# # 验证 Agent 存在
|
||||
# agent = self.db.get(AgentConfig, agent_id)
|
||||
# if not agent:
|
||||
# raise ResourceNotFoundException("Agent", str(agent_id))
|
||||
|
||||
# # 检查是否已存在
|
||||
# for sub_agent in config.sub_agents:
|
||||
# if sub_agent["agent_id"] == str(agent_id):
|
||||
# raise BusinessException("Agent 已存在于配置中", BizCode.DUPLICATE_RESOURCE)
|
||||
|
||||
# # 添加子 Agent
|
||||
# new_sub_agent = {
|
||||
# "agent_id": str(agent_id),
|
||||
# "name": name,
|
||||
# "role": role,
|
||||
# "priority": priority,
|
||||
# "capabilities": capabilities or []
|
||||
# }
|
||||
|
||||
# config.sub_agents.append(new_sub_agent)
|
||||
|
||||
# # 标记为已修改
|
||||
# self.db.add(config)
|
||||
# self.db.commit()
|
||||
# self.db.refresh(config)
|
||||
|
||||
# logger.info(
|
||||
# "添加子 Agent 成功",
|
||||
# extra={
|
||||
# "config_id": str(config.id),
|
||||
# "agent_id": str(agent_id),
|
||||
# "agent_name": name
|
||||
# }
|
||||
# )
|
||||
|
||||
# return config
|
||||
|
||||
# def remove_sub_agent(
|
||||
# self,
|
||||
# app_id: uuid.UUID,
|
||||
# agent_id: uuid.UUID
|
||||
# ) -> MultiAgentConfig:
|
||||
# """移除子 Agent
|
||||
|
||||
# Args:
|
||||
# app_id: 应用 ID
|
||||
# agent_id: Agent ID
|
||||
|
||||
# Returns:
|
||||
# 更新后的配置
|
||||
# """
|
||||
# config = self.get_config(app_id)
|
||||
# if not config:
|
||||
# raise ResourceNotFoundException("多 Agent 配置", str(app_id))
|
||||
|
||||
# # 查找并移除
|
||||
# original_count = len(config.sub_agents)
|
||||
# config.sub_agents = [
|
||||
# sub_agent for sub_agent in config.sub_agents
|
||||
# if sub_agent["agent_id"] != str(agent_id)
|
||||
# ]
|
||||
|
||||
# if len(config.sub_agents) == original_count:
|
||||
# raise ResourceNotFoundException("子 Agent", str(agent_id))
|
||||
|
||||
# # 标记为已修改
|
||||
# self.db.add(config)
|
||||
# self.db.commit()
|
||||
# self.db.refresh(config)
|
||||
|
||||
# logger.info(
|
||||
# "移除子 Agent 成功",
|
||||
# extra={
|
||||
# "config_id": str(config.id),
|
||||
# "agent_id": str(agent_id)
|
||||
# }
|
||||
# )
|
||||
|
||||
# return config
|
||||
|
||||
def list_configs(
|
||||
self,
|
||||
workspace_id: uuid.UUID,
|
||||
@@ -603,12 +570,12 @@ class MultiAgentService:
|
||||
pagesize: int = 20
|
||||
) -> Tuple[List[MultiAgentConfig], int]:
|
||||
"""列出多 Agent 配置
|
||||
|
||||
|
||||
Args:
|
||||
workspace_id: 工作空间 ID
|
||||
page: 页码
|
||||
pagesize: 每页数量
|
||||
|
||||
|
||||
Returns:
|
||||
配置列表和总数
|
||||
"""
|
||||
@@ -619,13 +586,21 @@ class MultiAgentService:
|
||||
.where(App.workspace_id == workspace_id)
|
||||
.order_by(desc(MultiAgentConfig.created_at))
|
||||
)
|
||||
|
||||
|
||||
# 总数
|
||||
count_stmt = stmt.with_only_columns(MultiAgentConfig.id)
|
||||
total = len(self.db.execute(count_stmt).all())
|
||||
|
||||
|
||||
# 分页
|
||||
stmt = stmt.offset((page - 1) * pagesize).limit(pagesize)
|
||||
configs = list(self.db.scalars(stmt).all())
|
||||
|
||||
|
||||
return configs, total
|
||||
|
||||
# ==================== 依赖注入函数 ====================
|
||||
|
||||
def get_multi_agent_service(
|
||||
db: Annotated[Session, Depends(get_db)]
|
||||
) -> MultiAgentService:
|
||||
"""获取工作流服务(依赖注入)"""
|
||||
return MultiAgentService(db)
|
||||
|
||||
Reference in New Issue
Block a user