跳到主要内容

Beyond Serverless:我们如何在 Cloudflare 上构建 Agentic 虚拟计算机

Robert
AFSArchitecture

云运行时的演进,以及我们从 Blocklet 1.0 到 2.0 的探索

Serverless 给过开发者一个很有吸引力的承诺:你来写应用,服务器交给平台管理。它改变了云开发。但部署成功之后,还有一个问题:应用到底是什么?

是一个函数?一个连接了部署平台的代码仓库?还是一组路由、数据库绑定和后台任务?这些答案有助于运行软件。使用软件的人还关心另外一些事情:数据放在哪里,谁可以操作它,软件换了之后,自己能留下什么。

我觉得下一层有用的抽象,需要把这两个视角连接起来。Serverless 改变了应用怎样运行。ARC 探索的是应用怎样定义、怎样组合,以及怎样由它的使用者拥有。现代云运行时,让这件事有了更实际的基础。

从 Blocklet 1.0 到 Blocklet 2.0,我们关注的问题也在变化。最初是让应用更容易打包和运维;现在,我们希望应用模型能够表达更多需求,把具体执行交给下面的运行环境。

1. Serverless 的承诺:不用自己管服务器

AWS 在 2014 年 11 月推出 Lambda。它的吸引力很直接:上传代码,接上事件来源,由 AWS 管理执行环境。开发者可以在存储里出现新文件时运行一段代码,不用专门准备一台服务器等着这件事发生。

函数是一个好用的单位。平台拿到了明确的执行入口,开发者少承担一部分运维工作。事件来源、权限和执行限制,成为编程环境的一部分。机器仍然存在,只是管理机器的工作被收进了服务接口后面。

即使一个应用远比单个函数复杂,这个变化也有意义。生成缩略图,可能一个事件处理函数就够了。一个包含用户、持久记录、定时任务和网页界面的应用,则需要多个服务协作。执行模型变简单了,连接这些服务的工作仍然要做。

计算领域经常发生这样的事情:一个好的抽象消除一类工作,也让另一类工作变得更明显。当准备机器变成常规操作,应用如何组合,就开始占用更多注意力。部署自动化之后,数据、权限与服务之间的关系,也更值得认真处理。

Lambda 至今仍然是这条路线的重要代表。它通过广泛使用的云服务,让事件驱动执行成为开发者能够直接使用的能力。此后的发展沿着几个相互交叠的方向展开,各自寻找更适合开发者的工作单位。

2. 从函数,到网站,再到全栈应用

Netlify 推动了以网站项目为单位的部署方式。代码管理、构建和交付连在一起,Deploy Preview 让一个准备发布的改动可以先被看见。JAMstack 强调预先构建的内容、JavaScript 和 API,平台围绕项目承担了更多操作流程。Netlify 的部署文档解释了代码怎样变成网站;Jamstack 的介绍则记录了这种架构思路的起源。

对开发者来说,日常发布软件的方式变了。一次 Git 提交,可以得到一个供人审阅的网站。平台理解构建过程和产物,部署也就能成为协作中的常规动作。

Vercel 则推动了另一种有影响力的应用交付方式:让框架行为与托管环境紧密结合。路由、渲染策略、缓存和服务端执行,可以放进同一套开发流程。今天的 Fluid compute 也说明,执行模型还在继续演进,已经走出了早期每次函数调用各自独立执行的简单印象。它的文档具体介绍了同一函数实例内的并发调用。

这些平台的能力彼此交叠。Lambda 可以服务于完整应用,网站平台可以执行服务端代码,围绕框架的平台也可以承接后台工作。回顾历史时,更值得区分的是:各自让哪一类责任变得容易表达。

技术与平台它帮助普及的抽象平台承担的工作
AWS Lambda由事件触发的函数准备执行环境,运行事件处理逻辑
Netlify可以部署的网站项目连接构建、预览和交付
Vercel理解框架的全栈应用交付协调应用行为与部署
Cloudflare Workers全球网络上的分布式服务执行请求,连接运行时服务

这些发展彼此交叠,分别关注函数、网站、全栈交付和分布式运行时;ARC 探索应用模型这一层

在我看来,这些变化说明,“应用”的边界一直在移动。开发者希望描述一个有意义的结果,把更多机械性的工作交给运行时。一个抽象要承担这些工作,就必须理解足够多的应用结构。

应用定义中有多少东西应该依赖某个托管环境,仍然是一项架构选择。部署配置自然会描述那个环境能提供什么。应用模型还要考虑更长久的关系:应用、它使用的资源,以及控制它的个人或组织。

3. Cloudflare Workers:从请求执行走向更丰富的运行基础

Cloudflare Workers 把 V8 isolate 带到了全球分布式执行环境中。多个 JavaScript 执行上下文可以共享运行时进程,同时保持隔离。这与为每个应用启动独立操作系统进程或虚拟机的方式不同。Cloudflare 的架构文档介绍了这种基于 isolate 的运行模型。

