Hacker News AI · 2026/10/13 23:49:56

Anthropic 日均合并代码量激增 12 倍:自研 Scion 版本控制系统重构 AI 原生开发基础设施

原标题:Redesigning Source Control at Anthropic
78AI 研判分
核心综述

Anthropic 指出随着 Claude 实现自主迭代与构建,传统面向人类规模设计的开发者基础设施(如源码控制、CI)成为新瓶颈。其内部日均合并代码量从 5 月的 2500 次飙升至 9 月的 30000 次以上,为此 Anthropic 专门构建了名为 Scion 的内部版本控制系统以支撑这一指数级增长。该案例揭示了在 AI 代理大规模生成代码的背景下,底层工程工具链正面临从“人机协作”向“机器主导吞吐”的范式转移。

报道全文原始报道全文

本文目录11 个章节

Anthropic 的工程实践

Anthropic 源代码管理的重新设计

在 Anthropic,编码已不再是构建系统或开展研究的瓶颈。Claude 能够自主迭代研究循环、对复杂程序进行微优化,并以我们前所未见的速度和规模从零开始构建新服务。现在的瓶颈在于所有为人类规模设计的开发者基础设施:源代码管理、构建系统和持续集成(CI)。

2026 年 5 月,Anthropic 平均每天合并约 2,500 个代码变更;截至 9 月,这一数字已超过每天 30,000 个。我们不认为这种增长速度会在短期内放缓:合并代码的潜在需求几乎是无限的,而且每消除一个瓶颈,都会立即导致我们产出的代码量进一步增加。

2026 年 1 月至 9 月期间,每日合并到我们单体仓库(monorepo)中的变更数量。

为了支持这种增长,我们构建了 Scion——一款内部开发的版本控制系统,并在五个月内将我们的单体仓库从 git 完全迁移过来。在同一时期内,我们还构建并上线了代码审查界面(名为 Antique)、代码搜索功能、丰富的源代码管理 IAM 系统、管理和落地大量已审查代码的新方法等。在这篇文章中,我们将重点介绍如何具体构建 Scion。这是一个有趣的案例研究:Claude 编写代码的能力既是让我们陷入当前处境的原因,也是我们能够快速构建高质量、可扩展系统以应对这一挑战的关键。

扩展我们的单体仓库

在探讨我们构建了什么之前,我们应该先认识到我们的工作负载有多么不寻常。不出所料,Anthropic 使用 Claude 编写软件的程度远超几乎任何其他公司,因此我们往往是最早看到那些为人类规模设计的工具开始出现压力迹象的人。源代码管理只是其中一个例子。虽然我们不期望许多组织在近期就遇到这些问题,但我们推测,其他使用 AI 编码工具的组织不久后也会经历同样的压力点,这就是为什么我们希望分享我们所构建的内容以及学到的经验。

Git 是一个去中心化系统:每一次克隆都是一个完整、自包含的仓库,即使完全离线,也能计算差异(diff)、读取历史记录和追溯代码归属(blame),并检出任意版本。对于绝大多数仓库而言,这是正确的设计选择,也是 Git 成为行业标准的重要原因之一。

随着我们的单体仓库(monorepo)不断膨胀,它越来越难以契合这一设计范式。仅主分支的历史记录就接近 100 GB,而压缩后的工作副本也超过 25 GB。我们每天执行约 2500 万次代码检出以支持 CI 流程,这还未计入开发者环境、智能体沙箱和研究任务的需求。如果采用朴素的方式获取数据,每天的 Git 流量将超过 600 PB。

Git 提供了一些工具来处理仓库的部分内容,例如浅克隆(shallow clones)、稀疏检出(sparse checkouts)和承诺远程(promisor remotes)。除此之外,针对大型单体仓库还有标准的变通方案,比如内部 Git 镜像以及存储在 Blob 存储中的仓库快照(种子文件)。我们曾使用过所有这些方法——在负载高峰期,我们运营着数百个内部 Git 镜像来应对压力。这些措施为我们争取了时间,但随着合并频率的增加,其运维难度也随之上升。每次刷新之间,种子文件与主分支最新提交(tip of main)的距离越来越远,而在部分克隆上维持依赖历史的操作(如 diff 和 blame)也需要越来越多的精细处理。

扩展 Git 检出的典型配置。

