多 Agent 系统的三个隐形工程问题,以及一个基于 MCP 的解法

一、从一个真实场景说起

假设你在构建一个通用 AI 助理,它需要覆盖外卖点餐、日历管理、邮件处理、数据查询四个领域。

你打开代码,开始注册工具:外卖域 10 个、日历 8 个、邮件 12 个、数据查询 15 个,加上每个域的 prompt 和 skill 文件......

第一周还好。第二周新增一个电商域,你开始在代码库里找该改哪几个文件。第三周有人反馈 Agent 回答质量下降,你意识到上下文里塞了 4 万 token 的工具定义。第四周安全团队告诉你,有几个从网上下载的 skill 文件行为可疑。

这不是极端案例。这是多 Agent 系统规模稍大之后的常态。


二、三个被低估的工程问题

问题 1:工具上下文膨胀

多工具 Agent 系统最直接的问题:所有域的工具定义被一次性注入主 Agent 的上下文。

每个 tool 定义通常消耗数百 token。50 个工具轻松吃掉 3-5 万 token,而用户的实际请求可能只涉及其中 1 个域的 8 个工具。大量无关工具定义占据上下文,推理质量下降,成本上升,这两件事同时发生。

diff 复制代码
用户:"帮我点个午饭"

主 Agent 的上下文:
- 外卖工具 ×10
- 日历工具 ×8       ← 完全无关
- 邮件工具 ×12      ← 完全无关
- 数据查询工具 ×15  ← 完全无关
= 45 个工具定义,实际用到 10 个

这个问题在 Anthropic 的 Claude Code 开源社区 issue #4476 中有 182 个 upvote,有用户反馈单次对话 MCP 工具定义就消耗了 4 万 token,强需求,官方尚未解决。


问题 2:Agent 定义碎片化,业务方无法主动提供标准化能力

创建一个领域 Agent,通常需要准备三类内容:

  • Prompt:角色定义和行为规范
  • Tools:可调用的接口能力
  • Skills:领域知识、操作指南、业务规则

在现有框架下,这三类内容分散在代码库各处------prompt 在某个字符串变量里,tools 在另一个注册文件里,skill 文件在某个目录下。用户需要自己组装,业务方想主动提供完整的 Agent 能力包,几乎没有标准化的方式。

更麻烦的是:每次接入新领域,都需要修改框架代码,重新注册工具,更新 prompt,调整路由逻辑。

如果麦当劳想为开发者提供一个"标准麦当劳 Agent"------包含它自己维护的点餐流程、菜单查询逻辑、优惠券规则------现在没有一个通用的方式让它发布这个能力,让任何 Agent 框架开箱接入。


问题 3:Skills 来源混乱,安全性和业务适配性难以保证

随着 Agent Skill 生态的兴起(OpenClaw 的社区 skill 市场已有 5700+ 插件),开发者面临新的问题:从哪里获取 skill,质量和安全性如何保证?

Cisco AI 安全研究团队近期测试了一个第三方 OpenClaw skill,发现其在用户无感知的情况下执行了数据外泄和 prompt 注入。skill 仓库缺乏有效审核机制,恶意 skill 可以伪装成普通功能。

更实际的问题是业务适配性:从社区下载的通用 skill 往往和具体业务的逻辑、术语、数据格式不匹配,开发者需要二次修改,反而增加维护成本。


三、一个洞察:MCP Server 本身就是完整的 Agent 定义

解决以上三个问题,我们需要重新看待 MCP(Model Context Protocol)。

一个 MCP Server 天然包含三类信息:

MCP 能力 Agent 角色
Prompts 定义 Agent 的角色和行为规范
Resources 提供领域知识和 Skills
Tools 暴露可执行的接口能力

这意味着,一个 MCP Server 本身就是一个完整的领域 Agent 定义。

IBM 在《MCP Architecture Patterns for Multi-Agent AI Systems》中明确写道:"each MCP server acts as one AI agent"。MCP 2025-11 规范新增的 Sampling with Tools (SEP-1577) 也在协议层面支持了 MCP Server 作为 Agent 执行 multi-step 推理的能力。

这个洞察,直接给出了一种新的 multi-agent 构建方式:MCP 地址即 Agent,配置即接入。


四、解法:MCP Server as Agent

基于上述洞察,我设计了 MCP Server as Agent,核心是一个通用 Plugin 层,动态将 MCP Server 实例化为域 Agent。

架构

