Claude Code 的构建方式

自今年5月全面发布以来,Claude Code 在开发者世界中掀起了一阵风暴。该工具目前的年收入达到超过5亿美元,并且在那之后的三个月内使用量激增了10倍以上。

我最近与 Claude Code 的两位创始工程师进行了交谈:Boris Cherny(最初原型的提出者,也是该项目的创始工程师),Sid Bidasaria(Claude Code 的第二位工程师,也是 Claude Code 子代理的创建者),以及创始产品经理 Cat Wu

我了解到 Claude Code 是如何构建的,并获得了关于成功“以 AI 为先的工程团队”如何运作的见解;这有点像窥视水晶球,也像是未来快速发展的初创公司可能如何运作的潜在预示。好消息是,软件工程师似乎在其中非常受欢迎……

今天,我们涵盖以下内容:

  1. 一切的开始。 Claude Code 的想法源于一个命令行工具,使用 Claude 来说明工程师在工作中听什么音乐。在获得文件系统访问权限后,这一想法在 Anthropic 内部迅速传播开来。如今,Claude Code 有自己的完整团队。
  2. 技术栈和架构。 TypeScript、React、Ink、Yoga 和 Bun。技术栈的选择是为了“分布”并发挥模型的优势。有趣的是:Claude Code 中 90% 的代码是由它自己编写的!
  3. 在几天而不是几周内构建和发布功能。 该团队以快速的速度工作,每位工程师每天大约有 5 次发布。原型设计出乎意料地快:我们为新功能进行 10 多个实际原型。这看起来像是 AI 代理确实加快了迭代速度。
  4. 重新设计终端用户体验。 Claude Code 为终端用户体验带来了许多创新功能,这些功能在我们能够与由 LLM 驱动的终端交互之前并不需要。看看其中的一些功能。
  5. “以 AI 为先”的软件工程是什么样的? 使用 AI 代理进行代码审查和测试,测试驱动开发(TDD)的复兴,自动化事件响应,以及谨慎使用功能标志。这是否预示着“以 AI 为先”的工程团队未来会如何运作?
  6. 构建子代理。 介绍如何在短短三天内构建子代理功能,其中两天的工作被丢弃。
  7. AI 辅助工程团队的未来? 从 Anthropic 的运作方式中,工程团队可以学到什么,以及需要注意哪些使其独特的东西,这些可能不太容易转移。

1、一切的开始

Boris Cherny 于 2024 年 9 月加入 Anthropic,并开始用 Claude 3.6 模型构建各种原型。当时,他想更熟悉 Anthropic 的公共 API。Boris 回忆起那段时期:

“我开始在终端中使用 Claude 进行一些实验。第一个版本非常基础:它不能读取文件,也不能使用 bash,也不能做任何工程相关的事情。但它可以与计算机进行交互。 我将这个原型连接到了 AppleScript:它可以告诉我我工作时听的音乐。然后它还可以根据我的输入更改正在播放的音乐。 这是一个很酷的演示,但并不是特别有趣。”

与此同时,Cat Wu 正在研究 AI 代理的计算机使用情况以及由此产生的新能力。在与 Cat 交谈后,Boris 想到给终端更多的功能,而不仅仅是使用 AppleScript。他说:

“我尝试给它一些工具来与文件系统和批处理进行交互;它可以读取文件、写入文件,并运行批处理命令。 突然间,这个代理变得 非常 有趣。我在我们的代码库中运行它,并开始向它提问。Claude 开始探索文件系统并阅读文件。因此,它会读取一个文件,查看导入的内容,然后读取导入中定义的文件!它一直这样下去,直到找到一个好答案。Claude 探索文件系统对我来说是令人震惊的,因为我以前从未使用过这样的工具。 在 AI 中,我们谈论“产品过剩”,这就是我们通过原型发现的情况。产品过剩意味着模型能够完成特定任务,但 AI 运行的产品并没有以捕捉这种能力的方式构建。我所发现的 Claude 探索文件系统的现象就是纯粹的产品过剩。模型已经可以做到这一点,但围绕这种能力并没有构建产品!”

1.1 市场匹配

Boris 每天都在工作中使用他的原型。然后他与将成为核心 Claude Code 团队的同事分享了它,其他开发人员也开始每天使用它。

Boris 和 Claude Code 团队于 2024 年 11 月发布了可狗食的版本——在第一个原型后的两个月。第一天,大约 20% 的工程团队使用了它,到第五天,50% 的工程团队都在使用 Claude Code。此时,Boris 对 Claude Code 在外部世界可能成为爆款感到相当自信。

但内部曾就是否应该发布这个工具存在争议,或者将其保留用于内部使用。Boris 回忆道:

