Send 对象是 LangGraph 实现并行的核心 API。当一个节点返回 [Send("node_a", state_a), Send("node_b", state_b)] 这样的 Send 列表时,LangGraph 会在同一个超级步中为每个 Send 创建独立的执行分支,所有分支并发执行。执行完毕后,各分支的结果通过 reducer 自动合并回主状态。这种模式非常适合 fan-out/fan-in 场景,如同时查询多个数据源或并行处理多个文档。
对于并发数量在编译期就固定的场景,可以使用多条 add_edge() 声明静态扇出。例如一个评估节点同时连接到三个并行评估 Worker,所有 Worker 完成后汇聚到一个聚合节点。这种方式实现简单但并发数量固定,不如 Send API 灵活。
并发执行时有几个常见陷阱需要注意:首先,并发节点同时写入同一状态字段时会触发 InvalidUpdateError,必须为对应的状态键声明合适的 reducer(如 operator.add);其次,Send 调度的是并行执行但并非真正的异步并发——如果节点函数中包含阻塞 I/O(如同步 HTTP 请求),仍然会串行执行,需要使用 async/await 实现真正的并发;最后,并发数过高可能触发 LLM API 的限流,建议通过 asyncio.Semaphore 限制最大并发数。
默认情况下,如果任何一个 Send 目标抛出异常,整个步骤都会失败。生产环境中应在路由节点中使用 try-except 包装,或将错误路由到专门的容错节点,将失败分支的结果聚合到状态中而不是让整个流程崩溃。对于关键任务,还可以在每个 Worker 节点内部实现重试逻辑。