推出 Kitesurf:首个以智能体为先的浏览器,在 Cloudflare Workers 的 V8 隔离环境中运行
我们是否应该构建自己的浏览器?
这是多年来 Cloudflare 内部每隔几个月就会出现一次的问题之一。不出所料,这类问题往往会引发长篇讨论,包含诸多理由和具有说服力的论点,说明我们为什么应该这样做。浏览器显然是我们每天在电脑上使用的最重要的软件;它可以说是互联网的操作系统。我们是一家致力于帮助构建更美好互联网的公司——谁不想接受构建新浏览器的挑战呢?
但我们始终未能在这一事业的技术难度与我们将通过它解决的独特问题之间找到平衡。因此,这个想法一次又一次地被搁置。直到现在。
神奇的事情发生了:我们达到了一个临界点——开发者平台上一系列强大的技术进步成为现实,与此同时,AI 智能体的兴起以及对新型浏览器的需求也变得至关重要。
在 Workers 中运行 WebAssembly(Wasm)现在已经非常成熟。动态 Workers、基于 SQLite 的 Durable Objects、Worker 间 RPC、服务绑定、更高的 NodeJS 兼容性以及更高的限制等原语,为更宏大、更复杂的应用打开了大门,而这些在以前根本不可能实现。
我们的无头浏览器自动化 API 产品 Browser Run,随着 AI 的兴起经历了巨大的增长。智能体需要浏览器来执行许多任务,而且在很多情况下,没有浏览器它们就无法成功。
但有一个问题——像 Chromium 这样的浏览器引擎是为人类而非智能体构建的,它们带来的开销是 AI 模型根本不需要的。它们消耗大量内存和计算资源,以至于为每个智能体提供独立实例的成本高得令人望而却步,这限制了 Web 的大部分内容只能由参数知识更丰富、最复杂且最昂贵的 AI 模型访问,同时将许多其他智能体应用拒之门外。
我们应该为所有智能体提供一个在 AI 模型关注的重点方面表现出色的浏览器,即使这意味着在仅对人类有用的功能上有所精简。例如:
- AI 不在乎标签页、主题、浏览器扩展或跨设备同步。它在乎的是 token 数量、上下文窗口、可扩展性、性能和成本。
- 结构化、机器可读的内容很重要,但视觉上的完美、流畅的 60 帧滚动并不重要。即使 CSS 解析稍有偏差或渲染并非像素级完美,智能体也不会在意。
- 在 AI 使用浏览器的背景下,威胁模型是不同的。提示词注入和工具安全等新问题成为首要任务。
面对这些认知,12 周前我们再次提出了那个问题:我们是否应该构建自己的浏览器?这一次,答案是 unanimous:是的!
今天,我们宣布推出 Kitesurf,这是一款完全运行在 Workers 之上的新浏览器,专为智能体打造,目前在 Browser Run 中免费提供测试版。
对于截图和 HTML 提取等常见的智能体任务,Kitesurf 在 CPU 和内存消耗方面比 Chromium 高效得多。以下是我们构建它的故事。系好安全带,这会有点技术性——但我们保证会保持有趣。
一切是如何开始的
Kitesurf 的诞生,和 Cloudflare 许多伟大创意的起源一样。有人发现了有趣的东西,转眼间,他们就用一个看似不可能但极具吸引力的想法“技术撩拨”了团队的其他成员。
我们的最初灵感来自 obscura,这是一个用 Rust 编写的、用于 AI 自动化的无头引擎,它“没有 Chrome,没有 Node.js,没有依赖”。

