11.3 ConcurrentWorkflow 并发编排
`ConcurrentWorkflow` 实现了 Fan-out/Fan-in 模式的 Agent 编排——所有 Agent 并行处理相同的输入,由 `WorkflowEngine` 驱动执行,自动获得并存控制、超时和完整事件流。
执行流程
sequenceDiagram
participant U as 用户
participant WF as ConcurrentWorkflow
participant E as WorkflowEngine
participant A1 as Agent A(分析师1)
participant A2 as Agent B(分析师2)
U->>WF: as_agent().run(input)
WF->>E: 构建图 source→FanOut→[A1,A2]→FanIn→sink
E->>E: SuperStep 启动,激活 source 和所有 Agent
par 并行执行
E->>A1: 消息分发
A1-->>E: NodeStreaming(实时)
A1-->>E: NodeCompleted
and
E->>A2: 消息分发
A2-->>E: NodeStreaming(实时)
A2-->>E: NodeCompleted
end
E->>E: FanIn 栅栏等待所有源到达
E->>E: 路由到 sink 节点
E-->>U: 工作流完成
内部建图:`source → FanOutEdge → [Agent₁, ..., Agentₙ] → FanInEdge → sink(aggregator) → output`
API 参考
ConcurrentWorkflowBuilder(对齐 MAF)
use rust_agent_workflow::ConcurrentWorkflowBuilder;
let workflow = ConcurrentWorkflowBuilder::new()
.add_agent(analyst_a)
.add_agent(analyst_b)
.add_agent(analyst_c)
.build()?;
let agent: Arc<dyn IAgent> = workflow.as_agent();
let stream = agent.run(input, session, None).await?;
快捷构造
let workflow = ConcurrentWorkflow::from_agents(vec![
analyst_a, analyst_b, analyst_c,
])?;
// 返回引擎双流(事件流 + 输出流)
let (events, outputs) = workflow.run(input, session, None).await?;
// 向后兼容单流接口
let stream = workflow.run_agent(input, session, None).await?;
内部实现
`ConcurrentWorkflow` 通过 `WorkflowBuilder` 构建 FanOut/FanIn 图:
fn from_agents(agents: Vec<Arc<dyn IAgent>>) -> Result<Self> {
let mut builder = WorkflowBuilder::new();
// 源节点:消息分发
builder.add_node("concurrent_source",
Arc::new(FunctionExecutor::new("concurrent_source", |msg: Vec<ChatMessage>| vec![msg])));
// FanOut 到所有 Agent
let mut agent_ids = vec![];
for (i, agent) in agents.iter().enumerate() {
let node_id = format!("concurrent_agent_{}", i);
builder.add_node(node_id.clone(),
Arc::new(AgentExecutor::new(node_id.clone(), agent.clone())));
agent_ids.push(node_id);
}
builder.add_fan_out_edge("concurrent_source", agent_ids.clone());
// FanIn 汇聚
builder.add_node("concurrent_sink",
Arc::new(FunctionExecutor::new("concurrent_sink", |_msg: String| vec!["aggregated".into()])));
builder.add_fan_in_edge(agent_ids, "concurrent_sink");
builder.with_output_from("concurrent_sink");
builder.build()
}
**并发控制**:通过 `WorkflowConfig.max_parallel_nodes` 限制同批执行的节点数。
完整示例
use std::sync::Arc;
use rust_agent_core::{IAgent, ChatMessage, Content};
use rust_agent_workflow::ConcurrentWorkflowBuilder;
use rust_agent_framework::AgentBuilder;
use futures_util::StreamExt;
async fn build_analysts(client: DeepSeekChatClient) -> Vec<Arc<dyn IAgent>> {
vec![
AgentBuilder::new("tech_analyst")
.chat_client(client.clone())
.instructions("你是技术分析师。从技术可行性角度分析。")
.build()?,
AgentBuilder::new("biz_analyst")
.chat_client(client.clone())
.instructions("你是商业分析师。从商业价值角度评估。")
.build()?,
]
}
async fn run_parallel_analysis() -> anyhow::Result<()> {
let client = DeepSeekChatClient::new(/* ... */)?;
let analysts = build_analysts(client).await;
let workflow = ConcurrentWorkflowBuilder::new()
.with_agents(analysts)
.build()?;
let agent: Arc<dyn IAgent> = workflow.as_agent();
let input = vec![ChatMessage::user("评估 Rust+WebAssembly 方案")];
let mut stream = agent.run(input, None, None).await?;
println!("=== 多方并行分析 ===");
while let Some(chunk) = stream.next().await {
match chunk {
Ok(result) => {
for content in &result.contents {
if let Content::Text(ref t) = content {
print!("{}", t.delta);
}
}
}
Err(e) => eprintln!("\n[错误: {}]", e),
}
}
Ok(())
}
适用场景
| 场景 | 说明 | |------|------| | 多方分析 | 技术、商业、风险等多角度并行评估 | | A/B 对比 | 不同提示词或模型处理同一问题,对比结果 | | 众包式解答 | 多个 Agent 各自给出答案,由用户选择最佳方案 | | 并行数据处理 | 将大任务拆分为独立子任务并发处理 |
注意事项
1. **并发限流**:通过 `WorkflowConfig.max_parallel_nodes` 控制,避免同时发起过多 LLM API 调用 2. **FanIn 栅栏**:所有 Agent 完成后才触发 sink 节点,确保完整性 3. **引擎驱动**:内部由 WorkflowEngine 执行,自动获得检查点和完整事件流 4. **向后兼容**:`FanOutWorkflow`、`ParallelWorkflow`、`ConcurrentPattern` 别名保留