跳到主要内容

世界没有预发布环境

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的技术栈通常有三个环境。开发环境(Dev)是可抛弃的,预发环境(Staging)是类生产环境,而生产环境(Prod)是神圣不可侵犯的。二十年的工程文化——CI 门禁、金丝雀发布、蓝绿部署——全都建立在这种分层之上。但当你给智能体(Agent)一个调用 Salesforce、QuickBooks 或 Gmail 的工具时,这种分层就悄然消失了。对于客户的组织来说,并没有“预发环境下的 Salesforce”。也没有发票账本的影子副本。一旦工具调用跨越网络边界进入第三方 SaaS,环境就只剩下一个,那就是生产环境。

这是智能体工程(Agent Engineering)中最少被讨论的鸿沟。我们已经擅长对智能体的“计算”进行沙箱化处理——容器、出口白名单、资源配额。我们在评估智能体的“推理”方面也做得还行——离线评估、LLM 作为评委、轨迹评分。但智能体对“外部世界”的操作仍然是在包含真实客户数据的生产系统上运行的,因为对于大多数 SaaS 界面来说,除此之外别无他法。团队只能通过仅有的两种方式悄悄解决这个问题:要么在生产环境中测试,要么根本不测试。

为什么你的 Dry-Run 标志不起作用

第一直觉通常是自己构建安全层:给每个写入工具添加一个 dry_run 参数,记录负载(Payload)而不是发送它,然后宣称系统已经过测试。这比什么都不做要好,但大部分时候只是“工程演戏”。

API 边界这边的 Dry-Run 只能验证你的智能体“构建”了一个请求。它无法告诉你服务商会对这个请求“做”什么。真正致命的故障模式往往发生在网线的另一端:

  • 服务商侧的校验。Salesforce 可能会因为管理员上季度添加的一条校验规则而拒绝更新商机。你的 Dry-Run 根本不知道那条规则的存在。智能体的计划在日志里看起来完美无缺,结果在生产环境的第三步就挂了。
  • 你看不到的副作用。在 QuickBooks 中创建发票可能会触发给客户发送邮件。更新 CRM 阶段可能会触发十个下游自动化流程。请求负载中完全没有关于它会“引爆”什么的任何信息。
  • 速率限制和配额。一个带有积极重试机制的智能体会刚好在执行重要任务时触发服务商在生产环境中的限流,甚至可能导致你的整个集成密钥被封禁。
  • 依赖状态的行为。同一个 API 调用可能会因为记录的当前状态(如已关闭的会计期间、已锁定的商机、在读取和写入之间被归档的线程)而成功或失败。Dry-Run 运行时完全没有这些状态。

还有一个比任何单一故障模式更深层的问题:Dry-Run 破坏了智能体循环本身。智能体是反馈机器——它们读取一个动作的结果来决定下一个动作。Dry-Run 工具返回的是一个虚构的“ok”,这意味着第一步之后的每一步都建立在虚构之上。你不是在测试智能体在生产环境中的路径(Trajectory);你是在测试一个根本不可能发生的路径。

替代方案阶梯,以及它们各自的局限性

如果 Dry-Run 是演戏,那么团队实际上在用什么?在实践中存在一个阶梯,每一级都在保真度(Fidelity)和安全性之间权衡。

**Mocks 和手写的模拟(Fakes)**位于最底层。它们速度快、免费,并编码了你的团队对服务商行为的“假设”——而这恰恰是你需要测试的东西。Mock 永远不会给你惊喜,而“意外惊喜”正是故障发生的模式。

**录制-回放代理(Record-replay proxies)**是中间的中坚力量。你在工具边界放置一个代理,录制一次真实的请求-响应流量,然后在 CI 中确定性地回放——这就是 VCR 模式,现在也出现在专门针对智能体的形式中,直接支持 MCP 的 JSON-RPC。这确实很有用:它使回归测试变得廉价、确定且安全。但回放只能覆盖你已经见过的路径。一旦智能体采取了一条全新的路径——而这正是智能体的定义性行为——就没有“录音带”可回放了,你又回到了真实流量中。

