11.4 HandoffWorkflow 交接编排
`HandoffWorkflow` 实现了智能路由(Triage)模式——一个分类 Agent 分析用户请求后,通过条件路由将其交接给最合适的专业 Agent 处理。内部由 `WorkflowEngine` 驱动,利用 `HandoffEdgeCondition` 实现基于 triage 输出的条件边。
执行流程
sequenceDiagram
participant U as 用户
participant WF as HandoffWorkflow
participant E as WorkflowEngine
participant T as Triage Agent
participant TA as Target Agent(专家)
U->>WF: as_agent().run(input)
WF->>E: 构建图 Triage→条件路由→[专家池]
E->>T: NodeInvoking + 消息分发
T-->>E: NodeStreaming + NodeCompleted
E->>E: HandoffEdgeCondition 评估 triage 输出
E->>E: 匹配到目标专家,路由消息
E->>TA: NodeInvoking + 消息分发
TA-->>U: 流式输出
内部建图:`TriageAgent → DirectEdge(with HandoffEdgeCondition) → [Expert₁, ..., Expertₙ]`
API 参考
HandoffWorkflowBuilder(对齐 MAF)
use rust_agent_workflow::HandoffWorkflowBuilder;
let workflow = HandoffWorkflowBuilder::new()
.triage(triage_agent) // 必须:分诊 Agent
.add_agent(code_agent) // 目标 Agent 1
.add_agent(writing_agent) // 目标 Agent 2
.add_agent(analysis_agent) // 目标 Agent 3
.build()?;
let agent: Arc<dyn IAgent> = workflow.as_agent();
let stream = agent.run(messages, session, None).await?;
关键约束
- `triage()` 必须调用,设置分诊 Agent - 至少调用一次 `add_agent()`(添加至少一个目标 Agent) - Agent 的匹配名称优先使用 `AgentMetadata.description`,为空则回退到 `AgentId` - 支持 `find_agent(&AgentId)` 手动查找子 Agent
HandoffEdgeCondition
内部通过条件边实现路由:
/// 转交边条件 —— 检查 triage Agent 输出是否包含特定专家名称。
pub struct HandoffEdgeCondition {
target_name: String,
triage_output: Arc<Mutex<Option<String>>>,
}
#[async_trait]
impl IEdgeCondition for HandoffEdgeCondition {
async fn evaluate(&self, envelope: &MessageEnvelope) -> Result<bool> {
if let Some(msg) = envelope.content.downcast_ref::<ChatMessage>() {
let text = &msg.content;
let matched = text.to_lowercase()
.contains(&self.target_name.to_lowercase());
return Ok(matched);
}
Ok(false)
}
}
每个专家节点对应一个 `HandoffEdgeCondition` 实例,当 triage 输出的文本包含对应名称时,该条件返回 `true`,消息沿该边传递。
与旧版差异
| 方面 | 旧版 HandoffPattern | 新版 HandoffWorkflow | |------|-------------------|---------------------| | 构建入口 | `HandoffWorkflow::new()` | `HandoffWorkflowBuilder::new()` | | 添加专家 | `.agent(agent)` | `.add_agent(agent)` | | 执行引擎 | 直接调用 `IAgent::run()` | `WorkflowEngine` 驱动 | | 路由方式 | 收集 triage 文本后匹配 | `HandoffEdgeCondition` 条件边 | | 检查点 | 不支持 | 自动支持 | | 事件流 | 无 | 完整 `WorkflowEvent` 流 |
完整示例
use std::sync::Arc;
use rust_agent_core::{IAgent, ChatMessage, Content};
use rust_agent_workflow::HandoffWorkflowBuilder;
use rust_agent_framework::AgentBuilder;
use futures_util::StreamExt;
async fn build_handoff_system(
client: DeepSeekChatClient,
) -> anyhow::Result<()> {
// 分诊 Agent
let triage = AgentBuilder::new("triage")
.chat_client(client.clone())
.instructions("你是智能路由员。分析用户请求并确定最合适的专家。")
.build()?;
// 代码专家
let coder = AgentBuilder::new("coder")
.chat_client(client.clone())
.instructions("你是资深软件工程师。")
.with_description("代码专家")
.build()?;
// 写作专家
let writer = AgentBuilder::new("writer")
.chat_client(client.clone())
.instructions("你是专业作家。")
.with_description("写作专家")
.build()?;
let workflow = HandoffWorkflowBuilder::new()
.triage(triage)
.add_agent(coder)
.add_agent(writer)
.build()?;
let agent: Arc<dyn IAgent> = workflow.as_agent();
// 测试路由
let code_req = vec![ChatMessage::user("写一个 Rust 快速排序")];
let mut stream = agent.run(code_req, None, None).await?;
while let Some(chunk) = stream.next().await {
if let Ok(result) = chunk {
for c in &result.contents {
if let Content::Text(ref t) = c { print!("{}", t.delta); }
}
}
}
Ok(())
}
适用场景
| 场景 | 说明 | |------|------| | 客服系统 | 路由到技术支持/账单/账户等专员 | | 多领域问答 | 根据问题领域自动分配专家 Agent | | 企业门户 | 不同类型的员工自助服务请求分发 | | 代码助手 | 区分前端/后端/数据库等专业领域 |
注意事项
1. **匹配精度**:基于不区分大小写的子串匹配,建议为每个 Agent 显式设置有意义的 `description` 2. **容错性**:无匹配时走回退路径(默认边将消息路由到备用节点) 3. **引擎驱动**:所有 Agent 执行通过 WorkflowEngine 进行,获得事件流和检查点 4. **向后兼容**:`HandoffBuilder` 别名和 `HandoffPattern` 别名仍可用