“我一行代码都没读就发布了”,被OpenAI收购后,uv工具创始人开始反思AI编程
创始人
2026-07-05 15:45:15

编译 | 宇琪

策划 | Tina

过去三年,Python 开发者工具领域发生了一场静悄悄的革命。一个叫 Charlie Marsh 的年轻工程师,从一家计算生物学公司辞职后,在“不知道自己要做什么”的状态下,花了 9 天时间搭出了 Ruff 的原型,一个比当时最快的 Python linter 还要快 10 到 100 倍的代码检查工具。Ruff 成功后,他顺势成立了 Astral 公司,并用 Rust 打造了 uv,一个快到让 pip 看起来像慢动作回放的包管理器。这两个项目迅速席卷了 Python 社区,GitHub 星标数以万计增长,最终让他在今年三月把整家公司卖给了 OpenAI。

这不仅仅是一个“技术天才靠 Rust 征服世界”的故事。日前,Charlie Marsh 在播客中,与主持人 Ryan Peterman 一起探讨了 AI Agent 如何重塑软件工程的每一个环节。除了技术本身,他还谈到了软件工程行业正在集体经历的困惑:当提交一个”看起来合理”的 PR 的成本降到零、而审查它的成本依然高昂,我们该信任什么?当你自己写代码的乐趣被”指挥 Agent 干活+逐行审查 Agent 输出”的工作流取代,编程还值得热爱吗?

这些问题没有标准答案,不过 Charlie Marsh 给出了一个一线实践者最诚实的思考。最近 X 上流行"I read the code"梗,调侃程序员已从"写代码"沦为"读代码"。Charlie 在给自己用的工具上反着来——一行代码没读,全扔给 AI。不过,他坦陈了自己从“全 AI 模式”中被同事打醒的经历,也去看了Bun的仓库——头号贡献者是一个bot,他发现Bun的仓库跟他们的仓库是完全不同的世界。他还分享了团队对抗 AI slop 的具体策略,也聊到了从普通工程师转向创业的经历、以及为什么他觉得”现在是早期职业工程师最难的时刻”。本文基于该播客视频整理,经 InfoQ 编辑。

太长不读版:

Q:Python 工具链为什么该被颠覆?

A:隔壁 JS 圈早把工具用 Go/Rust 重写了,快到飞起。Python 圈还在用 Python 写工具,慢得理所当然。我就想问:凭啥我们不能拥有同样爽的东西?

Q:Ruff 是怎么火起来的?

A:先写博客画大饼,然后构建出能用的 linter。核心策略: 10 秒抓住眼球——一个亮眼的标题、一张精心打磨的图片,不用废话,一看就懂。然后疯狂响应社区,今天提 issue 明天发修复,圈粉速度拉满。

Q:为啥选 Rust?

A:坦白说,当初就是跟风。但回头看香爆了——Cargo 一把梭,git clone 完就能跑,不用跟 C++ 那堆构建系统斗智斗勇。内存安全?当初根本不在乎,现在觉得真香。

Q:AI 时代还会考虑全部重写吗?

A: 不会。代码如果完全重写,作为人类你可能就不再理解任何代码了。而且用已知问题换未知问题太蠢,测试全过不代表行为一致,最终坑的是用户而且现在 AI 写 PR 成本为零,审查成本却更高,开源生态快被淹死了。

Q:性能提升全怪 Rust?

A:Rust 给你个高起点,但真正的杀手锏是 架构创新。UV 快是因为缓存设计得聪明,重复安装几乎零成本,这跟语言没关系,纯属脑子好用。

Q:跟 AI 结对编程啥感觉?

A: 以前同事闭眼合我 PR,现在逐行细审——因为代码不是我的了,是 Agent 的。信任崩塌了。但我也在适应,现在整天让 AI 跑各种实验,以前不敢想的问题随手就能验证,这种解锁感挺爽的。

Q:初级工程师会被 AI 坑惨吗?

A:会。他们没能力给 AI 当教练,只能被 AI 带沟里去。 我们倾向于招资深工程师,因为优秀的工程师用 AI 更猛。如果我是初期工程师,太容易掉进使用 Agent 时发生的那些坏事情里了。

以下是原文:

Python 工具链需要一场“Rust 革命”

Ryan:你最初开始构建这些开发工具时,整个领域是什么样子的?为什么你觉得它能做得更好?

Charlie:在创办 Astral 之前,我在一家计算生物学公司工作。我没有生物学和机器学习背景,但我的任务是用 Python 搭建所有支持机器学习运行的软件系统。那段时间我一边学 Python,一边接触了 Go 和 Rust,在多个不同的技术栈之间来回切换。

我们团队很小,但对一个只有几个软件工程师的团队来说,代码库规模相对较大。我们这些人要服务整个团队,包括机器学习研究员和科学家。我接触了各种生态系统的工具链,发现我们一直在试图从工具中榨取更多效率,无论是类型检查器、代码检查工具,还是包管理器,但随着规模增长,我们不断撞上工具能力的天花板。

我观察了一遍 Python 生态,发现它缺少其他生态中那种实验精神。比如 Web 生态里,很多疯狂的想法在被尝试,而且大家对性能有很强的执念。从用 Go 写的 ESBuild,到用 Rust 写的 SWC,再到 Bun、Deno 等等,原生工具链对于 Java 来说已经成了理所当然的事情,尤其是当应用越来越大、开发者机器上跑的活儿越来越多的时候。

但 Python 生态里没有这个趋势。所以对我来说,核心问题就是:为什么我们不能拥有同样的东西?我亲眼看到 Web 领域发生的一切,我自己也写过 Rust 和 Go,知道这些不同工具链的工作方式和用户体验。再看 Python,工具集更小,很多来自其他生态的有趣想法完全没被引入,而且所有工具都是 Python 写的。

