构建多智能体系统:何时使用以及如何正确使用

多智能体系统并不总是比单智能体更好——只有在上下文污染、并行执行和专业分工这三个明确场景下,引入多智能体才值得付出额外的协调成本。本文将帮你判断自己的项目是否真的需要多智能体架构,以及如果需要,应该如何正确拆分和编排。

Agent System Architecture
图片来源:Unsplash


为什么要从单智能体开始

核心问题:为什么不直接用多智能体系统来解决问题?

一个设计良好的单智能体,配合合适的工具集,能完成的事情远超大多数开发者的预期。多智能体系统引入了显著的开销——每一个额外的智能体都意味着一个潜在的故障点、一组需要维护的提示词,以及一个不可预期行为的来源。

在实践中有一种非常常见的现象:团队花数月时间搭建了精巧的多智能体架构,分别为规划、执行、审查和迭代各设一个智能体,结果发现每次交接都会丢失上下文,智能体之间协调消耗的 token 比实际执行工作还多。测试数据显示,完成同等任务,多智能体方案通常消耗的单 token 量是单智能体方案的 3 到 10 倍。这些额外开销来自三个方面:跨智能体的上下文重复、智能体之间的协调消息、以及交接时的结果摘要。

反思: 我见过不少团队把”多智能体”等同于”更高级的架构”,好像智能体越多系统就越智能。但现实恰恰相反——如果你的单智能体还没调好提示词和工具配置,加更多智能体只会把问题放大三到十倍。简单方案先跑通,复杂度是最后才加的东西。

本节小结: 多智能体不是默认选项,而是特定约束下的手段。在确认单智能体确实无法满足需求之前,不要贸然引入多智能体架构。


多智能体系统的决策框架

核心问题:到底什么情况下多智能体系统才真正有价值?

多智能体架构的价值在于解决单智能体无法克服的特定约束。只有在收益明确大于成本时,才值得引入。以下三种模式是在实践中被反复验证过的、能稳定产生正向回报的场景。

上下文隔离

核心问题:当上下文窗口被无关信息填满时,如何防止模型性能下降?

大语言模型的上下文窗口是有限的,随着上下文增长,响应质量会下降。当一个智能体的上下文中积累了与后续子任务无关的信息时,就发生了”上下文污染”。子智能体提供了一种隔离机制——每个子智能体在独立的、干净的上下文中运行,只关注自己的特定任务。

场景示例:客服系统中的订单查询与技术诊断

想象一个客服智能体,既需要查询订单历史,又需要诊断技术问题。如果每次订单查询都往上下文里塞入几千个 token 的订单详情,智能体推理技术问题的能力就会被稀释。

单智能体方式的问题在于,所有信息都堆积在同一个对话上下文中:

# 单智能体:所有内容堆积在同一个上下文里
conversation_history = [
    {"role": "user", "content": "我的订单 #12345 无法使用"},
    {"role": "assistant", "content": "让我查一下您的订单..."},
    # 工具返回结果添加了 2000+ token 的订单历史
    {"role": "user", "content": "...(订单详情、历史购买记录、物流信息)..."},
    {"role": "assistant", "content": "现在让我诊断技术问题..."},
    # 上下文已被不需要的订单详情污染
]

多智能体方式将订单查询和技术诊断分离:

from anthropic import Anthropic

client = Anthropic()

class OrderLookupAgent:
    def lookup_order(self, order_id: str) -> dict:
        # 独立上下文,只处理订单查询
        messages = [
            {"role": "user", "content": f"获取订单 {order_id} 的关键信息"}
        ]
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1024,
            messages=messages,
            tools=[get_order_details_tool]
        )
        # 只返回精炼后的摘要
        return extract_summary(response)

class SupportAgent:
    def handle_issue(self, user_message: str):
        if needs_order_info(user_message):
            order_id = extract_order_id(user_message)
            # 只获取需要的信息,而非全部历史
            order_summary = OrderLookupAgent().lookup_order(order_id)
            # 注入紧凑摘要,而非完整上下文
            context = f"订单 {order_id}{order_summary['status']},购买日期 {order_summary['date']}"
        
        # 主智能体上下文保持干净
        messages = [
            {"role": "user", "content": f"{context}\n\n用户问题:{user_message}"}
        ]
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=2048,
            messages=messages
        )
        return response

订单查询子智能体处理完整的订单历史并提取摘要,主智能体只收到它真正需要的 50-100 个 token,上下文始终保持聚焦。