退一步来看,我们发现,像大多数公司一样,我们将 Git 用作具有单一权威副本的中心化系统,但几乎所有的客户端都是本质上始终在线的智能体和任务。那些使 Git 在分布式离线工作中表现卓越的特性,实际上正在阻碍我们随着仓库增长而进行扩展的能力。因此,我们开始思考:如果从一开始就将“智能体始终在线”这一事实纳入源代码控制的设计考量,它会是什么样子?

面向智能体规模的源代码控制原则

随着智能体编程(agentic coding)的发展,关于软件开发方式的许多常见假设正在演变。我们在构建 Scion 时拥抱了这些变化,从而能够在几个核心原则上采取与 Git 根本不同的方法。针对超大型单体仓库的源代码控制已有先例,特别是 Google 的 Piper 和 Meta 的 Sapling,因此我们能够借鉴它们来之不易的经验教训来构建 Scion。我们的原则如下:

客户端始终在线。 Git 假设客户端离线工作,并需要仓库的完整副本。由于我们的几乎所有客户端都是代理(agents)和作业(jobs),我们围绕一个始终可达的服务器设计了 Scion 的客户端和协议,让客户端在需要时按需获取数据。

客户端-服务器的非对称性。 在 Git 中,每个客户端都有能力成为功能完备的服务器。而在 Scion 中,服务器负责回答有关文件历史和 blame(追溯)的问题、创建提交、执行合并和变基等操作。客户端则维护一个有界的本地对象缓存,将工作区文件布局到磁盘上,监控文件系统变化,并为用户提供一种符合人体工学的与服务器交互方式。客户端自身计算能力有限,但作为交换,它在本地所需的数据量大大减少。

全面的源代码控制服务可以驱动许多新型应用。 使用 Git 时,如果 CI 作业或工具需要询问关于仓库的问题(例如谁最后修改了某一行代码,或者两个提交之间有何关联),它必须维护仓库的本地副本,或者寄希望于特定供应商提供的 API 能给出答案。而在 Scion 中,客户端使用的所有源代码控制查询也都通过 API 暴露出来,因此在许多情况下,作业根本不需要本地仓库。如果没有这种廉价且可编程的源代码控制访问方式,许多内部工具(如我们的自动 bisect 和 revert 流水线)将无法在大规模场景下实用化。

一切必须具备水平可扩展性。 在我们的峰值时期,我们运行着数百个 git 镜像,这极大地消耗了容量,并且一旦仓库大小超过镜像的磁盘或内存限制,便无法继续扩展。在 Scion 中,仓库数据是分布式的,每个组件都可以独立扩展;任何地方(包括服务器端)都不存在完全物化的仓库副本。Scion 没有 packfiles(Git 中压缩的对象包)这一概念,因此无需进行仓库维护。

提交必须廉价、增量且无锁。 在 git 中,你在本地提交,然后推送以分享你的工作。而在 Scion 中,每次提交、变基(rebase)或合并都在服务器端发生,因此无需推送,但这些操作中的每一个都必须足够快。创建提交并更新其下游数据结构的成本必须随变更大小扩展,而非随仓库整体大小扩展,否则服务器将无法跟上节奏。Scion 的开发生命周期不鼓励使用引用(refs,即指向提交的指针,如分支和标签),除非是主引用或发布分支,因为全局状态需要所有服务器达成一致,这构成了一个迫在眉睫的扩展性难题。

工作副本是可选的,且在设计上即为稀疏模式。 由于我们的单体仓库(monorepo)规模庞大,且每天为 CI 执行数千万次代码检出,我们希望在可能的情况下尽量避免检出操作。借助 Scion,例如,当某个 CI 任务需要获取某次提交与其合并基点之间的差异时,可以直接向服务器请求。写入操作也是如此:许多写入负载也可以跳过检出步骤,完全通过 API 完成。Scion 的协议核心围绕稀疏检出(sparse checkouts,仅包含客户端请求的目录)和虚拟检出(virtualized checkouts,按需物化文件)展开,因此当任务确实需要将文件存储在磁盘上时,客户端只需为其实际读取的内容付出代价。

Scion 的工作原理

了解这些原则在构建 Scion 的过程中如何具体落地,有助于深入理解其设计。这些见解也可应用于其他版本控制系统,或更广泛地应用于软件开发生命周期的其他阶段。

数据结构

