Artifacts:会说 Git 的版本化存储
原文:Artifacts: versioned storage that speaks Git Source: https://blog.cloudflare.com/artifacts-git-for-agents-beta/
2026-04-16
Agent 改变了我们对源代码控制、文件系统和持久化状态的思考方式。开发者和 agent 正在生成比以往任何时候都更多的代码——未来 5 年里写下的代码,会比编程历史上所有时间加起来还多——这给满足这种需求所需的系统规模带来了数量级的变化。源代码控制平台在这里尤其吃力:它们是为人类的需求而构建的,而不是为永不睡眠、可以同时处理多个 issue、永不疲倦的 agent 带来的 10 倍流量增长而设计的。
我们认为需要一个新的原语:一个分布式、版本化、首先为 agent 而构建的文件系统,它能够支撑当今正在被构建的各种应用程序。
我们把它称为 Artifacts:一个会说 Git 的版本化文件系统。你可以与你的 agent、sandbox、Workers 或任何其他计算范式一起以编程方式创建仓库,并从任何常规 Git 客户端连接到它。
想给每个 agent 会话一个仓库?Artifacts 可以做到。每个 sandbox 实例?也是 Artifacts。想从一个已知良好的起点创建 10,000 个 fork?你猜对了:还是 Artifacts。Artifacts 暴露了一个 REST API 和原生 Workers API,用于在 Git 客户端不合适的环境中(比如任何 serverless 函数中)创建仓库、生成凭证和提交。
Artifacts 现已进入 private beta,我们的目标是在 5 月初开放为 public beta。
// Create a repo
const repo = await env.AGENT_REPOS.create(name)
// Pass back the token & remote to your agent
return { repo.remote, repo.token }
# Clone it and use it like any regular git remote
$ git clone https://x:${TOKEN}@123def456abc.artifacts.cloudflare.net/git/repo-13194.git
就这样。一个空仓库,即时创建,任何 git 客户端都可以对它进行操作。
如果你想从一个已存在的 git 仓库引导出一个 Artifacts 仓库,让你的 agent 独立工作并推送独立的更改,你也可以通过 .import() 来实现:
interface Env {
ARTIFACTS: Artifacts
}
export default {
async fetch(request: Request, env: Env) {
// Import from GitHub
const { remote, token } = await env.ARTIFACTS.import({
source: {
url: "https://github.com/cloudflare/workers-sdk",
branch: "main",
},
target: {
name: "workers-sdk",
},
})
// Get a handle to the imported repo
const repo = await env.ARTIFACTS.get("workers-sdk")
// Fork to an isolated, read-only copy
const fork = await repo.fork("workers-sdk-review", {
readOnly: true,
})
return Response.json({ remote: fork.remote, token: fork.token })
},
}
查看文档开始使用,或者如果你想了解 Artifacts 是如何被使用的、它是怎么构建的、以及它在底层是如何工作的,请继续阅读。
为什么是 Git?什么是版本化文件系统?
Agent 懂 Git。它深植于大多数模型的训练数据中。Agent 对它的常规路径和边缘情况都很熟悉,而代码优化的模型(以及/或者 harness)特别擅长使用 git。
此外,Git 的数据模型不仅适合源代码控制,也适合任何你需要追踪状态、时间旅行和持久化大量小数据的场景。代码、配置、会话提示词和 agent 历史:所有这些都是你常常希望以小块(“commit”)存储,并且能够回退或回滚(“history”)的对象。
我们本可以发明一个全新的、专门的协议……但那样你就有了引导问题。AI 模型不懂它,所以你必须分发 skill 或者 CLI,或者寄希望于用户已经接入了你的文档 MCP……所有这些都增加了摩擦。但是,如果我们能直接给 agent 一个经过认证的、安全的 HTTPS Git remote URL,让它们像操作 Git 仓库那样操作呢?事实证明,这相当好用。而对于不会说 Git 的客户端——比如 Cloudflare Worker、Lambda 函数或 Node.js 应用——我们暴露了一个 REST API 以及(很快推出的)各语言专用的 SDK。这些客户端也可以使用 isomorphic-git,但在很多情况下,一个更简单的 TypeScript API 可以减少所需的 API 表面。
不仅仅用于源代码控制
Artifacts 的 Git API 可能让你以为它只用于源代码控制,但事实证明,Git API 和数据模型是一种强大的方式,能够以可 fork、时间旅行和 diff 的形式持久化任何数据的状态。
在 Cloudflare 内部,我们将 Artifacts 用于我们的内部 agent:自动将文件系统的当前状态以及会话历史持久化到一个 per-session 的 Artifacts 仓库中。这让我们能够:
-
在不需要(永久)分配块存储的情况下持久化 sandbox 状态。
-
与他人共享会话,并允许他们通过会话(prompt)状态和文件状态进行时间旅行,无论“实际“仓库(源代码控制)是否有 commit。
-
而且最棒的是:可以从任意位置 fork 一个会话,这让我们的团队能够与同事分享会话并让他们从该处继续。在调试某个问题时想要再有人帮忙看一眼?发个 URL 让对方 fork 它就行。想要在某个 API 上即兴发挥?让同事 fork 它,从你停下的地方继续。
我们也跟一些团队聊过,他们想在不需要 Git 协议但需要其语义(回退、克隆、diff)的场景下使用 Artifacts。把 per-customer 的配置作为产品的一部分存储,并希望能够回滚?Artifacts 可以是一个不错的表达方式。
我们很期待看到团队探索 Artifacts 在非 Git 用例上的应用,就像探索 Git 用例一样。
底层原理
Artifacts 构建在 Durable Objects 之上。创建数百万(甚至数千万+)有状态、隔离的计算实例的能力,本就是 Durable Objects 当今工作方式的固有特性,这正是我们支持每个命名空间数百万 Git 仓库所需要的。
Major League Baseball(用于实况比赛粉丝分发)、Confluence Whiteboards 和我们自己的 Agents SDK 都在大规模地使用 Durable Objects,所以我们是在一个我们已经在生产环境中运行了一段时间的原语之上来构建这个东西的。
不过,我们确实需要一个能够运行在 Cloudflare Workers 上的 Git 服务器实现。它需要小巧、尽可能完整、可扩展(notes、LFS),并且高效。所以我们用 Zig 构建了一个,并将其编译成 Wasm。
为什么用 Zig?三个原因:
-
整个 git 协议引擎是用纯 Zig 编写的(没有 libc),编译成约 100KB 的 WASM 二进制(还有优化空间!)。它实现了 SHA-1、zlib inflate/deflate、delta 编码/解码、pack 解析以及完整的 git smart HTTP 协议——全部从零实现,除了标准库之外没有任何外部依赖。
-
Zig 给我们对内存分配的手动控制权,这在像 Durable Objects 这样的受限环境中很重要。Zig Build System 让我们可以轻松地在 WASM 运行时(生产环境)和原生构建(用于针对 libgit2 的正确性验证测试)之间共享代码。
-
WASM 模块通过一个轻量的回调接口与 JS 宿主通信:11 个用于存储操作的 host-imported 函数(host_get_object、host_put_object 等),以及一个用于流式输出(host_emit_bytes)的函数。WASM 端可以完全独立地进行测试。
在底层,Artifacts 还使用 R2(用于快照)和 KV(用于追踪 auth token):
How Artifacts works (Workers, Durable Objects, and WebAssembly)
一个 Worker 充当前端,处理认证和授权、关键指标(错误、延迟),以及在请求时查找每个 Artifacts 仓库(Durable Object)。
具体来说:
-
文件存储在底层 Durable Object 的 SQLite 数据库中。
-
Durable Object 存储有 2MB 的最大行大小限制,所以大的 Git 对象会被分片并存储在多行中。
-
我们利用了 sync KV API(state.storage.kv),它在底层由 SQLite 支持。
-
-
DO 有约 128MB 的内存限制:这意味着我们可以创建数千万个(它们快速且轻量),但必须在这些限制内工作。
-
我们在 fetch 和 push 路径中大量使用流式处理,直接返回从原始 WASM 输出 chunk 构建的 `ReadableStream<Uint8Array>`。
-
我们避免计算自己的 git delta,而是将原始 delta 和基础哈希与已解析的对象一起持久化。在 fetch 时,如果请求方客户端已经有了基础对象,Zig 就会发出 delta 而非完整对象,这样可以节省带宽和内存。
-
同时支持 git 协议的 v1 和 v2。
-
我们支持的能力包括 ls-refs、shallow clone(deepen、deepen-since、deepen-relative)以及带 have/want 协商的增量 fetch。
-
我们有一套全面的测试套件,包括对 git 客户端的一致性测试,以及针对一个 libgit2 服务器(用于验证协议支持)的验证测试。
-
在此之上,我们对 git-notes 提供了原生支持。Artifacts 被设计为 agent-first,而 notes 让 agent 能够给 Git 对象添加注释(metadata)。这包括 prompt、agent 归属和其他可以从仓库中读/写而不必修改对象本身的元数据。
大仓库,大问题?认识 ArtifactFS。
大多数仓库都不是那么大,而且 Git 在存储方面被设计得极其高效:大多数仓库克隆只需要几秒钟,主要时间花在网络建连、认证和校验和上。在大多数 agent 或 sandbox 场景下,这是可以接受的:在 sandbox 启动时克隆仓库,然后开始工作。
但如果是一个数 GB 的仓库,或者有数百万个对象的仓库呢?我们怎么能快速克隆这样的仓库,而不让 agent 阻塞数分钟、消耗算力呢?
一个流行的 web 框架(2.4GB,且有很长的历史!)克隆需要将近 2 分钟。Shallow clone 更快,但还不足以达到个位数秒级,而且我们也不总是想忽略历史(agent 觉得它有用)。
我们能让大仓库降到约 10-15 秒,以便 agent 能开始工作吗?可以,通过一些技巧:
作为 Artifacts 发布的一部分,我们正在开源 ArtifactFS,一个文件系统驱动,旨在尽可能快地挂载大型 Git 仓库,在不阻塞初始 clone 的情况下按需 hydrate 文件内容。它非常适合 agent、sandbox、container 和其他启动时间至关重要的用例。如果你能为每个大仓库节省约 90-100 秒的 sandbox 启动时间,而你每月运行 10,000 个这样的 sandbox 任务:那就节省了 2,778 个 sandbox 小时。
你可以把 ArtifactFS 想象成“Git clone 但是异步“:
-
ArtifactFS 运行一个 git 仓库的 blobless clone:它获取文件树和 ref,但不获取文件内容。它可以在 sandbox 启动期间这么做,然后让你的 agent harness 开始工作。
-
在后台,它通过一个轻量的守护进程并发地 hydrate(下载)文件内容。
-
它优先处理 agent 通常想首先操作的文件:package manifest(
package.json、go.mod)、配置文件和代码,在可能的情况下降低二进制 blob(图像、可执行文件和其他非文本文件)的优先级,让 agent 在文件本身被 hydrate 时就能扫描文件树。 -
如果 agent 尝试读取的文件还没有完全 hydrate,读取会阻塞直到完成。
文件系统不会尝试将文件“同步“回远程仓库:对于成千上万或数百万个对象,这通常非常慢,而且既然我们在说 git,我们也不需要这么做。你的 agent 只需 commit 和 push,就像在任何仓库中一样。没有要学的新 API。
更重要的是,ArtifactFS 适用于任何 Git remote,不仅是我们自己的 Artifacts。如果你正在从 GitHub、GitLab 或自托管的 Git 基础设施克隆大仓库:你仍然可以使用 ArtifactFS。
接下来会有什么?
我们今天的发布只是 beta,我们已经在做一些功能,你将在接下来几周看到它们落地:
-
扩展我们暴露的可用指标。今天我们发布了关键操作计数(per namespace、repo)以及每仓库存储字节数等指标,以便管理数百万个 Artifacts 不再是负担。
-
支持 repo 级别事件的Event Subscriptions,这样我们可以在命名空间内任何仓库的 push、pull、clone 和 fork 上发出事件。这也将允许你消费事件、编写 webhook,并使用这些事件来通知最终用户、驱动产品中的生命周期事件,以及/或者运行 post-push 任务(比如 CI/CD)。
-
用于与 Artifacts API 交互的原生 TypeScript、Go 和 Python 客户端 SDK。
-
仓库级搜索 API 和命名空间范围的搜索 API,例如“找到所有包含
package.json文件的仓库“。
我们还计划为 Workers Builds 提供 API,以便你可以在任何由 agent 驱动的工作流上运行 CI/CD 任务。
它会花我多少钱?
Artifacts 还处于早期,但我们希望我们的定价能够在 agent 规模上工作:拥有数百万个仓库需要具有成本效益,未使用(或很少使用)的仓库不应成为拖累,我们的定价应该匹配 agent 的大规模单租户特性。
你也不应该需要去想一个仓库是否会被使用、它是热的还是冷的、以及/或者 agent 是否会唤醒它。我们将根据你消耗的存储和针对每个仓库的操作(例如 clone、fork、push 和 pull)向你收费。
|
$/单位 |
包含 |
|
|---|---|---|
|
操作 |
$0.15 每 1,000 次操作 |
每月前 10k 次免费 |
|
存储 |
$0.50/GB-月 |
前 1GB 免费。 |
无论你有 1,000 个、100,000 个还是 1,000 万个仓库,大且繁忙的仓库会比小且较少使用的仓库花费更多。
随着 beta 进展,我们也将把 Artifacts 带到 Workers Free plan(带一些合理的限制),并且我们会在 beta 期间提供更新,以防定价发生变化,以及在对任何用量收费之前提前告知。
我从哪里开始?
Artifacts 正在 private beta 发布中,我们预计 public beta 将在 5 月初(明确指 2026 年!)就绪。我们将在接下来的几周里逐步引入客户,你可以直接登记 private beta 兴趣。
同时,你可以通过以下方式了解更多关于 Artifacts 的信息:
-
阅读文档中的入门指南。
-
访问 Cloudflare dashboard(Build > Storage & Databases > Artifacts)
-
阅读 REST API 示例
关注更新日志以追踪 beta 的进展。