核心思路是:每个 MCP Server 被封装为一个标准 LangChain StructuredTool(即 MCPTool ,主 Agent 的 tools 列表就是 MCPTool 列表。主 Agent 通过 tool 的 description(来自 MCP 的 init prompt)做意图路由,调用 MCPTool 时才 lazy 创建子 Agent。

flowchart TD A["🗂️ 配置层\n[MCP-A地址, MCP-B地址, ...]"] B["🤖 主 Agent\n标准 LangChain create_agent\n持有 MCPTool 列表"] C["🔧 MCPTool(StructuredTool)\n· description = MCP init prompt\n· 被调用时 lazy 创建子 Agent"] D["🔒 子 Agent(上下文完全隔离)\nprompt: 来自该 MCP 的 Prompts\nskills: 来自该 MCP 的 Resources\ntools: 仅含该 MCP 的 Tools"] A -->|"MCPTool.from_mcp()"| B B -->|"意图路由,调用对应 MCPTool"| C C -->|"MCPLoader 加载后实例化"| D

这个设计让 MCPTool 与任意 LangChain Agent 框架完全兼容------它本质上是一个标准 tool,用户可以把它混入任何现有的 tools 列表,无需迁移现有 Agent 代码。

接入新领域,只需一行配置:

yaml 复制代码
mcp_servers:
  - name: food
    url: https://mcp.mcdonalds.cn
  - name: calendar
    url: https://mcp.calendar-service.com
  - name: new_domain      # ← 新增领域,仅此两行
    url: https://mcp.new-service.com

接入新领域,只需一行配置:

yaml 复制代码
mcp_servers:
  - name: food
    url: https://mcp.mcdonalds.cn
  - name: calendar
    url: https://mcp.calendar-service.com
  - name: new_domain      # ← 新增领域,仅此两行
    url: https://mcp.new-service.com

三个问题的对应解法

问题 1 → 工具上下文隔离:子 Agent 仅加载自己域的 tools,主 Agent 只持有各域能力的轻量摘要。用户说"帮我点外卖",进入上下文的只有外卖域的 10 个工具。

问题 2 → 业务方可以主动发布标准化 Agent:业务方只需部署一个 MCP Server,将自己的 prompt、skill 文件(作为 resources)、tools 一并封装进去。任何接入 MCP Server as Agent 的系统,通过配置 MCP 地址即可获得完整能力。麦当劳、滴滴、美团可以各自维护自己的 MCP Server,开发者不需要了解任何内部细节。

问题 3 → Skills 来自 MCP Server,安全可信:skill 文件由 MCP Server 的业务方直接提供,不经过第三方社区,来源可验证,内容与业务强适配,避免了平台 skill 市场的安全风险。


五、场景演示

以下 demo 基于一个外卖域的 mock MCP Server,用 fastmcp 启动,5 分钟可以本地跑通。

搭建 mock MCP Server(外卖域)

python 复制代码
# food_agent_server.py
import fastmcp

mcp = fastmcp.FastMCP("food-agent")

@mcp.prompt(name="init")
def init_prompt() -> str:
    return "你是一个外卖助手,帮助用户查询菜单、下单。下单前先确认地址和预算。"

@mcp.resource("skill:///ordering-guide", description="外卖点餐标准流程:确认地址 → 查菜单 → 下单")
def ordering_guide() -> str:
    return "# 点餐指南\n1. 调用 query_menu 获取菜单\n2. 根据预算筛选\n3. 调用 create_order 下单"

@mcp.tool()
def query_menu(max_price: float = 50.0) -> list[dict]:
    """查询菜单,返回价格在 max_price 以内的套餐"""
    return [
        {"id": "m1", "name": "麦辣鸡腿堡套餐", "price": 28.9},
        {"id": "m2", "name": "双层牛堡套餐",   "price": 35.0},
    ]

@mcp.tool()
def create_order(meal_id: str, address: str) -> dict:
    """创建外卖订单"""
    return {"order_id": "ORD_001", "status": "confirmed", "eta": "30分钟"}

if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="127.0.0.1", port=8765)

场景 A:MCPTool + 标准 create_agent

MCPTool 是一个标准 StructuredTool,可以直接传给任意 LangChain agent,不改任何现有代码:

python 复制代码
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from mcp_broker import MCPTool

model = ChatOpenAI(model="deepseek-chat", base_url="https://api.deepseek.com/v1")

# 将 MCP Server 封装为标准 tool,description 自动从 init prompt 读取
tools = [MCPTool.from_mcp("http://127.0.0.1:8765/mcp", model, name="food_agent")]