在 Scion 中,工作单元是“变更集”(changeset),它是预写日志(write-ahead log)中的一个条目。变更集存储了你对 git 提交的大部分预期内容。但不同于 git 提交存储的是指向树对象(tree)的指针,变更集存储的是相对于其第一个父提交1发生变化的文件列表,以及指向 blob 存储中压缩文件内容的基于内容寻址(content-addressed)的指针。变更集在服务器端创建,并可即时在所有地方访问。

Scion 中变更集的结构形态。

这种结构让我们能够以极高的吞吐量接收变更集(changeset),因为无需处理 packfile,不需要加锁或跨服务器协调,也不需要移动引用(refs)。Scion 在技术上确实支持 refs,但由于创建和获取 commit 都不涉及它们,因此移动一个 ref 只是对单个 Spanner 行执行一次比较并交换(compare-and-swap)操作,且该操作与创建变更集是分离进行的。

变更集仅记录发生变化的内容,因此单凭它本身无法快速回答诸如“谁最后编辑了某一行”或“哪些 commit 影响了某个文件”之类的问题。为了回答这些问题,Scion 会从变更集中构建额外的数据结构,包括专门用于文件 blame 和路径历史的结构,以及用于 commit 图的跳表(skip list)。我们将所有不直接属于变更集的内容统称为“派生数据”,并通过一种通用机制来计算这些数据。每种类型的派生数据都是递归定义的,即其在某个变更集中的值是根据其父变更集中的值计算得出的。

这一机制带来三大优势。首先,当某种新数据结构能加速某些操作时,我们可以轻松添加新的派生数据类型。其次,对于每种类型,我们可以选择立即计算还是延迟计算,从而避免物化那些我们并不需要的数据。第三,由于客户端永远不会看到这些数据结构的内部细节,我们可以对其进行优化而无需更改客户端代码。随着系统的发展,我们已经多次添加了新的派生数据类型,例如用于检测复制文件或基于路径搜索文件的新索引。

Scion 的扩展性

一小群 Scion 服务器为客户端所需的任何操作提供源代码控制 API,例如获取变更集、计算 diff、查找合并基础(merge base)以及获取 blob。所有源代码控制数据均采用内容寻址方式存储,这意味着一旦数据被存储,就永远不会改变,因此任何服务器都可以缓存这些数据,而无需与其他服务器进行确认。结果是,这些服务器具备水平可扩展性,且几乎不需要协调。它们本质上就是大型缓存,同时也能即时计算派生数据并将结果写回 Spanner。

Scion 的众多用户不再需要维护自己的本地仓库。对于需要查询源代码管理信息(尤其是提交祖先关系和 blame 信息)的 CI 任务或工具而言,获取和维护仓库曾是一项沉重的维护负担。在迁移初期,当我们还没有自己的客户端、仓库格式或协议时,Scion 仅响应这些“元数据”查询。而获取文件内容和物化工作副本则是数据密集型操作得多,它们需要各自独立的设计方案。

Scion 的 scn 客户端在几个重要方面偏离了 git 的 fetch 协议,因此它天然适合一种高度可扩展的架构,其 CPU 需求远低于 git 服务器。Scion 的协商机制不会告诉服务器客户端已经拥有什么;相反,它完全基于客户端所需的树对象(trees)和 blob 对象进行操作。从根树对象开始,客户端检查本地存储中缺失的树对象并递归请求它们,然后对 blob 对象重复此过程。每个请求针对的都是一个永不变更的特定对象,因此任何缓存都可以响应这些请求,这种架构与传统分层缓存非常相似。该过程高效且可恢复,因为不存在单个多 GB 大小的 packfile 响应。稀疏检出甚至虚拟检出无需特殊支持,因为客户端根本不会请求它不需要的树对象。

在整个集群中,客户端通过套接字与守护进程 scion-daemon 通信,该守护进程为整个节点存储对象。我们大多数节点都需要访问单体代码库(monorepo),同一节点上的任务会复用大部分相同的对象。每个守护进程从一个定期刷新的快照开始,然后仅与其所在区域的树对象和 blob 对象缓存服务器(称为 scion-cache)通信。这些缓存服务器直接从内存中以守护进程将使用的磁盘格式流式传输对象,因此它们无需花费时间计算客户端缺失的对象或执行增量压缩。当缓存缺少某个对象时,它会向权威的 scion-servers 发起请求,后者根据需要从 Spanner 或云存储中读取数据。

