- 新增 CLIPluginAdapter 统一接口 (backend/app/core/agent_adapter.py) - 新增 LLM 服务层,支持 Anthropic/OpenAI/DeepSeek/Ollama (backend/app/services/llm_service.py) - 新增 Agent 执行引擎,支持文件锁自动管理 (backend/app/services/agent_executor.py) - 新增 NativeLLMAgent 原生 LLM 适配器 (backend/app/adapters/native_llm_agent.py) - 新增进程管理器 (backend/app/services/process_manager.py) - 新增 Agent 控制 API (backend/app/routers/agents_control.py) - 新增 WebSocket 实时通信 (backend/app/routers/websocket.py) - 更新前端 AgentsPage,支持启动/停止 Agent - 测试通过:Agent 启动、批量操作、栅栏同步 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
200 lines
5.7 KiB
Python
200 lines
5.7 KiB
Python
"""
|
||
角色分配器 - AI 驱动的角色分配
|
||
分析任务描述,自动为 Agent 分配最适合的角色
|
||
"""
|
||
|
||
import asyncio
|
||
from typing import Dict, List, Optional
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
|
||
from .agent_registry import AgentRegistry, AgentInfo
|
||
|
||
|
||
class AgentRole(str, Enum):
|
||
"""Agent 角色枚举"""
|
||
ARCHITECT = "architect"
|
||
PRODUCT_MANAGER = "pm"
|
||
DEVELOPER = "developer"
|
||
QA = "qa"
|
||
REVIEWER = "reviewer"
|
||
|
||
|
||
@dataclass
|
||
class RoleWeight:
|
||
"""角色权重配置"""
|
||
role: str
|
||
weight: float
|
||
keywords: List[str]
|
||
|
||
def matches(self, text: str) -> int:
|
||
"""计算匹配分数"""
|
||
score = 0
|
||
text_lower = text.lower()
|
||
for keyword in self.keywords:
|
||
if keyword.lower() in text_lower:
|
||
score += 1
|
||
return score
|
||
|
||
|
||
class RoleAllocator:
|
||
"""
|
||
角色分配器
|
||
|
||
分析任务描述,为 Agent 分配最适合的角色
|
||
"""
|
||
|
||
# 角色权重配置(来自 design-spec.md)
|
||
ROLE_WEIGHTS = {
|
||
"pm": RoleWeight("pm", 1.5, ["需求", "产品", "规划", "用户", "功能", "priority", "requirement", "product"]),
|
||
"architect": RoleWeight("architect", 1.5, ["架构", "设计", "方案", "技术", "系统", "design", "architecture"]),
|
||
"developer": RoleWeight("developer", 1.0, ["开发", "实现", "编码", "代码", "function", "implement", "code"]),
|
||
"reviewer": RoleWeight("reviewer", 1.3, ["审查", "review", "检查", "验证", "校对", "check"]),
|
||
"qa": RoleWeight("qa", 1.2, ["测试", "test", "质量", "bug", "验证", "quality"]),
|
||
}
|
||
|
||
def __init__(self):
|
||
pass
|
||
|
||
def _analyze_task_roles(self, task: str) -> Dict[str, float]:
|
||
"""
|
||
分析任务需要的角色及其权重
|
||
|
||
Args:
|
||
task: 任务描述
|
||
|
||
Returns:
|
||
角色权重字典
|
||
"""
|
||
scores = {}
|
||
for role_name, role_weight in self.ROLE_WEIGHTS.items():
|
||
match_score = role_weight.matches(task)
|
||
if match_score > 0:
|
||
scores[role_name] = match_score * role_weight.weight
|
||
else:
|
||
# 即使没有匹配关键词,也给予基础权重
|
||
scores[role_name] = 0.1 * role_weight.weight
|
||
|
||
return scores
|
||
|
||
async def allocate_roles(
|
||
self,
|
||
task: str,
|
||
available_agents: List[str]
|
||
) -> Dict[str, str]:
|
||
"""
|
||
为任务分配角色
|
||
|
||
Args:
|
||
task: 任务描述
|
||
available_agents: 可用的 Agent ID 列表
|
||
|
||
Returns:
|
||
Agent ID -> 角色映射
|
||
"""
|
||
# 获取所有 Agent 信息
|
||
# 注意:在实际实现中,这会从 AgentRegistry 获取
|
||
# 这里简化处理,假设已有 Agent 信息
|
||
|
||
# 分析任务需要的角色
|
||
role_scores = self._analyze_task_roles(task)
|
||
|
||
# 按分数排序角色
|
||
sorted_roles = sorted(role_scores.items(), key=lambda x: -x[1])
|
||
|
||
# 简单分配:将可用 Agent 按顺序分配给角色
|
||
allocation = {}
|
||
for i, agent_id in enumerate(available_agents):
|
||
if i < len(sorted_roles):
|
||
allocation[agent_id] = sorted_roles[i][0]
|
||
else:
|
||
allocation[agent_id] = "developer" # 默认角色
|
||
|
||
return allocation
|
||
|
||
def get_primary_role(self, task: str) -> str:
|
||
"""
|
||
获取任务的主要角色
|
||
|
||
Args:
|
||
task: 任务描述
|
||
|
||
Returns:
|
||
主要角色名称
|
||
"""
|
||
role_scores = self._analyze_task_roles(task)
|
||
if not role_scores:
|
||
return "developer"
|
||
|
||
return max(role_scores.items(), key=lambda x: x[1])[0]
|
||
|
||
async def suggest_agents_for_task(
|
||
self,
|
||
task: str,
|
||
all_agents: List[AgentInfo],
|
||
count: int = 3
|
||
) -> List[AgentInfo]:
|
||
"""
|
||
为任务推荐合适的 Agent
|
||
|
||
Args:
|
||
task: 任务描述
|
||
all_agents: 所有可用 Agent 列表
|
||
count: 推荐数量
|
||
|
||
Returns:
|
||
推荐的 Agent 列表
|
||
"""
|
||
primary_role = self.get_primary_role(task)
|
||
|
||
# 按角色匹配度排序
|
||
scored_agents = []
|
||
for agent in all_agents:
|
||
if agent.role == primary_role:
|
||
scored_agents.append((agent, 10)) # 完全匹配高分
|
||
elif agent.role in ["architect", "developer", "reviewer"]:
|
||
scored_agents.append((agent, 5)) # 相关角色中分
|
||
else:
|
||
scored_agents.append((agent, 1)) # 其他角色低分
|
||
|
||
# 按分数排序
|
||
scored_agents.sort(key=lambda x: -x[1])
|
||
|
||
return [agent for agent, _ in scored_agents[:count]]
|
||
|
||
def explain_allocation(self, task: str, allocation: Dict[str, str]) -> str:
|
||
"""
|
||
解释角色分配的原因
|
||
|
||
Args:
|
||
task: 任务描述
|
||
allocation: 分配结果
|
||
|
||
Returns:
|
||
解释文本
|
||
"""
|
||
role_scores = self._analyze_task_roles(task)
|
||
primary = self.get_primary_role(task)
|
||
|
||
lines = [f"任务分析: {task}", f"主要角色: {primary}"]
|
||
lines.append("角色权重:")
|
||
for role, score in sorted(role_scores.items(), key=lambda x: -x[1]):
|
||
lines.append(f" - {role}: {score:.2f}")
|
||
lines.append("分配结果:")
|
||
for agent_id, role in allocation.items():
|
||
lines.append(f" - {agent_id}: {role}")
|
||
|
||
return "\n".join(lines)
|
||
|
||
|
||
# 全局单例
|
||
_allocator_instance: Optional[RoleAllocator] = None
|
||
|
||
|
||
def get_role_allocator() -> RoleAllocator:
|
||
"""获取角色分配器单例"""
|
||
global _allocator_instance
|
||
if _allocator_instance is None:
|
||
_allocator_instance = RoleAllocator()
|
||
return _allocator_instance
|