175 lines
5.5 KiB
Python
175 lines
5.5 KiB
Python
|
|
"""
|
|||
|
|
Agent 调度器服务
|
|||
|
|
实现多种调度策略
|
|||
|
|
"""
|
|||
|
|
from typing import List, Optional
|
|||
|
|
from app.models import Agent
|
|||
|
|
|
|||
|
|
|
|||
|
|
class BaseScheduler:
|
|||
|
|
"""调度器基类"""
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
"""选择 Agent,子类实现"""
|
|||
|
|
raise NotImplementedError
|
|||
|
|
|
|||
|
|
|
|||
|
|
class RoundRobinScheduler(BaseScheduler):
|
|||
|
|
"""轮询调度器"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._index = 0
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
if not agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 只选择在线的 Agent
|
|||
|
|
online_agents = [a for a in agents if a.status == 'online']
|
|||
|
|
if not online_agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 轮询选择
|
|||
|
|
agent = online_agents[self._index % len(online_agents)]
|
|||
|
|
self._index += 1
|
|||
|
|
return agent
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WeightedRoundRobinScheduler(BaseScheduler):
|
|||
|
|
"""加权轮询调度器(默认)"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._index = 0
|
|||
|
|
self._weights = {}
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
if not agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 只选择在线的 Agent
|
|||
|
|
online_agents = [a for a in agents if a.status == 'online']
|
|||
|
|
if not online_agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 计算总权重
|
|||
|
|
total_weight = sum(a.weight for a in online_agents)
|
|||
|
|
if total_weight == 0:
|
|||
|
|
return online_agents[0] if online_agents else None
|
|||
|
|
|
|||
|
|
# 加权轮询
|
|||
|
|
current_weight = self._index % total_weight
|
|||
|
|
cumulative = 0
|
|||
|
|
|
|||
|
|
for agent in online_agents:
|
|||
|
|
cumulative += agent.weight
|
|||
|
|
if current_weight < cumulative:
|
|||
|
|
self._index += 1
|
|||
|
|
return agent
|
|||
|
|
|
|||
|
|
return online_agents[-1]
|
|||
|
|
|
|||
|
|
|
|||
|
|
class LeastConnectionsScheduler(BaseScheduler):
|
|||
|
|
"""最少连接调度器"""
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
if not agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 只选择在线且未达连接上限的 Agent
|
|||
|
|
available_agents = [
|
|||
|
|
a for a in agents
|
|||
|
|
if a.status == 'online' and a.current_sessions < a.connection_limit
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
if not available_agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 选择连接数最少的
|
|||
|
|
return min(available_agents, key=lambda a: a.current_sessions)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class LeastResponseTimeScheduler(BaseScheduler):
|
|||
|
|
"""最快响应调度器(基于最后心跳时间)"""
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
if not agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 只选择在线的 Agent
|
|||
|
|
online_agents = [a for a in agents if a.status == 'online']
|
|||
|
|
if not online_agents:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 选择最近有心跳的(响应快的)
|
|||
|
|
from datetime import datetime
|
|||
|
|
now = datetime.utcnow()
|
|||
|
|
|
|||
|
|
def response_score(agent):
|
|||
|
|
if not agent.last_heartbeat:
|
|||
|
|
return float('inf')
|
|||
|
|
# 最近心跳 = 分数低 = 优先选择
|
|||
|
|
return (now - agent.last_heartbeat).total_seconds()
|
|||
|
|
|
|||
|
|
return min(online_agents, key=response_score)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CapabilityMatchScheduler(BaseScheduler):
|
|||
|
|
"""能力匹配调度器"""
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
if not agents or not context:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
required_capabilities = context.get('capabilities', [])
|
|||
|
|
if not required_capabilities:
|
|||
|
|
# 没有特殊要求,使用加权轮询
|
|||
|
|
return WeightedRoundRobinScheduler().select_agent(agents, context)
|
|||
|
|
|
|||
|
|
# 只选择在线且有对应能力的 Agent
|
|||
|
|
matching_agents = []
|
|||
|
|
for agent in agents:
|
|||
|
|
if agent.status != 'online':
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
agent_caps = agent.capabilities or []
|
|||
|
|
# 检查是否具备所有必需能力
|
|||
|
|
if all(cap in agent_caps for cap in required_capabilities):
|
|||
|
|
matching_agents.append(agent)
|
|||
|
|
|
|||
|
|
if not matching_agents:
|
|||
|
|
# 没有匹配的,回退到加权轮询
|
|||
|
|
return WeightedRoundRobinScheduler().select_agent(agents, context)
|
|||
|
|
|
|||
|
|
# 在匹配的 Agent 中使用加权轮询
|
|||
|
|
return WeightedRoundRobinScheduler().select_agent(matching_agents, context)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class AgentScheduler:
|
|||
|
|
"""Agent 调度器工厂"""
|
|||
|
|
|
|||
|
|
STRATEGIES = {
|
|||
|
|
'round_robin': RoundRobinScheduler,
|
|||
|
|
'weighted_round_robin': WeightedRoundRobinScheduler,
|
|||
|
|
'least_connections': LeastConnectionsScheduler,
|
|||
|
|
'least_response_time': LeastResponseTimeScheduler,
|
|||
|
|
'capability_match': CapabilityMatchScheduler,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def __init__(self, strategy: str = 'weighted_round_robin'):
|
|||
|
|
self._strategy_name = strategy
|
|||
|
|
self._scheduler = self.STRATEGIES.get(strategy, WeightedRoundRobinScheduler)()
|
|||
|
|
|
|||
|
|
def select_agent(self, agents: List[Agent], context: dict = None) -> Optional[Agent]:
|
|||
|
|
"""选择 Agent"""
|
|||
|
|
return self._scheduler.select_agent(agents, context)
|
|||
|
|
|
|||
|
|
def get_strategy(self) -> str:
|
|||
|
|
"""获取当前策略"""
|
|||
|
|
return self._strategy_name
|
|||
|
|
|
|||
|
|
@classmethod
|
|||
|
|
def get_available_strategies(cls) -> list:
|
|||
|
|
"""获取可用策略列表"""
|
|||
|
|
return list(cls.STRATEGIES.keys())
|