资讯动态

从单体Agent到Multi-Agent:架构演进与手写实操指南

发布时间:2026/10/2 15:59:02 来源:尧图企业网站定制
1. 从单体 Agent 到 Multi-Agent 的必然演进1.1 单体 Agent 到底卡在哪里先说结论单体 Agent 不是“不够聪明”而是“装不下”。我过去一年里手写过至少五六个不同形态的 ReAct Agent从最简单的“读文件-改代码-跑测试”到稍微复杂点的“多轮检索工具编排”几乎每一个在任务复杂度上升之后都会撞到同一堵墙。这堵墙不是模型能力不够而是上下文窗口、工具数量和任务分解粒度这三者之间的结构性矛盾。你如果用过 ReAct 范式就知道它的核心循环是 Thought → Action → Observation 三步轮转。每一步的 Thought 和 Observation 都要塞回上下文里作为下一轮推理的输入。任务简单的时候没问题三五轮就结束了。但一旦任务需要十几步甚至几十步上下文里就会堆积大量中间状态历史工具调用记录、文件内容片段、报错信息、之前的推理链路。这些东西不会自动消失它们会一直占着 token 预算。我实测过一个典型场景让单体 Agent 完成“读取一个 Python 项目、定位某个函数的 bug、修改代码、运行测试、如果失败则重新分析”这样的闭环任务。在任务进行到第八轮左右的时候上下文长度已经逼近 60K token。这时候会出现两个典型症状一是模型开始“遗忘”早期的关键约束比如它明明在第三轮已经确认了某个函数签名不能改到第十轮又把它改掉了二是推理质量明显下降Thought 变得敷衍Action 选择开始重复。这里有个很多人忽略的点上下文长度不是“够用就行”而是“越满越笨”。即使没有触及模型的最大窗口限制当上下文填充率超过 60% 左右时推理质量就会开始可感知地退化。这不是玄学而是注意力机制在长序列上的固有特性。1.2 Multi-Agent 不是堆数量而是做分工很多人第一次听到 Multi-Agent直觉反应是“那就多开几个 Agent 一起干活呗”。这个理解不能说错但太粗糙了。Multi-Agent 的核心价值不在于“多”而在于职责隔离和上下文隔离。打个比方单体 Agent 就像一个全栈工程师从需求分析、架构设计、编码、测试到部署全是一个人干。项目小的时候没问题但项目一大他一个人脑子里要同时装太多东西就容易出错。Multi-Agent 则是把这个人拆成一个团队有人专门做需求拆解有人专门写代码有人专门做代码审查有人专门跑测试。每个人只关心自己那一块上下文干净职责清晰。这个思路在工程上的映射就是每个 Agent 拥有独立的上下文窗口和独立的工具集。规划 Agent 不需要知道具体代码怎么写它只需要输出任务分解和依赖关系执行 Agent 不需要知道全局规划它只需要拿到一个明确的子任务和对应的工具审查 Agent 不需要知道执行过程它只需要拿到产出物和验收标准。我自己的经验是当一个任务的子步骤超过 7 个或者需要同时使用超过 5 种不同工具或者中间状态数据量超过 30K token的时候就应该考虑拆成 Multi-Agent 了。这三个指标不需要同时满足任何一个触发了单体 Agent 的可靠性就会开始明显下降。1.3 为什么说这是“必然”而不是“可选”有人可能会说那我等模型上下文窗口再大一点不就行了现在不是已经有 1M token 的模型了吗这个问题我认真想过。上下文窗口变大确实能缓解问题但解决不了根本矛盾。原因有三第一成本随上下文长度超线性增长。你把 100K token 塞进去和塞 10K token推理成本差的不只是十倍延迟也会显著增加。在实际生产环境里一个任务跑十分钟和跑一分钟用户体验是天壤之别。第二长上下文中的信息衰减是客观存在的。即使模型宣称支持 1M token在中间位置的信息被有效利用的程度仍然会下降。这不是某一家模型的问题而是当前架构的共性。你把所有东西塞进一个窗口模型不一定能“看到”所有关键信息。第三工具数量和职责复杂度的增长是组合爆炸的。一个 Agent 挂 20 个工具它在每一步选择工具时的决策空间就是 20 选 1再加上参数组合搜索空间巨大。而拆成 4 个 Agent 各挂 5 个工具每个 Agent 的决策空间就小得多可靠性自然更高。所以我的判断是上下文窗口的扩大只是把单体 Agent 的天花板往上抬了一点但天花板本身依然存在。复杂任务走向 Multi-Agent 不是一种“选择”而是一种“必然”。2. Multi-Agent 的核心架构与通信机制拆解2.1 三种主流拓扑结构及其适用场景Multi-Agent 的拓扑结构决定了 Agent 之间怎么组织、怎么通信、怎么协调。我实际用过并且踩过坑的主要是三种中心化编排、去中心化协作、层级化分解。中心化编排是最常见也最容易落地的模式。一个 Orchestrator Agent 负责接收任务、拆解子任务、分配给 Worker Agent、收集结果、决定下一步。Worker 之间不直接通信所有协调都通过 Orchestrator 中转。这种模式的好处是控制流清晰调试方便出问题容易定位。坏处是 Orchestrator 容易成为瓶颈而且它对全局的把控要求很高如果拆解不合理后面全盘皆输。去中心化协作是多个 Agent 平等对话通过消息传递来协调。比如一个 Agent 提出方案另一个 Agent 审查并提出修改意见来回几轮直到达成一致。这种模式适合需要多视角碰撞的任务比如代码审查、方案评审。但它的缺点是收敛性难以保证有时候两个 Agent 会陷入无限循环的“你说我改”状态。层级化分解是中心化和去中心化的混合。顶层有一个规划 Agent它把任务拆成几个大模块每个模块下面再有一个子 Orchestrator 负责进一步拆解和协调。这种模式适合大型任务比如“重构一个微服务”这种需要多层分解的场景。但它的实现复杂度也最高通信开销大调试难度高。拓扑结构适用场景优势劣势中心化编排任务步骤明确、子任务独立性高控制流清晰、易调试Orchestrator 瓶颈、单点故障去中心化协作需要多视角评审、方案碰撞灵活、容错性好收敛难保证、通信开销大层级化分解大型任务、多模块并行可扩展性强、职责清晰实现复杂、调试困难我个人的建议是从中心化编排开始。除非你的任务天然需要多视角碰撞否则不要一上来就搞去中心化。中心化编排的调试体验好太多而且大部分任务其实并不需要 Agent 之间自由对话。2.2 Agent 之间怎么通信消息格式与状态传递Multi-Agent 的通信机制是很多人容易忽略但极其关键的一环。通信设计不好整个系统就会变成一团乱麻。我目前用得最顺手的方案是结构化消息 共享状态存储的组合。具体来说Agent 之间传递的消息不是自然语言而是结构化的 JSON 对象。每条消息包含这几个字段sender发送方、receiver接收方、task_id任务标识、status状态、payload具体内容、artifacts产出物引用。这样做的好处是消息可解析、可追踪、可回放出问题的时候能精确定位是哪一步出了差错。共享状态存储则是用一个外部的 KV 存储或者文件系统来保存中间产物。Agent 之间不直接传递大块数据而是传递引用。比如执行 Agent 生成了一个代码文件它不会把文件内容塞进消息里发给审查 Agent而是把文件路径放在artifacts里审查 Agent 自己去读。这样做的好处是避免了上下文膨胀每个 Agent 只加载自己需要的那部分数据。# 一个典型的结构化消息示例 message { sender: planner_agent, receiver: coder_agent, task_id: task_20260115_001, status: assigned, payload: { instruction: 实现用户登录接口的密码校验逻辑, constraints: [使用 bcrypt 做哈希, 密码长度至少 8 位], acceptance_criteria: [单元测试通过, 代码通过 lint 检查] }, artifacts: { input_files: [/workspace/src/auth/login.py], reference_docs: [/workspace/docs/auth_spec.md] } }这里有个实操心得消息里的constraints和acceptance_criteria一定要写清楚。我踩过的坑是规划 Agent 给执行 Agent 的任务描述太模糊执行 Agent 自由发挥结果产出物不符合预期来回返工好几次。后来我强制要求每个任务分配必须包含明确的约束条件和验收标准返工率直接降了一半。2.3 Context 隔离每个 Agent 只装自己需要的东西Context 隔离是 Multi-Agent 相比单体 Agent 最大的优势之一但也是最容易被做砸的地方。我见过不少实现虽然拆了多个 Agent但每个 Agent 的上下文里还是塞了一大堆全局信息。比如执行 Agent 的 prompt 里包含了完整的任务规划、所有历史对话、所有工具的输出记录。这跟单体 Agent 有什么区别只是把一个大上下文拆成了几个同样臃肿的小上下文而已。正确的做法是按需注入。每个 Agent 的上下文只包含三类信息角色定义你是谁、你负责什么、当前任务你要做的这一件事是什么、必要参考做这件事需要知道的约束和背景。其他的全局信息、历史记录、其他 Agent 的产出一律不注入。具体实现上我会给每个 Agent 定义一个context_builder函数它负责从共享状态里拉取当前 Agent 需要的信息组装成 prompt。这个函数是每个 Agent 独立的不同 Agent 拉取的信息完全不同。def build_coder_context(task_id, shared_state): task shared_state.get_task(task_id) return { role: 你是一名资深 Python 后端工程师负责实现具体的功能模块。, task: task[payload][instruction], constraints: task[payload][constraints], acceptance_criteria: task[payload][acceptance_criteria], relevant_files: load_files(task[artifacts][input_files]), available_tools: [read_file, write_file, run_test, lint_check] }这样做的好处是每个 Agent 的上下文都能控制在很小的范围内推理质量高成本低而且不会互相干扰。实测下来一个执行 Agent 的上下文通常能控制在 4K token 以内相比单体 Agent 动辄 50K 的上下文差距是数量级的。3. 手写一个 Multi-Agent 系统的完整实操3.1 环境准备与依赖安装这一节我以 Python 为例从零搭一个最小可用的 Multi-Agent 系统。不依赖任何重型框架纯手写方便你理解每一层的逻辑。等你理解了原理再去用 LangGraph、AutoGen 这些框架就会知道它们到底在帮你做什么。首先是环境准备。Python 版本建议 3.10 以上因为我们要用一些类型注解的新特性。安装依赖pip install openai pydantic httpx这里我只装了最基础的几个包。openai用来调模型接口pydantic用来做消息和状态的结构化校验httpx用来做异步 HTTP 请求。没有装任何 Agent 框架因为我们要手写。注意如果你用的是其他模型提供方把openai换成对应的 SDK 就行。核心逻辑不变只是 API 调用方式不同。目录结构我建议这样组织multi_agent_demo/ ├── agents/ │ ├── base.py # Agent 基类 │ ├── planner.py # 规划 Agent │ ├── coder.py # 执行 Agent │ └── reviewer.py # 审查 Agent ├── core/ │ ├── message.py # 消息定义 │ ├── state.py # 共享状态 │ └── orchestrator.py # 编排器 ├── tools/ │ └── file_tools.py # 工具集 └── main.py # 入口这个结构的好处是职责清晰每个 Agent 独立一个文件核心通信和状态管理放在 core 里工具单独抽出来方便复用。3.2 定义消息协议与共享状态先定义消息协议。用 Pydantic 来做好处是自动校验字段缺失或者类型不对会直接报错避免运行到一半才发现消息格式有问题。from pydantic import BaseModel, Field from typing import Any, Optional from enum import Enum class MessageStatus(str, Enum): ASSIGNED assigned IN_PROGRESS in_progress COMPLETED completed FAILED failed NEEDS_REVIEW needs_review class AgentMessage(BaseModel): sender: str receiver: str task_id: str status: MessageStatus payload: dict[str, Any] Field(default_factorydict) artifacts: dict[str, list[str]] Field(default_factorydict) error: Optional[str] None共享状态我用一个简单的内存字典加文件系统来实现。内存字典存任务元数据和消息历史文件系统存实际的产出物代码文件、测试报告等。import json from pathlib import Path class SharedState: def __init__(self, workspace: str): self.workspace Path(workspace) self.workspace.mkdir(parentsTrue, exist_okTrue) self.tasks: dict[str, dict] {} self.messages: list[AgentMessage] [] def create_task(self, task_id: str, payload: dict): self.tasks[task_id] { payload: payload, status: pending, assigned_to: None, result: None } def update_task(self, task_id: str, **kwargs): self.tasks[task_id].update(kwargs) def get_task(self, task_id: str) - dict: return self.tasks[task_id] def save_artifact(self, task_id: str, filename: str, content: str) - str: task_dir self.workspace / task_id task_dir.mkdir(exist_okTrue) filepath task_dir / filename filepath.write_text(content, encodingutf-8) return str(filepath) def load_artifact(self, filepath: str) - str: return Path(filepath).read_text(encodingutf-8)这个共享状态的设计要点是任务元数据和实际产出物分离。元数据小放内存里快速读写产出物可能很大放文件系统里按需加载。这样每个 Agent 在构建上下文的时候只加载自己需要的文件不会把所有东西都塞进 prompt。3.3 实现规划 Agent任务拆解与依赖分析规划 Agent 是整个系统的入口它接收用户的原始需求输出一个结构化的任务列表。这个任务列表包含每个子任务的描述、依赖关系、验收标准。import json from openai import OpenAI client OpenAI() PLANNER_PROMPT 你是一个任务规划专家。你的职责是把用户的复杂需求拆解成一系列可独立执行的子任务。 输出要求 1. 每个子任务必须足够具体一个执行者拿到后能直接开始工作 2. 每个子任务必须包含明确的验收标准 3. 标注子任务之间的依赖关系哪些任务必须在其他任务完成后才能开始 4. 输出格式为 JSON 数组每个元素包含id, description, acceptance_criteria, dependencies 不要输出任何额外的解释只输出 JSON。 def plan_task(user_request: str) - list[dict]: response client.chat.completions.create( modelgpt-4o, messages[ {role: system, content: PLANNER_PROMPT}, {role: user, content: user_request} ], temperature0.2 ) content response.choices[0].message.content # 清理可能的 markdown 代码块标记 content content.strip().removeprefix(json).removesuffix().strip() return json.loads(content)这里有几个实操细节值得说。第一temperature设成 0.2规划任务需要稳定性不需要创造性。第二prompt 里明确要求“只输出 JSON”但实际模型有时候还是会加一些解释文字所以代码里做了清理。第三依赖关系的标注很关键它决定了后续任务调度的顺序。我踩过的坑是早期版本的规划 Agent 拆出来的任务粒度太粗比如“实现用户模块”这种执行 Agent 拿到之后还是不知道从哪下手。后来我在 prompt 里加了一条“每个子任务的工作量应该控制在 30 分钟以内”拆解质量明显提升。3.4 实现执行 AgentReAct 循环与工具调用执行 Agent 是真正干活的那个。它接收一个具体的子任务通过 ReAct 循环来完成任务。核心逻辑是思考当前该做什么选择一个工具执行观察结果继续思考直到任务完成。import json CODER_PROMPT 你是一名资深 Python 工程师。你正在执行一个具体的编码任务。 你可以使用以下工具 - read_file(path): 读取文件内容 - write_file(path, content): 写入文件 - run_test(path): 运行测试文件 - lint_check(path): 检查代码风格 你的输出必须是以下 JSON 格式之一 1. 需要调用工具时{thought: 你的思考, action: 工具名, action_input: {...}} 2. 任务完成时{thought: 你的思考, action: finish, action_input: {summary: 完成总结}} 不要输出任何其他内容。 def execute_task(task: dict, shared_state: SharedState, max_steps: int 15) - dict: context build_coder_context(task, shared_state) messages [ {role: system, content: CODER_PROMPT}, {role: user, content: json.dumps(context, ensure_asciiFalse)} ] for step in range(max_steps): response client.chat.completions.create( modelgpt-4o, messagesmessages, temperature0.1 ) raw response.choices[0].message.content.strip() raw raw.removeprefix(json).removesuffix().strip() try: decision json.loads(raw) except json.JSONDecodeError: messages.append({role: assistant, content: raw}) messages.append({role: user, content: 输出格式错误请严格按照 JSON 格式输出。}) continue if decision[action] finish: return {status: completed, summary: decision[action_input][summary]} # 执行工具调用 tool_result dispatch_tool(decision[action], decision[action_input], shared_state) # 把思考和观察结果追加到上下文 messages.append({role: assistant, content: raw}) messages.append({role: user, content: f工具执行结果{tool_result}}) return {status: failed, error: f超过最大步数 {max_steps} 仍未完成}这个 ReAct 循环有几个关键设计点。第一max_steps是必须的防止 Agent 陷入死循环。我一般设 15 步超过就判定失败交给上层处理。第二每次工具调用的结果都会追加到 messages 里这就是 ReAct 的“观察”环节。第三如果模型输出格式不对不是直接报错而是给它一次纠正的机会把错误信息反馈回去让它重新输出。实操心得temperature设成 0.1 甚至 0 会显著提升工具调用的稳定性。我试过 0.7模型经常“发挥创意”输出一些不存在的工具名或者参数格式不对。编码任务不需要创造性稳定压倒一切。3.5 实现审查 Agent质量把关与反馈闭环审查 Agent 负责检查执行 Agent 的产出物是否符合验收标准。它的上下文里只有三样东西验收标准、产出物内容、检查工具。REVIEWER_PROMPT 你是一名严格的代码审查员。你的职责是检查产出物是否满足验收标准。 你需要输出 JSON 格式的审查结果 {passed: true/false, issues: [问题1, 问题2], suggestions: [建议1]} 如果所有验收标准都满足passed 为 true。否则为 false并列出具体问题。 def review_task(task: dict, artifacts: dict, shared_state: SharedState) - dict: context { acceptance_criteria: task[payload][acceptance_criteria], artifacts: {k: shared_state.load_artifact(v) for k, v in artifacts.items()} } response client.chat.completions.create( modelgpt-4o, messages[ {role: system, content: REVIEWER_PROMPT}, {role: user, content: json.dumps(context, ensure_asciiFalse)} ], temperature0.1 ) raw response.choices[0].message.content.strip() raw raw.removeprefix(json).removesuffix().strip() return json.loads(raw)审查 Agent 的价值在于它提供了一个独立的检查视角。执行 Agent 自己检查自己的产出往往会“自我感觉良好”漏掉一些问题。审查 Agent 的上下文里没有执行过程的干扰它只看结果和标准判断更客观。如果审查不通过编排器会把问题反馈给执行 Agent让它重新修改。这个反馈闭环是保证最终质量的关键。我一般设置最多 3 轮返工超过 3 轮还没通过就标记为需要人工介入。3.6 编排器串起整个流程编排器是 Multi-Agent 系统的“大脑”它负责调度任务、管理依赖、处理失败和返工。def orchestrate(user_request: str, shared_state: SharedState): # 第一步规划 subtasks plan_task(user_request) for st in subtasks: shared_state.create_task(st[id], st) # 第二步按依赖顺序执行 completed set() max_retries 3 while len(completed) len(subtasks): ready [st for st in subtasks if st[id] not in completed and all(dep in completed for dep in st[dependencies])] if not ready: raise RuntimeError(存在循环依赖或无法推进的任务) for task in ready: retries 0 while retries max_retries: result execute_task(task, shared_state) if result[status] ! completed: retries 1 continue review review_task(task, result.get(artifacts, {}), shared_state) if review[passed]: completed.add(task[id]) shared_state.update_task(task[id], statuscompleted, resultresult) break else: retries 1 # 把审查意见反馈给执行 Agent task[payload][feedback] review[issues] if retries max_retries: shared_state.update_task(task[id], statusfailed) completed.add(task[id]) # 跳过继续后面的任务 return shared_state.tasks这个编排器虽然简单但已经包含了 Multi-Agent 系统的核心要素任务调度、依赖管理、失败重试、审查反馈。实际生产环境里还需要加上日志、监控、超时控制、并发执行等但核心逻辑就是这个骨架。4. 常见问题与排查技巧实录4.1 Agent 之间“踢皮球”怎么办这是 Multi-Agent 系统里最常见的问题之一。表现是规划 Agent 把任务分给执行 Agent执行 Agent 说“这个任务不明确需要更多信息”把球踢回给规划 Agent规划 Agent 重新描述一遍执行 Agent 还是说“不明确”。来回几轮任务卡死。根本原因通常是任务描述缺少可执行的细节。执行 Agent 不是不想干而是它真的不知道从哪下手。比如“优化系统性能”这种任务执行 Agent 拿到之后完全懵因为“优化”是一个没有边界的概念。我的解决方案是在规划 Agent 的 prompt 里强制要求每个子任务必须包含具体的输入、输出和操作步骤。如果规划 Agent 自己都说不清楚这三样说明这个任务还需要进一步拆解。另一个技巧是给执行 Agent 设置一个“澄清预算”。它可以在执行前向规划 Agent 提出最多 2 个澄清问题超过 2 个就必须自己想办法推进。这样既给了执行 Agent 提问的机会又防止了无限踢皮球。问题表现根本原因解决方案执行 Agent 反复要求澄清任务描述缺少输入/输出/步骤规划 prompt 强制要求三要素规划 Agent 反复重新描述任务粒度过粗限制单任务工作量在 30 分钟内两个 Agent 互相等待依赖关系定义不清显式标注依赖编排器校验4.2 上下文爆炸的三种典型场景虽然 Multi-Agent 的核心优势是上下文隔离但如果实现不当上下文还是会爆炸。我遇到过三种典型场景第一种工具输出过大。执行 Agent 调用read_file读取了一个 5000 行的文件整个文件内容被塞进上下文。解决方案是给工具加截断逻辑或者让 Agent 先读文件头尾确认需要后再读具体段落。第二种消息历史累积。ReAct 循环跑了 20 步每一步的 Thought 和 Observation 都堆在 messages 里。解决方案是设置滑动窗口只保留最近 N 轮的交互更早的交互压缩成摘要。第三种审查 Agent 加载了全部产出物。审查 Agent 为了检查一个函数把整个项目的代码都加载进来了。解决方案是让执行 Agent 在提交审查时明确标注哪些文件是本次任务的产出物审查 Agent 只加载这些文件。def truncate_tool_output(output: str, max_chars: int 3000) - str: if len(output) max_chars: return output half max_chars // 2 return output[:half] f\n\n... [省略 {len(output) - max_chars} 字符] ...\n\n output[-half:]这个截断函数是我踩了无数次坑之后总结出来的。头尾保留中间省略因为文件的开头通常是导入和定义结尾通常是关键逻辑中间大段可能是重复的样板代码。4.3 工具调用失败的排查思路工具调用失败在 Multi-Agent 系统里非常常见排查起来也有套路。我一般按这个顺序查第一步看模型输出格式。大部分工具调用失败其实是模型输出的 JSON 格式不对。比如该用双引号的地方用了单引号该转义的地方没转义。解决方案是在 prompt 里给出明确的格式示例并且在解析失败时把错误信息反馈给模型让它重试。第二步看工具参数。模型选对了工具但参数传错了。比如read_file需要绝对路径模型传了相对路径。解决方案是在工具定义里写清楚参数的类型和格式要求并且在工具执行前做参数校验。第三步看工具本身。工具执行过程中抛异常了。比如文件不存在、网络超时、权限不足。解决方案是给每个工具加 try-except把异常信息作为 Observation 返回给 Agent让它自己决定怎么处理。第四步看上下文。Agent 在调用工具之前上下文里是否包含了足够的信息来正确选择工具和参数。如果 Agent 不知道有哪些文件可用它就可能瞎猜一个路径。解决方案是在上下文里明确列出可用的资源和约束。排查步骤检查内容常见问题修复方式1模型输出格式JSON 格式错误prompt 加格式示例解析失败重试2工具参数类型/格式不对参数校验错误反馈给模型3工具执行异常抛出try-except异常作为 Observation4上下文信息不足补充可用资源列表和约束4.4 成本与延迟的平衡技巧Multi-Agent 系统比单体 Agent 贵这是事实。因为多个 Agent 各自要调模型总 token 消耗量更大。但通过一些技巧可以把成本控制在可接受的范围内。技巧一分级用模型。规划 Agent 和审查 Agent 用强模型执行 Agent 用中等模型。因为规划和审查需要更强的推理能力而执行往往是按部就班的操作中等模型足够。技巧二缓存重复调用。如果多个任务需要读取同一个文件缓存第一次的读取结果后续直接命中缓存。这个在共享状态层实现对 Agent 透明。技巧三并行执行无依赖任务。编排器识别出没有依赖关系的任务后可以并发执行减少总延迟。Python 里用asyncio.gather就能实现。技巧四设置合理的 max_steps。执行 Agent 的循环步数不是越多越好。我实测下来大部分编码任务在 8 步以内能完成设 15 步是留了余量。设成 50 步只会让失败的任务消耗更多 token 而已。import asyncio async def execute_parallel(tasks: list[dict], shared_state: SharedState): async def run_one(task): return await asyncio.to_thread(execute_task, task, shared_state) results await asyncio.gather(*[run_one(t) for t in tasks]) return results这套组合拳打下来我的实测数据是一个中等复杂度的编码任务单体 Agent 平均消耗 45K tokenMulti-Agent 消耗 62K token成本增加约 38%但任务成功率从 61% 提升到了 89%。这个 trade-off 在大多数场景下是值得的。4.5 调试 Multi-Agent 系统的实用技巧调试 Multi-Agent 比调试单体 Agent 难因为涉及多个 Agent 的交互。我总结了几条实用技巧第一全链路日志。每条消息的发送、接收、处理、结果都要打日志带上task_id和step编号。出问题的时候能完整回放整个流程。第二单步模式。开发阶段加一个开关让编排器每执行一步就暂停等待人工确认后再继续。这样能精确定位是哪一步出的问题。第三消息可视化。把 Agent 之间的消息流用简单的文本图展示出来一眼就能看出哪个 Agent 卡住了、哪个环节消息断了。第四Mock 工具。调试 Agent 逻辑的时候把工具调用 Mock 掉返回固定结果。这样能排除工具本身的干扰专注于 Agent 的决策逻辑。第五最小复现。遇到问题时把任务简化到最小可复现的程度。比如把“重构整个项目”简化成“修改一个函数”看问题是否还存在。大部分时候问题在简化过程中就暴露出来了。这些技巧看起来简单但真正用起来能省大量时间。我刚开始搞 Multi-Agent 的时候没有全链路日志出了问题只能靠猜一个 bug 查一整天。后来把日志补上同样的 bug 十分钟就定位了。5. 从单体到多体的迁移策略与个人体会5.1 什么阶段该拆什么阶段不该拆不是所有任务都需要 Multi-Agent。我见过一些项目明明是一个简单的 CRUD 任务非要拆成五个 Agent结果复杂度上去了效果还不如单体。我的判断标准是先单体跑通遇到瓶颈再拆。具体来说如果你用单体 Agent 能满足以下所有条件就不需要拆任务步骤少于 7 步、工具数量少于 5 个、上下文填充率低于 50%、任务成功率高于 85%。任何一个条件不满足再考虑拆。拆的时候也不是一步到位。我建议的迁移路径是单体 Agent → 单体 审查 Agent → 规划 执行 审查 → 完整 Multi-Agent。每一步都先跑通、验证效果再进入下一步。这样风险可控出问题也容易回退。5.2 我踩过的三个大坑第一个坑过度设计。刚开始搞 Multi-Agent 的时候我设计了一个五层架构有全局规划、模块规划、任务分配、执行、审查五层。结果跑起来之后光是 Agent 之间的通信开销就占了总时间的一半而且调试极其困难。后来砍到三层效果反而更好。第二个坑忽视状态一致性。多个 Agent 并发读写共享状态的时候出现了数据竞争。一个 Agent 刚写入的结果被另一个 Agent 覆盖了。解决方案是给共享状态加锁或者用不可变数据结构每次更新产生新版本。第三个坑审查 Agent 太严格。审查 Agent 的 prompt 写得太苛刻导致执行 Agent 的产出物反复被打回一个简单任务返工了七次。后来调整了审查标准区分“必须修复”和“建议优化”返工率大幅下降。5.3 后续可以怎么扩展这套骨架跑通之后有几个方向可以继续扩展。方向一加入记忆机制。让 Agent 能够记住之前处理过的类似任务下次遇到的时候直接复用经验。这个可以用向量数据库来实现把历史任务的解决方案存进去新任务来了先检索相似案例。方向二支持人工介入。在关键决策点设置人工确认比如规划完成后让人类审核一下任务拆解是否合理审查不通过时让人类决定是返工还是接受。方向三多模型混用。不同 Agent 用不同的模型规划用推理强的执行用速度快的审查用准确性高的。这样能在成本和质量之间找到更好的平衡点。方向四加入监控和告警。生产环境里Agent 系统需要监控任务成功率、平均耗时、token 消耗等指标异常时自动告警。我个人在实际操作中的体会是Multi-Agent 不是银弹它解决的是单体 Agent 在复杂任务上的结构性瓶颈但同时也引入了新的复杂度。拆分的收益必须大于协调的成本这个账要算清楚。我的经验是当任务复杂度达到单体 Agent 明显吃力的程度时Multi-Agent 的收益通常是显著的但如果任务本身简单强行拆分只会得不偿失。先把手头的单体 Agent 跑到极限再考虑拆这个顺序不能反。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