上下文隔离在以下条件同时满足时效果最佳:

条件 说明
子任务产生大量上下文 超过 1000 token
大部分信息与主任务无关 需要过滤后才可使用
子任务定义清晰 有明确的信息提取标准
操作类型为查找或检索 天然适合”查完即弃”模式

Data Filtering Concept
图片来源:Unsplash

并行化

核心问题:当需要覆盖更大的信息搜索空间时,如何让多个智能体同时工作来提升结果质量?

并行运行多个智能体可以让你探索比单智能体更大的搜索空间。这种模式在搜索和研究类任务中价值尤为突出。

场景示例:多维度课题研究

假设你需要研究一个复杂问题,比如”2025年全球电动车市场趋势”。单智能体只能按顺序逐个维度搜索,而多智能体可以同时从技术路线、政策法规、市场竞争、供应链等多个维度并行展开调研。

import asyncio
from anthropic import AsyncAnthropic

client = AsyncAnthropic()

async def research_topic(query: str) -> dict:
    # 主智能体将查询拆分为多个研究维度
    facets = await lead_agent.decompose_query(query)
    
    # 生成子智能体并行研究每个维度
    tasks = [
        research_subagent(facet) 
        for facet in facets
    ]
    results = await asyncio.gather(*tasks)
    
    # 主智能体综合各维度的发现
    return await lead_agent.synthesize(results)

async def research_subagent(facet: str) -> dict:
    """每个子智能体拥有独立的上下文窗口"""
    messages = [
        {"role": "user", "content": f"研究主题:{facet}"}
    ]
    response = await client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=4096,
        messages=messages,
        tools=[web_search, read_document]
    )
    return extract_findings(response)

这里需要特别注意一个容易误解的地方:并行化的核心收益是全面性,而不是速度。多智能体系统通常消耗 3 到 10 倍于单智能体的 token,虽然并行减少了总执行时间(相比把同样的工作串行执行),但由于总计算量的增加,整体耗时往往还是比单智能体更长。你换来的是更全面的结果覆盖,而非更快的响应。

反思: 很多人在听到”并行”这个词时,第一反应是”更快”。但在多智能体场景下,并行的主要价值是”更全”。如果你追求的是响应速度,优化单智能体往往是更好的选择。如果你的场景真的需要”把每个角落都搜一遍”,那并行多智能体的额外成本才是值得的。

本节小结: 并行化适用于需要广泛覆盖信息空间的场景,代价是更高的 token 消耗和可能更长的总执行时间。

专业化

核心问题:当不同任务需要不同的工具集、提示策略或领域知识时,如何通过分工提升可靠性?

不同任务有时需要不同的工具集、系统提示或领域专长。与其给一个智能体塞入几十个工具,不如让专业化智能体只配备与自己职责匹配的聚焦工具集,这样可以显著提升可靠性。

专业化体现在三个层面:

工具集专业化

当一个智能体拥有过多工具时,性能会下降。以下三个信号表明你需要考虑工具专业化:

  1. 数量过多。 智能体拥有 20 个以上工具时,选择正确工具的能力显著下降。
  2. 领域混淆。 工具跨越多个不相关领域(数据库操作、API 调用、文件系统操作)时,智能体会搞混该用哪个领域的工具。
  3. 性能退化。 新增工具反而导致已有任务的表现下降,说明智能体的工具管理能力已到极限。

系统提示专业化

不同任务需要不同的角色设定、约束和指令,而这些指令在合并时会产生冲突。客服智能体需要耐心和同理心,代码审查智能体需要精准和批判性,合规检查智能体需要严格遵循规则,头脑风暴智能体需要创造性发散。当一个智能体必须在这些冲突的行为模式之间切换时,拆分为各自拥有定制提示词的专业智能体会产生更一致的结果。

领域知识专业化

某些任务需要深度的领域背景知识,如果全部塞入通用智能体,会严重挤占上下文窗口。法律分析智能体可能需要大量判例和法规框架,医学研究智能体可能需要临床试验方法论的专门知识。与其把这些全装进一个智能体,不如让专业化智能体各带各的领域知识。

场景示例:跨平台集成系统

假设一个集成系统需要同时操作 CRM、营销自动化和消息平台,每个平台有 10-15 个相关 API 端点。单个智能体面对 40+ 工具时经常选错,混淆不同平台上相似的操 作。拆分为专业化智能体后,问题迎刃而解:

