尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

从单体到Multi-Agent:复杂任务架构演进与Python实战

发布时间:2026/9/29 20:38:15

资讯中心
01
ARTICLE

从单体到Multi-Agent:复杂任务架构演进与Python实战

从单体到Multi-Agent:复杂任务架构演进与Python实战
1. 从一次上下文溢出报错说起单体 Agent 的真实瓶颈如果你正在做 Agent 开发大概率见过这个报错API error: 400 this models maximum context length is 1048576 tokens。第一次看到它的时候很多人的反应是模型上下文不够大换个更大的就行。但真正做过几个复杂任务之后你会发现哪怕上下文窗口再翻一倍单体 Agent 依然会在某个节点上崩掉——不是模型不行是架构本身到了天花板。我最早接触 Agent 是从 ReAct 范式入手的Thought → Action → Observation 循环一个 LLM 拿着几个工具反复调用直到任务完成。这套东西做 demo 极其惊艳写个爬虫、查个天气、算个数学题几十行 Python 就能跑起来。但一旦任务变成帮我分析这份财报找出异常项生成图表再写一份摘要报告单体 Agent 就开始露馅了工具越挂越多Prompt 越写越长中间结果越堆越乱最后要么上下文爆掉要么模型开始忘记前面做过什么要么在某个子步骤上反复打转。这篇文章想聊的就是这件事为什么复杂任务必然走向 Multi-Agent。不是跟风不是堆概念而是单体 Agent 在工程上真实撞墙之后被逼出来的架构演进。我会从上下文管理、职责边界、错误传播、并行效率几个角度拆开讲中间穿插可复现的 Python 代码片段和踩坑经验适合已经写过单体 Agent、正在被复杂任务折磨的开发者。2. 单体 Agent 的三重天花板上下文、职责与错误传播2.1 上下文窗口不是万能药token 预算才是真约束很多人把上下文窗口理解成记忆容量这是个危险的误解。1048576 tokens 听起来很大但你要知道这个数字是输入输出共享的而且实际可用量远小于标称值。原因有三第一注意力衰减。即使模型声称支持百万级上下文中间部分的信息召回率也会明显下降。业界常说的lost in the middle就是这个现象——放在上下文中间的关键信息模型经常视而不见。第二成本线性增长。每次 ReAct 循环都要把完整历史重新喂进去token 消耗是 O(n²) 级别的。一个跑 50 步的任务第 50 步的输入可能是第 1 步的几十倍。我实测过一个数据分析 Agent单次任务跑下来烧掉的 token 够跑几百次简单问答。第三噪声污染。工具返回的原始结果比如一整页 HTML、一段 5000 字的日志会挤占真正有用的推理空间。模型要在垃圾信息里找信号准确率自然下降。下面这段代码是我早期写的一个朴素单体 Agent 循环问题一目了然def naive_agent_loop(task, tools, max_steps50): history [{role: user, content: task}] for step in range(max_steps): # 每一步都把完整历史塞回去 response llm.chat(history) history.append(response) if response.is_final: return response.content # 工具结果原样追加不做任何压缩 result call_tool(response.tool_name, response.tool_args) history.append({role: tool, content: result}) return 任务未完成跑简单任务没问题跑复杂任务时history会迅速膨胀。你可能会想加个摘要压缩但摘要本身又会丢信息而且摘要谁来写还是同一个 Agent它既要做任务又要管记忆职责已经混了。2.2 一个 Agent 干所有事Prompt 必然变成缝合怪单体 Agent 的第二个天花板是职责耦合。为了让一个 Agent 既能规划、又能执行、还能校验你得把所有能力塞进同一个 System Prompt。结果就是 Prompt 越写越长规则越加越多最后变成一份谁都不满意的缝合怪文档。我见过一个真实案例某团队的单体 Agent System Prompt 写到 3000 多字里面既有你是严谨的分析师又有你是高效的执行者还有遇到错误要重试但不要超过三次。模型在这种自相矛盾的指令下行为极不稳定——有时候过度谨慎什么都不做有时候又鲁莽地乱调工具。更麻烦的是工具选择困难。当你有 20 个工具挂在一个 Agent 上模型选错工具的概率会显著上升。这不是模型笨而是工具描述之间的语义边界本来就模糊。让一个 Agent 同时理解查数据库和查缓存的区别还要在正确时机选对本身就是超负荷的认知任务。2.3 错误会沿着单链一路传染没有隔离带第三个天花板最隐蔽也最致命错误传播。单体 Agent 是一条链式结构第 3 步的一个小错误比如工具参数填错、返回结果解析错会作为事实进入第 4 步的上下文然后被后续所有步骤继承。等到第 10 步发现结果不对你已经很难定位是哪一步出的问题。我踩过最典型的一个坑让 Agent 从网页抓数据抓取工具返回了一个带 HTML 标签的字符串Agent 没清洗就直接当数值用了后面所有计算全错但表面上流程跑得通直到最后输出一个离谱的结论才被发现。这种静默错误在单体架构里极难排查因为没有中间检查点没有独立验证环节。提示如果你的单体 Agent 经常出现流程跑通但结果不对八成是错误传播问题而不是模型能力问题。3. Multi-Agent 到底拆的是什么职责、上下文与验证链3.1 拆的不是模型是上下文边界很多人对 Multi-Agent 有个误解以为就是多开几个 LLM 一起干活。其实核心不在数量而在上下文隔离。每个 Agent 拥有自己独立的上下文窗口只装跟自己职责相关的信息这样单个 Agent 的 token 预算就被控制住了。举个具体例子。一个财报分析任务可以拆成规划 Agent只负责把任务拆成子步骤输出一个结构化计划上下文里只有任务描述和拆解规则。数据获取 Agent只负责调工具拿数据上下文里只有工具定义和当前子任务。分析 Agent只负责对拿到的数据做计算和推理上下文里只有清洗后的数据。校验 Agent只负责检查分析结果是否合理上下文里只有原始数据和分析结论。报告 Agent只负责组织语言输出上下文里只有校验通过的结论。每个 Agent 的上下文都很干净token 消耗可控注意力集中准确率自然上去了。这就是为什么 Multi-Agent 能突破单体天花板——它把一个大而全的上下文换成了多个小而精的上下文。3.2 职责单一化让 Prompt 回归清爽拆开之后每个 Agent 的 System Prompt 可以写得非常聚焦。规划 Agent 的 Prompt 就是你是一个任务拆解专家输出 JSON 格式的步骤列表不需要它懂工具调用也不需要它懂报告写作。执行 Agent 的 Prompt 就是你是一个工具调用专家根据给定子任务选择合适工具。这种单一职责带来的好处是可测试、可迭代。你可以单独给规划 Agent 写测试用例看它拆解是否合理可以单独调执行 Agent 的工具选择准确率。而在单体架构里你改一处 Prompt 可能影响全局行为回归测试成本极高。3.3 验证链是 Multi-Agent 的隐藏价值前面提到单体 Agent 的错误传播问题Multi-Agent 天然提供了检查点。因为 Agent 之间通过结构化消息通信每个交接点都是一个可以插入验证的地方。比如数据获取 Agent 输出数据后可以有一个轻量的校验 Agent 检查数据格式和范围是否合理不合格就打回重做。这种生产者-校验者模式在单体架构里很难实现因为同一个 Agent 既当运动员又当裁判它倾向于认为自己的输出是对的。我在实际项目里加了一个简单的数值范围校验 Agent 之后静默错误率下降了大概七成。这个 Agent 本身逻辑很简单就是检查数值是否在合理区间、字段是否齐全但它拦住了大量低级错误。4. 用 Python 手写一个最小 Multi-Agent 编排框架4.1 核心抽象Agent、Message、Orchestrator不依赖任何重型框架我们用 Python 从零搭一个最小可用的 Multi-Agent 编排。核心就三个抽象from dataclasses import dataclass, field from typing import Callable, Any dataclass class Message: sender: str receiver: str content: Any msg_type: str task # task / result / feedback dataclass class Agent: name: str system_prompt: str tools: list field(default_factorylist) handler: Callable None def run(self, message: Message) - Message: # 每个 Agent 只看到发给自己的消息上下文天然隔离 prompt f{self.system_prompt}\n\n输入{message.content} output llm.chat(prompt, toolsself.tools) return Message( senderself.name, receivermessage.sender, contentoutput, msg_typeresult )关键点在于run方法每个 Agent 只接收发给自己的Message不共享全局历史。这就是上下文隔离的工程实现。4.2 Orchestrator决定谁在什么时候说话编排器负责调度它不参与具体推理只做路由class Orchestrator: def __init__(self): self.agents {} self.trace [] def register(self, agent: Agent): self.agents[agent.name] agent def dispatch(self, message: Message) - Message: self.trace.append(message) agent self.agents[message.receiver] result agent.run(message) self.trace.append(result) return result def run_pipeline(self, task: str, pipeline: list): msg Message(senderuser, receiverpipeline[0], contenttask) for step in pipeline: msg.receiver step msg self.dispatch(msg) return msg.contentpipeline是一个 Agent 名字的列表比如[planner, fetcher, analyzer, validator, reporter]。这种线性编排适合流程固定的任务复杂场景可以换成基于状态机的动态路由。4.3 一个可跑的财报分析流水线把前面的抽象拼起来跑一个简化版财报分析orchestrator Orchestrator() orchestrator.register(Agent( nameplanner, system_prompt你是任务拆解专家把用户任务拆成有序子步骤输出 JSON 列表。 )) orchestrator.register(Agent( namefetcher, system_prompt你是数据获取专家根据子任务调用工具拿数据。, tools[fetch_financial_data] )) orchestrator.register(Agent( nameanalyzer, system_prompt你是财务分析专家对给定数据做计算找出异常项。 )) orchestrator.register(Agent( namevalidator, system_prompt你是校验专家检查分析结论是否与原始数据一致输出 pass 或 fail 及原因。 )) orchestrator.register(Agent( namereporter, system_prompt你是报告撰写专家把校验通过的结论组织成结构化报告。 )) result orchestrator.run_pipeline( task分析 2024 年 Q3 财报找出异常项并生成报告, pipeline[planner, fetcher, analyzer, validator, reporter] )跑通之后你会发现每个 Agent 的 Prompt 都很短上下文都很干净调试起来也容易——出问题直接看orchestrator.trace每一步的输入输出都清清楚楚。4.4 编排模式选型线性、状态机还是黑板线性 pipeline 只适合流程固定的任务。真实场景里任务往往需要动态决策这时候有三种常见编排模式模式适用场景优点缺点线性 Pipeline流程固定的批处理简单可控、易调试不灵活无法处理分支状态机有明确状态流转的任务逻辑清晰、可回溯状态设计成本高黑板模式开放式探索任务灵活、Agent 自主协作难以预测、调试困难我的经验是能用线性就别上状态机能用状态机就别上黑板。复杂度是逐级上升的很多团队一上来就搞黑板模式结果调试成本爆炸。大部分业务场景线性 pipeline 加一两个条件分支就够了。5. 拆开之后的新麻烦通信开销、死循环与状态一致性5.1 Agent 之间传什么比怎么传更重要Multi-Agent 最容易踩的坑是消息格式不统一。规划 Agent 输出一段自然语言执行 Agent 期望结构化 JSON中间就得加一层解析解析失败又是一堆错误处理。我的做法是强制所有 Agent 间通信使用结构化格式通常是 JSON并且定义好 schema。# 好的做法结构化消息 { task_id: t001, step: fetch_data, params: {symbol: AAPL, period: 2024Q3}, expected_output: financial_metrics } # 坏的做法自然语言 请帮我获取一下苹果公司 2024 年第三季度的财务数据谢谢自然语言消息看起来灵活实际上把解析负担转嫁给了下游 Agent而且容易产生歧义。结构化消息虽然前期设计成本高但后期维护省心得多。5.2 死循环Agent 互相甩锅的经典场景Multi-Agent 有个经典故障模式校验 Agent 一直返回 fail分析 Agent 一直重做两者陷入死循环。我遇到过最夸张的一次两个 Agent 来回甩锅跑了 200 多轮token 烧了一大笔任务还没完成。解决办法是加全局步数预算和升级机制class Orchestrator: def __init__(self, max_rounds10): self.max_rounds max_rounds self.round_count 0 def dispatch(self, message): self.round_count 1 if self.round_count self.max_rounds: # 超过预算升级给人工或降级处理 return Message( senderorchestrator, receiveruser, content任务超出预算请人工介入, msg_typeescalation ) # ... 正常调度除了步数预算还要给每个 Agent 设置重试上限。校验 Agent 连续 fail 三次就应该触发升级而不是无限重试。5.3 状态一致性谁说了算多个 Agent 协作时共享状态是个大问题。比如分析 Agent 更新了中间结果报告 Agent 读到的却是旧版本。这在并发场景下尤其明显。我的建议是尽量避免共享可变状态让 Agent 之间通过消息传递数据而不是共享内存。如果确实需要共享状态比如任务进度用一个中心化的状态存储并且明确单一写入者原则——同一时刻只有一个 Agent 能写某个字段。注意Multi-Agent 的调试难度比单体高一个量级一定要在早期就把 trace 和日志做扎实否则出问题根本无从下手。6. 什么时候不该上 Multi-Agent过度拆分的代价6.1 简单任务拆开是负优化不是所有任务都值得 Multi-Agent。一个查天气的任务单体 Agent 一次工具调用就搞定你拆成规划、执行、校验三个 Agent反而增加了通信开销和出错概率。拆分的收益来自任务复杂度任务不够复杂时拆分就是纯成本。我给自己定的判断标准是如果单体 Agent 的 System Prompt 能控制在 500 字以内、工具不超过 5 个、单次任务步数不超过 10 步那就别拆。只有当这些指标明显超标或者出现上下文溢出、错误传播难排查时才考虑 Multi-Agent。6.2 拆分粒度按职责还是按数据拆分有两个维度按职责拆规划、执行、校验和按数据拆每个 Agent 处理一部分数据。前者适合流程型任务后者适合数据并行型任务。按数据拆的典型场景是批量处理1000 条数据要分析与其让一个 Agent 顺序跑不如开 10 个 Agent 并行处理每个负责 100 条。这种拆分收益直接体现在速度上而且 Agent 之间几乎不需要通信实现简单。按职责拆则要小心过度拆分。我见过把一个任务拆成 8 个 Agent 的项目结果光是 Agent 之间的消息传递和格式转换就占了大量 token实际推理反而成了小头。一般来说3 到 5 个 Agent 是比较舒服的区间超过 7 个就要警惕了。6.3 成本账Multi-Agent 的 token 消耗真相很多人以为 Multi-Agent 更省 token其实不一定。单体 Agent 的 token 消耗是 O(n²)Multi-Agent 虽然每个 Agent 上下文小但Agent 数量乘以调用次数总量未必更低。我实测过一个任务单体 Agent 跑完消耗约 8 万 token拆成 4 个 Agent 后总消耗约 6 万 token省了 25%。但如果拆成 8 个 Agent总消耗反而涨到 9 万——因为通信开销和重复上下文吃掉了收益。所以 Multi-Agent 的价值主要不在省钱而在突破能力上限。当单体 Agent 根本跑不通复杂任务时Multi-Agent 是唯一选择这时候讨论省不省 token 意义不大。7. 从单体到多体的迁移路径与实战心得7.1 渐进式迁移先加校验再拆执行不要一上来就把单体 Agent 大卸八块。我的推荐路径是第一步加校验 Agent。保持主体单体只在输出前加一个独立校验环节。这一步改动最小收益立竿见影能拦住大量静默错误。第二步拆出规划 Agent。把任务拆解从主循环里独立出来让主 Agent 专注执行。这一步能显著降低主 Agent 的 Prompt 复杂度。第三步按需拆执行。当工具数量超过 10 个或者出现明显的工具选择困难时再按工具类别拆执行 Agent。第四步引入编排器。当 Agent 数量超过 3 个手工调度开始混乱时引入正式的编排层。这个路径的好处是每一步都可回退而且每一步都有明确的收益信号不会出现拆完发现更糟的情况。7.2 调试 Multi-Agent 的三个实用技巧技巧一全链路 trace。每个 Message 的 sender、receiver、content、timestamp 都要记录最好能可视化。我习惯把 trace 存成 JSONL出问题直接 grep。技巧二单 Agent 可回放。每个 Agent 的输入输出要能单独回放这样定位问题时可以隔离到具体 Agent而不是在整条链上瞎找。技巧三Mock 下游。调试某个 Agent 时把下游 Agent 全部 mock 成固定返回这样能快速验证单个 Agent 的行为不受下游干扰。7.3 一个反直觉的经验Agent 越少越难调最后分享一个反直觉的观察Agent 数量少的时候反而更难调。因为 2 到 3 个 Agent 时职责边界容易模糊你很难判断某个问题该归谁。而 5 个以上 Agent 时职责划分反而清晰问题定位更直接。所以如果你决定拆不妨拆得干脆一点让每个 Agent 的职责足够单一边界足够清晰。半拆不拆的状态是 Multi-Agent 项目最容易翻车的地方。我在最近一个项目里从单体 Agent 迁移到 5 Agent 架构前期花了两周设计职责边界和消息 schema后面开发反而很顺两周就跑通了全流程。相比之下之前一个 3 Agent 的项目因为边界没划清来回重构了一个多月。这个对比让我确信Multi-Agent 的成败八成在设计阶段就决定了。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。