# 完全标准的 LangChain 用法
agent = create_agent(model, tools=tools)
result = agent.invoke({"messages": [HumanMessage(content="帮我查一下 30 元以内的套餐")]})
print(result["messages"][-1].content)
# → 根据查询结果,30元以内的套餐有:麦辣鸡腿堡套餐(28.9元)...

主 Agent 上下文里只有 food_agent 这一个 tool 的 description(来自 init prompt),而不是外卖域的所有工具定义。进入 food_agent 子 Agent 后,才加载 query_menucreate_order 等工具。

场景 B:MCPAgentLinker 便捷封装(多域)

python 复制代码
from mcp_broker import MCPAgentLinker

# 传入多个 MCP 地址,主 Agent 自动按意图路由
agent = MCPAgentLinker(
    model=model,
    mcp_urls=[
        "http://mcp.food-service.com/mcp",
        "http://mcp.calendar-service.com/mcp",
    ],
)
result = agent.invoke({
    "messages": [HumanMessage(content="查一下今天下午有没有空,有空帮我点个外卖")]
})

子 Agent 之间不直接通信,由主 Agent 编排。

场景 C:业务方发布标准 Agent

某 SaaS 公司想让自己的企业客户在任意 Agent 框架里使用自家的工单系统:

yaml 复制代码
# 他们只需要部署一个 MCP Server,包含:
Prompts:
  - name: init
    content: "你是工单助手,负责创建、查询、更新工单..."

Resources:
  - uri: skill:///ticket-guide
    content: "工单创建规范:优先级定义、SLA 要求..."

Tools:
  - create_ticket
  - query_ticket
  - update_status

接入方在配置里加一行 MCP 地址,自动获得完整的工单 Agent 能力,无需了解内部实现。


六、与现有方案对比

方案 工具加载 新域接入 Agent 定义 Skills 来源
LangGraph 全量加载 改代码 散落代码库 自行管理
CrewAI 全量加载 改代码 散落代码库 自行管理
AutoGen 全量加载 改 prompt 散落代码库 自行管理
mcp-agent 按 agent 分配 改配置 部分标准化 自行管理
MCP Server as Agent 按域隔离 加一行配置 MCP Server 自包含 业务方直接提供

七、当前进展与开放问题

MCP Server as Agent 目前核心组件已完成并通过集成测试:

  • MCPLoader :从 MCP Server 读取 prompt / tools / skills,返回结构化的 AgentDef
  • MCPTool :将 MCP Server 封装为标准 LangChain StructuredTool,完全兼容 create_agent,可混入任意现有 tools 列表
  • MCPAgentLinker:便捷封装,传入 MCP 地址列表直接返回可执行 Agent

其中 MCPTool 是这次设计迭代的核心------相比之前继承 CompiledStateGraph 的方式,MCPTool 不依赖任何框架内部机制,用户可以用完全标准的 LangChain 方式使用它。

还有一些开放问题值得探讨:

  • 子 Agent 实例的生命周期管理:复用 vs 每次新建,如何权衡延迟和内存?
  • 意图误路由的处理:主 Agent 识别错域时如何优雅降级?
  • MCP Resources 作为 Skills 的约定:是否需要推动形成社区规范?

项目地址:mcp-broker

欢迎交流,如果你也在做 MCP 相关的工程,非常想听你的想法。

相关推荐
AI大法师2 小时前
品牌IP工程化落地:9步流程+6类线上故障排查
人工智能
Sagittarius_A*2 小时前
小波变换:多分辨率分析与图像小波去噪 / 增强 / 融合【计算机视觉】
图像处理·人工智能·python·opencv·计算机视觉·小波变换
AAA小肥杨2 小时前
OpenClaw 和 GitHub 自动化,用于 PR 审核和 CI 监控
人工智能·ci/cd·自动化·大模型·github·openclaw
UCloud_TShare2 小时前
优刻得发布面向投研机构的OpenClaw安全解决方案
人工智能
AMxiaohua2 小时前
AI时代,传统企业如何用“一瓶水”的逻辑重塑竞争力?
人工智能·安盟智能·安盟ai
IT 行者2 小时前
每天了解几个MCP SERVER:提供语音合成和语音识别能力 AllVoiceLab
人工智能·语音识别
智能工业品检测-奇妙智能2 小时前
SpringBoot整合FFmpeg的方法
人工智能·ffmpeg·springboot·deepseek·openclaw
HP-Patience2 小时前
【Data Mining】01抽样技术
人工智能·数据挖掘·r语言
Rabbit_QL2 小时前
从 CLAUDE.md 到 Skill:什么时候该拆,怎么拆
人工智能