LangGraph 的 Send 怎么实现动态并行?与普通分支有什么不同?
🧑💻 面试官:用户上传一份报告,有时三章,有时二十章。每章都要独立摘要,最后合成总览。你会在图里画二十条固定分支吗?
🙋♂️ 我:不会。章节数要解析后才知道,适合由路由函数按当前章节列表生成多个 Send,把每一章交给同一个处理节点。
🧑💻 面试官:多个节点都把摘要写进同一个状态字段,会不会互相覆盖?
🙋♂️ 我:会有冲突风险。要给这个字段定义合适的 reducer,让各分支结果按规则合并,而不是依赖“最后一个写入者”。
🧑💻 面试官:那汇总结果的章节顺序一定和原文一样吗?
🙋♂️ 我:并行完成顺序不一定一致。每个子任务要带章节编号,汇总时按编号排序,再做总览。
Send 解决“运行时才知道要开多少个相同子任务”,Reducer 解决“这些子任务怎样把结果合起来”。
面试速答(60 秒版)
LangGraph 的 Send 适合动态扇出:图运行到某一步,才知道有几项工作要并行处理。比如解析报告得到 12 个章节,路由函数就针对 12 个章节分别返回一个 Send,指定同一个摘要节点,但给每次调用不同的章节内容和编号。
各子任务处理完会更新图状态。如果它们都写入 summaries,要为这个字段定义 reducer,明确怎样合并并行结果。汇总节点再按章节编号整理顺序,生成整份报告的总结。
与预先画死三条分支相比,Send 的分支数量由当前数据决定。工程上还要限制并发、处理某一章失败后的重试,并避免假设并行结果按完成顺序就等于原文顺序。
知识点详解:动态任务数与状态合并是两件事

固定分支处理不了“有多少章还不知道”
如果图设计时就确定“查数据库”和“查日志”两个分支,画两条边即可。但报告章节数来自运行时解析结果,今天三章、明天二十章。硬编码二十个节点会浪费,也无法自然应对第二十一章。
路由函数读取当前状态中的章节列表,为每个章节生成一个 Send。每个 Send 指向相同处理节点,却带着各自的局部输入,例如章节 ID、标题和正文。这样图结构不需要随章节数变化。
并行返回不能靠覆盖同一个字段
各章节摘要会在不同时间完成。如果它们都往 summaries 写值,而状态没有定义如何合并,并行更新就可能冲突。Reducer 的作用是规定多份更新怎样归并,例如把各章节结果收集成列表。
收集之后还要考虑顺序。最快完成的可能是第十章,不是第一章。结果里保留章节编号,汇总节点按编号排序,才能按原文顺序输出。
动态并行仍受资源和失败策略约束
二十章可以并行,不意味着应该无限并发。模型接口有限流,章节可能长短不一;需要设置并发和时间预算。某一章失败时,要决定只重试这一章、输出部分结果并说明缺失,还是让整个任务失败。
因此 Send 只解决任务分派,不会自动替你定义成本、失败恢复和结果质量。面试时把“分派、汇总、顺序、失败”四件事讲清楚,比背 API 名称有用得多。
面试官继续追问
Send 和普通条件边的差别是什么?
普通条件边常用于选择已有路径;Send 可以在运行时按数据生成多个发往节点的任务,并给每个任务不同输入。
定义了 reducer,就保证结果顺序了吗?
不保证。Reducer 解决合并规则,业务顺序要靠明确的序号或键在汇总时恢复。
某一章失败,要从头处理所有章节吗?
未必。可以按章节 ID 记录结果和失败状态,只重试失败项;具体恢复方式取决于图状态和执行器设计。
面试速记卡
- Send:运行时按数据动态分派多个子任务。
- 局部输入:每个子任务带自己的章节内容和编号。
- Reducer:规定并行结果怎样合并到状态。
- 顺序:汇总时按业务编号恢复,不靠完成先后。
- 工程边界:并发、重试、预算和部分失败要另设计。