scion-daemon、scion-cache 和 scion-server 针对此协议响应相同的 RPC,因此客户端无需了解缓存拓扑结构。理论上任何层级都可以与其他任意层级通信,但我们严格实施分层隔离以限制故障域。我们希望避免区域性 scion-cache 发生故障时压垮上游 scion-server 并导致整个系统瘫痪的情况。

Scion 的检出(checkout)架构。

该系统的每一层都保持超过 99% 的缓存命中率,且不需要维护长期状态,因此易于按需扩展。在 CPU 和内存需求方面,我们的 Scion 基础设施占用量比之前的 git 镜像基础设施减少了 200 倍。CI 和研究任务检出代码的速度提升了两个数量级(从分钟级降至秒级),从而释放了集群中大量的容量;仅 CI 就实现了 25% 的 CPU 容量节省。无论是客户端还是缓存都不需要执行仓库维护操作,这简化了我们任务的生命周期管理。

构建 Scion 的经验教训

我们开始构建 Scion 的时间大致与 Claude Mythos Preview 和 Claude Tag 内部可用时间相同。这两个版本的发布同时放大了对 Scion 的需求,并显著加速了其开发进程。

这里有一个特别突出的例子。今年早些时候,我们主要手写了第一版 git-to-Scion 摄取管道作为原型。我们认为它做得不错——直到我们拿到了 Claude Mythos Preview 的一个早期内部快照。我们要求它重写整个代码,在没有进一步指令的情况下,它生成的版本内存消耗降低了 20 倍,速度提高了 4 倍,同时保留了所有关于摄取顺序和数据结构的隐式不变量。

2026 年 1 月至 9 月期间,Scion 和 Antique 代码库每周合并的变更数。

我们在构建和运营 Scion 过程中获得的经验,为构建智能体规模(agent-scale)软件提供了有趣的启示。

小团队快速开发将变得更加普遍。 一个七人团队不仅构建了 Scion,还开发了 Antique(我们的代码审查工具,关于它我们可以轻松再写一篇博客文章),此外还有半打相关系统,并在五个月内完成了全面迁移。在此期间,每日合并的代码量增长了 10 倍。过去,开发和部署这样一个源代码控制系统通常需要一家公司花费数年时间进行迭代式迁移,并投入更多的工程师。我们认为,这种快速、灵活的迁移在未来将变得更加常见。

工程师的价值并未降低,但他们的工作内容正在发生变化。 参与该系统的每一位工程师现在都会认为 Claude 在编写代码方面比他们更强。但我们的工程师仍然提供了对高层系统间组件和设计层面权衡的宝贵理解,针对我们要解决的问题以及我们需要达到的规模做出了明智的选择。很多时候,我们发现工程师的角色是告诉 Claude “不”。智能体有时会违反核心系统约束,以满足那些本就不应被允许的模式。这种情况在我们的迁移过程中尤为常见。例如,有多个系统试图通过线性读取提交日志来暴力查找变更何时合并到主分支,而不是询问我们的代码审查工具。Anthropic 也广泛使用对抗性审查,虽然这在很多方面极其有效,但也可能存在视野狭窄的问题,因此需要熟练的工程师引导 Claude 避免针对假设性问题过度工程化系统的某些部分。例如,有一次审查对信任另一个内部服务表现出过度的防御性,导致 Claude 添加了过多的验证和复杂性。我们的团队成员仍然会审查系统的每一个变更请求,但现在他们关注的是变更的意图,而不是逐行阅读代码。

我们显著提升了优化效果与代码质量。 得益于 Claude 编写海量代码的速度远超人类,Scion 成为我们经手过的测试最充分、防护最严密的代码库之一。即便在时间紧迫的情况下,我们仍为所有非平凡的底层架构及版本控制交互构建了封闭(hermetic)模拟环境,并实施了模糊测试(fuzzing)和精细化的速率限制。Claude 还轻松发现了重大优化点——例如针对祖先查询的算法优化,该优化弥补了我们某一索引的缺失——这类工作原本需要专家花费数天甚至数周进行分析与调优……而它第二天又再次完成了类似任务。

Scion 原生仓库中观察到的性能提升。

我们为新型单体仓库(monorepo)安全模式奠定了基础。 在庞大的单体仓库中,管理安全性、合规性与规模同样重要。我们从一开始就基于这些考量构建 Scion。它支持丰富的仓库级访问控制,并允许对单个目录应用权限,从而在保护最敏感代码的同时,保留单体仓库的优势。此外,我们开发的代码审查工具能够表达复杂的语义约束,使我们能够区分仅涉及注释的简单变更与敏感的逻辑变更,从而让人类审查者专注于最具影响的关键改动。