今天,围绕 Workers 的平台已经能承接短时、无状态处理函数之外的许多工作。Durable Objects 把具有唯一地址的对象、协调执行和持久存储结合起来,为有状态交互提供一个组织位置,也能处理需要统一协调的工作。Workflows 则支持持久化的多步骤执行,保存进度,并在失败后重试。

Containers 为需要容器环境的工作负载增加了执行选择。Agents SDK 利用平台能力,支持持续存在的 agent、状态和通信。这些服务各有生命周期与运行约束,怎样组合它们,本身就是应用架构的一部分。

可以把它们理解成一套更丰富的建筑材料。请求处理函数可以发起工作;Durable Object 可以协调持续进行的交互;Workflow 可以让任务跨越多个步骤,并从中断处恢复;容器则可以运行对环境有额外要求的软件。

这些都是实质性的架构能力。建立在 Workers 上的应用层,需要理解并合理使用它们。如果把所有区别都藏进一个笼统的“计算”方框里,反而会让应用更难理解。

上一篇关于 ARC Cloudflare 运行时的文章,介绍了 ARC 运行在哪里,以及我们的托管实现怎样使用 Cloudflare。我们目前的官方在线服务都运行在 Cloudflare 上。这一篇进一步讨论:这样的运行基础,为应用层打开了什么空间?

我们不把 Cloudflare Workers 看成 ARC 需要取代的东西。包括 Workers 在内的现代 Serverless 运行时,是构建新一代应用抽象的基础。

4. 我们的变化:从 Blocklet 1.0 到 2.0

Blocklet 1.0 从打包入手。一个 Blocklet 把应用与安装、运行它所需的信息放在一起,Blocklet Server 则提供托管和管理这些应用的环境。它的生命周期 API 包括安装、启动、停止和配置。

喜欢 Serverless 理念的人,会熟悉这个目标:减少从“有一个应用”到“能用起来”之间的运维工作。Blocklet 1.0 采用的是应用托管环境,由服务器管理可执行应用。它的单位是打包好的应用,与 Lambda 的事件处理函数有所不同。

打包解决了真实问题,但应用内部的结构,很大程度上仍然藏在可执行代码里。宿主可以安装和运行一个包,却未必了解它使用哪些数据和能力。这些关系主要由应用自己的代码和集成来处理。

Blocklet 2.0 改变了这些结构的表达位置。应用内容和声明描述资源与接口,由 ARC 解释。自定义逻辑仍有作用;与此同时,应用用共同的形式表达更多需求,运行时就能承担更多行为。

对我来说,关键的变化在这里:从知道怎样启动一个应用,走向理解这个应用由什么构成。

架构关注点Blocklet 1.0Blocklet 2.0 / ARC 的方向
应用单位打包好的可执行应用应用内容、声明,以及受支持的执行逻辑
与宿主的关系Blocklet Server 管理可运行的应用ARC 通过对应平台的运行时解释应用
资源接入由应用代码和集成连接通过 AFS 接口和 Provider 实现提供
用户界面主要由应用自身实现AUP 提供声明式界面模型,与受支持的逻辑配合
演进方式更新和运维应用包演进应用模型及其运行时实现

Blocklet 1.0 把可执行应用交给 Blocklet Server;Blocklet 2.0 用内容和声明表达应用,由 ARC 连接能力并执行

改变这个边界需要工程投入。已有应用可能依赖子进程、本地文件,或者一个长期运行的服务器进程。适配新的执行模型时,需要逐项处理这些假设。Blocklet 2.0 采用的执行约定,已经离开了旧的子进程托管模式。

延续下来的是让应用容易使用和管理的目标。实现方式发生了足够大的变化,适配已有应用需要真正修改应用。

5. AFS、AOS、ARC:我们在建立一台虚拟计算机

理解 ARC,最重要的一点是:它是一台虚拟计算机。应用模型是这台计算机的一部分。应用可以安装、修改、移除,计算环境仍然存在,继续组织这些应用所使用的资源与权限。

这个出发点决定了我们的架构。底层是 AFS,即 Agentic File System:一套用路径访问数据和能力的虚拟文件系统。路径可以指向文档、集合、外部服务,也可以指向可执行工具。Provider 负责实现资源访问,应用和 agent 则通过共同的读取、列举、写入、执行等操作使用它们。

在 AFS 之上,AOS,即 Agentic Operating System,提供操作系统服务,组织身份与权限、会话、调度,以及应用生命周期。文件系统为资源提供地址,操作系统层则组织谁可以使用资源,以及工作怎样持续进行。

ARC,即 Agentic Realm Computer,把这些部分组合成一台能在具体宿主上工作的计算机。运行时负责初始化环境,通过适配器把各项服务连接到宿主。AUP,即 Agentic UI Protocol,描述用户界面,让人能够使用这个环境中的应用;agent 则通过 AFS 路径访问数据和能力。

人和 agent 在 ARC 虚拟计算机中使用 Blocklet;AOS 在 AFS 资源接口之上提供操作系统服务,宿主适配器连接具体运行环境

这里的“虚拟计算机”,指的是由软件定义的计算环境。它在资源、操作系统服务和应用这一层建立抽象,具体执行使用宿主的机制。在 Cloudflare 上,这包括 Workers 和 Durable Objects;在本地机器上,可以使用持续运行的 Node/Bun 进程;Swift 和 Kotlin 原生实现则把共同协议连接到设备能力。