然后,在 AI 智能体的帮助下,我们尝试将其移植到 Workers 上。起初效果并不理想。但当我们给 AI 一个扎实的计划和清晰的成功定义——详细到足以让智能体无限循环并在需要时提问——它确实成功了。被这个(勉强)可行的概念验证所震撼,我们决定让团队放手一搏。
设计决策
以下是我们开始之前做出的一些设计决策。
测试,测试,再测试
我们很清楚,从原型走向一个功能完备、能在生产环境中大规模处理实际任务的浏览器,需要大量的工作和反复迭代。我们也不讳言,利用 AI 来加速这一过程是关键。但问题是,在这样一个复杂的项目中,如何运用 AI,在保持代码和结果质量可控的同时,又不牺牲开发速度?答案是:尽可能多地提供测试。
于是我们引入了 Web Platform Tests(WPT),这是理想的选择:一套全面的成功标准,为 AI 智能体提供了清晰的评估功能符合性的目标。我们精心挑选了分配给智能体的功能及其顺序,让人类能够专注于架构工作,并审查智能体的实现方法。
然而,WPT 测试也有其局限性:它们衡量的是对 W3C 标准的符合程度,而非浏览器渲染真实网站并与之交互的能力。为了弥补这一差距,我们采用了集成测试与视觉回归测试相结合的方式——它在真实网站上对 Chromium 和 Kitesurf 运行多步骤的 Puppeteer 测试,不仅比较其断言语义,还在每一步渲染输出,以突出任何不期望出现的差异。
尽可能使用 Rust
Cloudflare 长期以来一直在为 Workers 提供对 WebAssembly(Wasm)的出色支持。这很棒,因为我们可以使用高性能的 C、C++ 和 Rust 包,并将它们编译为 Wasm。如果我们使用 Emscripten(例如)及其多层模拟依赖,编译出的二进制文件可能会变得臃肿且运行缓慢。
因此,我们尽可能选择原生 Rust,并使用 wasm-bindgen 直接编译为 WebAssembly,从而避免不必要的模拟层,尽可能贴近底层硬件,实现可靠运行。
异常处理
浏览器必须渲染整个不可靠甚至有时充满恶意的网络世界,同时绝不能丢失它正在处理的页面,因此异常处理不仅仅是一种代码卫生习惯——它是应用在遭遇不良输入时仍能存活而不至于直接崩溃的关键机制。
所以我们从一开始就定下一条规则:任何故障都降级为空白帧或缺失元素,绝不导致会话卡死。在每个边界捕获故障,默认回退到安全且为空的状态,并记录足够的日志以便诊断。
隔离
与在笔记本电脑上运行浏览器(访问的是你信任的网站,站点之间共享一些资源是可以接受的)不同,智能体被指向任务所需的任何内容:来自任意来源的任意代码。
因此,我们构建这个浏览器时基于这样的假设:每次页面加载都是不可信的输入,每个会话都从全新状态开始。每个组件都是隔离的,只能访问其功能严格必需的资源。

这看起来非常适合 Cloudflare Workers,其安全模型本身就围绕隔离设计。但该平台只为我们提供了隔离单元之间的边界。我们仍然需要在应用层面执行同样的原则,决定每个组件可以接触什么,并确保没有任何东西跨过它不应跨越的页面泄漏。
尽可能无状态
状态是让故障代价高昂的原因——如果无需重建任何东西,从崩溃中恢复就只是启动一个新实例并重放请求。无状态组件天生就是可丢弃且可并行的:一旦停滞就杀掉它,同时运行一千个,按需求调整规模而不是保持热备。这完美契合自动化场景,负载以突发形式到来,你能做的最便宜的事情就是启动只消耗实际使用资源、完成后即消失的工作。简而言之,凡是能做成无状态的组件,就应该做成无状态。
我们是如何构建的
有了周密的计划、全面的测试和良好的工具环境,我们准备好在初始概念验证之外继续推进。以下是 Kitesurf 中一个请求的极高层级生命周期,至今仍然适用:

让我们深入探讨让 Kitesurf 运转起来的三个主要组件:Engine、PageScript 和 PageRenderer。
从源站获取内容
为了渲染一个不可信的网页,浏览器必须从互联网上获取任意资源——图片、字体、CSS、JavaScript 和 Wasm 文件。这是浏览器能做的最危险的操作之一。
Kitesurf 通过一个单一组件——SandboxOutbound worker 来实现这一点,除此之外没有任何东西能直接接触网络——这一点由 Dynamic Workers 强制执行。Engine 利用它来引导页面加载,获取主文档及其脚本,而 PageScript 则获取其他所有内容:样式表、图片、字体,以及页面自身的 fetch() 调用。
我们使用 SandboxOutbound 来强制执行 CORS、注入浏览器形态的请求头、过滤响应,并将每个页面的 cookie 保存在各自的独立存储中。任何不符合我们策略的请求都会收到 403——每个组件都恰好获得它所需的网络访问权限,不多也不少。