from anthropic import Anthropic

client = Anthropic()

class CRMAgent:
    """处理客户关系管理操作"""
    system_prompt = """你是一名 CRM 专员。你负责管理联系人、商机和账户记录。
    更新前必须验证记录归属权,并维护关联记录之间的数据完整性。"""
    tools = [
        crm_get_contacts,
        crm_create_opportunity,
        # 8-10 个 CRM 专用工具
    ]

class MarketingAgent:
    """处理营销自动化操作"""
    system_prompt = """你是一名营销自动化专员。你负责管理营销活动、线索评分和邮件序列。
    优先保证数据卫生,尊重联系人的偏好设置。"""
    tools = [
        marketing_get_campaigns,
        marketing_create_lead,
        # 8-10 个营销专用工具
    ]

class OrchestratorAgent:
    """将请求路由到专业化智能体"""
    def execute(self, user_request: str):
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1024,
            system="""你负责协调平台集成。将请求路由到合适的专业人员:
- CRM:联系人记录、商机、账户、销售管道
- 营销:营销活动、线索培育、邮件序列、评分
- 消息:通知、告警、团队沟通""",
            messages=[
                {"role": "user", "content": user_request}
            ],
            tools=[delegate_to_crm, delegate_to_marketing, delegate_to_messaging]
        )
        return response

这种模式如同高效的团队协作——各自掌握与自己角色匹配的工具的专家,比试图精通所有领域的通才协作效果更好。但专业化也引入了路由复杂度:编排智能体必须正确分类请求并委派给合适的子智能体,路由错误会导致糟糕的结果。同时维护多个专业化智能体也增加了提示词维护成本。专业化在领域边界清晰、路由决策无歧义时效果最好。


单智能体架构何时不再够用

核心问题:有哪些具体的信号表明你已经超出了单智能体的能力边界?

除了上面的一般性框架,以下具体信号可以帮助你判断是否该考虑升级架构:

信号 表现 建议动作
逼近上下文限制 智能体频繁使用大量上下文且性能明显下降 考虑上下文隔离,但先评估上下文压缩技术
管理过多工具 智能体拥有 15-20+ 工具,选择准确度下降 先尝试工具搜索工具(可减少高达 85% token 用量),再考虑拆分
存在可并行的子任务 任务可自然分解为独立片段(多源研究、多组件测试) 适合引入并行子智能体

反思: 注意”先尝试 X,再考虑 Y”这个顺序。文中特别提到,在跳到多智能体方案之前,上下文压缩和工具搜索这两个单智能体层面的优化手段可能就够用了。这再次印证了一个原则:把简单方案用到极致,再考虑加复杂度。

需要强调的是,这些阈值会随着模型的进步而变化。当前的数字代表实用指南,而非根本性约束。


以上下文为中心的分解策略

核心问题:拆分多智能体工作时,应该按”做什么”来分还是按”需要什么上下文”来分?

采用多智能体架构时,最重要的设计决策是如何在智能体之间分配工作。实践中,很多团队在这个问题上做错了选择,导致协调开销完全抵消了多智能体设计的优势。

关键洞察是:按上下文边界分解,而不是按问题类型分解

按问题类型分解(通常适得其反): 按”做什么”来分工——一个智能体写功能、一个写测试、一个审查代码——会产生持续的协调开销。每次交接都丢失上下文:写测试的智能体不知道为什么做了某些实现决策,审查代码的智能体缺少探索和迭代过程的上下文。

按上下文边界分解(通常有效): 按上下文来分工——处理某个功能的智能体同时处理它的测试,因为它已经具备了所需的上下文。只有在上下文可以真正隔离时才拆分工作。

这个原则来自对多智能体系统失败模式的观察。当智能体按问题类型拆分时,它们陷入”传话游戏”——信息来回传递,每次交接都降低保真度。在一项实验中,按软件开发角色(规划者、实现者、测试者、审查者)分工的子智能体,花在协调上的 token 比实际工作还多。

有效的分解边界和有问题的分解边界对比如下:

分解方式 有效 ✅ 有问题 ❌
独立研究路径 “亚洲市场趋势” vs “欧洲市场趋势”——无共享上下文,可并行
接口清晰的独立组件 前后端通过定义好的 API 契约并行开发
黑盒验证 验证者只需运行测试并报告结果,不需要实现上下文
同一工作的顺序阶段(规划→实现→测试共享太多上下文)
紧耦合组件(需要频繁来回交互的应留在同一智能体)
需要共享状态的工作(需要频繁同步理解的应合并)