这对我来说就是一个有趣的假设。当我发布 Ruff 时,那篇博客的标题就是《Python 工具链可以快得多得多》。对我来说,这本质上就是一个待验证的假设:Python 工具链能不能更快? 我搭了一个原型,结果证明:是的,完全可以。

Ryan:你写了一篇关于 myPy 性能分析的文章,然后仅仅 9 天后就发布了那篇“可以快得多”的博客。你是在那 9 天里做出来概念验证的吗?

Charlie:对。我先写了一篇关于大规模类型检查的博客,想搞清楚瓶颈到底在哪。然后我开始构建一个 linter,因为我觉得 linter 比类型检查器容易得多,而且 linter 能让我用更小的体量验证同样的想法。做创业或做工具,核心就是尽快把东西交到用户手上,让他们真正用起来,证明价值,同时也能快速迭代。linter 恰好是个完美的形态:核心逻辑很简单,但规则可以无限扩展。用户从一个小核心加若干规则就能立刻获得价值。

我们很快做出了可用的版本,然后持续迭代,发布更多规则和功能。人们可以把它和其他工具配合使用。它从一开始就是有用的,这一点非常关键。相比之下,一个完成了 75%的类型检查器几乎毫无用处,包管理器也一样,这些工具必须做到足够完整才能产生价值。所以,能够迭代式地交付、同时保持对用户有用,是建立工具势能的核心能力之一。

开发者营销“10 秒法则”

Ryan:那篇博客发出去后,反响怎么样?

Charlie:博客发出去后上了 Hacker News 首页,在 Twitter 上也被大量转发,制造了相当多的兴奋和关注。上 Hacker News 首页这件事,我觉得一半靠运气,一半靠实力。它有帮助,但不是成功的必要条件,更不是保证,关键是你如何利用这波流量。

我当时采取的策略是极度积极地响应社区。有人提 issue,我会尽量在一天之内确认问题、修复并发布新版本。这种“一天内响应-修复-发布”的循环非常强大,你每完成一次,就赢得一个支持者,项目势能就增加一分。

同时,一些生态里的大人物也开始关注这个项目,比如 FastAPI 的作者 Sebastián Ramírez。他早期就说“这个挺有意思,我想用用”。我当时就问自己:“要让他真正用起来,需要做些什么?”然后我就去逐一实现那些条件。

我其实一直在思考开发者营销这件事。在工程师圈子里,“营销”这个词几乎是个脏话。很多人觉得技术产品就该靠实力说话,最好的技术方案就应该自动胜出。但我有个可能很蠢的假设:GitHub 上有成千上万个非常棒的项目,它们根本不知道怎么营销自己,所以永远没人发现,永远没发展起来。我不知道这是不是真的,但至少看 Ruff 这个项目,我觉得营销是值得认真对待的。

那么,具体怎么做呢?关键在于“10 秒内抓住注意力”。无论是写博客、写 README,还是做任何宣传材料,核心问题是:当一个人打开这个页面,我只有 10 秒钟让他对我的项目产生兴趣,让他明白“这对我有什么用”。不需要一堆 emoji 和截图,你需要的是在 10 秒内讲清楚“为什么这个项目值得你花时间”。

说起来有点沮丧,但这就是注意力经济的现实。我当年在 Spring 做生物医药的机器学习时,研究过 OpenAI 的博客。特别是 DALL-E 的那些老文章,即使你一个字都不读,光看图片和标题,你也能理解他们做了什么,而且会被震撼到。这就是我追求的:让那些只读标题、只看第一张图的人也能带走一个印象。当然也会有人从头读到尾,所以每个字都要精心打磨。但你必须接受:大多数读者只会扫一眼。所以,你要想清楚:如何用诚实、真诚的方式,在几秒钟内告诉别人“为什么你应该关心这个”。

Ryan:能举个具体的例子吗?比如你在 Ruff 的博客里具体做了什么?

Charlie:最典型的例子是那张 benchmark 图。我们在博客里放了一张非常清晰的性能对比图,在 Twitter 上被疯狂转发。那张图本身就能说明一切,它不需要任何文字解释,你一看就知道 Ruff 比竞争对手快多少。一张好的 benchmark 图,在注意力经济里是无价的。我不是说它能卖钱,而是说它能瞬间抓住人们的注意力。你看到那张图,脑子里立刻就会冒出一个念头:“这太明显了,发生了什么一目了然。”

Ryan:但我经常看到那种图,轴的起点不是零,而是故意从 50 或 100 开始。

Charlie:这就是所谓的“图表犯罪”(chart crime),我们不会这样。benchmark 本身其实非常复杂且充满争议,也许大多数用户根本看不到这些争议,但我每天都身处其中,因为性能优化这件事太微妙了。你不得不思考:是带缓存还是不带缓存?这两种情况下的性能表现天差地别。在不同的项目上运行,性能特征也会完全不同。我们在 UV 上就深有体会,有时候 UV 快得像闪电,但有时候安装一个包时,瓶颈却出在一个完全不相干的 C++编译流程上。这时候你怎么准确地说“UV 快”?你几乎不可能用一个数字或一张图,准确捕捉所有不同场景下的真实表现。

但另一方面,如果你完全不向用户传达性能差异的意义,那又是一种失职。用户需要知道:这个工具到底快多少?为什么快?这对他意味着什么?所以你必须在这两者之间找到平衡。我觉得这其实非常难,很多人在这方面都栽过跟头。但无论如何,不加任何方式去快速告诉用户“这东西用起来是什么感觉”,那才是最大的失职。

为什么选择 Rust?

Ryan:你提到那张图,我作为工程师,看到它的第一反应是:“你是怎么做到这么快的?”然后我注意到你们的标语里写着“用 Rust 写的 Python 开发工具”。所以,我第一个好奇的问题是:为什么选择 Rust?它的优点和缺点分别是什么?