“我们实际上甚至不确定是否想要公开发布 Claude Code,因为我们认为它可能是我们的竞争优势,就像我们的“秘密武器”:如果它给我们带来优势,为什么要发布呢? 最终,我们得出的结论是:
  • Anthropic 根本上是一家模型安全公司
  • 我们了解模型安全性和能力的方式是通过让人们使用工具
  • Claude Code 几乎肯定会是一个人们使用的工具,因为所有 Anthropic 的人都对它上瘾了 所以通过发布这个工具,我们能学到更多关于模型安全性和能力的知识。”

1.2 组建 Claude Code 工程团队

最初,团队只有 Boris,直到 11 月,Sid Bidasaria 加入 Anthropic 并接触到早期版本的 Claude Code。他喜欢这个想法,并加入了 Boris 的项目。

他们的两人团队在工作方式上有很大的自由度。Sid 告诉我:

“我们所做的大部分工作都是 非常 快速地进行原型设计,并构建展示底层模型强大功能的产品。我们在团队内部没有正式的流程:一切都非常灵活。我们可以几乎做任何我们想做的事情,所以我们一直选择最有前景的想法。”

团队在 7 月增长到约 10 名工程师,招聘一直在继续。如今,它是一个完整的产团队,包括工程师、产品管理、设计和数据科学人员——他们仍在招聘

1.3 Claude Code 不仅限于程序员

如今,超过 80% 的编写代码的 Anthropic 工程师日常使用 Claude Code,但这不仅仅是他们。Boris 说:

“我走进办公室,瞥见了一位数据科学家的屏幕。他正在运行 Claude Code。我问:‘等等,你为什么在运行 Claude Code?’ 他说:‘我找到了一种方法让它运行,并为我编写查询。’ 现在,当我走过数据科学家的排位时,他们都运行着 Claude Code——其中许多人运行多个实例——执行查询、创建可视化效果和其他类型的有用工作”。

一个有趣的点是,Boris 一开始只考虑软件工程师使用 Claude Code——所以才叫这个名字!——但产品显示它在其他领域也有进一步的用途。

1.4 在团队规模翻倍的同时增加工程产出

如果我们以每个工程师的 pull request 数量作为指标;当工程团队规模迅速翻倍时,这个指标通常会下降。这是因为现有工程师花更多时间培训新同事,而少花时间编码,而新员工也需要一段时间才能适应。像任何指标一样,每个工程师的 pull request 数量并不是完美的指标,但它确实给出了迭代速度的感觉。PR 吞吐量由 GitHub、Dropbox、Monzo、Adyen 等公司测量

但 Anthropic 在团队规模翻倍的情况下,PR 吞吐量增加了 67%——这要归功于 Claude Code。 按照正常情况,平均 PR 合并数量指标应该会下降,但实际上却上升了!这要归功于 Claude Code:工程师使用它更快地完成 PR。在某种程度上,这似乎是幸运的事件组合,Anthropic 在 Claude Code 被整个工程团队采用的同时,其工程人数翻了一番。

我也注意到,使用 Claude Code 完成一项工作要快得多,而且使用这个工具时,我在编码任务上的进展更好。当我要构建的东西可以通过 Claude Code 验证代码的正确性时,它也会有所帮助,比如运行程序并检查输出或运行测试。

2、技术栈和架构

Claude Code 的技术栈:

  • TypeScript:Claude Code 是用这种语言构建的
  • React with Ink:UI 是用 React 编写的,使用 Ink 框架来创建交互式命令行元素
  • Yoga:布局系统,由 Meta 开源。它是一种基于约束的布局,工作得很好。基于终端的应用程序有一个缺点,即需要支持所有大小的终端,因此你需要一个布局系统来实际实现这一点
  • Bun:用于构建和打包。团队选择了它,因为它比其他构建系统如 Webpack、Vite 等更快。

Ink 框架是一个很棒的组件,允许在终端中创建美观的 UI。例如,要创建这个 UI:

你可以用 React 编写代码:

一个在控制台中更新的计数器的代码。来源:Ink on GitHub

npm 用于分发 Claude Code。它是 Node 生态系统中最流行的包管理器。要开始使用 Claude Code,你需要安装 Node 18 或更高版本,然后运行:

npm install -g @anthropic-ai/claude-code

一旦完成,你可以通过 Claude 命令启动该工具。

技术栈的选择是为了“分布”在 Claude 模型上。 在 AI 中,有“分布”和“非分布”的术语。“分布在分布”意味着模型已经知道如何做这件事,“非分布”意味着它不擅长这样做。