Engine
Engine 是 Kitesurf 唯一面向外部的组件。它处理 Chrome DevTools Protocol (CDP) WebSocket 和 HTTP REST API,提供一个用于内部测试目的的有用落地页,并且最重要的是,存储每个会话的状态。所有其他组件都是无状态的。

使用 CDP 的优势在于客户端兼容性:Puppeteer、Playwright、chrome-remote-interface 以及实际的 Chrome DevTools 前端。将它们指向 Kitesurf,它们都能直接正常工作。这也是 Browser Run 的工作方式(稍后会详细说明为什么这一点很重要)。
与名称所暗示的相反,Engine 实际上是 Kitesurf 组件中最简单的一个。有趣的部分还在后面。
PageScript
PageScript 很好地展示了我们新 Workers 特性的强大之处:在这里,就是 Dynamic Workers。在此之前,Kitesurf 根本不可能实现。
下面是一个简化示意图,展示 PageScript 的内部工作原理。

每一个新页面或进程外 iframe (OOPIF) 都使用 Dynamic Workers 来启动一个长期运行的 PageScript 隔离环境,该环境负责处理页面会话,包含一个干净的 globalThis 和 DOM document 对象。
然后,DOM 对象会填充上解析 HTML 文档并运行所有 JavaScript 脚本的结果。为了解析 HTML 和 CSS,我们使用了 Blitz(一个模块化渲染引擎)和 Stylo(Firefox 的高性能 CSS 解析器)的部分代码,两者都是用 Rust 编写的。
对于找到的每个 <script> 标签或 .wasm 文件,我们都在同一个隔离环境中运行 JavaScript 和 WebAssembly 代码。
是的,但 eval
你可能会问,那 eval 怎么办?eval 处理起来更棘手,因为出于安全原因,我们目前还不支持在 Workers 中原生使用 eval。我们也不能再启动一个 isolate 来处理它们,因为它无法访问 globalThis。
我们的解决方案是使用 Boa JS——一个用 Rust 编写的 ECMAScript 引擎——在 Workers 上编译和运行。我们基本上是在一个运行时之上再执行一个运行时,这看起来不是最优方案,实际上也确实不是,但它足以处理我们在代码中偶尔遇到的 eval。将来,当 Workers 原生支持 eval 时,我们会从 Boa 迁移出去。
PageRenderer
这个组件主要负责根据计算出的页面对象生成实际的像素。它的工作方式如下:

PageRenderer 与 Engine Worker 在一个循环中协同工作。每当引擎需要一帧时,PageRenderer 会从 PageScript(也称为场景)获取页面对象,从 Static Assets 获取内部字体和图像,将所有内容光栅化到图像缓冲区中,然后将缓冲区以客户端可以显示的格式(如 JPEG/PNG 或 PDF)返回给引擎。
这里的很大一部分魔法由另一个 Blitz 模块 blitz-paint 处理,而它又使用 Parley 来将字符塑形为字形、选择字体以及将文本断行。
Workers 内置的 RPC 系统:同一个应用,多个 isolate
Cloudflare Workers 有一个内置的远程过程调用(RPC)系统,允许你在其他 Workers 上调用方法、在它们之间传递对象,并调用这些对象上的方法。你无需担心 API 模式、类型或身份验证,只需调用 remoteFunction(...params) 即可。你既能受益于远程 Worker 的隔离性和资源,又不会失去使用 JavaScript 在本地访问其所有函数的便利性。
Kitesurf 使用这套 RPC 系统:Engine Worker 通过 RPC 从 PageRenderer Worker 调用 renderFrame(),只需一次调用就能拿到一张 PNG 作为结果。由于渲染器不持有页面状态(只有一个一次性缓存),引擎可以在任何失败或卡住的 RPC 调用时安全地杀掉并重启它——这让每次渲染请求都自包含、可重试,而且它的 isolate 既廉价又可随时丢弃。
Kitesurf 已通过 215,000+ 项 WPT 测试,且数量还在增长
Kitesurf 是可行的。它已经通过了大约 215,000+ 项 WPT 测试,而且我们每周都会新增数百项通过的测试。你可以在这里看到自项目启动以来,直到最新版本的通过情况随时间的变化:

