非常感谢大家的参与。我想既然座无虚席,我们就开始吧。大家好,我是Priyanka,Anthropic的技术人员成员。我领导着构建云托管代理的工程团队,非常高兴能在这里与大家交流,帮助大家部署他们的第一个托管代理。我在Anthropic工作已两年有余,过去12个月我专注于构建智能体基础设施,希望能与大家分享我们的一些经验教训。
大家好,我是Gabe Semach,Priyanka团队中构建云托管代理的技术人员成员。我在Anthropic工作了一年多,这段时间我主要都在从事这项工作。
好的,以下是我们的议程。我们将首先回顾一下我们如何构建和扩展托管代理的演变故事,以及途中遇到的陷阱和经验教训。然后我们将进入工作坊的实践部分。第一部分,我们将使用云平台的控制台构建一个非常简单的代理。在这一阶段你们不需要编写任何代码,我们只是通过提示词来创建第一个代理并进行测试。
接下来我会交给Gabe带大家进行实践环节,我们将使用云代码或你们喜欢的编码智能体编写代码。然后构建一个更复杂的金融代理,最后留出充足的时间进行问答环节。我们有两个小时的时间段,我知道它被分成了四个部分,但基本上是一个长演讲。希望不会占满整整两个小时。我们希望这能相当互动,所以如果你们有问题请举手,周围有几位工作人员可以跑过来给你们递麦克风提问,特别是在进入实践环节时。好了,让我们开始吧。
我先从基础讲起。那么,什么是代理?或者说是什么让代理运作起来呢?基本上,代理就是一个带工具的模型循环。如左图所示,你有一个模型在决定并采取下一步行动,并在一个循环中调用工具,直到任务完成。这就是代理最基本的定义。
不好意思。是幻灯片吗?哦,幻灯片的链接。我们可以尝试……我们可以在之后分享它。是的,我们会在结束后分享。现在很难把它发出来。不过我很乐意回答问题并在最后分享幻灯片。从后排看幻灯片困难吗?好的,抱歉。
接下来我想谈谈什么是“Harness”(控制层/框架)。Harness通常是一层包裹在模型周围的机制,它帮助你在循环中进行工具调用,从而获得当前任务的结果。它对模型无法做的事情做出假设,并试图填补这些空白。它在循环中运行、进行工具调用、管理上下文,封装了所有模型无法处理的部分。
一个很好的例子是我们的Sonnet 45模型有一种我们称为“上下文焦虑”的现象。每当Sonnet 45感觉接近上下文限制时,它就会试图快速结束任务。因此,在为Sonnet 45构建Harness时,你会添加类似“上下文重置”的功能来克服这种焦虑带来的限制。但对于下一个模型如Opus 45,它没有这个局限性,因此不需要为Opus 45做这种上下文重置。
所以在构建Harness时,你想要封装针对不同模型的所有这些假设,并随着每个新模型的推出而保持更新。这就是为什么构建一个好的Harness非常重要。这也是我们试图在云托管代理中做的事情。
最后一部分,你需要让你的代理能够访问沙箱或计算机,本质上是一个它运行所写代码以执行任务的地方。通常你会给云访问权限到一个沙箱或容器,在其中它执行所写的代码。它能够编辑文件、安装依赖项等。云代码就是一个很好的例子,它本质上是一个在你的计算机本地运行的Harness,可以访问你的文件,并在执行过程中更新这些文件。
它还编写不受信任的代码,代码可能有缺陷。因此,当你部署生产环境的代理时,你需要确保:第一,代理编写的代码在容器内被沙箱隔离和 containment。第二,你的沙箱需要是隔离的,并将爆炸半径限制在最小范围内。因此,通常你希望在单独的容器中执行每个任务,这样就不会混淆,也不会增加任务的爆炸半径。
接下来我将介绍我们最初构建托管代理时使用的第一个架构。这是去年12月,当时我们将首个架构交付给早期访问客户,收到了大量反馈,随后我们实际上转向了新的架构。我将介绍一些我们在第一个架构中看到的陷阱和问题。
在最初的架构中,我们将所有内容都放在了容器里。因此,我们拥有该会话内发生的一切的会话日志。“测试会话”本质上就是你的工作单元。Harness也在容器内运行,沙箱执行也发生在容器内部。这样做的好处是:因为所有内容都在容器中,所以无需设计服务边界。一切都是本地的,易于编辑。文件编辑本质上就像系统调用一样简单。
但我们后来意识到我们采用了一种“宠物”模式。如果你没听说过旧基础设施时代的“宠物与牲畜”类比,宠物是指你拥有一个命名且人工照管的实体。当它生病时,你必须悉心照料使其恢复生机;否则你基本上无法承受失去它的代价。而牲畜更具可互换性,更可丢弃。当一个失败时,你可以用另一个替换它并继续前进。
一个很好的例子是:假设你有一个单一的数据库分片,如果它宕机了,你的产品就挂了,这就是宠物。但假设你设置了主从副本集,当主机宕机时,你可以启动一个副本。这就是牲畜,对吧?你有很多实例,其中一个出了问题没关系,可以重新启动它。而我们最初的设置本质上就是一个宠物模式。因此出现了一些问题:
由于所有操作都在容器内运行,调试变得非常困难。我们不清楚是什么导致了问题,因此丢包或容器死机表现出的症状几乎相同,我们必须通过 WebSocket 流式连接进入容器进行调试。另一个问题是调查困难,因为客户数据存储在容器中,我们缺乏直接进入并调试的方法。这是我们在早期访问阶段发现的另一个问题。最后,如果客户希望我们连接到其 VPC 中的某个 MCP(模型上下文协议),这意味着需要进行网络对等连接,或者向他们发送我们的运行环境让他们自行部署。这种架构存在许多挑战,我们当时无法找到良好的解决方案来克服这些问题。
因此,我们要做的决定是将“大脑”与“手脚”解耦。代理本质上变成了三个独立的接口:左侧是会话,即记录到目前为止发生的所有事件的追加式日志;中间是大脑,包括运行环境或代理循环以及云端服务;右侧是手脚,例如按需配置、工作完成后销毁的沙箱和 MCP 工具调用。如果沙箱丢失或损坏,只需重新启动即可。每个组件都变成了可互换的“牲畜”(即无状态、可随时替换)。当沙箱崩溃时,运行环境或云端可以选择将其重新拉起。
错误信息会返回给云端,沙箱与云端的交互本质上就像其他工具调用一样。如果工具调用失败或沙箱故障,系统会决定下一步操作:是重新启动还是继续前进。当运行环境崩溃时,你可以启动一个新的实例,并通过读取会话中的事件日志从中断处继续。工作从最后一个事件恢复,仿佛什么都没发生一样。这里唯一需要保护的是会话日志,其他组件都是可互换的,即使宕机也可以重新拉起。
我们还采取了一项措施:凭证永远不会进入沙箱。在之前的设置中,你的凭证存储在沙箱内,这使得你更容易受到提示注入的攻击。我们做出的改变是:如果沙箱需要调用涉及令牌或访问控制的外部服务,该请求会通过代理路由。代理会在调用外部端点或 MCP 之前注入你的令牌。这样,模型永远看不到你的凭证或令牌,这意味着你无法通过提示让 Claude 输出、打印或将令牌写入文件。因为云端实际上从未见过你的令牌,所以这种攻击不可能实现。
由于会话中拥有追加式事件日志,我们的压缩策略可以保持灵活。没有任何内容会被丢弃,我们不会通过压缩来改变你的事件流。我们始终存储发生的每一个事件,而压缩策略则决定是查看整个日志并总结放入上下文,还是仅查看最近 N 个事件。这种接口设计使我们能够采用更灵活的上下文策略。此外,由于我们可以立即启动推理调用,我们将首令牌生成时间(TTFB)降低了约 90%。
云端仅在需要时才启动沙箱,并且不会等待容器沙箱启动完毕才返回第一个令牌。因此,通过这种架构变更,我们获得了更快速、响应更快的体验。以下是“一个大脑连接多个手脚”的示意图:你的代理循环或运行环境现在可以调用沙箱容器、客户的 VPC 或 MCP 服务器。所有这些“手脚”本质上都是可互换的,你可以连接多种类型,这使得我们的架构更加灵活。
如果从这次分享中只带走一个观点,那就是:运行环境编码了假设,而假设可能会过时。我们设计了能够超越这些假设的接口,使架构更加灵活。正如我所说的,这允许我们更改压缩策略或完全更换运行环境,而接口和架构保持不变。我们可以以一种更具可插拔性的方式进行操作。接下来我们将进入一些动手实践环节。我们为大家提供了一些免费的 API 额度,以帮助大家今天与我们一起构建应用。
请扫描二维码,登录你的云端平台账户或创建一个新账户,你应该能够获取这些额度,以便与我以及 Gabe 一起进行构建。我先留在这里一会儿。(嗨。)>>(抱歉,你说什么?)>>(最后一张幻灯片。)
这基本上就是我们在这里讨论的内容。这是我们设计的三个接口,对吧?之前有人问我们设计了哪些接口来使系统能够适应变化。我们有追加式会话日志,有可互换的运行环境,还有手脚部分,你可以在此插入沙箱工具调用或模型可能需要访问的任何内容。这使得系统更加通用和可扩展。(好的,回到额度问题。)在我们开始之前,还有其他人需要扫描这个吗?(好的,我看到还有一些手机在扫。我会给大家大约 30 秒时间。感谢大家的耐心。)
哦,网络有问题。(噢,不。)>>(Gabe,我们有麦克风吗?因为我听不到一些问题。)
是的,一旦你注册成功,额度应该会在大约一两分钟内到达。嗯,我们正在获取麦克风,以便我们希望能走动并收集一些问题。但我会先带你构建一个非常简单的代理来给你讲笑话。首先,我将介绍一些核心 API 和概念,然后我们会跳转到 platform.anthropic.com 来构建你的第一个代理。我们的第一步是创建环境 API,即 v1 environments,它帮助你为沙箱创建设置或模板。这将包括你的网络设置:你是希望拥有不受限制的网络,还是将其限制为特定域或 MCP?你可以定义你想要的包。
安装在你的容器或沙箱中。这是我们要采取的第一步,以设置我们的环境。接下来你要创建智能体(Agent)。本质上你可以给智能体起个名字,比如这里我们叫它“讲笑话的人”。然后选择你要为该智能体使用的模型,你可以使用 Opus 48、Haiku 或 Sonnet,由你决定。随后我们要为智能体提供系统提示词(System Prompt),例如说“你是一个喜剧演员,找一个关于该主题的新鲜笑话并精彩地讲出来”。接着你可以为智能体提供工具集,这里我们提供一个基础的工具集合,包括 Bash、读取、写入、图形处理等,几乎所有智能体都需要这些。
第三步是创建会话(Session)。会话需要传入一个智能体 ID 和一个环境 ID,从而创建一个任务单元或工作任务。当会话配置完成时处于空闲状态,没有执行任何工作,直到你发送一个事件为止。这大致就是会话上的事件流的样子:你会发送一些事件,智能体也会返回给你一些事件。在左侧你可以看到用户消息,比如你说“给我讲个关于分布式系统的笑话”,然后智能体会返回一个有趣的笑话。
你可以使用一种叫做自定义工具(Custom Tool)的功能,它允许你定义一个希望由自己处理的特定逻辑。Claude 会在事件流上放置一个自定义工具使用的事件,你可以监听并处理该事件,然后将结果返回以声明工具执行完毕。此外还有一些其他示例展示你会看到的事件类型:如果会话出错或遇到错误,会显示“Session Error”;当会话空闲未工作时状态为“Idle”,这通常意味着你没有使用沙箱环境。
左侧的“中断”(Interrupt)用于停止或终止会话,不再继续工作。这大致是我们的功能列表全貌。如果时间允许,最后 Gabe 可能会回来深入探讨这些概念。Gabe 将在工作坊的环节中与你一起更深入地研究多智能体和记忆等我们提供的概念。好的,在进入下一部分之前,我们现在跳转到 platform.anthropic.com(注:原文为claw.com,结合语境应为Anthropic平台)。
希望你能使用 API 额度并看到相关界面。如果没有的话,我有 Travis 拿着麦克风在场内走动,如果你有问题或需要引起注意可以拦住他。在控制台的“管理智能体”部分有一个名为“快速开始”(Quick Start)的功能,这大致是我们引导你构建第一个智能体的导览之旅。