团队希望为 Claude 选择一个“分布在分布”的技术栈,它已经很擅长。TypeScript 和 React 是模型非常擅长的两种技术,因此是合理的选择。然而,如果团队选择了模型不太擅长的更奇特的堆栈,那么它就是一个“非分布”的堆栈。Boris 总结道:

“在非分布的堆栈中,模型仍然可以学习它。但你必须向它展示路线并付出努力。我们想要一个不需要教学的技术栈:一个 Claude Code 可以自我构建的栈。而且它运行得非常好;大约 90% 的 Claude Code 是用 Claude Code 编写的。”

2.1 架构:选择最简单的选项

有趣的是,Claude Code 在客户端方面并没有太多模块、组件和复杂的业务逻辑。对于一个能执行复杂任务如遍历文件系统和代码库的工具来说,这有些令人惊讶!但 Claude Code 只是在 Claude 模型之上的轻量级 shell。这是因为模型几乎完成了所有工作:

  • 定义 UI,并为模型暴露钩子以修改它
  • 为模型暴露工具
  • …然后退到一边

Claude Code 团队试图尽可能少地编写业务逻辑。 Boris 告诉我:

“这听起来可能有点奇怪,但我们构建它的方法是希望人们能尽可能感受到模型的原始状态。我们相信模型能做的比当今产品能实现的多得多。 当你看到很多编码产品时,它们会妨碍模型;它们通过添加 UI 元素和其他部分来增加支架,从而让模型在这些工具中运行时感觉像是一只脚跛行。那些旨在帮助用户的功能最终限制了模型。因此,我们试图使 UI 尽可能简洁。 每次有新的模型发布时,我们都会删除大量代码。 例如,随着 4.0 模型的发布,我们删除了大约一半的系统提示,因为我们不再需要它。我们尽量在模型周围放置尽可能少的代码,这包括最小化提示和最小化工具的数量。我们不断删除工具并尝试新的工具”。

Claude Code 不使用虚拟化——它在本地运行。 一个主要的设计决定是是否在虚拟机中运行 Claude Code——比如在 Docker 容器中或在云中——从而创建一个沙盒环境。但团队决定采用本地版本,因为:简单!从 Boris 的话:

“在每一个设计决策中,我们几乎总是选择最简单的可能选项。问题是:“你在哪里运行批处理命令?”和“你从哪里读取文件系统?”最简单的答案是本地运行。 所以我们选择了这种方法:Claude Code 在本地运行批处理命令,并读取和写入文件系统。没有虚拟化”。

2.2 权限系统

Claude Code 最复杂的部分是权限系统。在本地运行 Claude Code 的风险是,代理可能会执行不应该做的不可逆操作,比如删除文件。但如何安全地做到这一点?

再次,团队选择了简单性,并构建了一个在执行操作前寻求权限的权限系统。用户可以选择:

  • 一次性授予权限
  • 为未来的会话授予权限
  • 拒绝权限

Claude Code 在删除文件前寻求权限

Boris 告诉我,正确获取权限需要努力:

“我们最重要的原则是:如果你开始运行 Claude Code,它不应该在未经许可的情况下改变你系统上的东西。这可能会很危险。 然而,我们也应该提供让人们对某些事情说“不”的方式,例如“实际上,在我工作的上下文中,我不希望每次都给予权限。” 权限系统有很多细微差别。例如,当一个命令进来时,我们会对其进行静态分析,以检查这是否已经在设置文件(在 settings.json 文件中)中被允许。 设置系统是一个多层系统,可以根据项目、用户和公司进行配置。 你也可以与你的团队共享设置。我们观察到团队共享设置文件,这些文件白名单命令,这样 Claude Code 不会要求权限,例如检查到源代码控制中”。

2.3 其他功能

Claude Code 在某些方面很简单,但有许多功能增加了其复杂性。一些功能已记录。值得注意的包括:

  • 钩子:为 Claude Code 创建自定义 shell 命令
  • MCP 支持:通过连接到 MCP 服务器,为 Claude Code 提供更多功能。参见我们关于 Model Context Protocol (MCP) 的深度解析
  • GitHubGitLab 支持:使用 GitHub Actions 并将 Claude Code 集成到 GitLab CI/CD 中。
  • 输出样式:切换输出样式或定义自己的样式。内置的输出样式包括:
  • 解释性:教育你关于实现选择
  • 学习性:一种协作风格,Claude 会让你自己做一些小任务。这是一种非常聪明的方法,保持在循环中,动手操作,并学习!这可能是经验较少的工程师学习的好方法,或者对不熟悉的人
  • 配置:使用各种配置文件和设置来配置你的终端、模型、状态行等
  • 子代理:如下所述
  • 企业功能:设置 Identity and Access Management (IAM) 以在整个组织中使用 Claude Code,并访问 组织范围内的分析s 来跟踪使用情况
  • Claude Code SDK:使用为 Claude Code 提供动力的代理框架构建自定义 AI 代理
  • …以及查看 Claude Code 的最新功能 的总结