值得注意的是,浏览器中对智能体重要的部分(例如 CSS、DOM、HTML、selection、SVG 和 XHR)已经有了很好的覆盖率。即使是那些在智能体语境下可能不太重要的东西,比如 streams,现在也支持得相当不错。

在性能方面,Kitesurf 表现相当不错。下面是五次 Browser Run 快速操作在 14 个 URL 语料库上的中位数结果,对比了 Chromium 和 Kitesurf。
指标 | Kitesurf | Chromium(热池) | Kitesurf,相对值 |
|---|---|---|---|
CPU:截图 | 380 毫秒 | 1,173 毫秒 | 比 Chromium 少 3.1 倍 CPU |
CPU:HTML 提取 | 229 毫秒 | 877 毫秒 | 比 Chromium 少 3.8 倍 |
内存:截图 | 57.8 MiB | 271.0 MiB | 比 Chromium 少 4.7 倍 |
内存:HTML 提取 | 39.4 MiB | 273.7 MiB | 比 Chromium 少 7.0 倍 |
墙钟时间:截图 | 1,148 毫秒 | 637 毫秒 | 比 Chromium 慢 1.8 倍 |
墙钟时间:HTML 提取 | 820 毫秒 | 472 毫秒 | 比 Chromium 慢 1.7 倍 |
Chromium 在秒表上胜出,因为一个已经见过这个页面的 JIT 总是能打败冷启动的软件渲染器——而目前确实如此,大约快 1.7 倍。这个差距大部分来自光栅化和 JPEG/PNG 编码,我们会持续优化这些部分。
但 Kitesurf 在内存和 CPU 上胜出,而这两项才是真正决定你账单的因素,比 Chromium 的用量少 3-7 倍。更少的内存意味着我们可以运行更多会话、更好地扩展,并从根本上降低我们和你的成本。
最重要的测试来了:Kitesurf 能跑 Doom
我们在设计决策中强调了测试的重要性,但众所周知,无论你写了多少测试,一个项目只有能跑起 Doom 才算真正完成。这是我们几年前用那个小小的 Doom 实验跑 https://silentspacemarine.com/ 时 Kitesurf 的表现。
今天就到 Browser Run 里试试吧
你现在就可以通过 Browser Run 体验 Kitesurf,测试版期间免费使用,但受每账号限额约束。
Browser Run 的 CDP 端点现在支持将 Kitesurf 作为一个选项,因此你现有的客户端 Puppeteer、Playwright、chrome-remote-interface,或者任何支持 MCP 和 CDP 的 AI 智能体,都可以直接使用。你只需在我们的端点中添加 browser=kitesurf 参数即可。
例如,要在 Opencode 中使用 Kitesurf,请参阅我们开发者文档中的“与 MCP 客户端(CDP)配合使用”部分,并使用以下配置:
{
"mcp": {
"kitesurf": {
"type": "local",
"command": [
"npx",
"-y",
"chrome-devtools-mcp@latest",
"--wsEndpoint=wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-run/devtools/browser?browser=kitesurf",
"--wsHeaders={\"Authorization\":\"Bearer <API_TOKEN>\"}"
],
"enabled": true
}
}
} 使用 Kitesurf 的另一种方式是通过 Browser Run 的快捷操作。同样,只需在快捷操作端点中添加 browser=kitesurf,它就能正常工作。例如,如果你需要快速截取维基百科的页面截图,这样操作完全没问题:
curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-run/screenshot?browser=kitesurf' \
-H 'Authorization: Bearer <apiToken>' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com"
}' \
--output "screenshot.png" 使用带 Chrome DevTools 的 Kitesurf Playground
另一个开始探索 Kitesurf 的方式是使用我们的公共 Playground。你可以输入任意 URL,查看 Kitesurf 如何渲染该页面并与之交互。
Playground 的一个有趣特性是我们在界面中注入了 Chrome DevTools,因此你可以在 Kitesurf 渲染页面时检查展开后的 DOM 元素、读取控制台消息并观察网络活动。更有趣的是,我们实现了必要的 CDP 指令,让 Memory 面板能够报告每个隔离区的 WebAssembly 占用情况(包括帧),这样你就能清晰了解每个页面消耗的资源。