运营卓越性达到了新高度。 我们的团队大量使用 Claude Tag,这帮助我们监控系统中的每个组件。例如,我们创建了 Slack 频道,指派 Claude 专注于单一组件的健康状况。我们将这些 Claude 实例称为“超级粉丝”(superfans)。我们有 scion-daemon 超级粉丝、scion-cache 超级粉丝、Antique 合并队列超级粉丝等。它们可以访问我们的遥测数据和日志,表现得像一位经验丰富的工程师,除了刷新图表和寻找异常之外别无他事。虽然我们也为所有系统设置了传统告警,但我们的“超级粉丝”能够检测到那些让传统告警显得单薄的细微且新颖的问题。

我们正在彻底重构先验假设。 这个项目促使我们重新审视那些为人类规模设计的其他工作流。例如,在智能体(agent)规模下,传统的合并队列(merge queue)已不再合理。当数百甚至数千个变更在测试运行期间即可合并时,“持续集成”(CI)究竟意味着什么?由于我们无法有效复现业界标准的“全局仓库锁”机制来管理合并队列,因此转而投资于合并后及部署前的自动化测试。这确实意味着并发变更可能会产生冲突,但 Claude 通常能比人类识别冲突的速度更快地修复这些冲突。

贡献于更广泛的生态系统

我们将 Scion 视为应对日益强大的 AI 智能体所引发的规模化挑战的答案之一。我们分享这些细节旨在展示团队如何解决类似挑战,但并不指望我们的解决方案或考量适用于所有场景。

Scion 绝非 git 的通用替代品。此处阐述的概念仅对真正庞大的单体仓库(monorepo)有意义——这类仓库要么拥有数万名工程师,要么由大量智能体高效地编写代码。此外,Anthropic 的独特之处在于,我们为内部使用投入 token 的能力远超其他企业现实中的意愿。我们这样做既是为了满足自身的软件开发需求,也是为了测试 Claude 的能力。

从实际操作层面来看,很难将 Scion 以广泛适用于其他组织的形式提供。它与 git 存在显著差异,这意味着公司需要迁移开发生命周期的每一个环节,并且它还需要配套的代码审查、代码搜索和 CI 系统。我们内部的这些组件版本高度定制化,因此其他组织难以采用;我们也担心,试图构建一个迎合所有人的公开版本实际上并不会非常有用。

然而,我们预计这类问题在未来六到十二个月内将变得更加普遍。如果每家使用 git 的公司都独自面对类似的挑战,那将是对工程资源的低效利用。鉴于此,我们认为最具影响力的做法是分享我们的思考,以便其他开发者能够在不偏离整体模型的前提下,将 Scion 中最成功的部分应用到 git 中。git 服务器不必以与 git 客户端相同的方式工作;现有的新型服务器架构能够带来显著的可扩展性提升。Git 平台可以提供类似 Scion 的全面服务端 RPC(远程过程调用),甚至可能以一种标准化的方式跨代码托管平台(forges)实现,让 git 客户端学会与之通信。协商协议也不必完全照搬现状,git 中的各种稀疏(sparse)和浅克隆(shallow)功能也可以更好地组合协同。

最后,我们要承认,git 社区已经花了近二十年的时间来为数百万开发者扩展该平台。我们的贡献则更为聚焦:分享我们对代理式软件开发(agentic software development)如何与这些系统交互的早期见解,从而能够与 GitHub、GitLab 以及开源社区合作,支持开发者不断变化的需求。在软件开发生命周期与 AI 指数级增长交汇之际,我们携手共进。

致谢

本文由 Nick G. 及源代码控制团队撰写:S.G., R.K., Dan C., Garrett H., Ben L., Colin M., Joe P. 感谢 Vilas J. 和 Sergiu D. 在这一雄心勃勃的旅程中对源代码控制团队的支持,以及 Amir O. 对 Antique 项目的早期贡献。

脚注

  1. 将变更文件存储于合并操作第一个父提交(first parent)的相对位置是一种风格选择;在实践中,我们发现人们只关心主干开发(trunk-based development)模式下 monorepo 中主线提交的 history(历史)或 blame(追溯)信息。

订阅开发者通讯

获取产品更新、操作指南、社区亮点等内容。每月发送至您的收件箱。