Charlie:坦白地说,我当初选择 Rust 很大程度上就是因为跟风(hype)。当时 Rust 在开发者社区里非常火,大家都在谈论它。在那个时候,我对不同生态系统之间的技术权衡了解得并不多,也没有做过太多系统编程。我的印象就是:Rust 是一种编写高性能软件的、更易上手的方式,所以我因为这个原因开始了。

但回过头来看,我认为这是一个极其正确的决定。现在我对 Rust 有了更多的经验,我确实觉得,如果当时我尝试用 C 或 C++来写这个项目,我可能早就放弃了。因为即使到现在,我仍然觉得那些生态系统更令人望而生畏、更难上手、更难学习。

我经常觉得,Rust 一个被严重低估的优势就是它的工具链。因为你一上来就用 Cargo,所有事情都通过它来做。如果我看到一个我们使用的 crate,我想给它的仓库提交一个 PR,我极其有信心,我克隆下来就能弄清楚如何运行和构建,几乎不需要做任何额外工作。能做到“git clone然后cargo runcargo buildcargo test”就能跑起来,这其实非常了不起。

尤其对于像我这样刚接触系统编程的人来说,我不想去搞清楚整个 C++工具链、构建系统那一堆乱七八糟的东西。Rust 在这些方面非常“有主见”(opinionated),确实有很多东西很难学,但它让我可以把精力集中在那些真正应该难学的事情上,而不是花时间在“我怎么让这个东西编译通过、跑起来”这种你根本不想花时间的事情上。

这对我们来说是一个非常成功的赌注。Rust 随着项目规模的增长,扩展性非常好。而且,OpenAI 也在大量使用 Rust。作为一个为开发者构建工具的人,我对 Rust 非常看好。它已经增长得非常迅猛,我认为它还会继续快速增长。

但同时,我从来不是一个对生态系统特别教条的人,我认为所有这些生态系统都有可取之处。比如 Zig 正在发生的事情就非常有趣,我希望有更多时间去深入研究它,形成更细致的观点,我确信它在某些方面比 Rust 做得更好,Rust 也应该向它学习。同样,很多人用 Go 也取得了巨大的成功,这也很棒。我喜欢用 Rust,不过也有不少抱怨,但我把这些抱怨看作是需要改进的地方,尤其是随着 LLM 改变了我们构建软件的方式。

Ryan:所以听起来,你今天根本不会考虑 C 和 C++?因为它们的工具链不够好。而 Zig、Rust 和 Go,你是在它们之间做不同的权衡?

Charlie:没错。我真的不太理解,除非有非常特定的技术原因,或者你正在维护现有软件,否则我基本不明白为什么要在新项目里用 C 或 C++,我本人肯定不会这么做。当然,如果你对那个生态系统非常熟悉,那另当别论。但如果你是一个想学系统编程的新手,或者你对这些语言同样熟悉,那我真的不理解你为什么要选 C/C++。我知道这么说会被骂,但我无所谓。

我现在非常在意 Rust 给我的那些东西,而这些是我以前根本不在乎的,比如内存安全。 当我开始做 Ruff 的时候,我甚至不知道内存安全是什么,也完全不在乎。但现在我觉得这简直太棒了。我想构建安全的东西,不会在用户面前崩溃,速度极快,性能极强,不需要做任何妥协。在 Rust 里我可以做到这些,所以对我来说,它虽然不是完美的语言,但它是目前我最喜欢用的语言。

AI 时代的代码重写

Ryan:在当今世界,你几乎可以把现有代码完全转译到你选择的任何语言里,比如我见过有人把 Zig 一次性转成 Rust。如果你觉得另一种语言更好,你会考虑把你构建的那些开发工具全部重写吗?比如从 Rust 转成 Zig 或 Go?

Charlie:这个问题很微妙,是因为现在构建软件的方式变化太快了。我直到去年圣诞假期才开始真正用 Agent 编程,到现在也不过几个月。但如今我几乎不在编辑器里直接改代码了,所有修改都通过 Codex 完成,即使是小改动也是用提示词驱动。这完全是另一种工作方式,而且变化发生得如此之快,我甚至无法预测六个月后会是怎样。

所以对于 Bun 那样的重写,我现在不会做,但我很欣赏他们敢于实验和突破边界的精神。这引发了我几个层面的思考,首先是代码理解问题:如果代码被完全重写,作为人类你可能就不再理解任何代码了。虽然他们尝试做非常直接的转译来保留抽象层,但问题是,如果团队已经重度依赖 Agent 开发,理解代码到底还重不重要?