回放也会过时。服务商会改变响应结构,一个三月份录制的固定脚本(Fixture)可能会通过一项在五月份行为就已经发生变化的 API 测试。

**模拟环境(Simulated environments)**是研究界所追求的。τ-bench 是一个揭示了使用工具的智能体在客户服务领域多么不可靠的基准测试,它的工作原理是同时模拟用户和后端数据库,然后对比最终数据库状态与目标状态。即使是前沿模型在航空公司任务中的通过率也低于一半,而且当同一个任务运行八次时,可靠性会进一步崩溃。这个结果应该被视为关于环境而非仅仅是模型的论点:我们之所以“知道”这些智能体不稳定,是因为有人构建了一个高保真的模拟器,在那里运行同一个场景八次是零成本的。你无法在客户真实的 Salesforce 生产组织中衡量这种“八次通过率(Pass^8)”。

**服务商沙箱(Vendor sandboxes)**是最高级的一环——使用服务商自己的代码,针对可抛弃的状态运行。当它们存在且足够忠实于真实环境时,没有任何方案能与之媲美。这就引出了一个令人不安的部分。

供应商沙盒的抽奖游戏

目前,你的智能体演练层的质量取决于你的客户恰好使用了哪些 SaaS 产品。这就像一场抽奖。

Stripe 是这一做法可行性的存在性证明。沙盒是完全隔离的环境,拥有自己的 API 密钥、Webhook 和数据——你的 CI、预发环境以及每个开发人员都可以指向独立的沙盒而不会发生冲突。模拟的支付链路表现得与真实链路完全一致,甚至包括针对特定拒绝代码的测试卡。Stripe 将沙盒视为一等产品特性,这体现在生态系统中绝大多数默认针对 Stripe 进行的测试中。

Salesforce 在其智能体野心的驱动下也朝着同样的方向发展。Scratch orgs(临时组织)和沙盒现在都支持 Agentforce,其测试中心(Testing Center)之所以存在,正是因为 Salesforce 意识到,你无法发布一个从未针对生产形态的元数据、校验规则和自动化程序进行过演练的自主智能体。注意其中的因果关系:供应商发布智能体,迫使 该供应商投入建设智能体级的测试环境。

接下来,梯子到这里就断了。QuickBooks 虽然有沙盒,但 Intuit 官方指南承认其 Webhook、错误代码和限流行为可能与生产环境不同——而这些恰恰是智能体最需要演练的依赖状态、带有副作用的行为。Gmail 作为通过 MCP 服务器连接的最常见智能体界面之一,根本没有沙盒层。市面上没有“临时收件箱(scratch inbox)”产品。你的智能体邮件工具要么在属于某个真实用户的邮箱上测试,要么根本不测试。

结果是一种支离破碎的安全态势:同一个智能体,拥有相同的架构和相同的评估规范,在 Stripe 工具上得到了充分测试,在 QuickBooks 工具上得到了部分测试,而在 Gmail 工具上则完全未经测试。内部工程的严谨性再高也无法解决这个问题,因为缺失的部分在供应商的边界那一侧。

真正的演练层需要什么

假设你严肃对待此事并构建了目前可能达到的最佳环境层。它分为三层,每一层都补足了供应商未能提供的部分。

第一层:在现有的供应商沙盒基础上,将其接入为一等环境。 你的智能体工具配置应该像你的服务一样带有环境维度——同一个 send_invoice 工具,在预发环境中解析为沙盒凭证,在生产环境中解析为正式凭证。这听起来理所当然,但实际上被广泛忽视;大量的智能体技术栈中每个工具只有一套凭证,这意味着任何人进行的任何测试都是生产测试。OWASP 的 MCP 指南道出了真相:高风险操作需要运行时控制,正是因为大多数部署没有更早的阶段来练习这些操作。

