17种AI代理架构实战:从ReAct到多代理协作的选型与落地 1. 为什么“17 种架构”不是噱头而是代理设计的真实分水岭很多人第一次接触 AI 代理脑子里浮现的画面是“一个会调用工具的聊天机器人”。这个理解在 2023 年还算够用但放到今天已经严重落后了。我见过太多团队把代理做成了“提示词套壳”——一个 while 循环里塞几个 if-else再挂上三五个工具就敢叫自己“智能体平台”。结果一上生产环境任务稍微复杂一点就崩上下文爆炸、工具调用死循环、多步推理中途丢失状态、并发一上来就互相踩踏。问题的根子不在模型能力而在架构。代理不是“模型 工具”这么简单它本质上是一个有状态、可调度、能容错、可观测的分布式决策系统。你用什么架构组织它的记忆、规划、执行和反思直接决定了它能处理多复杂的任务、能扛住多大的并发、能跑多久不崩。“17 种架构”这个数字听起来像营销话术但如果你真的把主流代理设计模式摊开来看从最简单的 ReAct 单循环到 Plan-and-Execute 的两段式再到多代理协作的 Supervisor、Hierarchical、Swarm以及带长期记忆和反思回路的 Reflexion、LATS确实能梳理出十几个有本质区别的范式。它们不是互相替代的关系而是针对不同任务复杂度、不同延迟要求、不同成本预算的工程取舍。这篇文章要做的就是把这 17 种架构从“论文里的名词”变成“你能直接抄的代码结构”。我会用 LangChain 和 LangGraph 作为主要实现载体因为这两个库目前对代理状态机和多代理编排的支持最成熟Jupyter Notebook 作为实验环境方便你边读边跑。但重点不在库本身而在于每种架构解决什么问题、在什么场景下该选它、以及实际落地时会踩哪些坑。如果你正在做以下任何一件事这篇内容都值得你花时间读完想把一个单轮问答机器人升级成能处理多步任务的代理已经在用 LangChain 但发现代理一复杂就失控需要让多个代理协作完成一个长流程任务想给代理加上长期记忆、反思和自我纠错能力在选型阶段不确定该用哪种架构怕选错了后期重构成本太高。我会尽量少讲抽象概念多讲“这个架构的代码骨架长什么样”“为什么这里要用状态图而不是链”“什么情况下多代理反而比单代理更简单”。这些都是我在实际项目里反复验证过的判断不是从文档里抄来的。2. 从 ReAct 到 Reflexion单代理架构的四种基本盘在进入多代理和复杂编排之前必须先把单代理的几种基本架构吃透。因为后面所有的多代理系统本质上都是把这些单代理模式组合起来。如果单代理都没搞明白多代理只会让你更混乱。2.1 ReAct最经典的“思考-行动”循环也是最容易失控的ReActReasoning Acting是绝大多数人接触的第一个代理架构。它的核心逻辑非常直观模型先输出一段“思考”Thought然后决定调用哪个工具Action拿到工具返回结果Observation再继续思考直到得出最终答案。用 LangGraph 实现一个最小 ReAct 代理核心就是一个带条件边的循环图from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated import operator class AgentState(TypedDict): messages: Annotated[list, operator.add] def should_continue(state): last state[messages][-1] if last.tool_calls: return tools return END builder StateGraph(AgentState) builder.add_node(agent, call_model) builder.add_node(tools, tool_node) builder.set_entry_point(agent) builder.add_conditional_edges(agent, should_continue, {tools: tools, END: END}) builder.add_edge(tools, agent) graph builder.compile()这个结构看起来简单但实际用起来问题很多。最常见的就是无限循环模型反复调用同一个工具或者在一个死胡同里来回打转。我遇到过最离谱的一次代理为了查一个日期连续调用了 14 次搜索工具每次返回的结果都一样但它就是“不甘心”。解决这个问题的关键不是加一个 max_iterations 就完事而是要理解 ReAct 的适用边界它适合步骤数在 3 到 7 步之间、每步决策相对独立、工具返回结果明确的任务。一旦任务需要长期规划或者跨步骤的状态维护ReAct 就会力不从心。实操心得在 ReAct 代理里工具描述的质量比模型选择更重要。我试过同一个任务把工具描述从“搜索信息”改成“根据关键词搜索最新网页信息返回标题和摘要适用于查询事实性内容”成功率直接从 60% 拉到 85%。工具描述要写清楚“什么时候用”和“返回什么”而不是只写“这个工具是干嘛的”。2.2 Plan-and-Execute先规划再执行适合步骤明确的长任务ReAct 的问题是“走一步看一步”缺乏全局视野。Plan-and-Execute 的思路正好相反先让模型生成一个完整的执行计划把任务拆成若干子步骤然后逐步执行每个步骤必要时再重新规划。这个架构在 LangGraph 里的典型结构是一个 planner 节点负责生成计划一个 executor 节点负责执行当前步骤一个 replanner 节点根据执行结果决定是继续还是调整计划。class PlanExecuteState(TypedDict): input: str plan: list[str] past_steps: list[tuple] response: str def plan_node(state): plan planner_chain.invoke({input: state[input]}) return {plan: plan.steps} def execute_node(state): task state[plan][0] result executor_agent.invoke({task: task}) return {past_steps: [(task, result)]} def replan_node(state): # 根据已完成步骤决定下一步 ...Plan-and-Execute 最大的优势是可控性强。因为计划是显式的你可以在执行前审查计划是否合理也可以在执行过程中插入人工确认。这在企业场景里非常重要——没有哪个业务方愿意让代理“自己决定要干什么”。但它也有明显的代价规划本身消耗大量 token而且如果初始计划有偏差后续执行会一路错下去。我的经验是对于步骤超过 10 步的复杂任务Plan-and-Execute 比 ReAct 稳定得多但对于步骤少、需要灵活应变的任务它反而更慢更贵。2.3 Reflexion给代理加上“自我批评”回路Reflexion 的核心思想是代理执行完一个任务后不是直接结束而是对自己的表现进行反思把反思结果存入记忆下次遇到类似任务时可以参考。这个架构在代码上表现为在 ReAct 循环外面再套一层“评估-反思”循环def reflect_node(state): # 评估执行结果 evaluation evaluator.invoke(state[messages]) if evaluation.score threshold: reflection reflector.invoke({ task: state[input], result: state[messages][-1], feedback: evaluation.feedback }) return {reflections: [reflection]} return {reflections: []}Reflexion 在需要反复试错的场景下效果显著比如代码生成、数学推理、复杂查询。我实测过一个 SQL 生成任务加上 Reflexion 后首次执行成功率从 45% 提升到 72%因为代理会从失败的查询中学习避免重复犯错。但要注意Reflexion 不是免费的。每次反思都要额外调用模型延迟和成本都会增加。而且如果评估器本身不准反思就会变成“瞎反思”甚至把正确的做法改错。所以评估器的设计比反思器更关键。2.4 LATS把树搜索引入代理决策LATSLanguage Agent Tree Search是把蒙特卡洛树搜索MCTS的思路用到代理决策上。它不只走一条路而是同时探索多条可能的行动路径根据每条路径的预期收益决定往哪个方向深入。这个架构实现复杂度明显高于前三种但在决策空间大、单步试错成本低的场景下非常有效。比如网页操作代理每一步可以点击的按钮很多LATS 可以并行探索几个候选动作选择最有希望的那个继续。LangGraph 本身不直接提供树搜索原语但你可以用子图递归的方式模拟。核心是把每个候选动作作为一个分支用评分函数决定扩展哪个节点。这个架构的代码量大概是 ReAct 的三到四倍除非任务确实需要否则不建议一上来就用。架构适用任务复杂度延迟Token 成本实现难度ReAct低到中3-7 步低中低Plan-and-Execute中到高10 步中高中Reflexion中到高需试错高高中LATS高决策空间大很高很高高3. 多代理协作的三种主流拓扑Supervisor、Swarm 和 Hierarchical单代理再强也有能力边界。当任务需要不同领域的专业知识、或者需要并行处理多个子任务时多代理架构就派上用场了。但多代理不是“代理越多越好”拓扑结构选错了协调成本会吃掉所有收益。3.1 Supervisor一个“经理”代理调度多个“员工”代理Supervisor 是最容易理解的多代理拓扑有一个中心代理负责理解任务、决定把子任务分配给哪个专业代理、收集结果并决定下一步。其他代理都是“干活”的不负责全局决策。在 LangGraph 里Supervisor 通常实现为一个路由节点根据当前状态决定下一个激活哪个代理def supervisor_node(state): decision supervisor_chain.invoke(state[messages]) if decision.next researcher: return {next: researcher} elif decision.next coder: return {next: coder} elif decision.next FINISH: return {next: END}这个架构的优点是控制流清晰所有决策都经过一个中心点容易调试和加约束。缺点是 Supervisor 本身可能成为瓶颈——如果子任务很多Supervisor 的上下文会迅速膨胀而且它需要理解所有子代理的能力提示词会变得很复杂。我实际用下来Supervisor 最适合子任务类型明确、数量在 3 到 5 个之间的场景。超过 5 个代理Supervisor 的路由准确率会明显下降这时候就该考虑 Hierarchical 了。3.2 Swarm去中心化的代理交接Swarm 的思路和 Supervisor 相反没有中心调度器每个代理都可以把控制权“交接”给另一个代理。这更像是一个团队里大家互相喊话谁擅长什么谁上。在 LangGraph 里Swarm 通常用 Command 对象实现代理间的跳转def agent_a(state): # 判断是否需要交接给 agent_b if need_handoff: return Command(gotoagent_b, update{messages: [...]}) return {messages: [...]}Swarm 的优点是灵活适合流程不固定、需要动态决定下一步谁来处理的场景。但它的缺点也很明显调试困难。因为没有中心控制点出问题时很难追踪是哪个代理在什么情况下做了错误决策。而且如果代理之间互相交接形成环很容易死循环。我的建议是Swarm 适合代理数量少2-4 个、交接规则清晰的场景。如果代理多、关系复杂还是老老实实用 Supervisor。3.3 Hierarchical多层 Supervisor 解决大规模协作当代理数量超过 5 个Supervisor 的路由准确率下降时Hierarchical 架构就派上用场了。它的思路是分层顶层 Supervisor 只负责把任务分给几个“团队负责人”每个团队负责人再管理自己的几个专业代理。这个架构在 LangGraph 里通过子图嵌套实现。每个团队是一个独立的子图顶层图只负责团队间的调度。这样每个 Supervisor 只需要理解自己团队内的代理认知负担大大降低。Hierarchical 的代价是实现复杂度高而且跨团队的通信需要额外设计。我一般只在代理数量确实很多、且任务可以自然分组成几个领域时才用这个架构。如果只是三五个代理Supervisor 完全够用没必要过度设计。实操心得多代理系统里代理之间的“通信协议”比代理本身的能力更重要。我见过太多项目每个代理单独测都很好一协作就乱套根本原因是消息格式不统一、状态传递有歧义。建议在项目早期就定义清楚代理间传递的消息结构包括任务描述、上下文、期望输出格式并且用类型检查强制约束。4. 记忆与状态管理代理能不能“记住事”决定了它能干多复杂的活代理和普通聊天机器人的核心区别之一就是代理需要跨步骤维护状态。一个任务执行到第 5 步时它必须记得第 2 步得到了什么结果、第 3 步为什么选择了那个工具。如果状态管理没做好代理就会“失忆”反复问已经问过的问题或者基于错误的前提继续执行。4.1 短期记忆用 LangGraph 的 State 做步骤间传递LangGraph 的 State 本质上是一个贯穿整个图执行的共享数据结构。每个节点读取 State、返回 State 的更新框架负责合并。这是代理短期记忆的基础。但 State 的设计有很多讲究。最常见的问题是State 膨胀把所有中间结果都塞进 State导致上下文越来越长最后超出模型窗口。我的做法是分层管理核心状态当前任务、已完成步骤摘要始终保留详细中间结果只在需要时通过工具查询。class AgentState(TypedDict): task: str current_step: int step_summaries: Annotated[list[str], operator.add] # 详细结果不直接放 State而是存到外部State 里只放引用 artifact_refs: list[str]4.2 长期记忆向量库 结构化存储的组合拳短期记忆解决的是“当前任务内不忘事”长期记忆解决的是“跨任务学习”。代理需要记住用户的偏好、过去成功的解决方案、常见的错误模式。我的标准做法是双轨制向量库存非结构化经验比如“上次类似任务用了什么方法”关系型或键值存储存结构化事实比如“用户偏好中文回复”“这个 API 的 rate limit 是 100/min”。检索时先查结构化事实再补充向量检索的相关经验。LangChain 提供了多种记忆组件的抽象但实际用起来我建议不要过度依赖框架的 Memory 类而是自己控制写入和检索逻辑。因为框架的自动记忆往往写入太多噪音检索时反而干扰判断。4.3 状态持久化让代理能“断点续跑”生产环境里代理执行可能因为各种原因中断模型超时、工具报错、人工介入。如果状态没有持久化中断后就得从头再来成本极高。LangGraph 提供了 checkpointer 机制可以把每一步的状态存到数据库。配置起来很简单from langgraph.checkpoint.sqlite import SqliteSaver memory SqliteSaver.from_conn_string(:memory:) graph builder.compile(checkpointermemory) # 执行时指定 thread_id同一 thread 可以恢复 config {configurable: {thread_id: task-001}} graph.invoke(input, config)这个机制在长任务场景下几乎是必须的。我做过一个需要跑 30 多步的数据分析代理没有持久化之前任何一步失败都要重跑全部平均完成时间 12 分钟加上持久化后失败重试只从断点继续平均完成时间降到 4 分钟。注意状态持久化不是免费的。每一步都写数据库会增加延迟尤其是状态对象很大时。我的经验是对于步骤少于 10 步的任务可以不持久化超过 10 步或者单步耗时很长的任务一定要开持久化。5. 工具调用与外部交互代理的“手脚”怎么接才稳代理再聪明如果工具调用不稳定整个系统就是空中楼阁。工具调用这块的坑比模型选择多得多。5.1 工具描述决定代理“会不会用”这个工具前面提过工具描述的重要性这里展开说。一个好的工具描述应该包含四个要素功能说明、适用场景、输入格式、输出格式。缺任何一个代理都可能用错。举个例子一个查询天气的工具差的描述是“查询天气”好的描述是根据城市名称查询当前天气。 适用场景用户询问某个城市的实时天气、温度、湿度时使用。 输入城市名称字符串如北京、Shanghai。 输出包含温度、天气状况、湿度的 JSON 对象。 注意只支持中国主要城市不支持历史天气查询。这个描述多花了几十个 token但能显著降低误用率。我实测过加上“注意”这一条后代理不再尝试用这个工具查历史天气而是会主动告诉用户“这个工具不支持历史查询”。5.2 工具调用错误处理不要让一个工具报错拖垮整个代理工具调用失败是常态不是异常。网络超时、API 限流、参数格式错误都会发生。代理必须能区分“这个工具暂时不可用”和“这个工具不适合这个任务”并做出不同反应。我的做法是在工具层做统一包装把错误分类返回def safe_tool_call(tool, args): try: result tool.invoke(args) return {status: success, data: result} except TimeoutError: return {status: retryable, error: timeout} except ValidationError as e: return {status: invalid_args, error: str(e)} except Exception as e: return {status: fatal, error: str(e)}代理看到retryable可以重试看到invalid_args应该修正参数看到fatal应该换工具或放弃。这样比直接抛异常让代理“懵掉”要好得多。5.3 并行工具调用什么时候该并行什么时候不该LangGraph 支持在一个节点里并行调用多个工具这对独立子任务很有效。比如同时查三个城市的天气并行比串行快三倍。但并行不是无脑用。如果工具之间有依赖或者共享限流配额并行反而会出问题。我的判断标准是工具之间无数据依赖、且各自有独立配额时才并行。否则串行更稳。6. 调试与可观测性代理出问题时你怎么知道是哪一步错了代理系统的调试难度远高于普通程序。因为决策是模型做的同样的输入可能得到不同输出传统的断点调试基本失效。没有好的可观测性你就是在盲人摸象。6.1 结构化日志记录每一步的输入、输出和决策依据最基本的可观测性手段是结构化日志。每个节点执行时记录节点名称、输入状态摘要、模型输出、工具调用及结果、耗时、token 消耗。这些日志用 JSON 格式存方便后续查询和分析。LangGraph 提供了 callback 机制可以挂载自定义的日志处理器。我一般会实现一个 callback把每个节点的执行信息写到结构化日志里同时上报到监控系统。6.2 轨迹回放把一次执行完整重放出来当代理行为异常时最有效的调试方式是回放整个执行轨迹。因为状态是持久化的你可以把一次执行的每一步按顺序重放观察在哪一步开始偏离预期。我通常会在 Jupyter Notebook 里做这件事加载某次执行的 checkpointer 数据逐步打印每个节点的输入输出人工检查决策是否合理。这个过程很笨但非常有效。很多问题一看轨迹就明白了比如“代理在第 3 步误解了用户意图导致后面全错”。6.3 评估集用固定测试用例衡量架构改动的影响代理系统最怕的是“改了一个提示词不知道是变好了还是变坏了”。没有评估集你就是在凭感觉调优。我的做法是维护一个 20 到 50 个用例的评估集覆盖典型任务和边界情况。每次改动架构或提示词后跑一遍评估集看成功率、平均步数、平均 token 消耗的变化。这个习惯能帮你避免很多“以为改好了实际改坏了”的情况。可观测性手段解决什么问题实现成本推荐优先级结构化日志知道每步发生了什么低高轨迹回放定位哪一步出错中高评估集衡量改动效果中高实时监控告警及时发现生产问题高中7. 架构选型的决策框架别问哪个最好问哪个最适合讲了这么多架构最后回到最实际的问题我到底该选哪个我的建议是不要追求“最先进”的架构而是从任务特征出发做匹配。下面这个决策框架是我在实际项目中总结出来的你可以直接对照使用。7.1 按任务复杂度选从 ReAct 开始不够再加如果你的任务步骤在 7 步以内先用 ReAct。它实现简单、调试容易、成本低。只有当 ReAct 明显不够用时——比如步骤经常超过 10 步、或者需要显式规划——才升级到 Plan-and-Execute。不要一上来就上多代理。多代理的协调成本很高很多任务单代理加好工具就能解决。我见过一个团队用三个代理做本来一个代理就能做的事结果延迟翻倍、成本翻三倍效果还更差。7.2 按延迟要求选实时场景慎用反思和树搜索如果用户等着看结果延迟是硬约束。Reflexion 和 LATS 都会显著增加延迟不适合实时交互场景。这种情况下ReAct 或者简单的 Plan-and-Execute 更合适。如果任务是异步的、用户可以等那就可以用更重的架构来换取更高的成功率。7.3 按成本预算选token 消耗差三到五倍是常态不同架构的 token 消耗差异很大。ReAct 最省Plan-and-Execute 因为要生成计划会多花一些Reflexion 和 LATS 可能贵三到五倍。在预算有限的情况下优先优化工具描述和提示词而不是换更重的架构。7.4 按团队能力选复杂架构需要匹配的运维能力Hierarchical 和 LATS 这类架构实现和运维复杂度都高。如果团队没有足够的可观测性和调试能力上了这些架构只会让自己更痛苦。先从简单的开始等团队对代理系统有了足够的理解和工具积累再逐步升级。实操心得我一般会建议团队先用 ReAct 跑通一个真实任务把工具、状态、日志、评估这套基础设施搭好。这套基础设施比架构本身更重要。基础设施好了换架构就是改几十行代码的事基础设施没有换什么架构都是灾难。8. 从 Notebook 到生产17 种架构的落地路径Jupyter Notebook 是探索架构的好地方但生产环境和 Notebook 差别很大。这部分讲讲从实验到上线的关键差异。8.1 并发与隔离每个任务独立的状态空间Notebook 里通常一次只跑一个任务生产环境可能同时跑几百个。这时候状态隔离就至关重要。每个任务必须有独立的 thread_id 和状态空间不能互相污染。LangGraph 的 checkpointer 天然支持按 thread_id 隔离但你要确保工具调用也是无状态的或者状态按任务隔离。我见过因为工具层用了全局变量导致任务间数据串味的案例排查了很久。8.2 超时与熔断不能让一个卡住的任务拖垮整个系统生产环境必须有超时和熔断机制。每个节点设置最大执行时间超时就中断并记录。如果某个工具连续失败触发熔断暂时跳过这个工具避免拖垮整个任务。这些机制在 Notebook 里通常被忽略但生产环境没有它们就是定时炸弹。8.3 版本管理提示词、工具、架构都要可追溯代理系统里提示词和工具描述的改动对行为影响很大。必须像管理代码一样管理它们每次改动有记录、可回滚、能关联到评估结果。我的做法是把提示词和工具描述都存在版本控制系统里每次部署时记录使用的版本号。出问题时可以快速定位是哪个版本引入的。8.4 渐进式上线先影子模式再小流量最后全量代理系统直接全量上线风险很高。我的做法是三步走先在影子模式下运行不实际执行动作只记录决策人工检查合理性然后小流量灰度观察真实表现最后逐步放量。这个过程看起来慢但能避免很多生产事故。我见过一个团队跳过影子模式直接上线结果代理在生产环境误删了数据代价很大。9. 我在实际项目里踩过的三个坑最后分享三个真实的坑都是文档里不会写、但实际做代理系统一定会遇到的。第一个坑以为模型越强代理越好。早期我总想用最强的模型觉得这样代理决策更准。后来发现对于结构化的工具调用任务中等模型加上好的工具描述和清晰的架构效果往往比强模型加混乱架构更好。模型能力是上限架构决定你能不能摸到上限。第二个坑忽略状态大小对延迟的影响。有一次做长流程代理状态里累积了大量中间结果到第 20 步时每次模型调用都要传几万 token 的上下文延迟从 2 秒涨到 15 秒。后来把中间结果外置状态里只保留摘要和引用延迟降回 3 秒以内。状态管理不是“能存就行”要主动控制大小。第三个坑多代理系统里代理“互相甩锅”。用 Supervisor 架构时遇到过子代理返回“这不是我的任务”然后 Supervisor 又把它路由回去形成死循环。后来在子代理的提示词里明确写了“如果任务不属于你的职责返回特定标记不要尝试处理”Supervisor 看到标记就换代理。这种边界情况的处理必须在设计时就考虑到。代理架构这个领域变化很快新的模式和工具不断出现。但底层的东西——状态管理、工具调用、错误处理、可观测性——是不变的。把这几个基础打牢不管上层架构怎么变你都能快速适应。