
1. 从单Agent到Multi-Agent被逼出来的架构升级我在实际项目里做LLM应用落地时最开始真的非常抗拒多Agent架构。单Agent 一个巨大的System Prompt 一堆工具听起来简单可控实际跑起来却是另一回事提示词越写越长每加一个业务规则就要在Prompt里打补丁工具多了以后模型经常拿不准该调用哪一个甚至出现“顺着工具调用结果胡说八道”的情况更头疼的是一旦某个环节需要人工介入整个流程就卡死在那个State里想跳出来都不知道怎么跳。真正让我下决心换方案的是一个真实需求做一个面向内部研发团队的技术咨询助手。它需要同时处理几类任务——查文档、看监控指标、翻工单历史、生成周报。每个任务背后的数据源、接口风格、上下文结构完全不一样硬塞进一个Agent里Prompt随便就能写到两千行效果还很差经常答非所问。后来接触了LangGraph它是专门为LLM应用做编排的框架把Agent执行流程抽象成一张有向图——节点是步骤边是步骤之间的状态转移。它天然支持状态管理、循环控制、条件分支而且允许把一个复杂流程拆成多个子Agent各自维护各自的Prompt和工具再由一个调度者统一协调。对我来说最大的价值不是“多Agent听起来高级”而是它终于让我能把复杂度拆开——拆到每一个节点都足够简单、足够容易调试。这篇文章不是官方文档的翻译是我自己把LangGraph多Agent方案从0到1跑通、并且放进真实业务里调优之后的完整笔记。内容包括为什么必须拆成多个Agent、LangGraph的核心抽象怎么理解、三种主流多Agent拓扑怎么选、一个完整可运行案例的逐步实现以及跑通Demo之后才遇到的坑和对应的工程化改进。代码基于LangGraph目前的主流API写法如果你之前只看过零散的版本差异很大的教程跟着这篇的逻辑走应该能少走很多弯路。2. 理解LangGraph的四个核心概念比背API更重要2.1 State整个图的“共享黑板”在LangGraph里State是这个图的灵魂相当于多Agent之间共享的那块“黑板”。所有节点都可以读取State、修改State节点与节点之间不直接传参而是通过State传递信息。举个例子。我的技术咨询助手涉及三个子Agent文档查询Agent、监控分析Agent、工单汇总Agent。它们之间如果每个Agent都用自己的私有数据结构那我得写一堆胶水代码做转换。LangGraph要求你提前定义整体的State结构各个子Agent只需要增删改自己负责的那个字段段就行。from typing import TypedDict, Annotated from langgraph.graph.message import add_messages class SupportState(TypedDict): user_request: str messages: Annotated[list, add_messages] current_agent: str doc_search_result: str monitor_analysis: str ticket_summary: str final_report: str这里需要关注Annotated[list, add_messages]这种写法。add_messages是一个归约器决定了图在执行过程中如何更新这个字段。默认情况下对新字段赋值会直接覆盖旧值但messages这种对话历史需要追加用add_messages就可以把新产生的消息自动追加到列表末尾不需要手动list.append。注意State字段的变更方式不是小事。我最初把所有字段都设成普通覆盖模式结果多个Agent之间共享的中间结果被下一个Agent覆盖得干干净净排查了半天。2.2 Node最小的工作单元Node就是图中真正执行动作的节点。每个Node接收State对象执行自己的业务逻辑然后返回一个字典这个字典里的键值对会更新到State上。from langgraph.graph import StateGraph, START, END def doc_search_node(state: SupportState) - dict: # 从state里读取用户请求 query state[user_request] # 调用外部文档检索服务 result search_internal_docs(query) # 返回dictLangGraph会把结果写入state的对应字段 return {doc_search_result: result, current_agent: doc_search}这看起来很简单但有两点值得注意。Node返回的dict覆盖或者追加到State上是自动完成的所以你不需要显式去改传入的state对象。不要在函数内部直接修改传入的state虽然很多情况下能用但一旦启用了并发分支或者流式输出直接改入参会踩到严重的状态一致性问题。正确做法就是返回一个新的dict让框架统一合并。Node内部可以调用LLM、调用Tool、调用任意Python函数。它本身不关心其他Agent在做什么只关心“我入口拿到什么数据、输出什么数据”这种纯粹的接口设计让测试变得非常舒服。2.3 Edge与Conditional Edge流程的“路径选择”普通Edge就是一条从节点A到节点B的固定连线标准流程不需要分支时直接用add_edge。但多Agent系统里大多数跳转逻辑是动态的这时候需要用条件边。def route_after_selection(state: SupportState) - str: # 根据意图识别的结果决定下一跳交给哪个Agent intent identify_intent(state[user_request]) if intent 监控: return monitor_agent elif intent 工单: return ticket_agent else: return doc_agent条件边返回的是一个字符串这个字符串是目标节点的名字。LangGraph会根据返回值自动跳到对应节点。用生活类比来理解**普通Edge是“流水线传送带”一个工位做完传给下一个固定工位条件Edge是“车间门口的分配员”根据工件类型决定送去哪个工位。**多Agent系统之所以灵活正是因为有大量这类“分配员”角色的节点。2.4 图构建与编译写流程就像画图把Node和Edge组装成图并编译成可执行实例。builder StateGraph(SupportState) builder.add_node(doc_search, doc_search_node) builder.add_node(monitor, monitor_node) builder.add_node(ticket, ticket_node) builder.add_node(supervisor, supervisor_node) builder.add_edge(START, supervisor) builder.add_conditional_edge(supervisor, route_after_selection) builder.add_edge(doc_search, supervisor) builder.add_edge(monitor, supervisor) builder.add_edge(ticket, supervisor) builder.add_edge(supervisor, END) graph builder.compile()compile之后拿到的是一个可执行对象可以直接调graph.invoke({user_request: 帮我看看生产环境最近5分钟的延迟异常})。LangGraph会从START开始按图结构执行节点、做条件判断最终走到END并返回最终State。我在这个阶段踩过的一个坑是条件边返回的节点名和add_node注册的节点名必须完全一致拼写错一个字符运行时报错极其隐晦——它不会直接告诉你“找不到节点”而是挂在图编译或执行时报出了一堆关于状态转移的异常。建议把所有节点名抽成常量别写裸字符串。3. 三种主流的Multi-Agent拓扑按场景而不是按噱头选多Agent架构不是只有一种LangGraph灵活到几乎可以把任意图结构映射成代码。做选型时我先梳理了三种最常见的拓扑然后对每种都做了对比实验。3.1 Network拓扑所有Agent平级互相自由通话所有Agent都是平级节点彼此之间可以有边相连。A做完可以直接交给BB做完也可以再回到A。这种结构的表达能力最强但控制力和可预测性最差。实际项目中我不太建议在一开始就上手Network拓扑原因很简单路径组合数会爆炸。假设有4个Agent全连接图里任意两个都能互相跳转路径数远远超过人能手工穷举的范围。一旦某个Agent产生了错误中间结果错误会在网状的边里被放大多次排查问题是灾难性的。我全网搜了一圈看到的大多数LangGraph入门demo其实只是两三个Agent之间的简单链条那已经是图的最简形态了。真正的Network适合的是研究型场景比如多角色辩论、多方案对抗生产系统里我很难说服自己把关键路径交给一张不可控的网。3.2 Pipeline拓扑链式接力像流水线Pipeline拓扑很好理解Agent按照固定顺序逐个执行前一个的输出是后一个的输入中间没有回头路。Pipeline适合的是任务切割明确、单向依赖、不需要反复修正的场景。比如先做意图识别Agent → 再做数据提取Agent → 再做回答生成Agent。优点是真简单流程完全可控缺点是灵活性差。如果数据提取阶段发现用户真实意图和意图识别阶段判断的不一样Pipeline里没有任何机制能跳回去重跑除非在前一个Node里就把兜底逻辑做完。3.3 Supervisor拓扑主管Agent调度分工但集中决策这是我在生产项目里最终选择的方案。一个supervisor节点作为“主管”负责解析用户意图、决定把任务分配给哪个专家Agent各专家Agent只负责自己擅长的子任务做完把结果汇报回主管由主管汇总之后决定是直接输出还是继续下达下一步指令。这种架构的好处很明显控制权集中在主管手里流程仍然可预测每个专家Agent的逻辑高度内聚独立维护、独立调试扩展新技能时只需要新增一个Agent再在主管的决策逻辑里多加一个分支对既有节点完全无侵入。代价就是主管容易成为瓶颈而且prompt里需要在“调度决策”上反复调优这也是后面调优章节重点讲的部分。三种拓扑放在一起比较拓扑类型控制力灵活性错误传播难度适合场景Network低高高错误被多路径放大研究实验、角色辩论Pipeline高低低链路固定好定位固定流程、流水线型任务Supervisor中中高中错误集中在主管节点客服、运维助手、多工具汇聚选型建议就一句话**能Pipeline解决的别硬上Supervisor能Supervisor解决的别碰Network。**架构复杂度是成本不是荣誉。4. 案例拆解一个带Supervisor的技术咨询支持系统下面进入完整案例。我选的技术咨询支持系统内部的架构是一个Supervisor主管 三个专家Agent文档检索、监控分析、工单汇总外加一个final report生成步骤。整个图里还包含故意设置的循环边让“主管能追问专家”的能力成为可能。4.1 需求与图结构的设计业务需求是用户用自然语言提问系统自动判断问题类型分配给对应专家Agent执行最后汇总成一份结构化报告。我的图结构设计如下START │ ▼ supervisor主管意图识别 任务分配 │ ├───────────────┼───────────────┐ ▼ ▼ ▼ doc_search monitor ticket 专家Agent 专家Agent 专家Agent │ │ │ └───────────────┼───────────────┘ ▼ report_generator │ ▼ END注意专家Agent执行完之后路径并不是直接到END而是回到supervisor。这一步非常关键它是让“主管专家”形成闭环的原因——主管可以在拿到专家结果后决定是继续追问还是觉得可以汇总输出。这就是Multi-Agent相对单Agent的“流程图式控制流”价值所在。该图结构对应代码里的实现专家节点执行完后add_edge都指向 supervisor而不是直连 report_generator。许多初学者习惯“一条线画到底”结果主管失去重新分派能力变成只做一次转发那就退化成了Pipeline。4.2 定义专家Agent每个专家只做一个动作每个专家Agent我都会单独写成模块文件避免所有代码堆在一个图定义文件里。以监控分析专家为例def monitor_agent_node(state: SupportState) - dict: # 调用一个prompt模板约束LLM只做监控数据解析 prompt ( 你是监控诊断专家。请基于以下用户问题提取查询条件\n f{state[user_request]}\n 输出JSON格式例如 {\metric\: \latency\, \time_range\: \5m\} ) llm get_llm() parsed extract_json(llm.invoke(prompt)) # 调用监控系统API raw_data query_monitor_metric(parsed[metric], parsed[time_range]) # 第二段LLM调用把原始数据进行初步解读 analysis llm.invoke( f这是监控数据{raw_data}。请总结异常点和可能原因。 ) return {monitor_analysis: analysis}这里面的模式是两个LLM调用第一段做结构化抽取第二段做业务解读。好处是“抽取”阶段天然和业务解读解耦哪怕数据源换了解析逻辑改动范围也小。文档检索专家的结构类似def doc_search_node(state: SupportState) - dict: query state[user_request] candidates search_internal_docs(query) context format_docs_for_prompt(candidates) answer get_llm().invoke( f根据以下文档片段回答问题如果资料不足请明确说明\n{context}\n问题{query} ) return {doc_search_result: answer}这里一个非常容易被忽视的点是专家Agent的System Prompt不要长篇大论地重复“你是整个系统XX的一部分记住你的职责……”直接聚焦在任务本身才有效。我把“如何调度”的职责完全交给supervisor专家Agent只让它专注“如何做好这件事”效果立刻提升。4.3 Supervisor节点的职责分配逻辑Supervisor的代码是全图逻辑最复杂、也是最值得花时间调优的节点。它要做的事是读取用户请求 综合各位专家返回的中间结果决定下一步走向。def supervisor_node(state: SupportState) - dict: # 第一段意图识别决定谁来处理 query state[user_request] intent_prompt ( 根据用户请求判断应该由哪个专家处理。可选doc / monitor / ticket。\n 规则\n - 涉及文档、API用法、开发问题 - doc\n - 涉及监控指标、延迟、错误率、性能 - monitor\n - 涉及历史工单、线上问题记录 - ticket\n - 无法确定时返回 doc\n f用户请求{query}\n 只输出一个词doc / monitor / ticket ) next_route get_llm().invoke(intent_prompt).strip().lower() state[current_agent] next_route return {current_agent: next_route}这里的实现要点是supervisor的LLM调用只输出一个词不生成任何解释。这个设计理念叫“structured output minimalism”它极大压低了LLM生成链路里不必要的自由度也降低了下一步条件路由的解析错误率。最开始我的supervisor是让模型自由输出文本然后用正则去匹配意图。结果模型时不时就来一句“根据用户问题这似乎涉及……我认为应该由monitor处理”虽然正则能勉强匹配但总是出现边界case。改成输出一个词之后准确率和稳定性都立刻提升了。4.4 条件路由与循环边的实现细节路由函数和之前一样def route_from_supervisor(state: SupportState) - str: return state[current_agent]注意route_from_supervisor返回的值来自supervisor写入state的current_agent字段。而state里这个字段是普通覆盖模式——只有最后一次写入有效所以我在每个专家节点返回时都会把state[current_agent]改成自己的名字确保下一轮循环时supervisor的后续判断能看到“当前已经由谁处理过”。这一行“状态更新”是最容易被忽略的也最容易引发死循环。如果不更新current_agent图就会无限循环跳转到同一个专家。图构建代码其实在前面已经出现过但为了可运行性我补全最终版builder StateGraph(SupportState) builder.add_node(supervisor, supervisor_node) builder.add_node(doc_search, doc_search_node) builder.add_node(monitor, monitor_agent_node) builder.add_node(ticket, ticket_agent_node) builder.add_node(report_generator, report_generator_node) builder.add_edge(START, supervisor) builder.add_conditional_edge(supervisor, route_from_supervisor) builder.add_edge(doc_search, supervisor) builder.add_edge(monitor, supervisor) builder.add_edge(ticket, supervisor) # 从supervisor到report_generator我也用条件边 def route_to_report(state: SupportState) - str: # 如果已经完成至少一次专家处理且有汇总报告标记则去报告节点 if state.get(summarize_requested): return report_generator return supervisor builder.add_conditional_edge(supervisor, route_to_report) builder.add_edge(report_generator, END)这套设计支持了这样的执行流用户一句话 → 主管分配给doc专家 → doc做完 → 回到主管 → 主管判断还需要监控佐证 → 再发给monitor → monitor做完 → 回到主管 → 主管标记可以汇总 → 到report_generator生成最终报告 → END。这是我在单Agent里没法干净实现的“多轮动态规划能力”。4.5 报告生成与最终输出报告生成节点负责把多位专家返回的内容组装成用户能直接用的结构化答案def report_generator_node(state: SupportState) - dict: sections [] if state.get(doc_search_result): sections.append(f### 文档检索结果\n{state[doc_search_result]}) if state.get(monitor_analysis): sections.append(f### 监控分析\n{state[monitor_analysis]}) if state.get(ticket_summary): sections.append(f### 历史工单参考\n{state[ticket_summary]}) combined \n\n.join(sections) final_answer get_llm().invoke( f请把以下多个维度的结果整合成一份给研发人员看的最终报告 f要求结论先行、包含数据出处\n{combined} ) return {final_report: final_answer}建议这个节点的prompt里强调“结论先行”否则LLM会把所有内容平铺先讲背景再给结论做运维和技术支持的同事会看得非常着急。到这里案例里最核心的部分已经能跑通了。用一句话总结这个完整方案**主管节点是一个“路由大脑”专家节点是“技能执行体”循环边让主管能够多轮追问报告节点把多源结果收敛成最终产出。**这就是LangGraph多Agent比单Agent加工具库模式强大得最具体的体现。5. 案例跑通之后我实际踩到的坑5.1 状态字段的污染与覆盖最隐蔽的错误源我的技术咨询支持系统上线后的第一个故障表现为用户明明问的是“最近5分钟延迟高”系统却返回“当前没有工单记录建议新建工单。”我排查了半天才发现问题是State里的ticket_summary字段残留了上次会话的历史结果。LangGraph的默认行为是每一次invoke都是独立的图执行理论上state每次从零开始。**但我为了让系统带记忆功能在invoke之前从一个持久化存储里加载了历史State然后再和新的user_request合并。**这个设计本身没问题问题出在我加载历史State时没有区分“跨会话持久化的记忆字段”和“每次执行必须清空的临时字段”。修复方案是区分两类字段跨会话字段只保留对话历史执行状态字段全部重建。我在state定义里把需要持久化的字段单独抽出来组成memory_state每次执行前从数据库只恢复memory_state执行状态字段用空值初始化。resumed_state load_memory_from_db(session_id) execution_state { user_request: new_query, doc_search_result: None, monitor_analysis: None, ticket_summary: None, current_agent: , summarize_requested: False, # 合并历史消息 messages: resumed_state.get(messages, []), } result graph.invoke(execution_state)这类问题的本质是**State是共享的所有人都能写那么“谁负责清空、谁负责保留”必须在架构设计之初就定下来。**我建议你在定义State数据结构时就给字段明确注释是“每次执行重建”还是“跨会话持久化”代码Review时真的能救命。5.2 死循环从“一次请求调用几十次”说起在我加入循环边之后很长一段时间里每次用户请求LLM调用次数都不稳定正常是5次左右有时候突然跳到20多次。图确实在转圈但逻辑上看起来每一步都走了不同节点。后来我打印了完整的执行轨迹发现问题出在supervisor的路由判断上它不知道这个专家已经处理过这个问题了。对于“帮我查一下监控同时看下工单”这种混合请求doc和monitor都合理主管在两三个候选节点之间反复横跳始终不满足“可以汇总”的条件。解决办法有两个方向。第一在route_to_report里增加循环计数和“是否已处理过”检查def route_to_report(state: SupportState) - str: executed_agents state.get(executed_agents, []) if state.get(summarize_requested) or len(executed_agents) 3: return report_generator return supervisor同时在没有更高优先级可执行时直接无条件追加入口def route_from_supervisor(state: SupportState) - str: next_agent state.get(current_agent) if next_agent in state.get(executed_agents, []): return report_generator # 防止来回横跳 return next_agent第二也是最根本的**prompt里明确告知supervisor“你必须选择合适的专家如果最优专家已经处理过但结果不满足要求可以尝试次优专家如果所有可用专家都已处理过直接跳到汇总。**这种把“终止条件”写进prompt的做法是解决多Agent死循环的最通用手段。5.3 Supervisor的“中央瓶颈”与并发优化Supervisor拓扑把控制和决策集中到一个节点带来的代价是意图识别这一步如果很慢整个系统都在等它。我的第一个版本supervisor每次都调LLM做完整意图识别即使前面专家已经返回了结果、只需要做“是否继续”的二分类判断也坚持走那套完整prompt。这就让简单判断也付出了高延迟。优化手段是“分层次判断”首轮用完整prompt做意图识别后续轮次只需要判断“已有结果是否足够”换成更小、更快的prompt甚至可以换成规则判断——比如所有专家都已执行、或者某个字段已经非空就直接去report。def supervisor_fast_path(state: SupportState) - str: # 如果已有至少两个专家的结果就直接汇总 filled sum(1 for x in [state.get(doc_search_result), state.get(monitor_analysis), state.get(ticket_summary)] if x) if filled 2: return report_generator return state[current_agent]这一行简单的判断把我的单次请求平均延迟降了大约一小半因为大多数请求只需要一次专家处理就能满足“一维度回答”的需求第二次判断走的就是规则分支不再额外消耗LLM调用。关于并发LangGraph本身支持节点级并行只要State里的字段不冲突多个专家可以同时执行。Supervisor模式里这有点不太好直接用因为主管需要等所有专家结果回来统一判断。如果遇到了“先并行做多路专家分析再统一汇总”的需求可以考虑给主管下面再挂一个“并行分支层”。不过我个人建议先别急着追逐并发多Agent系统90%以上的项目瓶颈都出在状态设计与循环逻辑而不是并发不够。5.4 Token消耗的隐形增长多Agent不是免费午餐多Agent至少意味着多轮LLM调用Token消耗和单Agent完全不是一个量级。我做过粗略统计同一个需求单Agent一次完成可能消耗约10001500 tokens用Supervisor多Agent跑完总消耗经常冲到5000 tokens以上主要花在了“意图识别”、“专家解读”、“汇总整合”这些重复描述上下文的环节。几个降低Token消耗的实用手段尽量精简每一轮prompt里的历史消息只保留必要的上下文而不是把整个State序列化之后全部塞给LLM。LangGraph的add_messages会自动追加历史如果你不去手动裁剪对话轮次一多就必然爆Token。专家Agent只接收和它相关的字段而不是全量State。我的每个专家节点在组装prompt时只从state取自己需要的字段其他字段不拼接进上下文。report_generator使用高压缩prompt它已经拿到了专家的结构化输出只是做整合排版不需要把完整的用户原始问答和中间链路都重新塞给它。Token消耗是一个需要持续监控的指标。我给每个节点都加了计数器——每次LLM调用的输入token、输出token都会落到日志里每过几天就去分析一次看哪些节点在不合理地重复读取大段Context。6. 从Demo到生产多Agent系统还要补的四件事6.1 记忆管理不是简单把历史拼接进Prompt生产环境中的对话几乎都不是一次性的。LangGraph为持久化提供了checkpoint机制可以把每次执行完的State保存下来下次运行从某个checkpoint恢复。我用的方案是用数据库存储关键State字段的快照而不是存整个对象。原因有两个状态里可能包含大段的中间结果比如完整的监控原始数据全量存储会撑爆数据库而且恢复的时候我也不需要把一份几万字的原始数据塞进下一次Graph执行的初始State里只需要关键结论和历史消息。所以我的memory_payload是轻量级的用户最近3轮的问题摘要、最后生成的报告、还包括偏好信息比如喜欢表格输出还是文字输出。这些数据在每次Graph执行前合并进execution_state的messages字段就足够LLM形成记忆连续性了。有一点提醒**LangGraph的checkpoint和它的API绑定得比较紧如果你换了存储方案或者改了State结构历史恢复逻辑大概率要跟着改。**所以建议在早期就定义State快照的序列化协议别等在数据库里攒了几个GToken的历史了才想起来改。6.2 人与机器的混合编排该放手的节点用于切换这类架构比较适合“机器执行人工审批”的场景这也是我在生产环境中实际验证过的组合场景。LangGraph有interrupt机制可以让图在某个节点暂停等待人工输入后再往下跑。比如生成对外回复之前如果判断“这属于重大故障沟通”就暂停让值班人确认。我做过一个版本当supervisor判断“用户问题涉及安全敏感操作”时走到一个human_review_node这个节点通过interrupt暂停图执行返回一个“等待人工确认”的状态给外部人工在界面上点击确认后继续执行后续节点。这其实让Multi-Agent架构的适用性大大增加——不再是全自动流程而是人机协同工作流。实现上要提前想清楚哪些节点允许自动执行哪些节点必须人工介入人工介入的输入格式是什么超时怎么处理。6.3 追踪与可观测性多Agent排错的第一刚需多Agent系统最痛苦的是“黑盒化”——你看看不到的中间过程出了问题连是谁的错都不知道。LangGraph提供了轨迹信息包括每一步执行了哪个节点、节点输入输出state的快照你可以直接把这些信息序列化成日志。我在生产环境里的做法是每个Graph执行分配一个唯一的trace_id每次节点执行时把节点的状态快照和LLM调用的prompt/response写入日志在用户反馈“回答不对”的时候直接根据trace_id把完整的执行链路捞出来逐节点检查是哪个专家agent的哪一步产生了错误中间结果。这种可观测性救了我很多次。最典型的一次案例是系统回答“服务不可用”但实际监控数据显示一切正常——后来靠trace才定位到是监控专家Agent的prompt把“无数据返回”误解成了“服务不可用”错误结论被层层传递放大。没有trace链路这种问题几乎无从查起。6.4 效果评估体系给LLM的“质检员”多Agent系统的评估比单Agent更复杂——不仅要测最终输出质量还要测每个节点每一步的执行质量。我建议至少建三层评估维度级评估supervisor判断的意图是否准确这一步错了后面全完蛋。工具调用评估专家Agent提取的参数是否正确参数错误通常意味着调了错误的API或者拿到了无意义的数据。最终输出评估报告是否覆盖了用户核心问题、有没有捏造数据、格式是否符合约定。这层可以基于LangSmith或者自定义评估脚本做。我不追求用LLM-as-a-Judge替代人工评估而是把“抓明显错误”和“快速回归”交给自动化把“深度内容判断”留给人工。毕竟多Agent系统本身就在不断演化每个prompt的微调都可能改变路由行为没有回归测试的话上线风险会非常高。7. 从这套案例里沉淀下来的选型与设计思路如果你现在正纠结要不要把项目从单Agent迁到Multi-Agent或者正头疼多Agent方案的参数怎么调我会建议你先想清楚三件事第一**你的流程里是否存在“多个专业领域之间的协作与流转”**如果只是单领域的“问答→检索→回答”一个封装良好的Agent就够了不需要付出多Agent的复杂度。我用这套架构做技术咨询是因为它天然跨了文档、监控、工单三个领域而且它们之间还需要互相引用和交叉验证。这种情况下Multi-Agent的收益才明显。第二**你的“主管”能做好决策吗**Supervisor是整个系统的决策核心它的prompt调优会消耗你大量时间。判断意图的准则必须非常清晰不能出现“A和B都行”的模糊地带。不然你会不断遇到主管来回横跳的灵异事件。我的实测经验是先把意图分类收敛到你可以枚举出来的5种以内再上多Agent类别一多supervisor模型就开始闹脾气。第三**你愿意为可观测性付出多少精力**多Agent系统一旦上线状态流转链路太长排查成本远高于单Agent。如果你没有日志追踪体系遇到线上问题会非常痛苦。这个投入不敢省。在这套LangGraph多Agent案例里我的核心观点已经写得足够直白了**它不是银弹但它把“多个专业Agent协同处理一个复杂任务”这个工程问题从“我的prompt能不能别崩”升级到了“我的图结构能不能hold住”。**你拿到这篇文章最应该做的事情是把我这套技术咨询系统的模式抽象成你自己的业务场景——先把意图分类定义清楚找3个能明确切分的专家角色画出图和流转条件然后打开代码直接跑。最后分享一个跟我合作过的开发同学问我的问题“你这套图和普通的if-else状态机到底有什么区别”我的回答是**如果流程是完全固定、可以穷举的用状态机就够了一旦流程节点本身需要大模型来决策走哪条边、而且决策结果还依赖前面多次执行的结果时LangGraph是比你手写状态机安全得多的载体。**这句话也是我这几个月最想让你记住的体会。