第二层:在其他所有工具边界处建立录制回放代理。 不是在智能体框架内部,而是在边界上,无论是由哪个模型或编排器生成的工具调用,它都能看到。录制生产流量(擦除 PII)可以让你免费获得回归测试数据。通过注入故障(如 429 错误、部分失败、乱序的 Webhook)进行回放,可以为你提供任何供应商沙盒都无法提供的混沌测试。

使第二层发挥作用的纪律是:将录制文件(cassettes)视为带有有效期的依赖项,并定期重新录制。一个过时的固定数据(fixture)只是一个穿着风衣的 Mock。

第三层:为没有沙盒的界面构建合成租户。 针对 Gmail 这类场景,这意味着一个你拥有的真实账号,其中填充了生成的但真实的数据——带有附件的邮件往来、标签、写了一半的草稿,以及实际使用中累积的“沉积物”。合成租户的构建和维护成本很高,这就是为什么几乎没人拥有它们,但它们也是在供应商不提供任何支持的情况下,进行写入操作测试的唯一诚实答案。填充数据的问题是真实存在的:一个空的测试组织无法告诉你太多信息,因为大多数有趣的智能体故障都源于状态——重复的联系人、已关闭的会计期间、带有法律保留标签的邮件。

这些都不是什么外星技术。这与我们过去二十年来为内部服务所做的环境工程完全相同,只是应用于一个我们历来视作他人责任的边界。之所以觉得新奇,是因为在智能体出现之前的集成是低频率且由人为触发的——人点击一个按钮,触发一次 API 调用,如果失败了,由人来查看错误。智能体同时改变了调用量、自主权和爆炸半径,而测试基础设施却原地踏步。

临时组织正向你的领域袭来,无论你是否准备好

这是一个前瞻性的声明:由智能体驱动,沙盒质量即将成为 SaaS 采购的标准之一。

压力机制很简单。每个 SaaS 供应商目前都在竞相变得“智能体可访问”——发布 MCP 服务器、公开工具 Schema、寻求集成。但是,一个没有智能体可测试环境的智能体可访问 API 是买家继承的负债。部署智能体的企业将开始向供应商提出他们已经针对 SSO 和审计日志提过的问题:你的平台是否有带有生产形态数据的沙盒?Webhook 会在其中触发吗?限流规则是否匹配?我能否将租户的配置(而非数据)克隆到临时环境中?

Salesforce 已经完成了这一转变,因为 Agentforce 迫使其不得不这样做。Stripe 在十年前就做到了,因为支付业务会惩罚任何疏忽。长尾的 B2B SaaS 还没有做到这一点,当客户的智能体在一个没有更廉价演练层的环境中做出某些昂贵的操作时,这种差距将变得显而易见。“Scratch org(临时组织)”将不再是 Salesforce 的术语,而将成为核对清单上的一个项目——就像今天的“支持 SAML”一样,成为一个平淡无求的要求。

在这种压力产生效果之前,对智能体团队的实际建议是很朴素的:按环境层对你的工具进行盘点。对于每个具有写入能力的工具,回答一个问题——这个动作可以在哪里演练? 供应商沙盒、回放代理、合成租户,还是无处可练。在“无处可练”那一栏中的工具是你真正的风险登记册,远比你的提示词注入威胁模型中的任何内容都重要。将它们封装在运行时控制中——审批门禁、白名单、支出上限——这些措施的存在是为了补偿环境的缺失,并且要诚实地承认,它们就是补偿性控制。

这个世界还没有预发环境。内化了这一点的团队不再询问“我们的智能体足够聪明到可以发布了吗?”,而是开始询问那个更老、更好的问题:“这玩意儿在哪儿演练过?”

References:Let's stay in touch and Follow me for more thoughts and updates