Collaboration vs Silos
图片来源:Unsplash

独特见解: “按上下文分解”这个原则其实不仅适用于多智能体系统。想想人类团队的组织方式——最痛苦的协作往往发生在”需要相同信息却被分到不同部门”的人之间。多智能体系统的分解逻辑和人类组织设计在底层是相通的:减少不必要的信息传递,让拥有上下文的人(或智能体)做需要该上下文的决策。


验证子智能体模式

核心问题:如何让一个独立的智能体可靠地验证另一个智能体的输出?

在所有多智能体模式中,验证子智能体是跨领域表现最稳定的一种。这是一个专职智能体,唯一职责就是测试或验证主智能体的工作。

值得注意的是,能力更强的编排模型(如 Claude Opus 4.5)正在越来越多地能够直接评估子智能体的工作,无需额外的验证步骤。但验证子智能体在以下情况下仍然有价值:使用能力较弱的编排模型时、验证需要专门工具时、以及你希望在工作流中强制执行显式验证检查点时。

验证子智能体之所以有效,是因为它天然绕过了”传话游戏”问题。验证本质上只需要最少的上下文传递——验证者可以在不了解构建过程完整历史的情况下,对产物进行黑盒测试。

具体实现

主智能体完成一个工作单元后,在继续之前生成一个验证子智能体,携带待验证的产物、清晰的通过标准和执行验证的工具:

from anthropic import Anthropic

client = Anthropic()

class CodingAgent:
    def implement_feature(self, requirements: str) -> dict:
        """主智能体实现功能"""
        messages = [
            {"role": "user", "content": f"实现以下需求:{requirements}"}
        ]
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=4096,
            messages=messages,
            tools=[read_file, write_file, list_directory]
        )
        return {
            "code": response.content,
            "files_changed": extract_files(response)
        }

class VerificationAgent:
    def verify_implementation(self, requirements: str, files_changed: list) -> dict:
        """独立智能体验证工作成果"""
        messages = [
            {"role": "user", "content": f"""
需求:{requirements}
变更文件:{files_changed}

请运行测试套件并验证:
1. 所有现有测试通过
2. 新功能按规格正常工作
3. 没有明显的错误或安全问题

你必须在标记为通过之前运行完整的测试套件。
不要在只运行了少数测试后就标记为通过。
运行:pytest --verbose
只有在所有测试通过且无失败时才标记为 PASSED。
"""}
        ]
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=4096,
            messages=messages,
            tools=[run_tests, execute_code, read_file]
        )
        return {
            "passed": extract_pass_fail(response),
            "issues": extract_issues(response)
        }

def implement_with_verification(requirements: str, max_attempts: int = 3):
    for attempt in range(max_attempts):
        result = CodingAgent().implement_feature(requirements)
        verification = VerificationAgent().verify_implementation(
            requirements,
            result['files_changed']
        )
        
        if verification['passed']:
            return result
        
        requirements += f"\n\n上次尝试失败,问题如下:{verification['issues']}"
    
    raise Exception(f"经过 {max_attempts} 次尝试后仍未通过验证")

适用场景

验证子智能体在以下场景中效果显著:

  • 质量保障: 运行测试套件、代码检查、按 schema 验证输出
  • 合规检查: 验证文档是否满足策略要求、按规则检查输出
  • 输出验证: 在交付前确认生成内容符合规格
  • 事实核查: 让独立智能体验证生成内容中的声明或引用

“提前宣布胜利”问题

核心问题:验证智能体为什么经常”偷懒”,如何防止它在不充分测试的情况下就给出通过结论?

验证子智能体最显著的失败模式是:不加彻底测试就标记输出为通过。验证者跑了一两个测试,看到通过了,就宣布成功。

这个问题的本质是智能体倾向于走捷径——它看到了部分证据就推断整体通过,而不是真正执行完整的验证流程。

应对策略包括:

策略 具体做法 示例
具体化标准 用精确的指令替代模糊要求 “运行完整测试套件并报告所有失败” 而非 “确保能用”
全面检查要求 要求验证多个场景和边界情况 “测试正常路径、边界输入和错误处理”
加入反向测试 要求验证者尝试应该失败的输入 “用无效参数调用并确认返回了正确的错误码”
显式强制指令 明确禁止跳过步骤 “你必须在标记通过之前运行完整测试套件”

