
1. 从单兵作战到团队协作为什么我们需要多Agent系统如果你已经用LangChain或者类似的框架搭建过一些AI应用大概率体验过单个AI智能体Agent的威力。它能根据你的指令调用工具、查询知识库完成一个相对独立的任务比如分析一份文档、生成一段代码。但当你面对一个复杂问题时比如“分析我们上个季度的销售数据找出表现最好的三个产品并为每个产品写一份市场推广文案最后汇总成一份报告”你会发现单个Agent开始力不从心。它可能擅长数据分析但文案写作是另一套逻辑或者它写文案不错但缺乏全局统筹和报告整合的能力。这时候一个自然的想法就出现了能不能让多个各有所长的AI智能体一起工作像一支训练有素的团队那样分工协作这就是多Agent系统Multi-Agent System要解决的核心问题。它不再是让一个“全能超人”去处理所有事而是组建一个“特种部队”。在这个部队里有擅长数据挖掘的“分析师”有文笔流畅的“文案专家”还有逻辑严谨的“架构师”和负责最终汇总的“项目经理”。每个Agent专注于自己的领域通过一套明确的协作机制比如聊天、共享状态、传递任务来共同完成一个宏大目标。这种架构带来的好处是显而易见的专业化每个Agent可以针对特定任务进行深度优化、可扩展性新加一个功能就引入一个新专家、鲁棒性一个Agent出错不影响整体流程以及处理复杂工作流的能力。而LangGraph正是LangChain生态中为构建这种复杂、有状态的、多参与者工作流而生的利器。它不像LangChain主要关注链Chain的线性组合而是引入了“图”Graph的概念。你可以把整个业务流程画成一张有向图节点Node就是一个个Agent或者处理函数边Edge则定义了控制流决定下一步该谁“接棒”。这种模型天然契合多Agent协作的场景分析师干完活把结果“扔”给文案专家文案专家写完再“传”给架构师审核。LangGraph负责维护整个团队的“共享白板”State并指挥任务流转。所以当我们谈论“让Agent学会分工”本质上是在用LangGraph设计和编排一个智能体团队的协作剧本。这不仅仅是技术实现更是一种系统设计思维的转变。2. 理解LangGraph的核心三要素State、Node与Edge在动手搭建团队之前我们必须先理解LangGraph管理这个团队的“基本法”。它围绕着三个核心概念构建状态State、节点Node和边Edge。这套机制决定了团队成员如何沟通、任务如何传递以及团队记忆如何保存。2.1 State团队的共享工作区与记忆体State是LangGraph中最重要的概念你可以把它想象成团队项目室里的那块共享白板或者一个共享的数据库。所有Agent的输入、输出、中间结果、对话历史、乃至整个团队的当前目标都记录在这个State里。它通常是一个Python字典Dict或者Pydantic模型定义了工作流中需要流转和持久化的所有数据。为什么需要State因为多Agent协作不是一次性的函数调用而是一个有状态的会话过程。例如分析师Agent从State里读取“原始销售数据”分析完后将“TOP3产品列表”写回State接着文案Agent从State里读取这个列表为每个产品生成文案后再把“文案草稿”写回State。State确保了信息在不同专家间无损传递是团队协作的基石。在定义State时我的经验是宁简勿繁按需扩展。初期只定义工作流必需的核心字段避免过度设计。一个典型的多Agent文案生成State可能长这样from typing import Annotated, List, Dict, Any from typing_extensions import TypedDict import operator class AgentState(TypedDict): # 输入用户最原始的问题 input_query: str # 中间结果分析后的结构化数据 analyzed_data: Dict[str, Any] # 中间结果生成的文案片段列表 draft_contents: List[str] # 最终输出整合后的报告 final_report: str # 系统指令指导整个流程的元指令 system_directive: str # 对话历史记录Agent间的交流用于上下文理解 message_history: Annotated[List[Any], operator.add] # 关键这是一个可追加的列表注意message_history字段使用了Annotated和operator.add这是LangGraph的一个高级特性声明这个字段是一个列表并且当多个节点对它进行写操作时是**追加append**而不是覆盖。这完美模拟了聊天历史的累积过程至关重要。2.2 Node团队中的专家成员Node节点是工作流中执行具体任务的基本单元。在多Agent系统中一个Node通常对应一个具有特定技能的Agent。每个Node都是一个函数它接收当前的State作为输入执行一些操作比如调用LLM、运行计算、查询数据库然后返回一个更新后的State字典或包含更新的部分字典。关键点在于Node是纯函数。给定相同的State输入它应该产生相同的State更新。这保证了工作流的确定性和可调试性。一个数据分析Node的函数签名看起来是这样的def data_analysis_agent(state: AgentState) - Dict[str, Any]: 数据分析专家节点。 # 1. 从State中获取输入 query state[“input_query”] raw_data state.get(“raw_data”, fetch_data(query)) # 假设有获取数据的方法 # 2. 执行核心任务例如调用一个分析链 analysis_chain create_analysis_chain() # 这是一个LangChain链 analyzed_result analysis_chain.invoke({“data”: raw_data, “query”: query}) # 3. 返回State的更新部分 return {“analyzed_data”: analyzed_result, “message_history”: [HumanMessage(contentf“数据分析完成结果已就绪。”)]}在构建Node时一个常见的坑是忘记返回完整的更新。如果你只返回{“analyzed_data”: result}那么message_history就不会被更新对话历史就断了。确保你的更新包含了所有需要修改的State字段。2.3 Edge任务交接的规则与路由Edge边定义了工作流的控制逻辑在当前Node执行完毕后接下来应该由哪个Node来接手这相当于团队工作的流程规范。LangGraph提供了几种类型的边最常用的是条件边Conditional Edge和普通边Normal Edge。普通边直接指定下一个节点。比如“数据分析节点”完成后无条件交给“文案生成节点”。条件边根据当前State的内容动态决定下一个节点。这是实现智能路由和决策的关键。条件边的强大之处在于实现了动态路由。例如一个“路由Agent”或称“主管Agent”可以根据用户问题的“意图”决定派发给哪个专家处理。from langgraph.graph import END def route_by_intent(state: AgentState): 根据分析出的意图决定下一个节点。 # 假设state[‘analyzed_data’]里包含了意图分类结果 intent state[“analyzed_data”].get(“intent”) if intent “data_query”: return “data_analysis_agent” # 去找数据分析师 elif intent “content_creation”: return “copywriting_agent” # 去找文案专家 elif intent “summarization”: return “summarization_agent” # 去找总结专家 else: return END # 无法处理结束流程在这个例子中route_by_intent函数就是一个路由函数它检查State返回下一个要执行的Node的名称。LangGraph会根据这个返回值来引导工作流的走向。这种模式使得构建能处理多种类型查询的、灵活的智能助理成为可能。3. 实战构建一个多Agent协作的营销文案生成团队理论说得再多不如动手搭一个。我们来构建一个相对完整的场景一个能为产品生成营销文案的多Agent系统。这个团队由以下成员构成产品分析Agent解析用户输入提取产品核心卖点和目标受众。风格规划Agent根据产品特点和受众决定文案的风格如专业、活泼、复古。文案撰写Agent根据卖点和风格生成具体的文案段落。评审优化Agent对生成的文案进行润色和优化。3.1 定义团队工作流与状态首先我们定义团队需要共享哪些信息from typing import TypedDict, List, Optional from langchain_core.messages import BaseMessage, HumanMessage, AIMessage import operator class MarketingCopyState(TypedDict): 营销文案生成团队的状态定义。 # 用户原始输入 user_input: str # 分析出的产品卖点 product_highlights: List[str] # 分析出的目标受众 target_audience: str # 确定的文案风格 copy_style: str # 生成的初始文案 draft_copy: str # 优化后的最终文案 final_copy: str # 团队对话历史 messages: Annotated[List[BaseMessage], operator.add]3.2 实现四位专家成员Node接下来我们实现四个Agent节点。每个节点我都会用简单的逻辑模拟在实际项目中这里会集成LLM调用。from langgraph.graph import StateGraph, END # 1. 产品分析专家 def product_analyst(state: MarketingCopyState): print(“[产品分析Agent] 开始工作...”) # 模拟分析过程从用户输入提取关键词 input_text state[“user_input”] # 假设我们有一些简单的规则或调用一个LLM链 highlights [“续航时间长”, “设计轻薄”, “性价比高”] # 模拟输出 audience “年轻职场人士与大学生” # 更新状态并添加到对话历史 new_message AIMessage(contentf“我已分析产品核心卖点{‘’.join(highlights)}目标受众{audience}。”) return { “product_highlights”: highlights, “target_audience”: audience, “messages”: [new_message] } # 2. 风格规划专家 def style_planner(state: MarketingCopyState): print(“[风格规划Agent] 开始工作...”) highlights state[“product_highlights”] audience state[“target_audience”] # 根据受众和卖点决定风格 if “年轻” in audience and “设计” in highlights: chosen_style “活泼、时尚、富有感染力” else: chosen_style “专业、稳重、突出参数” new_message AIMessage(contentf“文案风格已确定为{chosen_style}以契合{audience}。”) return {“copy_style”: chosen_style, “messages”: [new_message]} # 3. 文案撰写专家 def copywriter(state: MarketingCopyState): print(“[文案撰写Agent] 开始工作...”) highlights state[“product_highlights”] style state[“copy_style”] audience state[“target_audience”] # 模拟生成文案 draft f”面向{audience}的文案风格{style}\n” draft “””全新产品闪耀登场它拥有{highlights[0]}的卓越特性结合{highlights[1]}的便携体验为您带来前所未有的{highlights[2]}选择。立即拥有开启高效生活“”” new_message AIMessage(contentf“文案初稿已生成\n{draft}”) return {“draft_copy”: draft, “messages”: [new_message]} # 4. 评审优化专家 def reviewer(state: MarketingCopyState): print(“[评审优化Agent] 开始工作...”) draft state[“draft_copy”] # 模拟优化过程这里可以接入LLM进行润色 optimized draft.replace(“闪耀登场” “匠心之作”).replace(“立即拥有” “现在行动”) new_message AIMessage(contentf“文案已优化完成最终版\n{optimized}”) return {“final_copy”: optimized, “messages”: [new_message]}3.3 编排团队协作流程构建Graph现在我们用LangGraph把四位专家组织起来形成一个顺序工作流。# 初始化一个状态图指定我们定义的状态类型 workflow StateGraph(MarketingCopyState) # 将四个函数添加为图中的节点 workflow.add_node(“analyze”, product_analyst) workflow.add_node(“plan_style”, style_planner) workflow.add_node(“write_copy”, copywriter) workflow.add_node(“review”, reviewer) # 设置工作流的起点 workflow.set_entry_point(“analyze”) # 定义节点之间的边交接规则 workflow.add_edge(“analyze”, “plan_style”) # 分析完就去规划风格 workflow.add_edge(“plan_style”, “write_copy”) # 规划完风格就去写文案 workflow.add_edge(“write_copy”, “review”) # 写完文案就去评审 workflow.add_edge(“review”, END) # 评审优化后工作流结束 # 编译图得到一个可执行的应用 app workflow.compile()3.4 运行团队并查看成果让我们给这个团队派发第一个任务。# 初始化输入状态 initial_state {“user_input”: “为我们的新款轻薄笔记本写一篇推广文案”, “messages”: []} # 运行工作流 final_state app.invoke(initial_state) print(“\n 工作流执行完成 \n”) print(“最终生成的文案”) print(final_state[“final_copy”]) print(“\n 团队完整对话记录 ) for msg in final_state[“messages”]: print(f”{msg.type}: {msg.content}”)执行上述代码你会在控制台看到一个清晰的、顺序执行的团队协作过程并得到最终的优化文案。每个Agent的输出都记录在messages历史中整个State的演变一目了然。这就是一个最基本的多Agent顺序工作流。4. 进阶模式引入主管Agent与动态路由上面的例子是一个简单的流水线每个环节固定。但在真实场景中问题往往更复杂需要动态决策。比如用户可能问“这个手机电池多大”这直接交给“问答Agent”就行不需要走完整的文案生成流程。这时我们就需要引入一个主管AgentOrchestrator Agent来负责意图识别和任务分发。4.1 设计一个具备意图识别能力的主管主管Agent通常是工作流的第一个节点。它的核心任务是理解用户输入Intent Recognition然后更新State并决定下一个执行节点。我们修改一下State和流程class DynamicRouterState(TypedDict): user_input: str detected_intent: str # 新增识别的意图 query_answer: str # 用于存储简单问答的结果 marketing_copy: str # 用于存储营销文案 messages: Annotated[List[BaseMessage], operator.add] # 主管Agent意图识别与路由 def orchestrator_agent(state: DynamicRouterState): input_text state[“user_input”].lower() # 简单的基于关键词的意图识别实际应用应使用更复杂的NLU模型 if “电池” in input_text or “续航” in input_text or “多大” in input_text: intent “qa” elif “推广” in input_text or “文案” in input_text or “广告” in input_text: intent “copywriting” else: intent “general” # 将意图存入State update {“detected_intent”: intent} update[“messages”] [AIMessage(contentf“已识别用户意图为{intent}”)] # 关键这里不直接返回State更新而是返回一个元组 # LangGraph允许返回 (state_updates, next_node_name) # 但更常见的模式是在边Edge的条件函数里做路由决策。 # 我们这里采用条件边模式所以主管只更新状态路由逻辑放在边的条件函数里。 return update # 问答专家 def qa_agent(state: DynamicRouterState): answer “该款笔记本电池容量为78Wh续航时间可达15小时。” return {“query_answer”: answer, “messages”: [AIMessage(contentanswer)]} # 精简版文案生成专家 def marketing_agent(state: DynamicRouterState): copy “这是一篇为您生成的精彩推广文案...” return {“marketing_copy”: copy, “messages”: [AIMessage(contentcopy)]}4.2 配置条件边实现动态流转现在我们构建一个图从orchestrator开始然后根据detected_intent的值动态选择下一步是去qa_agent还是marketing_agent。from langgraph.graph import StateGraph, END workflow StateGraph(DynamicRouterState) workflow.add_node(“orchestrator”, orchestrator_agent) workflow.add_node(“qa”, qa_agent) workflow.add_node(“marketing”, marketing_agent) workflow.set_entry_point(“orchestrator”) # 定义条件边函数 def route_after_orchestrator(state: DynamicRouterState): intent state[“detected_intent”] if intent “qa”: return “qa” elif intent “copywriting”: return “marketing” else: return “general_fallback” # 假设有一个兜底节点 # 添加从orchestrator出发的条件边 workflow.add_conditional_edges( “orchestrator” # 源节点 route_after_orchestrator # 决定下一个节点的函数 { “qa”: “qa” # 如果函数返回”qa”则前往qa节点 “marketing”: “marketing” “general_fallback”: END # 可以直接结束或指向其他节点 } ) # 为qa和marketing节点添加普通边指向结束 workflow.add_edge(“qa”, END) workflow.add_edge(“marketing”, END) app workflow.compile()现在当你输入“笔记本电池多大”工作流会走orchestrator - qa - END。当你输入“写个推广文案”则会走orchestrator - marketing - END。这就实现了一个能理解意图、动态分配任务的智能多Agent系统雏形。5. 避坑指南与效能优化让多Agent系统稳定运行构建好玩但让系统稳定、高效地跑起来才是挑战。以下是我在实战中积累的一些关键经验和常见坑点。5.1 状态管理的陷阱与最佳实践坑点1状态污染与冲突。当多个节点并发或异步修改State时如果设计不当可能会发生状态覆盖。虽然我们上面的例子是顺序执行但LangGraph支持更复杂的模式。最佳实践精心设计State的结构使用Annotated注解来明确字段的更新语义如operator.add用于列表追加。对于需要原子性更新的复杂状态考虑将关键数据放在一个子字典中或使用更高级的状态管理后端如Redis。坑点2State过于臃肿。把所有可能用到的数据都塞进State会导致序列化/反序列化开销大且难以维护。最佳实践遵循“最小化状态”原则。只存储工作流节点间必须传递的数据。对于大型静态数据如知识库应该通过节点的上下文如传入配置或全局对象来访问而不是放在State里流转。5.2 节点设计的单一职责与可测试性坑点3一个Node做太多事。把数据分析、文案生成、格式校验全写在一个Node里失去了多Agent模块化的意义也难于调试。最佳实践每个Node应只完成一件定义清晰、职责单一的任务。这符合Unix哲学也使得每个Agent可以独立开发、测试和替换。例如data_analysis_agent只负责分析copywriting_agent只负责生成文本。坑点4Node函数有副作用。比如在Node里直接修改全局变量、写入文件等这会让工作流的行为不可预测难以重现问题。最佳实践确保Node函数是“纯”的或副作用可控。所有输出都应通过返回的State更新来体现。如果必须要有副作用如发送邮件、调用外部API应将其封装在明确的工具Tool中并在Node里通过State传递必要的参数这样逻辑更清晰也便于Mock和测试。5.3 工作流编排的复杂性与调试坑点5图结构过于复杂形成循环或死锁。随意添加条件边和循环可能导致工作流在某个环节无限循环无法到达END。最佳实践在开发初期先用纸笔画出工作流的草图明确起点、终点和所有可能的分支。使用app.get_graph().draw_mermaid_png()需要安装pygraphviz将图可视化检查逻辑是否正确。对于循环一定要设置明确的终止条件例如循环次数上限、状态检查。坑点6错误处理缺失。某个Agent调用LLM或API失败导致整个工作流崩溃。最佳实践在Node内部实现健壮的错误处理try-catch。LangGraph也支持在Graph层面定义错误处理节点Error Handling。你可以将一个节点设置为另一个节点的“fallback”当主节点执行失败时控制流会自动跳转到fallback节点进行错误恢复或记录。# 伪代码示例为某个节点设置fallback workflow.add_node(“main_task”, main_agent) workflow.add_node(“handle_failure”, failure_handler_agent) workflow.add_edge(“main_task”, “next_step”) # 设置当main_task抛出特定异常时转向handle_failure workflow.add_exception_edge(“main_task”, “handle_failure”) workflow.add_edge(“handle_failure”, END) # 或导向其他恢复流程5.4 性能与成本考量坑点7串行执行导致总耗时过长。如果所有节点都必须一个接一个执行那么总时间就是所有节点耗时的总和。优化建议分析节点间的依赖关系。如果某些节点之间没有数据依赖即它们不需要彼此的输出可以考虑使用LangGraph的并行执行特性。通过add_edge的配置可以让多个节点同时从同一个父节点开始执行然后将它们的结果聚合。这能显著缩短整体运行时间。坑点8每次调用都重新初始化LLM等重型对象。这会造成不必要的开销。优化建议利用LangGraph的checkpointer机制或配合FastAPI等Web框架在应用生命周期内复用LLM客户端、数据库连接等资源。可以将这些资源作为上下文context传入图编译过程或在Node函数中通过闭包访问全局共享对象。构建多Agent系统是一个迭代过程。从最简单的顺序流开始逐步引入路由、循环、并行和错误处理。始终牢记State是团队沟通的桥梁Node是各司其职的专家Edge是高效协作的流程。在真实项目中你会花大量时间在State schema的设计、单个Agent的Prompt工程以及工作流逻辑的调试上。但一旦跑通这种将复杂问题分解、由专业化模块协同解决的范式其威力和灵活性是单一智能体难以比拟的。