Article · AI translation
本文由 MoEngage 的 Nikhil Kumar 和 Shakir Khan 共同撰写。当工程团队开始构建 AI 智能体时,这些智能体所需的能力通常已经存在于内部 API 中:创建营销活动、查询受众细分、查看投递统计数据。难点不在于构建新功能,而在于如何让智能体安全地访问数百个私有 API,同时不将它们暴露在公共互联网上,不让模型控制身份信息,也不让数百个工具定义塞满上下文窗口。MoEngage 是一个智能体驱动的客户互动平台,超过 1,350 个消费品牌使用它,通过推送、电子邮件、应用内消息、短信、WhatsApp 和 RCS 提供个性化体验。它遇到的正是这个问题。该产品背后有约 400 个内部 REST API,由 25 个工程团队构建,运行在分布于 7 个 AWS 区域的私有虚拟私有云(VPC)中。MoEngage 按区域隔离这些 API,以履行数据驻留承诺,并且不将它们暴露在公共互联网上。智能体需要的能力已经在生产环境中运行。困难的是如何让智能体安全地访问这些能力。本文介绍 MoEngage 如何使用 Amazon Bedrock AgentCore 的一项功能 AgentCore Gateway,将这些私有 API 转化为按权限限定的智能体工具。MoEngage 估计,这种做法节省了 6 个月的平台工程工作量;现在接入一个新 API 只需数小时,而不是数天。没有产品团队编写模型上下文协议(MCP)服务器代码,没有为每项集成单独配置网络,整个访问路径中也不存在公共端点。为什么 20 个 MCP 服务器不是合适的答案 模型上下文协议(MCP)为智能体提供了发现和调用工具的标准方式。采用它的一种直接做法是让每个团队提供自己的 MCP 服务器。MoEngage 估算了这种做法的成本,并决定不采用。超过 20 个 MCP 服务器意味着有超过 20 个部署需要监控、打补丁,并随着 MCP 的演进保持协议兼容。那些有用的跨领域智能体——例如读取营销活动、检查其受众细分并查看投递统计数据的智能体——需要连接多个服务器并整合结果。而且,每个团队都得掌握与自身实际产品工作无关的 MCP 专业知识。因此,MoEngage 确立了影响后续所有设计的一项原则:各工程团队不实现 MCP。团队构建 REST API,并声明哪些操作应成为工具。AI 平台团队端到端负责 MCP 层。各团队的职责止于提供描述清晰的 OpenAPI 规范。这项原则立即带来了 3 项要求:智能体只需连接 1 次的中央工具入口,而不是分别连接各项服务;在服务器端强制执行针对每个智能体的授权,而不是依靠约定;以及无需为每个新 API 重新搭建的私有连接。也可以从头构建所有这些能力。自定义的中央 MCP 服务器可以解决 20 个服务器的问题,但 MoEngage 仍需构建工具生成流水线、策略文件格式、用于处理重命名的工具别名注册表和断路器。这些都是由一个团队负责的自定义代码,都是无法让 MoEngage 的智能体更聪明、也无法改善客户营销活动的通用性工作。塑造架构的 4 项约束 在评估任何解决方案之前,MoEngage 定义了 4 项约束,必须同时满足。只满足其中 2 项、却违反第 3 项和第 4 项的方案不可行。不能有任何公共端点。按照政策,MoEngage 的内部 API 仅在 VPC 内可访问。任何要求将其暴露出去的方案,即便增加了身份验证,也无法接受。传统的变通办法是针对每项集成配置网络:这里部署一个 NAT 网关,那里部署一个反向代理,再为第 3 项集成建立一条 VPN 隧道。将这些工作扩展到 7 个区域后,运维范围的增长速度会超过智能体数量的增长速度。每增加一个新 API,就意味着又要提出一次网络变更申请、进行一轮安全审查,并维护一项新的基础设施。身份不能由智能体决定。每次内部 API 调用都携带租户、用户、角色和数据库上下文。如果这些上下文是大语言模型(LLM)可见的工具参数,模型就可能填错,或在诱导下将其更改。MoEngage 需要从结构上使模型无法触及身份信息:由调用服务注入身份,而不将其作为模型可以设置或覆盖的内容呈现。包含 400 个工具的目录装不进上下文窗口。按每个工具的 JSON Schema 约占 50 个 token 计算,覆盖全部服务的完整 tools/list 每次连接都会传输超过 20,000 个 token。智能体还没做任何有用的事,就已经消耗了这部分 token 预算,而且挤占了它真正需要用来推理任务的上下文。在客户端过滤(ADK 或 MCP SDK 中的 tool_filter)无法解决这个问题。完整目录已经通过网络传输了,而且依靠客户端约定进行过滤并不是授权边界。不应看到写入操作的智能体,一开始就不该收到这些操作。最后这项约束使显而易见的替代方案也不合适。自定义的中央 MCP 服务器可以解决 20 个服务器的问题,但 MoEngage 仍需构建工具生成流水线、策略文件格式、用于处理重命名的工具别名注册表和断路器。这些都是由一个团队负责的自定义代码,没有一项能改善 MoEngage 的产品。AgentCore Gateway 如何对应这些约束 Amazon Bedrock AgentCore Gateway 是一个完全托管的 MCP 服务器。将 OpenAPI 规范注册为目标后,网关会据此生成 MCP 工具,并将调用路由到后端服务。它的 4 项特性直接对应 MoEngage 的约束。输入 OpenAPI,输出 MCP 工具。无需构建或运行 MCP 服务器,也无需维护与 API 保持同步的另一份制品。团队已经在维护的规范就是工具定义。每项操作都会成为一个名为 Target___operationId 的工具,例如 CampaignsAPI___searchCampaigns。规范变更时,工具随之变更。团队新增端点时,工具就会出现;删除端点时,工具就会消失。无需部署,无需协议专业知识,也无需与 AI 平台团队协调。在序列化目录之前评估 Cedar 策略。AgentCore 策略引擎使用部分求值,按主体过滤 tools/list。每个智能体都以自己的 IAM 角色进行身份验证,而其 Cedar 策略决定它能看到和调用哪些工具。这使管理 400 个工具成为可能:作用范围是在服务器端构建响应之前确定的,而不是事后在客户端过滤。例如,营销活动质检机器人可以读取营销活动和受众细分工具,但不能调用写入操作:permit( principal == Agent::"campaign-qa-bot-v1", action == Action::"tools/call", resource in ToolGroup::"campaigns-read" ); forbid( principal == Agent::"campaign-qa-bot-v1", action == Action::"tools/call", resource in ToolGroup::"write-actions" ); 该机器人在 tools/list 响应中看不到写入工具。工具根本没有发送过来,因此客户端也无需过滤。通过 Amazon VPC Lattice 实现托管出站连接。网关通过 AgentCore 托管的出站连接访问 MoEngage 的内部服务,无需 MoEngage 自行构建和运营这部分网络。在入站方向,只能通过启用了私有 DNS 的 VPC 接口端点访问网关,不存在通往它的公共路径。接入新 API 只需添加目标,无需改变网络拓扑。正是这项特性解决了跨 7 个区域重复配置网络的问题。网络只需建立 1 次,所有 API 都可使用。将语义搜索作为网关能力。借助 x_amz_bedrock_agentcore_search 功能,智能体可以描述任务来查找工具,而不必说出工具名称。这消除了对自定义发现层的需求,也顺带消除了重命名带来的脆弱性:如果 get_segment_user_count 改名为 get_segment_size,搜索受众细分用户数量的智能体仍能找到它,因为匹配依据的是描述,而不是标识符。架构在实践中的运作方式 从智能体到内部 API 的请求路径很短,每一层都有明确职责。智能体服务通过 VPC 接口端点连接 AgentCore Gateway;网关评估 Cedar 策略,并通过 Amazon VPC Lattice 上的托管出站连接,将工具调用路由到内部 API。下图展示了各组件如何连接。图 1:MoEngage AgentCore Gateway 架构 运行在 Amazon Elastic Compute Cloud(Amazon EC2)上或容器中的智能体服务调用 MCP 客户端。客户端可以是官方 MCP SDK、LangChain、Google ADK,也可以是 MoEngage 自己的智能体运行器。客户端使用该服务已有的 AWS Identity and Access Management(IAM)角色,通过 SigV4 对请求签名。请求经 HTTPS 传输至启用了私有 DNS 的 VPC 接口端点,全程不经过公共网络节点。AgentCore Gateway 接收请求并评估 Cedar 策略,以确定该主体可以查看或调用什么。随后,它通过 Amazon VPC Lattice 上的托管出站连接,将工具调用路由到内部 API。MoEngage 作出了 2 项值得说明的身份验证决策。首先,它为内部网关选择了 SigV4,而不是 JWT。这里的智能体是已经拥有 IAM 角色的服务。使用 SigV4,它们可以用已有凭证签名,无需新签发、轮换或存储凭证。MoEngage 另有一个公共 MCP 服务器,通过 AgentCore 运行时为来自 Claude 和其他客户端、经过人工身份验证的会话提供服务;它使用 OIDC JWT。那是另一个具有不同要求的服务入口。其次,身份信息通过标头传递,而不是作为工具参数传递。客户端库将一个小型 Identity 对象中的租户、用户、角色和数据库上下文转换为 X-MOE-* 标头。模型看不到这些信息,也无法设置它们。对于构建类似系统的人来说,有一个细节很重要:由于 SigV4 签名占用了 Authorization 标头,调用方转发的 bearer token 必须移到别处。MoEngage 将其放在一个专用的、带有 MoEngage 前缀的标头中。标头传递也有数量上限,因此传递哪些标头是经过选择的,而不是不断累积的。发现和执行对身份信息的要求不同。列出和搜索工具不携带租户身份;只有 tools/call 才携带。这种区分使发现操作保持轻量,也让审计记录清晰明确:每个携带身份信息的请求都是真正的数据访问。即使 Cedar 将智能体的访问范围限定在目录的一个子集,该子集仍可能很大。MoEngage 的客户端库只向模型提供一个元工具 search_tools。模型描述自己的需求,网关的语义搜索返回候选工具,只有这些候选工具会在该轮交互余下的过程中变为可调用。完整目录不会进入上下文。智能体一开始的上下文只包含 1 个工具定义,搜索后再加入少数相关工具,而不是放入数百个它永远不会使用的定义。接入新 API 团队若要将某个 API 作为智能体工具提供,会在现有的 OpenAPI 规范中添加以下代码块:paths: /campaigns: get: operationId: listCampaigns description: | 返回分页的营销活动列表。支持按状态、渠道、日期范围和标签筛选。x-moe-mcp: expose: external: false internal: true tool_description: | 按状态或渠道查找营销活动。返回营销活动 ID、名称、状态和渠道。使用返回的 campaign_id 调用 get_campaign 获取完整详情,或调用 send_campaign 启动该活动。param_overrides: status: description: | 按营销活动状态筛选。使用 'active' 查找正在运行的活动,使用 'scheduled' 查找即将开始的活动。省略此参数可查找所有活动。这个代码块中的 4 项设计选择值得解释。公开为工具必须明确选择加入。没有 x-moe-mcp 代码块的端点不是工具。持续集成(CI)不会就缺少该代码块发出警告,因为对于大多数端点,缺少它才是正确状态。缓存预热路由和迁移触发器不是智能体工具,不应促使团队将其设为工具。通过 internal 和 external 标志,团队可以独立决定将某项操作提供给内部智能体、公共 MCP 服务器,或同时提供给两者。工具描述不同于 API 描述。API 描述告诉阅读文档的开发者端点返回什么。工具描述告诉模型何时应使用该工具,以及应该传入什么。MoEngage 发现,逐字复用 API 描述会导致工具选择效果不佳。模型会根据实现细节(“返回分页列表”)而不是意图(“按状态或渠道查找营销活动”)选择工具。设置 tool_description 和 param_overrides 字段,就是为了让团队能在不改变面向开发者的文档的情况下,编写面向模型的文本。CI 流水线负责从规范到工具运行的全部工作。团队推送规范变更后,流水线会验证 x-moe-mcp 代码块、向 AgentCore Gateway 注册目标,并应用 Cedar 策略。无需手动操作,也无需向 AI 平台团队提交工单。从未考虑过 MCP 的团队,也能在流水线运行完毕时,将一项操作作为智能体工具提供。客户端库有 2 种模式。插件模式将 AgentCore Gateway MCP 服务器封装为 LangChain、Google ADK 或兼容 MCP 的框架中的工具提供方。智能体运行器模式则运行完整的智能体循环,供希望拥有独立智能体、但不想采用框架的团队使用。MoEngage 当前的运行情况 如今,MoEngage 已在 7 个 AWS 区域部署 AgentCore Gateway。网关向 10 个内部智能体提供约 400 项已注册的 API 操作。没有产品团队编写过 MCP 服务器代码,没有产品团队为智能体集成配置过网络,也没有产品团队实现过 Cedar 策略。这些工作都由 AI 平台团队负责,而接入新 API 的成本仅是添加规范注释并运行一次 CI。AgentCore 功能的可用性因区域而异。有关支持的区域,请参阅 Amazon Bedrock AgentCore 文档。该系统已在生产环境运行了 3 个月。这些智能体覆盖营销团队成员日常接触的工作流程。营销活动质检智能体在活动启动前验证定向规则和内容。投递健康状况智能体监控各渠道的发送率和退信模式。受众细分构建智能体将自然语言描述的受众转换为受众细分查询。每个智能体都使用自己的 IAM 角色进行身份验证,只能看到其 Cedar 策略允许的工具,并通过描述任务来发现工具,而无需记住工具名称。MoEngage 估计,由于无需构建和运营 20 个独立的 MCP 服务器,也无需在 7 个区域为每个 API 配置网络,这种做法节省了约 6 个月的工程工作量。现在接入新 API 只需花数小时添加规范注释,而不再需要花数天配置网络和进行安全审查。先搜索再调用的模式改变了 MoEngage 对智能体设计的思考方式。新智能体起初不包含任何硬编码的工具引用。它们描述意图、接收候选工具,然后调用找到的工具。团队重命名某项操作或推出新操作时,现有智能体无需更改代码就能使用它。结论 MoEngage 这套方法背后的关键见解是按工程组织的实际工作方式划分职责。产品团队负责 API,并清晰描述它们。平台团队负责协议层、策略层和连接层。AgentCore Gateway 消除了两者之间的通用性工作,使这种分工切实可行:无需 MCP 服务器代码,无需为每个 API 配置网络,也无需把客户端过滤当作授权。最终,在这个智能体系统中,添加新工具只需修改规范,限制访问只需修改策略,两者都不要求另一团队参与。要开始使用 AgentCore Gateway,请参阅 Amazon Bedrock AgentCore 文档。有关编写 Cedar 策略的信息,请参阅 Cedar 策略语言参考文档。有关私有连接模式的信息,请参阅 Amazon VPC Lattice 文档。如果想讨论适用于贵组织的类似架构,请联系您的 AWS 客户经理或与 AWS 联系。关于作者 Nikhil Kumar Nikhil 是 MoEngage 首席技术官办公室的首席软件工程师,负责领导构建智能体 AI 能力的 AI Labs 团队。他的工作涵盖 MCP 服务器和工具目录架构、LLM 网关与路由基础设施,以及评估用于内部工具和公共智能体体验的智能体框架。他拥有超过 4 年大规模构建软件和云基础设施的经验。Shakir Khan Shakir 是 MoEngage 的架构师,负责领导 API 治理,并构建支撑该公司客户互动平台的核心流式处理基础设施。他的工作涵盖网关架构、使用 Flink 和 Kafka 进行实时流式处理,以及大规模数据迁移。他拥有超过 11 年设计服务于数十亿次客户互动的系统的经验,其中包括在 MoEngage 工作的 5 年。Bhupesh Chadha Bhupesh 是 Amazon Web Services 的首席客户经理,与独立软件供应商(ISV)合作,使其平台战略与业务目标保持一致。他与首席管理层和高级领导团队合作,推动增长、将新能力推向市场,并将技术投资转化为客户覆盖范围和差异化优势。Anant Murarka Anant 是 Amazon Web Services 的解决方案架构师,与 ISV 客户合作设计多租户架构,并推动 AI 驱动的解决方案投入生产。他的专业领域包括智能体 AI、智能体编排模式、负责任的 AI,以及帮助产品公司在 AWS 上采用生成式 AI。工作之余,Anant 热衷于探索新兴 AI 范式如何重塑软件产品的构建和交付方式。