查看我们的开发者文档,了解如何将 Kitesurf 与 Browser Run 配合使用的全部细节。
Kitesurf 什么时候表现更好?
截至目前,Kitesurf 能正确渲染 TodoMVC(vanilla、React、Vue、Angular、Preact)、维基百科、Hacker News、Cloudflare 博客以及 Cloudflare 控制台的大部分页面。我们将持续改进 Kitesurf,提高 WPT 测试的通过率,以增强对更复杂网页的兼容性。
Kitesurf 非常适合需要渲染页面、但能接受不使用功能完整、像素级完美的 Chromium 浏览器的 AI 智能体。它也非常适合依赖一次性快捷操作(Quick Actions)的自动化任务和应用,例如从页面提取内容、生成 PDF 或截图,适用于兼容的网站。
可以把 Kitesurf 理解为一个临时性、完全隔离、无状态的引擎,它只为完成某项任务而存在,并且能很好地扩展以应对突发性的、由 AI 驱动的工作负载。
Kitesurf 目前还无法做到的事情
如果你需要播放视频、渲染 WebGL、使用真实 TLS 指纹完成机器人挑战握手,或者启动一个需要持久状态的十分钟认证会话——Kitesurf 目前还不是合适的选择。直接使用 Browser Run 的默认引擎即可,它由 Chromium 驱动。
判断某个特定网站是否与 Kitesurf 兼容的最佳方式就是直接尝试。你可以通过使用 API 来测试,或者更快的方式是在我们的公共 playground 中试用。
探索 DevTools 面板,看看幕后发生了什么,特别要关注控制台和内存指标。
未来方向
Kitesurf 才诞生十二周。第一次代码提交是在五月。以下是我们正在积极推进的一些工作:
- 更完善的 CDP 覆盖。Kitesurf 实现了 CDP 协议的一个子集——足以满足大多数智能体和自动化工具的需求,包括强大的 DOM 和网络检查——并且我们持续扩展其能力,力求尽可能完整。
- 提升截图和 PDF 的渲染保真度,因为我们知道 LLM 往往能从图像中比从底层文本中更好地理解内容。
- WPT 覆盖。我们正在快速迭代,以添加更多 Web API 并通过更多 WPT 测试,朝着让 Kitesurf 达到生产就绪状态的目标迈进。
- 效率。我们持续运行 CPU、内存和墙钟时间基准测试,并与其他开发者平台团队紧密合作,让 Kitesurf 尽可能具有成本效益和高效率。
结语
感谢你一路读到这里——我们知道这是一篇篇幅很长、技术性很强的博客文章,但希望它足够有趣。我们之所以写得如此详细,是因为我们深知构建一款新浏览器(哪怕是一款非常小众的浏览器)有多么重要,同时也多么复杂。
Kitesurf 目前仍处于早期阶段,但我们希望尽快向你开放,并从你的反馈中学习。团队将持续积极改进它,并围绕性能、效率和兼容性进行高频更新。
最后一点:一旦我们准备好了,就会将 Kitesurf 开源——希望这一天不会太远。我们的目标是让任何客户都能按需在自己的账户上部署他们自己的 Kitesurf 版本。
所以,欢迎在 playground 里试试看,留意我们的 changelog,并来 Discord 与团队交流。分享你的体验、给我们反馈——我们一直在倾听。