多 Agent 协作的工程挑战——Demo 好看,生产很难
多 Agent 协作的工程挑战——Demo 好看,生产很难
适读人群:正在考虑或已经在做多 Agent 系统的工程师 | 阅读时长:约 12 分钟 | 核心价值:一个判断框架,帮你区分"真的需要多 Agent"和"过度设计",附真实案例
去年我做过一个需求,大致是这样的:给定一家公司的名字,自动生成一份投资尽调报告。
需要搜索新闻、查财务数据、分析竞争格局、评估管理团队、输出风险摘要。
按照当时多 Agent 的热度,我理所当然地想:这不就是多 Agent 的典型场景吗?分配几个专门的 Agent——新闻搜索 Agent、财务分析 Agent、竞争分析 Agent、综合报告 Agent——互相协作,完美。
我花了三周做出了一个原型。演示效果很好,每个 Agent 各司其职,看起来很专业。
然后我花了两周把它推翻,用一个 Agent + 工具调用重写了。
多 Agent 原型的真实问题
让我说说那个"好看的多 Agent 原型"在生产里遇到的问题。
协调成本高得出乎意料。
每个 Agent 之间要通信。A Agent 完成了,要把结果传给 B Agent,B Agent 要知道 A 做了什么。这些协调逻辑,在 Demo 里你可以假设它完美运行,但在生产里,消息格式不对、Agent 理解了上下文的一部分、某个 Agent 的输出格式和下一个 Agent 的期望格式不匹配……这些问题层出不穷。
调试变得非常困难。
单 Agent 的调试:你看它的输入是什么、工具调用了什么、输出是什么,很直观。多 Agent 出问题了:是 A 的输出有问题,还是 B 对 A 的输出理解有问题,还是协调层的传递出了问题?定位一个 bug 要追好几个 Agent 的日志。
延迟叠加。
每个 Agent 都要调用 LLM。如果串行执行,总延迟是各 Agent 延迟之和。我那个尽调报告,串行跑完 4 个 Agent 要 3-5 分钟,而且还不稳定。
Token 消耗翻倍。
每个 Agent 都有自己的 System Prompt,每次对话都要把上下文发给 LLM。多 Agent 场景下,同样的信息可能被多个 Agent 重复处理,token 消耗远高于单 Agent。
我为什么最终换回单 Agent
换掉多 Agent 的决定是在某天下午做的。我在修一个 bug:财务分析 Agent 给出了一个结论,综合报告 Agent 在引用这个结论的时候改变了细节,输出了一个不准确的数据。
我花了一个下午追这个问题。最后发现根因:财务 Agent 的输出格式是自然语言,综合 Agent 在理解这段文字的时候引入了偏差。
我意识到:这些 Agent 之间的通信用的是自然语言,而自然语言是有歧义的。每次 Agent 之间传递信息,都是一次潜在的失真点。
而单 Agent + 工具调用的架构:
- 工具调用的输入输出是结构化的,不会失真
- 所有工具调用的结果都在同一个上下文窗口里,LLM 可以直接看到所有信息做综合判断
- 调试直接:看这一个 Agent 的调用链
我花了 3 天用单 Agent 重写,性能更好,稳定性更高,代码量少了一半。
判断框架:什么时候真的需要多 Agent
我总结了一个判断方法,三个问题:
问题一:任务能不能并行?
如果你的任务是天然串行的(B 依赖 A 的结果,C 依赖 B 的结果),多 Agent 带来的只是复杂度,没有吞吐量提升。
如果任务可以并行(搜索新闻、查财务数据、分析竞争格局可以同时进行),多 Agent 可以把总时间从"各任务之和"压缩到"最长任务的时间"。这是多 Agent 真正有价值的地方之一。
问题二:单个上下文窗口装得下吗?
GPT-4o 支持 128k token 上下文。对于大多数任务,这个窗口已经足够把所有工具调用结果都放进去让 LLM 综合判断。
如果你的任务确实需要同时处理几十万 token 的信息(比如同时分析 100 份文档),上下文窗口装不下,这时候分多个 Agent 分头处理才有意义。
问题三:专门化真的带来质量提升吗?
有些任务,给一个 LLM 安排专门的角色("你是一个专注于财务分析的专家")确实能提升质量,因为 System Prompt 可以深度定制。
但我的实际测试是:对于大多数任务,一个有完善工具调用能力的通用 Agent,比几个专门 Agent 协作的效果更好,因为通用 Agent 有完整的上下文。
判断结论:
如果三个问题都是"否"——任务串行、上下文装得下、专门化不必要——那就是典型的过度设计,单 Agent 就够了。
只有至少有一个问题答案是"是",多 Agent 才值得考虑。
真的需要多 Agent 的场景
讲了这么多"不需要",讲几个真正需要的场景。
场景一:大规模并行处理
你需要同时分析 50 份合同,找出其中的风险条款。用单 Agent 串行处理需要很长时间。用多个 Worker Agent 并行处理,一个协调 Agent 汇总结果,这是多 Agent 真正有价值的地方。
# 并行 Agent 的正确用法
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI()
async def analyze_single_contract(contract_text: str) -> dict:
"""单个合同分析 Agent"""
response = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "分析合同风险,输出JSON格式"},
{"role": "user", "content": contract_text}
]
)
return {"result": response.choices[0].message.content}
async def analyze_contracts_parallel(contracts: list[str]) -> list[dict]:
"""并行分析多份合同"""
# 真正意义上的并行,这才是多 Agent 的价值
tasks = [analyze_single_contract(contract) for contract in contracts]
results = await asyncio.gather(*tasks)
return list(results)场景二:需要相互独立的视角
你想对一份方案同时进行"支持者视角"和"反对者视角"的分析,然后综合这两个视角。两个 Agent 如果在同一个上下文里,一个的观点可能影响另一个。独立的两个 Agent 分开分析,最后让第三个 Agent 综合,这种场景有一定价值。
场景三:上下文确实超过窗口限制
处理非常长的文档,比如一本书的内容分析,128k token 装不下,就需要多个 Agent 分章节处理,最后汇总。
如果真的要做多 Agent,工程上要注意什么
我踩过坑,给几条具体建议:
Agent 之间的通信必须结构化
Agent 之间传递信息,一定要用结构化数据(JSON Schema),不要用自然语言。这是防止"失真传递"最有效的手段。
# 错误做法:自然语言传递结果
agent_a_result = "该公司2023年营收约为50亿,同比增长约15%,但利润率有所下滑..."
# 正确做法:结构化传递
from pydantic import BaseModel
from typing import Optional
class FinancialAnalysisResult(BaseModel):
revenue_2023: float # 单位:亿元
revenue_growth_yoy: float # 百分比
profit_margin: float
profit_margin_trend: str # "increasing", "stable", "declining"
key_findings: list[str]
data_confidence: str # "high", "medium", "low"做好每个 Agent 的错误处理
多 Agent 系统的一个 Agent 失败,不应该让整个流程崩溃。要有降级策略:
async def safe_agent_call(agent_func, *args, fallback=None, **kwargs):
try:
return await agent_func(*args, **kwargs)
except Exception as e:
print(f"Agent 调用失败: {e}")
if fallback is not None:
return fallback
return {"error": str(e), "status": "failed"}限制协作深度
多 Agent 系统里,Agent 之间的协作层数超过 2-3 层就很难调试了。如果你发现自己在设计"A 调 B,B 调 C,C 再回调 A"这种结构,停下来重新想想是不是设计有问题。
可观测性是强需求
单 Agent 你可以用 print 调试,多 Agent 不行。一定要在每个 Agent 的关键节点打结构化日志:
import logging
import time
logger = logging.getLogger("agent")
class AgentLogger:
def log_agent_start(self, agent_name: str, task: str):
logger.info({"event": "agent_start", "agent": agent_name, "task": task[:100]})
def log_agent_complete(self, agent_name: str, duration_ms: float, result_summary: str):
logger.info({
"event": "agent_complete",
"agent": agent_name,
"duration_ms": duration_ms,
"result_summary": result_summary[:200]
})
def log_agent_failed(self, agent_name: str, error: str):
logger.error({"event": "agent_failed", "agent": agent_name, "error": error})我现在对多 Agent 的判断
两年做下来,我的结论是:
多 Agent 是解决特定工程问题的工具,不是 AI 应用的必选项。
很多"看起来需要多 Agent"的场景,仔细分析后都可以用"单 Agent + 更好的工具调用设计"解决,而且更稳定、更便宜、更好调试。
多 Agent 真正有价值的场景不多:大规模并行处理、需要独立视角的分析、上下文超限的长文档处理。
如果你的 Demo 用了多 Agent,在把它推向生产之前,先认真问自己:我是不是把它复杂化了?
很多时候,把这个问题问出来,你就会发现答案是"是的"。
