Skip to main content

mofa_foundation/secretary/
agent_router.rs

1//! Agent路由器 - 阶段3扩展: 动态Agent注入与智能决策
2//!
3//! 支持SDK调用者自行决定注入哪些Agent,框架通过提示词或规则引擎进行动态决策。
4//!
5//! ## 核心特性
6//!
7//! 1. **AgentProvider trait**: SDK调用者实现此trait来动态提供Agent
8//! 2. **AgentRouter trait**: 动态决策使用哪个Agent执行任务
9//! 3. **LLMAgentRouter**: 基于LLM提示词的智能路由
10//! 4. **RuleBasedRouter**: 基于规则引擎的确定性路由
11//!
12//! ## 使用示例
13//!
14//! ```rust,ignore
15//! // 1. 实现AgentProvider提供动态Agent
16//! struct MyAgentProvider {
17//!     agents: Vec<AgentInfo>,
18//! }
19//!
20//! impl AgentProvider for MyAgentProvider {
21//!     async fn list_agents(&self) -> Vec<AgentInfo> {
22//!         self.agents.clone()
23//!     }
24//!
25//!     async fn get_agent(&self, id: &str) -> Option<AgentInfo> {
26//!         self.agents.iter().find(|a| a.id == id).cloned()
27//!     }
28//! }
29//!
30//! // 2. 配置路由策略
31//! let router = LLMAgentRouter::new(llm_provider)
32//!     .with_custom_prompt(my_prompt);
33//!
34//! // 3. 在SecretaryAgent中使用
35//! let secretary = DefaultSecretaryBuilder::new()
36//!     .with_agent_provider(Arc::new(my_provider))
37//!     .with_agent_router(Arc::new(router))
38//!     .build()
39//!     .await;
40//! ```
41
42use super::default::types::{ProjectRequirement, Subtask};
43use super::llm::{ChatMessage, LLMProvider, parse_llm_json};
44use serde::{Deserialize, Serialize};
45use std::collections::HashMap;
46use std::sync::Arc;
47use tokio::sync::RwLock;
48
49// =============================================================================
50// Agent信息与能力描述
51// =============================================================================
52
53/// Agent信息 - 描述一个可执行任务的Agent
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct AgentInfo {
56    /// Agent唯一标识
57    pub id: String,
58    /// Agent名称
59    pub name: String,
60    /// Agent描述(用于LLM理解Agent能力)
61    pub description: String,
62    /// 能力标签列表
63    pub capabilities: Vec<String>,
64    /// 支持的任务类型
65    pub supported_task_types: Vec<String>,
66    /// Agent的prompt模板(可选,用于调用时)
67    pub prompt_template: Option<String>,
68    /// 当前负载(0-100)
69    pub current_load: u32,
70    /// 是否可用
71    pub available: bool,
72    /// 性能评分(历史表现)
73    pub performance_score: f32,
74    /// 元数据
75    pub metadata: HashMap<String, String>,
76}
77
78impl AgentInfo {
79    /// 创建新的AgentInfo
80    pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
81        Self {
82            id: id.into(),
83            name: name.into(),
84            description: String::new(),
85            capabilities: Vec::new(),
86            supported_task_types: Vec::new(),
87            prompt_template: None,
88            current_load: 0,
89            available: true,
90            performance_score: 0.8,
91            metadata: HashMap::new(),
92        }
93    }
94
95    /// 设置描述
96    pub fn with_description(mut self, desc: impl Into<String>) -> Self {
97        self.description = desc.into();
98        self
99    }
100
101    /// 添加能力
102    pub fn with_capability(mut self, cap: impl Into<String>) -> Self {
103        self.capabilities.push(cap.into());
104        self
105    }
106
107    /// 批量添加能力
108    pub fn with_capabilities(mut self, caps: Vec<String>) -> Self {
109        self.capabilities.extend(caps);
110        self
111    }
112
113    /// 添加支持的任务类型
114    pub fn with_task_type(mut self, task_type: impl Into<String>) -> Self {
115        self.supported_task_types.push(task_type.into());
116        self
117    }
118
119    /// 设置prompt模板
120    pub fn with_prompt_template(mut self, template: impl Into<String>) -> Self {
121        self.prompt_template = Some(template.into());
122        self
123    }
124
125    /// 设置性能评分
126    pub fn with_performance_score(mut self, score: f32) -> Self {
127        self.performance_score = score;
128        self
129    }
130}
131
132// =============================================================================
133// AgentProvider Trait - 动态Agent注入
134// =============================================================================
135
136/// Agent提供者Trait
137///
138/// SDK调用者实现此trait来动态提供可用的Agent列表。
139/// 这允许在运行时动态添加、移除、更新Agent。
140#[async_trait::async_trait]
141pub trait AgentProvider: Send + Sync {
142    /// 获取所有可用的Agent列表
143    async fn list_agents(&self) -> Vec<AgentInfo>;
144
145    /// 根据ID获取特定Agent
146    async fn get_agent(&self, agent_id: &str) -> Option<AgentInfo>;
147
148    /// 根据能力标签筛选Agent
149    async fn filter_by_capabilities(&self, capabilities: &[String]) -> Vec<AgentInfo> {
150        let agents = self.list_agents().await;
151        agents
152            .into_iter()
153            .filter(|agent| {
154                capabilities.is_empty()
155                    || capabilities
156                        .iter()
157                        .any(|cap| agent.capabilities.contains(cap))
158            })
159            .collect()
160    }
161
162    /// 根据任务类型筛选Agent
163    async fn filter_by_task_type(&self, task_type: &str) -> Vec<AgentInfo> {
164        let agents = self.list_agents().await;
165        agents
166            .into_iter()
167            .filter(|agent| {
168                agent.supported_task_types.is_empty()
169                    || agent.supported_task_types.contains(&task_type.to_string())
170            })
171            .collect()
172    }
173
174    /// 更新Agent状态
175    async fn update_agent_status(&self, agent_id: &str, load: u32, available: bool);
176
177    /// 注册新Agent(可选实现)
178    async fn register_agent(&self, _agent: AgentInfo) -> anyhow::Result<()> {
179        Ok(())
180    }
181
182    /// 注销Agent(可选实现)
183    async fn unregister_agent(&self, _agent_id: &str) -> anyhow::Result<()> {
184        Ok(())
185    }
186}
187
188// =============================================================================
189// 默认AgentProvider实现
190// =============================================================================
191
192/// 内存中的Agent提供者
193///
194/// 简单的基于内存的AgentProvider实现
195#[derive(Clone)]
196pub struct InMemoryAgentProvider {
197    agents: Arc<RwLock<HashMap<String, AgentInfo>>>,
198}
199
200impl InMemoryAgentProvider {
201    pub fn new() -> Self {
202        Self {
203            agents: Arc::new(RwLock::new(HashMap::new())),
204        }
205    }
206
207    /// 添加Agent
208    pub async fn add_agent(&self, agent: AgentInfo) {
209        let mut agents = self.agents.write().await;
210        agents.insert(agent.id.clone(), agent);
211    }
212
213    /// 移除Agent
214    pub async fn remove_agent(&self, agent_id: &str) {
215        let mut agents = self.agents.write().await;
216        agents.remove(agent_id);
217    }
218}
219
220impl Default for InMemoryAgentProvider {
221    fn default() -> Self {
222        Self::new()
223    }
224}
225
226#[async_trait::async_trait]
227impl AgentProvider for InMemoryAgentProvider {
228    async fn list_agents(&self) -> Vec<AgentInfo> {
229        let agents = self.agents.read().await;
230        agents.values().filter(|a| a.available).cloned().collect()
231    }
232
233    async fn get_agent(&self, agent_id: &str) -> Option<AgentInfo> {
234        let agents = self.agents.read().await;
235        agents.get(agent_id).cloned()
236    }
237
238    async fn update_agent_status(&self, agent_id: &str, load: u32, available: bool) {
239        let mut agents = self.agents.write().await;
240        if let Some(agent) = agents.get_mut(agent_id) {
241            agent.current_load = load;
242            agent.available = available;
243        }
244    }
245
246    async fn register_agent(&self, agent: AgentInfo) -> anyhow::Result<()> {
247        self.add_agent(agent).await;
248        Ok(())
249    }
250
251    async fn unregister_agent(&self, agent_id: &str) -> anyhow::Result<()> {
252        self.remove_agent(agent_id).await;
253        Ok(())
254    }
255}
256
257// =============================================================================
258// 路由决策上下文与结果
259// =============================================================================
260
261/// 路由决策上下文
262#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct RoutingContext {
264    /// 子任务信息
265    pub subtask: Subtask,
266    /// Todo ID
267    pub todo_id: String,
268    /// 原始需求
269    pub raw_idea: String,
270    /// 项目需求(如果已澄清)
271    pub requirement: Option<ProjectRequirement>,
272    /// 上下文元数据
273    pub metadata: HashMap<String, String>,
274    /// 对话历史(用于LLM路由)
275    pub conversation_history: Vec<String>,
276}
277
278impl RoutingContext {
279    pub fn new(subtask: Subtask, todo_id: &str) -> Self {
280        Self {
281            subtask,
282            todo_id: todo_id.to_string(),
283            raw_idea: String::new(),
284            requirement: None,
285            metadata: HashMap::new(),
286            conversation_history: Vec::new(),
287        }
288    }
289
290    pub fn with_raw_idea(mut self, idea: &str) -> Self {
291        self.raw_idea = idea.to_string();
292        self
293    }
294
295    pub fn with_requirement(mut self, req: ProjectRequirement) -> Self {
296        self.requirement = Some(req);
297        self
298    }
299
300    pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
301        self.metadata.insert(key.to_string(), value.to_string());
302        self
303    }
304}
305
306/// 路由决策结果
307#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct RoutingDecision {
309    /// 选中的Agent ID
310    pub agent_id: String,
311    /// 决策理由
312    pub reason: String,
313    /// 匹配分数
314    pub confidence: f32,
315    /// 备选Agent列表(按优先级排序)
316    pub alternatives: Vec<String>,
317    /// 决策类型
318    pub decision_type: RoutingDecisionType,
319    /// 是否需要人类确认
320    pub needs_human_confirmation: bool,
321    /// 额外的执行参数
322    pub execution_params: HashMap<String, String>,
323}
324
325/// 路由决策类型
326#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
327pub enum RoutingDecisionType {
328    /// 精确匹配
329    ExactMatch,
330    /// 能力匹配
331    CapabilityMatch,
332    /// LLM推理
333    LLMInference,
334    /// 规则匹配
335    RuleMatch,
336    /// 默认分配
337    Default,
338    /// 人类指定
339    HumanAssigned,
340}
341
342// =============================================================================
343// AgentRouter Trait - 动态路由决策
344// =============================================================================
345
346/// Agent路由器Trait
347///
348/// 负责决定将任务分配给哪个Agent。
349/// 可以基于LLM提示词、规则引擎或自定义逻辑。
350#[async_trait::async_trait]
351pub trait AgentRouter: Send + Sync {
352    /// 路由器名称
353    fn name(&self) -> &str;
354
355    /// 为子任务选择最合适的Agent
356    async fn route(
357        &self,
358        context: &RoutingContext,
359        available_agents: &[AgentInfo],
360    ) -> anyhow::Result<RoutingDecision>;
361
362    /// 批量路由多个子任务
363    async fn route_batch(
364        &self,
365        contexts: &[RoutingContext],
366        available_agents: &[AgentInfo],
367    ) -> anyhow::Result<Vec<RoutingDecision>> {
368        let mut results = Vec::new();
369        for ctx in contexts {
370            let decision = self.route(ctx, available_agents).await?;
371            results.push(decision);
372        }
373        Ok(results)
374    }
375
376    /// 验证路由决策是否有效
377    async fn validate_decision(
378        &self,
379        decision: &RoutingDecision,
380        available_agents: &[AgentInfo],
381    ) -> bool {
382        available_agents.iter().any(|a| a.id == decision.agent_id)
383    }
384}
385
386// =============================================================================
387// 基于LLM的智能路由器
388// =============================================================================
389
390/// LLM智能路由器
391///
392/// 使用LLM分析任务需求,智能选择最合适的Agent。
393pub struct LLMAgentRouter {
394    /// LLM提供者
395    llm: Arc<dyn LLMProvider>,
396    /// 自定义系统提示词
397    system_prompt: Option<String>,
398    /// 自定义路由提示词模板
399    routing_prompt_template: Option<String>,
400    /// 是否详细解释决策
401    explain_decisions: bool,
402    /// 置信度阈值(低于此值需要人类确认)
403    confidence_threshold: f32,
404}
405
406impl LLMAgentRouter {
407    pub fn new(llm: Arc<dyn LLMProvider>) -> Self {
408        Self {
409            llm,
410            system_prompt: None,
411            routing_prompt_template: None,
412            explain_decisions: true,
413            confidence_threshold: 0.7,
414        }
415    }
416
417    pub fn with_system_prompt(mut self, prompt: impl Into<String>) -> Self {
418        self.system_prompt = Some(prompt.into());
419        self
420    }
421
422    pub fn with_routing_prompt_template(mut self, template: impl Into<String>) -> Self {
423        self.routing_prompt_template = Some(template.into());
424        self
425    }
426
427    pub fn with_confidence_threshold(mut self, threshold: f32) -> Self {
428        self.confidence_threshold = threshold;
429        self
430    }
431
432    pub fn with_explain_decisions(mut self, explain: bool) -> Self {
433        self.explain_decisions = explain;
434        self
435    }
436
437    /// 生成路由提示词
438    fn generate_routing_prompt(&self, context: &RoutingContext, agents: &[AgentInfo]) -> String {
439        if let Some(ref template) = self.routing_prompt_template {
440            // 使用自定义模板
441            template
442                .replace("{subtask_description}", &context.subtask.description)
443                .replace(
444                    "{required_capabilities}",
445                    &context.subtask.required_capabilities.join(", "),
446                )
447                .replace("{raw_idea}", &context.raw_idea)
448                .replace(
449                    "{agents}",
450                    &agents
451                        .iter()
452                        .map(|a| {
453                            format!(
454                                "- {}: {} (能力: {})",
455                                a.id,
456                                a.description,
457                                a.capabilities.join(", ")
458                            )
459                        })
460                        .collect::<Vec<_>>()
461                        .join("\n"),
462                )
463        } else {
464            // 默认模板
465            format!(
466                r#"请为以下任务选择最合适的执行Agent。
467
468## 任务信息
469- 任务描述: {}
470- 所需能力: {}
471- 原始需求: {}
472
473## 可用Agent列表
474{}
475
476## 要求
477请以JSON格式返回路由决策:
478```json
479{{
480    "agent_id": "选中的Agent ID",
481    "reason": "选择理由",
482    "confidence": 0.0-1.0的置信度,
483    "alternatives": ["备选Agent ID列表"]
484}}
485```
486
487请基于任务需求和Agent能力做出最佳匹配。"#,
488                context.subtask.description,
489                context.subtask.required_capabilities.join(", "),
490                context.raw_idea,
491                agents
492                    .iter()
493                    .map(|a| format!(
494                        "- ID: {}\n  名称: {}\n  描述: {}\n  能力: {}\n  任务类型: {}\n  性能评分: {:.2}",
495                        a.id,
496                        a.name,
497                        a.description,
498                        a.capabilities.join(", "),
499                        a.supported_task_types.join(", "),
500                        a.performance_score
501                    ))
502                    .collect::<Vec<_>>()
503                    .join("\n\n")
504            )
505        }
506    }
507
508    /// 默认系统提示词
509    fn default_system_prompt(&self) -> &'static str {
510        r#"你是一个任务路由专家,负责将任务分配给最合适的执行Agent。
511
512你需要考虑以下因素:
5131. 任务所需的能力与Agent的能力是否匹配
5142. Agent的历史性能评分
5153. 任务类型与Agent支持的任务类型是否匹配
5164. Agent的当前负载情况
517
518做出决策时,请确保:
519- 选择能力最匹配的Agent
520- 如果有多个匹配的Agent,优先选择性能评分高的
521- 如果没有完全匹配的,选择最接近的并降低置信度
522- 始终提供清晰的决策理由"#
523    }
524}
525
526#[async_trait::async_trait]
527impl AgentRouter for LLMAgentRouter {
528    fn name(&self) -> &str {
529        "llm_router"
530    }
531
532    async fn route(
533        &self,
534        context: &RoutingContext,
535        available_agents: &[AgentInfo],
536    ) -> anyhow::Result<RoutingDecision> {
537        if available_agents.is_empty() {
538            return Err(anyhow::anyhow!("No available agents"));
539        }
540
541        // 构建消息
542        let messages = vec![
543            ChatMessage::system(
544                self.system_prompt
545                    .as_deref()
546                    .unwrap_or_else(|| self.default_system_prompt()),
547            ),
548            ChatMessage::user(self.generate_routing_prompt(context, available_agents)),
549        ];
550
551        // 调用LLM
552        let response = self.llm.chat(messages).await?;
553
554        // 解析响应
555        #[derive(Deserialize)]
556        struct LLMRoutingResponse {
557            agent_id: String,
558            reason: String,
559            confidence: Option<f32>,
560            alternatives: Option<Vec<String>>,
561        }
562
563        match parse_llm_json::<LLMRoutingResponse>(&response) {
564            Ok(parsed) => {
565                let confidence = parsed.confidence.unwrap_or(0.8);
566                Ok(RoutingDecision {
567                    agent_id: parsed.agent_id,
568                    reason: parsed.reason,
569                    confidence,
570                    alternatives: parsed.alternatives.unwrap_or_default(),
571                    decision_type: RoutingDecisionType::LLMInference,
572                    needs_human_confirmation: confidence < self.confidence_threshold,
573                    execution_params: HashMap::new(),
574                })
575            }
576            Err(_) => {
577                // 回退:选择第一个可用Agent
578                let fallback_agent = available_agents
579                    .first()
580                    .ok_or_else(|| anyhow::anyhow!("No available agents"))?;
581
582                Ok(RoutingDecision {
583                    agent_id: fallback_agent.id.clone(),
584                    reason: "LLM响应解析失败,使用默认分配".to_string(),
585                    confidence: 0.5,
586                    alternatives: available_agents
587                        .iter()
588                        .skip(1)
589                        .map(|a| a.id.clone())
590                        .collect(),
591                    decision_type: RoutingDecisionType::Default,
592                    needs_human_confirmation: true,
593                    execution_params: HashMap::new(),
594                })
595            }
596        }
597    }
598}
599
600// =============================================================================
601// 基于规则的路由器
602// =============================================================================
603
604/// 路由规则
605#[derive(Debug, Clone, Serialize, Deserialize)]
606pub struct RoutingRule {
607    /// 规则ID
608    pub id: String,
609    /// 规则名称
610    pub name: String,
611    /// 规则优先级(数字越大优先级越高)
612    pub priority: i32,
613    /// 匹配条件
614    pub conditions: Vec<RuleCondition>,
615    /// 条件组合方式
616    pub condition_logic: ConditionLogic,
617    /// 目标Agent ID
618    pub target_agent_id: String,
619    /// 规则启用状态
620    pub enabled: bool,
621}
622
623/// 规则条件
624#[derive(Debug, Clone, Serialize, Deserialize)]
625pub struct RuleCondition {
626    /// 条件字段
627    pub field: RuleField,
628    /// 操作符
629    pub operator: RuleOperator,
630    /// 匹配值
631    pub value: String,
632}
633
634/// 规则字段
635#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
636pub enum RuleField {
637    /// 子任务描述
638    SubtaskDescription,
639    /// 所需能力
640    RequiredCapability,
641    /// 任务类型
642    TaskType,
643    /// 优先级
644    Priority,
645    /// 元数据字段
646    Metadata(String),
647    /// 原始需求
648    RawIdea,
649}
650
651/// 规则操作符
652#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
653pub enum RuleOperator {
654    /// 等于
655    Equals,
656    /// 不等于
657    NotEquals,
658    /// 包含
659    Contains,
660    /// 不包含
661    NotContains,
662    /// 以...开头
663    StartsWith,
664    /// 以...结尾
665    EndsWith,
666    /// 正则匹配
667    Regex,
668    /// 在列表中
669    In,
670    /// 不在列表中
671    NotIn,
672}
673
674/// 条件组合逻辑
675#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
676pub enum ConditionLogic {
677    /// 所有条件都满足
678    All,
679    /// 任一条件满足
680    Any,
681}
682
683/// 基于规则的路由器
684pub struct RuleBasedRouter {
685    /// 规则列表
686    rules: Arc<RwLock<Vec<RoutingRule>>>,
687    /// 默认Agent ID(无规则匹配时使用)
688    default_agent_id: Option<String>,
689    /// 是否需要人类确认规则匹配
690    confirm_on_match: bool,
691}
692
693impl RuleBasedRouter {
694    pub fn new() -> Self {
695        Self {
696            rules: Arc::new(RwLock::new(Vec::new())),
697            default_agent_id: None,
698            confirm_on_match: false,
699        }
700    }
701
702    pub fn with_default_agent(mut self, agent_id: impl Into<String>) -> Self {
703        self.default_agent_id = Some(agent_id.into());
704        self
705    }
706
707    pub fn with_confirm_on_match(mut self, confirm: bool) -> Self {
708        self.confirm_on_match = confirm;
709        self
710    }
711
712    /// 添加规则
713    pub async fn add_rule(&self, rule: RoutingRule) {
714        let mut rules = self.rules.write().await;
715        rules.push(rule);
716        // 按优先级排序
717        rules.sort_by(|a, b| b.priority.cmp(&a.priority));
718    }
719
720    /// 移除规则
721    pub async fn remove_rule(&self, rule_id: &str) {
722        let mut rules = self.rules.write().await;
723        rules.retain(|r| r.id != rule_id);
724    }
725
726    /// 检查条件是否匹配
727    fn check_condition(&self, condition: &RuleCondition, context: &RoutingContext) -> bool {
728        let field_value = match &condition.field {
729            RuleField::SubtaskDescription => context.subtask.description.clone(),
730            RuleField::RequiredCapability => context.subtask.required_capabilities.join(","),
731            RuleField::TaskType => context
732                .metadata
733                .get("task_type")
734                .cloned()
735                .unwrap_or_default(),
736            RuleField::Priority => context
737                .metadata
738                .get("priority")
739                .cloned()
740                .unwrap_or_default(),
741            RuleField::Metadata(key) => context.metadata.get(key).cloned().unwrap_or_default(),
742            RuleField::RawIdea => context.raw_idea.clone(),
743        };
744
745        match &condition.operator {
746            RuleOperator::Equals => field_value == condition.value,
747            RuleOperator::NotEquals => field_value != condition.value,
748            RuleOperator::Contains => field_value.contains(&condition.value),
749            RuleOperator::NotContains => !field_value.contains(&condition.value),
750            RuleOperator::StartsWith => field_value.starts_with(&condition.value),
751            RuleOperator::EndsWith => field_value.ends_with(&condition.value),
752            RuleOperator::Regex => regex::Regex::new(&condition.value)
753                .map(|re| re.is_match(&field_value))
754                .unwrap_or(false),
755            RuleOperator::In => condition.value.split(',').any(|v| v.trim() == field_value),
756            RuleOperator::NotIn => !condition.value.split(',').any(|v| v.trim() == field_value),
757        }
758    }
759
760    /// 检查规则是否匹配
761    fn check_rule(&self, rule: &RoutingRule, context: &RoutingContext) -> bool {
762        if !rule.enabled {
763            return false;
764        }
765
766        match rule.condition_logic {
767            ConditionLogic::All => rule
768                .conditions
769                .iter()
770                .all(|c| self.check_condition(c, context)),
771            ConditionLogic::Any => rule
772                .conditions
773                .iter()
774                .any(|c| self.check_condition(c, context)),
775        }
776    }
777}
778
779impl Default for RuleBasedRouter {
780    fn default() -> Self {
781        Self::new()
782    }
783}
784
785#[async_trait::async_trait]
786impl AgentRouter for RuleBasedRouter {
787    fn name(&self) -> &str {
788        "rule_based_router"
789    }
790
791    async fn route(
792        &self,
793        context: &RoutingContext,
794        available_agents: &[AgentInfo],
795    ) -> anyhow::Result<RoutingDecision> {
796        let rules = self.rules.read().await;
797
798        // 查找第一个匹配的规则
799        for rule in rules.iter() {
800            if self.check_rule(rule, context) {
801                // 验证目标Agent是否可用
802                if available_agents
803                    .iter()
804                    .any(|a| a.id == rule.target_agent_id)
805                {
806                    return Ok(RoutingDecision {
807                        agent_id: rule.target_agent_id.clone(),
808                        reason: format!("匹配规则: {} ({})", rule.name, rule.id),
809                        confidence: 1.0,
810                        alternatives: Vec::new(),
811                        decision_type: RoutingDecisionType::RuleMatch,
812                        needs_human_confirmation: self.confirm_on_match,
813                        execution_params: HashMap::new(),
814                    });
815                }
816            }
817        }
818
819        // 没有匹配的规则,使用默认Agent或第一个可用Agent
820        let agent_id = self
821            .default_agent_id
822            .clone()
823            .or_else(|| available_agents.first().map(|a| a.id.clone()))
824            .ok_or_else(|| anyhow::anyhow!("No available agents"))?;
825
826        Ok(RoutingDecision {
827            agent_id,
828            reason: "无匹配规则,使用默认分配".to_string(),
829            confidence: 0.5,
830            alternatives: available_agents.iter().map(|a| a.id.clone()).collect(),
831            decision_type: RoutingDecisionType::Default,
832            needs_human_confirmation: true,
833            execution_params: HashMap::new(),
834        })
835    }
836}
837
838// =============================================================================
839// 能力匹配路由器
840// =============================================================================
841
842/// 能力匹配路由器
843///
844/// 基于能力标签进行简单的匹配路由
845pub struct CapabilityRouter {
846    /// 能力权重配置
847    capability_weights: HashMap<String, f32>,
848    /// 是否启用负载均衡
849    load_balancing: bool,
850    /// 性能权重
851    performance_weight: f32,
852}
853
854impl CapabilityRouter {
855    pub fn new() -> Self {
856        Self {
857            capability_weights: HashMap::new(),
858            load_balancing: true,
859            performance_weight: 0.3,
860        }
861    }
862
863    pub fn with_capability_weight(mut self, capability: impl Into<String>, weight: f32) -> Self {
864        self.capability_weights.insert(capability.into(), weight);
865        self
866    }
867
868    pub fn with_load_balancing(mut self, enabled: bool) -> Self {
869        self.load_balancing = enabled;
870        self
871    }
872
873    pub fn with_performance_weight(mut self, weight: f32) -> Self {
874        self.performance_weight = weight;
875        self
876    }
877
878    /// 计算Agent与任务的匹配分数
879    fn calculate_match_score(&self, agent: &AgentInfo, required_caps: &[String]) -> f32 {
880        if required_caps.is_empty() {
881            return 1.0;
882        }
883
884        let mut score = 0.0;
885        let mut total_weight = 0.0;
886
887        for cap in required_caps {
888            let weight = self.capability_weights.get(cap).copied().unwrap_or(1.0);
889            total_weight += weight;
890
891            if agent.capabilities.contains(cap) {
892                score += weight;
893            }
894        }
895
896        let capability_score = if total_weight > 0.0 {
897            score / total_weight
898        } else {
899            1.0
900        };
901
902        // 加权计算
903        let load_score = if self.load_balancing {
904            1.0 - (agent.current_load as f32 / 100.0)
905        } else {
906            1.0
907        };
908
909        let performance_score = agent.performance_score;
910
911        // 综合评分
912        capability_score * 0.5 + load_score * 0.2 + performance_score * self.performance_weight
913    }
914}
915
916impl Default for CapabilityRouter {
917    fn default() -> Self {
918        Self::new()
919    }
920}
921
922#[async_trait::async_trait]
923impl AgentRouter for CapabilityRouter {
924    fn name(&self) -> &str {
925        "capability_router"
926    }
927
928    async fn route(
929        &self,
930        context: &RoutingContext,
931        available_agents: &[AgentInfo],
932    ) -> anyhow::Result<RoutingDecision> {
933        if available_agents.is_empty() {
934            return Err(anyhow::anyhow!("No available agents"));
935        }
936
937        let required_caps = &context.subtask.required_capabilities;
938
939        // 计算所有Agent的匹配分数
940        let mut scored_agents: Vec<(&AgentInfo, f32)> = available_agents
941            .iter()
942            .map(|a| (a, self.calculate_match_score(a, required_caps)))
943            .collect();
944
945        // 按分数排序
946        scored_agents.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
947
948        let (best_agent, best_score) = scored_agents[0];
949
950        Ok(RoutingDecision {
951            agent_id: best_agent.id.clone(),
952            reason: format!(
953                "能力匹配得分最高 ({:.2}),匹配能力: {:?}",
954                best_score,
955                required_caps
956                    .iter()
957                    .filter(|c| best_agent.capabilities.contains(c))
958                    .collect::<Vec<_>>()
959            ),
960            confidence: best_score,
961            alternatives: scored_agents
962                .iter()
963                .skip(1)
964                .map(|(a, _)| a.id.clone())
965                .collect(),
966            decision_type: RoutingDecisionType::CapabilityMatch,
967            needs_human_confirmation: best_score < 0.5,
968            execution_params: HashMap::new(),
969        })
970    }
971}
972
973// =============================================================================
974// 复合路由器
975// =============================================================================
976
977/// 复合路由器
978///
979/// 组合多个路由器,按优先级顺序尝试
980pub struct CompositeRouter {
981    /// 路由器列表(按优先级排序)
982    routers: Vec<Arc<dyn AgentRouter>>,
983    /// 回退路由器
984    fallback_router: Option<Arc<dyn AgentRouter>>,
985}
986
987impl CompositeRouter {
988    pub fn new() -> Self {
989        Self {
990            routers: Vec::new(),
991            fallback_router: None,
992        }
993    }
994
995    /// 添加路由器
996    pub fn add_router(mut self, router: Arc<dyn AgentRouter>) -> Self {
997        self.routers.push(router);
998        self
999    }
1000
1001    /// 设置回退路由器
1002    pub fn with_fallback(mut self, router: Arc<dyn AgentRouter>) -> Self {
1003        self.fallback_router = Some(router);
1004        self
1005    }
1006}
1007
1008impl Default for CompositeRouter {
1009    fn default() -> Self {
1010        Self::new()
1011    }
1012}
1013
1014#[async_trait::async_trait]
1015impl AgentRouter for CompositeRouter {
1016    fn name(&self) -> &str {
1017        "composite_router"
1018    }
1019
1020    async fn route(
1021        &self,
1022        context: &RoutingContext,
1023        available_agents: &[AgentInfo],
1024    ) -> anyhow::Result<RoutingDecision> {
1025        // 尝试每个路由器
1026        for router in &self.routers {
1027            match router.route(context, available_agents).await {
1028                Ok(decision) if decision.confidence >= 0.5 => {
1029                    return Ok(decision);
1030                }
1031                _ => continue,
1032            }
1033        }
1034
1035        // 使用回退路由器
1036        if let Some(ref fallback) = self.fallback_router {
1037            return fallback.route(context, available_agents).await;
1038        }
1039
1040        // 默认选择第一个Agent
1041        let agent = available_agents
1042            .first()
1043            .ok_or_else(|| anyhow::anyhow!("No available agents"))?;
1044
1045        Ok(RoutingDecision {
1046            agent_id: agent.id.clone(),
1047            reason: "所有路由器均无高置信度匹配,使用默认分配".to_string(),
1048            confidence: 0.3,
1049            alternatives: available_agents
1050                .iter()
1051                .skip(1)
1052                .map(|a| a.id.clone())
1053                .collect(),
1054            decision_type: RoutingDecisionType::Default,
1055            needs_human_confirmation: true,
1056            execution_params: HashMap::new(),
1057        })
1058    }
1059}
1060
1061// =============================================================================
1062// 测试
1063// =============================================================================
1064
1065#[cfg(test)]
1066mod tests {
1067    use super::*;
1068
1069    #[tokio::test]
1070    async fn test_in_memory_agent_provider() {
1071        let provider = InMemoryAgentProvider::new();
1072
1073        // 添加Agent
1074        provider
1075            .add_agent(
1076                AgentInfo::new("agent_1", "Test Agent 1")
1077                    .with_capability("backend")
1078                    .with_performance_score(0.9),
1079            )
1080            .await;
1081
1082        provider
1083            .add_agent(
1084                AgentInfo::new("agent_2", "Test Agent 2")
1085                    .with_capability("frontend")
1086                    .with_performance_score(0.85),
1087            )
1088            .await;
1089
1090        // 列出所有Agent
1091        let agents = provider.list_agents().await;
1092        assert_eq!(agents.len(), 2);
1093
1094        // 按能力筛选
1095        let backend_agents = provider
1096            .filter_by_capabilities(&["backend".to_string()])
1097            .await;
1098        assert_eq!(backend_agents.len(), 1);
1099        assert_eq!(backend_agents[0].id, "agent_1");
1100    }
1101
1102    #[tokio::test]
1103    async fn test_capability_router() {
1104        let router = CapabilityRouter::new()
1105            .with_load_balancing(true)
1106            .with_performance_weight(0.3);
1107
1108        let agents = vec![
1109            AgentInfo::new("agent_1", "Backend Agent")
1110                .with_capability("backend")
1111                .with_capability("database")
1112                .with_performance_score(0.9),
1113            AgentInfo::new("agent_2", "Frontend Agent")
1114                .with_capability("frontend")
1115                .with_capability("ui")
1116                .with_performance_score(0.85),
1117        ];
1118
1119        let context = RoutingContext::new(
1120            Subtask {
1121                id: "task_1".to_string(),
1122                description: "Build API".to_string(),
1123                required_capabilities: vec!["backend".to_string()],
1124                order: 1,
1125                depends_on: Vec::new(),
1126            },
1127            "todo_1",
1128        );
1129
1130        let decision = router.route(&context, &agents).await.unwrap();
1131        assert_eq!(decision.agent_id, "agent_1");
1132        assert_eq!(decision.decision_type, RoutingDecisionType::CapabilityMatch);
1133    }
1134
1135    #[tokio::test]
1136    async fn test_rule_based_router() {
1137        let router = RuleBasedRouter::new();
1138
1139        // 添加规则
1140        router
1141            .add_rule(RoutingRule {
1142                id: "rule_1".to_string(),
1143                name: "Backend Rule".to_string(),
1144                priority: 10,
1145                conditions: vec![RuleCondition {
1146                    field: RuleField::RequiredCapability,
1147                    operator: RuleOperator::Contains,
1148                    value: "backend".to_string(),
1149                }],
1150                condition_logic: ConditionLogic::All,
1151                target_agent_id: "backend_agent".to_string(),
1152                enabled: true,
1153            })
1154            .await;
1155
1156        let agents = vec![
1157            AgentInfo::new("backend_agent", "Backend Agent"),
1158            AgentInfo::new("frontend_agent", "Frontend Agent"),
1159        ];
1160
1161        let context = RoutingContext::new(
1162            Subtask {
1163                id: "task_1".to_string(),
1164                description: "Build API".to_string(),
1165                required_capabilities: vec!["backend".to_string()],
1166                order: 1,
1167                depends_on: Vec::new(),
1168            },
1169            "todo_1",
1170        );
1171
1172        let decision = router.route(&context, &agents).await.unwrap();
1173        assert_eq!(decision.agent_id, "backend_agent");
1174        assert_eq!(decision.decision_type, RoutingDecisionType::RuleMatch);
1175    }
1176
1177    #[tokio::test]
1178    async fn test_composite_router() {
1179        let rule_router = Arc::new(RuleBasedRouter::new());
1180        let capability_router = Arc::new(CapabilityRouter::new());
1181
1182        let composite = CompositeRouter::new()
1183            .add_router(rule_router)
1184            .with_fallback(capability_router);
1185
1186        let agents = vec![
1187            AgentInfo::new("agent_1", "Agent 1")
1188                .with_capability("general")
1189                .with_performance_score(0.8),
1190        ];
1191
1192        let context = RoutingContext::new(
1193            Subtask {
1194                id: "task_1".to_string(),
1195                description: "General task".to_string(),
1196                required_capabilities: vec![],
1197                order: 1,
1198                depends_on: Vec::new(),
1199            },
1200            "todo_1",
1201        );
1202
1203        let decision = composite.route(&context, &agents).await.unwrap();
1204        assert_eq!(decision.agent_id, "agent_1");
1205    }
1206}