反思: “提前宣布胜利”这个失败模式让我联想到人类审计中的类似问题——审计员抽查了几个样本就出具”无重大问题”的结论。无论是人还是 AI,当验证工作本身很耗时且枯燥时,都会倾向于”看到好的迹象就收手”。解决方案也相通:把验证标准从模糊的”确保没问题”变成精确的”执行这 5 个具体检查项,每项都给出明确结果”。


实用摘要与操作清单

决策操作清单

在引入多智能体架构之前,逐项确认以下内容:

  • [ ] 单智能体是否已经调优? 提示词是否经过充分迭代?工具配置是否合理?
  • [ ] 是否存在多智能体才能解决的真正约束? 具体是上下文污染、可并行化、还是专业化需求?
  • [ ] 是否尝试过单智能体层面的优化? 上下文压缩、工具搜索工具等方案是否已评估?
  • [ ] 分解是否按上下文边界而非问题类型? 确认没有把紧密相关的连续阶段拆到不同智能体
  • [ ] 是否有清晰的验证点? 子智能体能否在不依赖完整上下文的情况下独立验证工作?
  • [ ] 是否接受了成本权衡? 3-10 倍 token 开销、更长的总执行时间(并行化场景)、更高的维护复杂度

一页速览

维度 要点
默认选择 始终从单智能体开始,简单方案先跑通
三大有效场景 上下文隔离、并行化、专业化
核心分解原则 按上下文边界分解,不按问题类型分解
最可靠模式 验证子智能体——黑盒测试天然适合独立验证
最常见错误 按角色拆分(规划/实现/测试/审查)导致传话游戏
最常见验证错误 “提前宣布胜利”——需用显式强制指令对抗
成本预期 通常 3-10 倍 token 开销,换来的不是速度而是全面性/可靠性
升级前检查 先尝试上下文压缩和工具搜索工具,再考虑多智能体

常见问答

Q1:多智能体系统比单智能体系统更快吗?

不一定。虽然并行化减少了相比串行执行的时间,但由于总计算量大幅增加(3-10 倍 token),多智能体系统的总执行时间往往比单智能体更长。并行化的核心收益是结果更全面,而非速度更快。

Q2:一个智能体最多能管理多少个工具?

当工具数量超过 15-20 个时,选择准确度通常会开始下降。但在此之前,应先尝试工具搜索工具(按需发现工具而非预加载全部定义),这可以减少高达 85% 的 token 用量并提升选择准确度,可能无需拆分智能体。

Q3:为什么按”规划-实现-测试-审查”角色拆分智能体效果不好?

因为这些阶段共享大量上下文。实现者不知道规划者的探索过程,测试者不知道实现者的设计决策,审查者缺少整个迭代历史。每次交接都是一次”传话游戏”,信息保真度不断下降,协调开销超过实际工作开销。

Q4:验证子智能体和让主智能体自我审查有什么区别?

主智能体自我审查容易受到”确认偏差”影响——它倾向于认可自己的输出。验证子智能体在独立上下文中运行,没有构建过程的先入为主,更容易发现问题。但能力足够强的编排模型可以部分替代独立验证子智能体。

Q5:上下文隔离在什么情况下效果最好?

当子任务产生超过 1000 token 但大部分与主任务无关的信息、子任务定义清晰有明确提取标准、且操作类型为查找或检索时,上下文隔离效果最好。

Q6:专业化拆分后,编排智能体路由错误怎么办?

路由错误是专业化模式的主要风险。缓解方式包括:确保领域边界清晰无歧义、在编排智能体的系统提示中明确每种请求类型的路由规则、以及对路由决策本身增加验证逻辑。如果领域边界模糊,说明专业化拆分可能不合适。

Q7:”提前宣布胜利”问题只出现在验证智能体中吗?

这是一个普遍倾向,但在验证场景中危害最大,因为验证的整个价值在于”真正发现问题”。在其他场景中也可能出现类似捷径行为,只是后果不那么严重。应对的核心方法一致:用精确、具体、不可跳过的指令替代模糊要求。

Q8:多智能体系统的 token 开销具体来自哪里?

主要来自三个方面:每个智能体都需要自己的上下文(上下文重复)、智能体之间需要交换协调消息、以及在智能体之间传递结果时需要做摘要压缩。这三者叠加导致同等任务下 3-10 倍的 token 消耗。