Blocklet 是这台计算机里的应用。目录和 manifest 描述内容、资源挂载与接口;Mount 将资源放到路径上,Surface 把选定路径通过 HTTP 暴露出去。执行逻辑使用提供给这个应用的资源。你正在阅读的网站,本身就是这样的一个 Blocklet。

一个人可以在同一个计算环境中使用不同的应用。我们希望身份、应用内容和个人数据能够长期保留,延续到某个应用或某次部署之外。这需要可理解的格式、明确的权限边界,以及兼容的实现。每种宿主仍然需要提供应用所需的适配器和能力;Lambda 或其他基于容器的宿主,也需要相应的适配与验证。

因此,从 Blocklet 1.0 到现在,变化已经超出了部署格式。我们在建立应用所生活的那台计算机。

Cloudflare 怎样支撑这台计算机

一台虚拟计算机需要执行能力、持久状态、存储,以及调度工作的机制。Cloudflare 为这些责任提供了一套能够协作的服务。在这个基础上构建 ARC,是一个自然的架构选择:把成熟的托管基础设施,组合成我们希望提供的计算环境。

Workers 特别吸引我的地方,在于 isolate 模型改变了运行软件的起点。运行时可以接收工作,而不必为每个应用准备一个传统的应用服务器进程。再加上可以寻址的状态与持久服务,我们就有了构建计算机所需的材料,它的各个部分可以分布在多个服务中,协同工作。

在当前的 Cloudflare 实现里,这些材料承担着明确的工作:

ARC 需要承担的责任Cloudflare 提供的基础当前实现怎样连接
接收请求,执行应用工作WorkersCloudflare 运行时初始化 ARC,把请求分派到应用环境
维持交互式 AUP 会话Durable Objects会话对象协调实时交互,保存会话相关状态
持久保存文件内容R2Cloudflare 上的 DID Space 后端存储内容对象
查找和组织内容D1树索引与元数据把路径、作用域连接到记录和内容
驱动定时工作Cron Triggers定时入口驱动 ARC 调度器,再由调度器分派到期任务
连接运行时与配套服务Service bindings通过绑定接口调用配套的 ARC services Worker,包括身份服务集成

ARC 的虚拟计算机层由 Cloudflare 的 Workers、Durable Objects、R2、D1、Cron Triggers 和 Service bindings 分别支撑

存储的对应关系最容易看清这一层分工。AFS 提供路径和操作,Cloudflare 存储实现用 D1 组织目录树,用 R2 保存内容。应用面对自己的资源接口,适配器与 Provider 处理具体的平台机制。会话也是类似的:AOS 定义会话行为,Cloudflare 运行时利用 Durable Objects 协调持续交互。

这些对应关系按责任划分。一个 ARC 服务可以使用多个 Cloudflare 组件,一个组件也可以支持多项 ARC 服务。我们构建的计算环境,仍然要负责权限和数据边界。

图中画的是当前实现已经连接的基础。Cloudflare 的 Workflows、Containers 和 Agents SDK,还提供了值得继续评估的能力。它们增加了工程选择,每一项接入都需要明确的接口约定和实现。

6. Agent 时代,下一层抽象要回答什么

AI agent 让“应用是什么”这个问题变得更迫切。Agent 可以生成大量代码。第一次演示成功之后,仍然需要有人理解结果、授予访问权限,并把它持续运行下去。

声明式结构的价值,是让运行时与操作者有东西可以检查。一个拟议中的界面或资源声明,可以在执行前审阅;一项具名能力,可以有明确的权限边界;共同的路径,让 agent 用较一致的方式找到可用数据和工具。这样,就能减少必须从任意应用代码中推断的行为。

与之相应的责任,是让人继续控制有实际影响的选择。Agent 构建应用,需要与任务相称的访问权限。发布应用、授予新的权限,则是另外的决定。生成的软件越多,应用环境越需要保留这些区别。

这也是我为什么同时关心执行与所有权。云平台可以让应用在全球可用,应用模型还要说明:它使用谁的数据,获得了什么授权,换一种实现之后,哪些东西能够留下来。基础设施与应用架构,在这个边界上相遇。

Serverless 减少了大量管理服务器的工作。持续演进的基础设施,又把分布式执行、协调状态和持久任务变成可以直接使用的服务。有了这些能力,应用运行时能够承担一些过去需要投入大量基础设施工程才能完成的责任。

从 Blocklet 1.0 到 2.0,我们希望认真利用这个机会。打包让我们能够说明一个应用怎样安装;ARC 则进一步建立这些应用所处的虚拟计算机:AFS 提供资源接口,AOS 组织操作系统服务,对应宿主的运行时让环境运转起来。应用怎样定义、怎样长期拥有,也就有了持续存在的环境来承接。

部署成功之后,开头的那个问题仍然值得追问:应用到底是什么?一个有用的答案,应该能够延续到今天执行请求的机器或服务之外。这就是我们正在探索的下一层。