第二个更核心的问题是:当你做这样的重写时,你是在用已知问题交换新的未知问题。假设合并后你关闭了 GitHub 上的 50 个 issue,这很好,但你可能同时引入了 50 个之前不存在的新 issue。因为即使是最好的测试套件,也只是程序正确性的近似逼近。希拉姆定律(Hyrum's Law)告诉我们:任何实现细节最终都会变成某些人依赖的行为。即使没被编码为行为的东西,也会成为你 API 的一部分。这意味着即使测试全部通过,程序隐含的行为可能已经改变。而最糟糕的是,你最终把这个问题推给了用户,他们不得不先遇到问题、再报告、再帮你去排查,这是我对自动重写最大的担忧。我其实相当信任模型的能力,但真正可怕的是如何安全地推出这种变更。

第三个层面关乎开发方式的选择。现在的软件开发光谱已经变得非常宽,从 Andrej Karpathy 定义的 Vibe Coding,到完全不使用 LLM,中间有无数种可能。我对不同项目采取完全不同的方法,比如上周我写了个个人用的自定义 Rust linter,全程由 GPT-5.5 完成,我一行代码都没读。因为那是只有我们内部使用的工具,很容易判断正确性。但 UV 被数百万工程师和无数公司依赖,对它的任何变更都必须极其谨慎。关键在于你做的项目是什么、你对用户负有多大责任。这不是在评价 Bun 的做法,而是我思考如何在不同领域突破边界的方式。

Ryan:这让我想到代码变更的风险管理。如果是只有你我使用的内部工具,我可能直接打上“没问题”的戳就发布了。但如果是影响客户结账的关键系统,我们可能需要两人审核、多重验证。所以这个光谱现在多了一个新层级——人类一眼都不看,直接发布。

Charlie:我有时候会去 Bun 的仓库看看,发现它跟我们的仓库完全是两个世界。最明显的是,Bun 仓库的头号贡献者是一个 bot。有时候你点开人类提交的 PR,看到人类账号在来回评论,但很明显那些评论全是 agent 写的。你会忍不住感叹:“这太不一样了。”我很高兴有人在尝试不同的软件构建方式,不过我不确定自己是否准备好那么做,但我认为很多事都会改变。

Ryan:那你们会在自己的仓库里屏蔽这种纯 agent 提交的贡献吗?

Charlie:会的。我们现在有一套 AI 政策,目的不是反 AI,而是要过滤掉那些净负面贡献,保留真正有用的东西。你想,一个贡献者进来,贴了一条 agent 写的评论,我们问他问题,他直接把 agent 的回复粘贴过来。这有什么价值?我们还不如直接问 agent 本身。我们需要的是人类贡献者的洞察力、复现步骤、以及我们能喂给 agent 的关键信息,在 GitHub issue 上跟 LLM 对话毫无意义。所以我们的政策很简单:你提交的东西,你自己得理解。我知道这听起来门槛很低,但实际并不低。

Ryan:那你怎么监管呢?

Charlie:如果看不出来它是 agent 写的,那我觉得应该没事。

Zig 项目的 LLM 政策比我们严格得多,完全禁止任何 LLM 编写的代码进入项目。而我们这边,我自己的 PR 现在全是 LLM 写的。Zig 团队发过一篇博客,提出了一个概念叫“贡献者扑克”——你像下注一样在贡献者身上下注。传统开源模式下,一个新贡献者来了,你给他反馈,他学习、改进,下一次提交的 PR 质量就提升了。这种反馈会累积,他会成长为未来的维护者,本质上是在投资“人”。但 agent 写的 PR 完全打破了这种循环:你给反馈,他把反馈塞回 agent,生成一个新版本,然后合并。没有累积,没有成长。

更关键的是,提交一个“看起来合理”的 PR 的成本已经降到了零,但审查和验证一个“看起来合理”的 PR 的成本依然很高,甚至更高。以我们的类型检查器 TY 为例,这是我做过最难的项目之一,架构极其复杂。如果有人给 TY 提交了一个“看起来合理”的 PR,他可能只花了 2 分钟写,但我们需要花 1 小时去理解它,这种不平衡正在严重破坏开源社区的生态。我不知道怎么解决,它只会越来越糟,直到我们找到新的方法。

Ryan:听起来审查正在成为越来越大的瓶颈。那 Bun 的重写呢?你知道那些代码是人类审查过的,还是直接就是 YOLO 式的……?

Charlie:我觉得没有经过人类审查。至少在我录制这期节目的时候,Jared 还没发布那篇博文。他一直在开玩笑,说那篇博客文章花的时间比重写还长。我其实对那篇博文很感兴趣,因为我认为他们确实有一套相当成熟的重写方法论,读起来会很有意思。这绝不是那种“用 Rust 重写这个”的单一 prompt。从我看到的 PR 来看,我印象中重写实际上分了不同的阶段,每个文件都要经过几个不同的阶段,每个阶段都有验证正确性的方法。所以答案是:没有人类审查。我不认为有人真正读过那些代码的实质性部分,这基本上是不可能的。

Ryan:那如果我们俩今天都同意 Zig 客观上比 Rust 更好,然后你团队里有人说“我可以把这个用 Zig 重写一遍”,你会阻止吗?

Charlie:我想我会阻止。我不确定这样做对不对,但我觉得我们团队还没到那个阶段。也许有一天我们会走到那一步,但现在我们仍然觉得深入理解我们的代码、工具链和生态有巨大的价值。

性能优化与代码质量

Ryan:你构建的所有东西,都比当时可用的方案快一个数量级。Rust 在多大程度上贡献了这种性能提升?

Charlie:这取决于项目。在 Ruff 中,很大一部分功劳确实归 Rust。但随着时间的推移,我们在这方面又有了很大改进。你可以看看项目的历史,基本上项目是越来越快的。有时候也会有回退,但总体趋势是向上的。即便都用 Rust 写,不同的实现方式也会带来截然不同的性能表现。所以我的看法是,Rust 更像是一个性能地板或基线,你用它写出来的程序,基线性能会显著高于其他语言。

但即便如此,你仍然需要深入思考性能和架构设计才能获得更多收益。比如同一个程序,用 Rust 和 Python 实现最接近的版本,Rust 版本肯定更快。但你完全可以在这个 Rust 版本上继续优化,可能还能再快 10 倍。即使在 Rust 生态内,仍有巨大的优化空间。我刚开始做 Ruff 时,目标之一就是学习 Rust,所以写了很多烂代码,这没关系,我发布的产品对人们很有帮助。但随着时间的推移,它变得越来越好,性能也越来越高。

在 UV 这个项目上,架构创新带来的贡献甚至超过了 Rust 本身。UV 是一个包管理器,它要做大量的 I/O 操作,下载网络文件、解压缩、写入磁盘、移动文件。而 linter 不需要做这么多 I/O,它只需要读取所有文件。包管理器几乎全是 I/O,你需要以极高的效率完成这些操作。所以在这里,Rust 固然重要,但 UV 中更多的性能提升来自于我们对架构的深入思考,比如缓存的设计就非常刻意,重复安装同一个包几乎是瞬间完成的,这完全得益于缓存布局的方式以及从缓存安装到项目的方式。这意味着如果你之前安装过某个包,再次安装的成本极低,无论是磁盘空间还是时间。这种设计思路与之前所有的 Python 包管理器都截然不同。

所以,无论你用 Rust 还是 Python 写代码,永远都有思考性能的空间。你总是可以让东西更快或更慢。即使是用 Python 写,通过更深入地思考性能和设计,你也可以让事情快得多。这是多种因素的混合,取决于具体项目。

Ryan:在整个项目开发过程中,有没有哪几件事在技术实现上最具挑战性,或者让你觉得最有趣?

Charlie:我特别喜欢我们团队 Andrew(网名 BurntSushi,Ripgrep 作者)做的一个优化,关于我们如何表示版本号。

当解析和安装一个非常复杂的 Python 项目时,我们需要解析并创建大量的版本对象,比如 1.0.1、1.0.2 这种,我们程序内部会生成海量的版本对象。结果发现,分配这些内存的开销大得惊人,尤其是考虑到我们操作的次数。Andrew 想出了一个表示方式:用单个 u64 整数就能表示 90%以上的版本,效率高太多了。

在 TY 方面,有很多非常有趣的性能工作正在进行,尤其是让它支持增量检查。TY 的设计目标就是一个类型检查器加语言服务器,整个系统是高度增量化的。核心想法是:如果你在文本编辑器里打开一个文件,你肯定不希望为了分析这一个文件,就必须把整个项目、所有依赖、每个文件都重新类型检查一遍,因为你根本不需要。但另一块是:如果你同时打开两个文件,编辑了其中一个,你只希望重新计算必须重新计算的部分。你不想因为保存了一个文件,就让整个代码库重新类型检查一遍。尤其是你在 PyTorch 这种大项目里工作时,如果每次保存都要等两秒钟才能拿到分析结果,那体验就太糟糕了。

这有点像宏观设计层面,整个系统基于一个叫 Salsa 的框架构建——这也是 Rust Analyzer(Rust 的流行语言服务器)使用的框架,我们后来有意无意地成了 Salsa 的主要贡献者。整个架构围绕查询展开,这在架构层面非常有意思。增量部分确实很难,因为你需要一个方式,当数据变化时,只让数据流经依赖图中受影响的那部分节点,这花了很多功夫。

我最近花了很多时间在 Codex 上做优化,因为它特别擅长那种微观层面的调优。在 TY 里,我们不仅要考虑速度,还要考虑内存,如果你在一个超大型项目上工作,你不会希望语言服务器吃掉几十 GB 的内存。所以理想情况下,它必须既快又省。比如我可以设定一个目标:“试试在这个项目上把 Salsa 的内存占用降低 1%。”然后它就能想出非常合理的方案。我觉得这非常酷,因为它几乎能持续地优化你的软件。

Ryan:关于版本号的优化,你觉得如果你直接丢给 Codex,说“嘿,别搞坏东西,但把内存降下来”,它自己能想到那个方案吗?还是说那超出了它的能力范围?

Charlie:以我的经验,如果你只是简单地要求降低内存或提升性能,它通常只会给出边缘性的改进,而不是更大的重新设计或根本性的重新思考。但如果你通过提示去引导和协作,你是可以到达那些更大的设计的。比如你可以问:“我们是不是应该更大胆地想想,为什么非要用这种方式来表示数据?”这样你就能引导它产生更大的想法。

如果通过提示一步步来,先做性能分析,找出时间花在哪儿,比如“版本解析和版本分配占了大量时间”,然后问“我们怎么能更紧凑地表示这些?”它可能会先给出一些微观优化,比如“这个字段可以和那个字段合并”之类的。但如果你不断追问,它是有可能到达那个方案的。不过,这不是它默认就能想到的。

这让我想起 Mitchell Hashimoto(HashiCorp 的联合创始人,现在在做 Ghostty),他上周发了一条很有洞察力的推文。他写了一个渲染器,故意写得很糟糕,然后让 LLM 去优化,结果 LLM 把它优化快了 10 倍。但实际上,他自己手写的版本比 LLM 优化后的版本还要快 100 倍。如果你不先用大脑从第一性原理去思考“这个东西理论上应该有多快”、“系统应该怎么工作”,那你就会把那些积累起来的,我不会称之为“slop(垃圾代码)”,但就是那些东西,直接交付出去,然后说“哦天哪,我把它优化快了 10 倍”,但实际上它应该能快 100 倍。所以我觉得,仍然有很大的空间需要你用大脑去思考。

我在这方面其实也很挣扎。我大量使用 Agent,也在某种程度上推动团队更多地使用 Agent,其中一部分原因,是因为我们为软件工程师构建工具,而我们的很多用户现在也在用 Agent。如果我们做的一切好事,都源于对用户的深刻理解,那我们就必须跟上这个趋势。

但现在出现了一个很有意思的现象。我们团队有人直接跟我说:“以前你提 PR,我基本扫一眼就过了,因为我对你的工作有很高的信任度。但现在你提 PR,我得逐行细审,因为那些代码不是你写的,是 Agent 写的。”我当时的第一反应是:“这真的很值得深思。”他们说得完全对。这种信任的瓦解不只发生在别人身上,我自己也经历同样的事。有时候我晚上睡一觉,第二天早上起来看自己昨晚提的 PR,心里想的却是:“等等,这代码写得也太烂了吧?”你很容易就骗过自己,以为自己交付了和之前同样标准的工作,但实际上根本不是。

Charlie:我希望未来能到一个状态——如果你提的 PR 全是绿色通过,那它被合并的概率极高,这意味着大部分重要的事情都有自动化验证来兜底。我们在项目中做了很多这类工作,比如在 TY 项目中,每个 PR 都会在 Valgrind 和 CodSpeed 上运行大量 benchmark ,覆盖内存使用、模拟时间、墙钟时间。还有一整套生态测试,每次提 PR,都会对比前后生态项目中所有诊断信息的差异,新增了哪些错误、修复了哪些错误。这些自动化验证在 Agent 出现之前就很重要,没有它们我们几乎没法开发。

现在还有一个新假设:团队成员提 PR 之前,应该已经用 Codex Review 审核过好几轮了。 这其实很简单,就是在 Codex 里跑个/review命令。因为现在提交 PR 后,第一件事就是让 Codex Review 跑一遍,它确实能发现不少问题。

所以,一个方向是建立更多自动化系统来保证代码正确性,包括持续优化agents.md文件,如果审核中反馈的问题 Agent 没有解决,就要想办法让 Agent 学会,甚至培养一些团队共享的 skill,这些都不复杂。另一个方向是确保自己投入精力去创建高质量的 PR。听起来标准很低,但我真的应该理解 PR 里的每一行代码。我还会在 GitHub UI 里自己审核一遍 PR,如果你像审阅者一样打开文件从头读到尾,往往能发现本地 diff 时忽略的问题,这非常有用。

还有就是把 skill 编码化,把我和 Agent 经常犯的错误写进 skill 里,比如最近我常收到这样的反馈:“这个 if 语句想捕获什么场景?如果我把它注释掉,所有测试都能通过。”于是我就在提 PR 前加了一道工序:让 Agent 检查“这些条件判断是否仍然相关,还是之前重构时遗留的?”我还在学习,但这些是我正在做的事情。

我觉得现在做软件开发真的挺难的。很长一段时间里,我一直有个恐惧:AI 会让我们更高效,但编程会变得没那么有趣,因为我就是热爱编程本身。我当时想,“天哪,以后我得把所有时间花在审查代码和提示这个总犯错、但最终确实更高效的蠢 Agent 上。”

不过,我现在的感受其实比几个月前好多了。我想 Agent 在变好、工具在变好、我自己也更适应了,这是一方面。另一方面是,我越来越欣赏与 Agent 协作所解锁的那些事情。比如运行实验的成本变得极低,有太多事情我一直想尝试,或者一直想回答的问题,现在几乎可以瞬间得到答案。

举个有点傻的例子:在 UV 项目中,所有东西都是快照测试,基本上我们所有的测试就是运行 UV 然后验证输出。这意味着我们有大量的测试,测试输出最终会留在测试文件里。所以我们有一个叫lock.rs的 Rust 文件,里面全是 UV lock 的测试,非常长,因为所有 lock 输出的快照都嵌在测试里。我当时想:“如果我们把快照存在单独的文件里呢?这样会不会让编译更快?因为从技术上讲,那些快照也是 Rust 代码,如果移走它们,构建会不会变快?”

我一直想做这个实验,但作为人类手动去做会极其痛苦,因为你得转换所有测试。结果我只是让一个 Agent 在后台做这件事,同时我去干别的。然后,我得到了一大堆数据,答案有点微妙:如果你只是在迭代快照输出,确实有好处,因为不再需要重新编译整个程序。但我说这个的重点是,我现在整天都在做这种实验:尝试那些以前很难、成本很高才能回答的问题。从实验到生产还有真正的工作要做,但能做的事情完全不一样了。

我越来越意识到,我从构建软件中获得的大量价值其实被保留了下来。因为其中一部分是仔细思考一个数据结构的布局,很大一部分是合并一个关闭用户问题的 PR,我从真正修复和改进某个东西中获得巨大满足感,而不仅仅是敲出代码。所以,对于那些觉得与 Agent 协作失去了什么的人,我真的很能共情。但比起几个月前,我现在对与 Agent 一起工作的感觉好多了。

初级工程师在 AI 时代的困境

Ryan:你刚才在性能优化那个例子里提到,如果直接放 Codex 出来,它擅长做局部优化,但不太擅长系统级的优化。这让我想起你发过的一条推文。你说:“我有点担心,如果我在没有扎实软件工程基础的情况下使用这些工具,会产出多少垃圾代码。”

Charlie:我现在仍然担心这一点。

Ryan:这让我想起 Mitchell Hashimoto 发的那条推文——“Codex,去干这个”和“你像工具一样挥舞它,不断往正确方向戳”之间,存在巨大的差别,你怎么看?

Charlie:成为一名优秀的软件工程师,比以往任何时候都更有用。我们团队里那些工程能力最强的人,即使在使用 Agent 时也是最有效的。现在有很多关于“Token 最大化”的讨论,公司应该搞 Token 排行榜吗?我觉得,Token 排行榜会创造糟糕的激励,让人们尽可能多地消耗 Token。我们内部确实可以查 Token 使用量,但我并不关心谁用了最多的 Token。你会发现团队里最高效的人,往往确实用了很多 Token。这不是因果关系,但很多优秀工程师能够非常有效地使用 Agent,从而放大自己的技能。

现在对初级工程师来说,真的非常难。我目前跟初级工程师接触不多,Astral 团队很小,我们倾向于招聘资深工程师。我很难想象,如果我是一个刚入行的工程师,我的学习迭代回路会是什么样?我大概只能从 Codex 那里学习,而不是反过来。对我来说,很多时候其实是我在指导 Codex,纠正它,为它提供安全护栏。而如果我是初期工程师,太容易掉进使用 Agent 时发生的那些坏事情里了。

没预料到的快速创业历程

Ryan:你当初用 Rust 构建了那个概念验证,反响很好,但为什么围绕它创办了一家公司?融资过程又是怎样的?背后的动机是什么?

Charlie:其实是我离开 Spring 的时候,被一个非常亲密的朋友说服了,他差不多同一时间从 Meta 离职,他说:“我们应该一起创办一家公司。”我说:“行。”当然,事情没那么简单。我离职后,我们进入了所谓的“想法迷宫”,不知道具体要做什么。我们花了很多时间探索想法的维恩图,有些东西他感兴趣而我觉得没意思,反之亦然。中间有一些交集,我们就去探索那些交集。

但在所有业余时间里,我都在搞开发者工具,因为那才是我真正感兴趣的,这和他的方向不太合拍。那时我在做 Ruff,还搞了好几个 GitHub 上的其他项目,我对 WebAssembly 很感兴趣,写过一个 Type 的 CI/CD 工具包,可以把 pipeline 转译成 Docker。

关键转折点在于:我决定先和投资人建立关系,但不想急着融资,因为我还没想清楚到底要做什么。我的策略是:先认识一些喜欢投这类东西的人,等三到六个月后再联系他们,说“我们之前聊得很好,现在我在做 xxx”。我确实联系到了几位投软件基础设施和开发者工具的投资人,聊得不错。但问题是,事情发展得太快了。

我实际上没预料到这么快就开始融资。Ruff 在快速成长,但当时我心里想的是:“我不知道这怎么变成一家公司”,但投资人们让我相信了,我挺感激的。他们还说服了我另一件事,如果我不喜欢,六个月后可以退出,把钱还回去。这招很聪明,因为我大概率永远不会那么做,但它让我感觉压力小了很多。

于是我开始全职搞 Ruff。我和早期投资人进行了很多长时间的对话,讨论我的想法,后来我写了一个产品路线图。然后他们说:“我们想投你,这是条款。”我当时想:“哇,好吧,看来这事真要成了。”我从来没做过这种事,整个职业生涯就是个普通软件工程师,突然就要创办公司了。

有趣的是,决定全力以赴创办公司这件事,其实没那么大压力,真正的压力是在公司开始成功后到来的。一开始我没什么可失去的,但后来公司走上正轨,我有了一个 20 人的团队依赖我,我就开始想:“公司真的在运转了,接下来会怎样?”作为一个创始人,我其实挺风险厌恶的,但创办公司的决定比后来那些压力大的决定更容易做得多。整个过程发生得非常快,几乎是无意的,和投资人形成了一种共生关系,这完全出乎我的意料。

Ryan:我以为创始人会渴望融资,求着“请投我”,但投资人反而是主动来找你的?

Charlie:我们做了三轮融资:种子轮、A 轮和 B 轮。我们甚至从未公开宣布过 A 轮和 B 轮,它们是在收购公告里才被提到的。原因很复杂,基本上就是一直有理由让我们想再等等。对我来说,这总感觉是很多额外的工作,而且我觉得这不是最重要的事。公司运营得很好,我们不需要那种营销。我们最后确实计划过宣布,但还没做就被收购了。每一轮融资基本上都是投资人主动发起的,因为公司发展得好,人们想投。我一直有点保守,没有很激进地去筹钱。但我们很幸运,在做的东西让人们有很强的信心。

Ryan:这给了你很大的谈判筹码,最好的位置就是你可以随时走人,你甚至不需要它,他们来找你说“请收下这笔钱”。

Charlie:我不会说自己是个优秀的谈判者,但至少我手里有张好牌。而且我们很幸运,投资人非常棒,超级支持。他们和我想要的公司发展方向完全一致,从来没有冲突,从来没有压力让我做任何特定的事情,只有支持。可能唯一的持续反馈是:我本可以在规模扩张和增长方面更激进一些,但我喜欢我们运营的方式。

开源与商业产品的平衡

Ryan:我猜投资人投资时,看的是未来的收入承诺。但你们公司怎么赚钱呢?毕竟你们把软件免费送出去了。

Charlie:我们在去年八月推出了商业产品,叫 PYX,它有点像 UV 的托管版本。很多 UV 用户会购买私有注册表软件,而不是使用公共注册表,要么是出于安全考虑,要么是需要发布自己的私有工件。于是,我们建了自己的私有注册表,对 UV 有一流支持。这让我们能解决 issue 跟踪器里用户用其他方案时遇到的一堆问题,也让我们能做得很快,因为客户端和服务器是垂直整合的,它们可以做一些特殊操作,变得非常快、非常易用。

我们花了一段时间来销售这个产品,收入增长得相当不错。当然,在这个 AI 时代,你总听到“最快做到 1 亿美元收入的公司”之类的故事,我们没到那个级别,但我们确实能卖给一些大企业。最酷的是,因为我们做了开源,每个人都在用我们的开源工具,所以我们的销售漏斗非常好,我们有一小批质量极高的客户。

整体思路是:继续做开源,工具保持免费、开源、完全非商业化,然后我们构建一些东西,当你用我们的工具时,自然就会需要。比如你用 UV,你大概率会遇到私有注册表的问题,我们就卖给你注册表。这个注册表只是平台的一部分,我们计划卖一整套东西,比如一个 Python 云,这就是我们正在构建的方向。

收购的一个很酷的地方是,我们可以把平台的一部分免费开放给大家。举个例子:Python 社区有很大一部分人用 GPU,比如 PyTorch,整个 PyTorch 生态有很多软件是构建在它之上的。由于各种原因,这些工具的人机工程学不太好——安装难,版本匹配难,还取决于你用什么 GPU、什么 CUDA 版本。我们尝试用一种方式解决这个问题:构建自己的发行版,有点像 Linux 发行版。我们预构建了很多能协同工作的东西,提供给客户。现在我们可以把这些东西免费开放给所有人,因为我们不再试图建立一个独立业务,而是想构建能扩大整个生态的优秀工具。

坚持原则,别信“标准答案”

Ryan:作为首次创业的工程师,有什么让你惊讶的学习收获,可以分享给其他想走这条路的人吗?

Charlie:我其实不太喜欢别人给创业建议,因为这个行业太多幸存者偏差了。你给出完全相同的建议,可能会得到完全相反的结果。你去听两场演讲,两个极其成功的创始人给你完全矛盾的建议,你会想:“我真的不知道该怎么做。”我的看法是,你必须弄清楚什么对你来说是真的。

比如,远程办公还是线下办公?你必须有一个原则并且坚持下去,两者都可以很出色。我们整个公司都是远程构建的,进展非常顺利。当然,我认为线下办公有好处。但如果我们在线下,我绝对招不到我们组建的那个团队。所以每件事都有取舍,你必须有原则,弄清楚什么与你产生共鸣。

我在这件事上很幸运。我尽量把最少的时间花在融资和见投资人上。我追求的是找到真正信任的投资人,而不是跟无数投资人周旋,让他们互相竞价来获取最好条款。我的目标始终是:找一个真正信任的合伙人,拿到好条款,然后快速推进,把融资时间压到最短。所以,想想你在乎什么,然后专注于此,这些事情没有标准答案。

我刚开始创业时,很多人建议我找个联合创始人,我基本没听。我知道他们可能是对的,但我心里没有合适的人选。我不想强求,所以就没找。后来我觉得,有个人和你一起在战壕里摸爬滚打确实会有帮助,但你会用其他方式来弥补。比如,我经常跟妻子倾诉,我对员工也比正常情况下更开放,这有好有坏,我会跟早期团队分享很多东西,尤其是在需要建议的时候。我还尝试建立其他创始人的圈子,特别是在纽约,我们有六七个人,每年争取一起吃两次饭。听起来不多,但这成了一个非常有用的支持系统。

X 上很多人在讨论“公司里每个人都应该每周工作七天吗”之类的事情。我基本上一直在工作,这是我做的选择,而且我非常满意。但我不期望团队里的人一直工作,我希望这是一个你可以通过正常工作时间取得巨大成功的公司,你的产出和表现会得到回报。我认为,没有唯一正确的方式。不要过多关注你认为应该怎么做,想想你想怎么做,以及什么真正符合你希望的工作方式。

Ryan:你推荐什么书?技术类的,或者对创始人有帮助的。

Charlie:我读的技术材料不多,但有几场演讲对我影响很大。比如 Zig 语言的创造者 Andrew Kelley 做过一场关于数据导向设计的演讲,我学到了很多。那场演讲讲的是他们在 Zig 编译器里做的设计决策,关于内存、分配这些。我当时刚进入系统编程的职业生涯不久,看完之后心想:哇,这些人真的在乎他们在做什么,它让我用完全不同的视角看待软件。

Ryan:如果你能回到职业生涯的起点,刚毕业那会儿,你会给自己什么建议?

Charlie:这很难回答,因为有太多后见之明。我大概会告诉自己:你做的是正确的决定,别太焦虑。但很难说如果重来一千次会怎样。比如,我离开学校去可汗学院工作时,心里有一部分在嘀咕:我是不是应该去大厂?我会不会后悔没有大厂经历?可汗学院的薪水不错,但大厂给的肯定更多。我看到朋友们拿着巨额奖金,心里有点不安,怀疑自己是不是选错了。从长远看,这个选择回报了我。也许大厂也不错,但可汗学院的经历才是我真正想要的。我觉得自己是基于正确的理由做的决定,所以很多事情,如果你基于原则做决定,最终会好起来的。

Ryan:我们开头聊过,你之所以进入这个领域,是因为尝试了各种不同的生态,有了更广的视角。如果你去了 Google,只用 Google 的封闭系统,可能就不会有这种洞察。

Charlie:对。我在 Spring 待了四年半,离开时他们正要转型,后来被 Genentech 收购。我们当初想建立一个疯狂的药物发现公司,专注于衰老,用计算机视觉,非常雄心勃勃。后来公司没有达到所有梦想,我一度怀疑:我是不是浪费了时间?但最终我意识到:没有。作为早期员工,我经历了所有阶段,学到了如何运营自己的公司,所有技术积累都用到了我自己的公司里。所以,虽然我给出这些建议有点奇怪,因为一切最终都进展顺利,但确实有很多时刻我怀疑过自己的职业选择。事后看来,你只能回头看才能把点串成线,所有东西加起来,让我找到了我真正热爱的事情,那就是构建工具并为之投入。

访谈视频原链接:

https://www.youtube.com/watch?v=Iw65FD4MGgs

声明:本文为 InfoQ 编译,不代表平台观点,也不构成投资建议,未经许可禁止转载。

相关内容

热门资讯

己二腈:从根源降低钠电池碳酸酯... 构建超宽稳定电化学窗口,适配4.2V以上高压正极常规碳酸酯电解液氧化上限仅4.0V,4.2V以上剧烈...
应对台风“美莎克” 交通运输部... 新京报讯 据交通运输部微信公众号消息,据气象部门预计,受台风“美莎克”影响,7月5日14时至6日14...
广西钦州通报散货船“中泓发展”... (来源:现代快报)据“钦州发布”微信公众号消息,7月5日,钦州海上搜救中心发布情况通报:7月4日18...
12个新职业,要来了! (来源:环渤海新闻网)近日,人社部办公厅发布《关于对拟发布船舶岸基管理工程技术人员等职业信息进行公示...
4名高考生打暑假工高温硬扛32... (来源:河南商报) 【#4名高考生打暑假工高温硬扛32吨...