3、在几天而不是几周内构建和发布功能

对于一个大约十几名工程师的团队,他们工作得非常快:

每天约 60-100 次内部发布。 任何时候工程师对 Claude Code 进行更改,他们都会发布一个新的 npm 包。Anthropic 的每个人都使用内部版本,开发团队会得到快速反馈。

在夏季,工程师每天推送约 5 个 pull request —— 这比大多数科技公司每天 1-2 个 pull request 的节奏快得多。

每天 1 次外部发布。 几乎每天都会发布一个新的包版本作为部署的一部分。

3.1 两天内制作 20 个原型:构建待办事项列表

让我惊讶的是,这个开发过程中的团队比我看过的任何地方都做了更多的原型设计。例如,Boris 向我展示了他如何在两天内几个小时内制作了大约 20 个新功能的原型,即待办事项列表。

他很慷慨地分享了他为各种迭代使用的实际提示。每次之后,Boris:

  • 有时调整结果
  • 玩弄它
  • 如果感觉良好,与同事分享以获得反馈
  • 当某件事感觉不对时,他会用新的提示构建一个新的原型

原型 #1:显示已完成的待办事项

想法:待办事项列表是跟踪 Claude 运行情况的最容易方式之一,所以他们尝试在最近一次工具调用下方直接显示列表。

提示:

让待办事项不再按顺序出现,而是隐藏工具使用和结果,将固定的待办事项列表放在输入上方。标题为“/todo (1 of 3)”并用灰色显示

看起来是这样的:

原型 #1

原型 #2:在底部显示进度

另一种变化是在线显示每个待办事项的更新。

提示:

实际上不要显示待办事项列表,而是将使用的工具内联显示,当模型开始处理待办事项时,用粗体标题显示。保留“步骤 2 of 4”或其他内容,并添加 middot /todo 以在灰色中查看

看起来是这样的:

原型 #2

原型 #3 和 #4:一个“互动药丸”

如果待办事项是一个互动药丸(在控制台底部的矩形),你可以拉出来查看进度,就像背景任务一样?

提示和输出:

也在文本输入下方添加一个待办事项药丸,类似于背景任务。它应显示“待办事项:1 of 3”或类似内容
原型 #3
让药丸具有交互性,像背景任务药丸一样
原型 #4

原型 #5 和 #6:使用“抽屉”

如果我们有一个“抽屉”滑入侧边的待办事项怎么办?

提示和输出:

实际上撤销药丸和标题。相反,让待办事项列表显示在输入右侧,垂直居中,并带有灰色分隔线。当待办事项处于活动状态时显示它,完成后隐藏它
原型 #5,待办事项作为“抽屉”在右侧。查看动画版本
它有点跳跃,你能像抽屉一样动画化吗
原型 #6。查看动画版本

原型 #7、#8 和 #9:可见性的实验

为了使待办事项列表尽可能可见,Boris 尝试让它始终显示在输入上方。

提示和输出:

实际上,如果你在输入上方显示待办事项列表呢?
原型 #7
截断为 5 并显示“...还有 4 个”或其他内容
原型 #8
添加一个“待办事项:”的标题,用灰色文字
原型 #9

原型 #10-20:移动旋转 UI 元素

Boris 继续尝试待办事项列表的可见性位置,并在经过几次更多的原型后。最后,Boris 将待办事项列表移到了旋转器中,最大化了可见性,并开始感觉良好。经过几次迭代,他们有了最终发布的公共版本。

在第 20 个原型左右,经过可视性和旋转器的尝试

3.2 再一次迭代

该团队从社区收到了很多反馈,他们希望可以看到所有的待办事项。因此,团队添加了通过 CTRL + T 切换待办事项的能力。这就是今天上线的内容!

这次迭代(大约第 21 次)目前在生产中——按下 Tab 键可以切换正在执行的步骤列表

使用 AI 代理可以在一天内构建和测试 5-10 个原型想法。 以前的原型设计非常耗时,如果有两天的时间来原型设计,到结束时能做出两个不同的原型就已经很幸运了。但现在,代理可以非常快速地构建原型,因此每天轻松完成 5-10 个原型的测试,正如 Claude Code 团队所做的那样。

我不建议每个人都能如此快速地构建这么多原型,但我认为忘记原型设计过去所需的时间是合理的:这些工具改变了原型设计的速度!


原文链接:How Claude Code is built

汇智网翻译整理,转载请标明出处