GitHub 分享在大型项目中使用 AI 的最佳实践,517 分高热度和 418 条讨论反映程序员的强烈需求。
人们似乎已经普遍接受这样一个事实:AI 编程工具很难应对真实的生产代码库。斯坦福大学关于 AI 对开发者生产力影响的研究发现:
AI 工具交付的大量“额外代码”,最终只是在返工上周刚刚交付的那些垃圾代码。
编程智能体很适合新项目或小范围改动,但在大型、成熟的代码库中,它们往往反而会降低开发者的生产力。
常见的回应介于悲观的“这永远行不通”和更克制的“也许等将来模型变得更聪明时可以”之间。
经过几个月的摸索,我发现,只要遵循上下文工程的核心原则,就能让今天的模型走得非常远。
这并不是又一篇鼓吹“让你的生产力提升 10 倍”的文章。面对 AI 炒作机器时,我通常相当克制。但我们偶然摸索出了一些工作流,让我对未来的可能性抱有相当大的乐观态度。我们已经让 claude code 成功处理了一个 30 万行代码的 Rust 代码库,在一天内完成通常需要一周的工作,同时保持了足以通过专家审查的代码质量。我们采用了一系列我称之为“频繁的有意压缩”的技术——在整个开发过程中,有意识地设计向 AI 提供上下文的方式。
现在我完全相信,将 AI 用于编程并不只是拿来制作玩具和原型,而是一门具有深厚技术内涵的工程技艺。
视频版:如果你更喜欢视频,这篇文章基于我 8 月 20 日在 Y Combinator 所做的一场演讲。
来自 AI Engineer 的基础背景
AI Engineer 2025 上的两场演讲从根本上塑造了我对这个问题的思考。
第一场是 Sean Grove 关于“规格说明就是新的代码”的演讲,第二场是斯坦福大学关于 AI 对开发者生产力影响的研究。
Sean 认为,我们全都用错了凭感觉编程。花两个小时与 AI 智能体聊天,说明你想要什么,然后丢掉所有提示词,只提交最终代码……这就像 Java 开发者编译出一个 JAR,提交编译后的二进制文件,却把源代码扔掉一样。
Sean 提出,在 AI 时代,规格说明将成为真正的代码。两年后,你在 IDE 中打开 Python 文件的频率,大概会和今天打开十六进制编辑器阅读汇编代码的频率差不多——对我们大多数人来说,也就是从来不会。
Yegor 关于开发者生产力的演讲处理了一个正交的问题。他们分析了 10 万名开发者的提交,并发现了以下情况:
AI 工具经常会导致大量返工,从而削弱人们感受到的生产力提升。
AI 工具很适合绿地项目,但对于棕地代码库和复杂任务,往往会适得其反。
这与我同创业者交流时听到的反馈一致:
“在大型代码仓库里行不通。”
“在复杂系统里行不通。”
对于使用 AI 编写高难度代码,人们通常的看法是:
也许将来模型变得更聪明时可以……
甚至连 Amjad 也在 9 个月前参加 Lenny 的播客时谈到,产品经理会使用 Replit agent 为新东西制作原型,然后再把它交给工程师实现为生产版本。(免责声明:我最近没有和他叙过旧——好吧,其实从来没有——所以他的立场可能已经改变。)
每当我听到“也许将来模型变聪明了就可以”,通常都会立刻跳出来强调:这正是上下文工程的意义所在——充分挖掘当今模型的能力。
今天实际上能做到什么
我会在后面更深入地讨论这一点,但为了证明这不只是理论,先让我概述一个具体案例。几周前,我决定在 BAML 上测试我们的技术。BAML 是一个用于处理 LLM 的编程语言项目,拥有 30 万行 Rust 代码。我充其量只能算一个业余 Rust 开发者,而且此前从未接触过 BAML 的代码库。
大约一个小时内,我就提交了一个修复 bug 的 PR,并在第二天早上获得了维护者批准。几周后,@hellovai 和我结对为 BAML 交付了 3.5 万行代码,增加了取消支持和 WASM 编译功能——团队估计,一名高级工程师完成其中每项功能都需要 3 到 5 天。我们大约花了 7 个小时,就准备好了这两个 PR 的草稿。
再次强调,这一切都围绕着一种我们称为“频繁的有意压缩”的工作流构建——本质上,是围绕上下文管理来设计整个开发流程,将上下文利用率保持在 40%~60% 的范围内,并在恰到好处的节点引入高杠杆的人类审查。我们采用“研究、规划、实现”的工作流,但这里的核心能力和经验远比任何特定工作流或提示词集合更具普适性。
我们走到这里的奇怪历程
我当时正与我见过的最高产的 AI 程序员之一合作。每隔几天,他就会扔过来一个 2,000 行的 Go PR。而且这并不是什么 Next.js 应用或 CRUD API。这是复杂且容易出现竞态问题的系统代码:通过 Unix 套接字执行 JSON RPC,并管理从派生 Unix 进程流式传出的标准输入输出——其中大多数是 claude code sdk 进程,稍后会详细介绍 🙂。
每隔几天就仔细阅读 2,000 行复杂的 Go 代码,根本无法持续下去。我开始有点理解 Mitchell Hashimoto 为何要为 ghostty 增加“必须披露 AI 贡献”的规则了。
我们的做法是采用类似 Sean 所说的规格驱动开发。
刚开始时很不舒服。我必须学会放下逐行阅读每个 PR 代码的习惯。我仍然会相当仔细地阅读测试,但规格说明成为了我们判断“正在构建什么”以及“为什么要构建”的事实来源。
这次转变耗时约 8 周。对所有参与者来说,这都令人极其不适,尤其是对我而言。但现在我们已经起飞了。几周前,我一天交付了 6 个 PR。过去三个月里,我手动编辑非 Markdown 文件的次数,一只手就数得过来。
面向编程智能体的高级上下文工程
能够在棕地代码库中良好运作的 AI
能够解决复杂问题的 AI
在整个团队中保持认知一致
(当然,也让我们试着尽可能多地消耗 token。)
我们在将上下文工程应用于编程智能体时学到了什么
从哪些维度来看,使用这些智能体是一门技术性极强的技艺
为什么我认为这些方法不具备普适性
我对第 3 点一再被证明错误的次数
但首先:管理智能体上下文的朴素方式
我们大多数人最初都会像使用聊天机器人一样使用编程智能体。你来我往地同它交谈(或者醉醺醺地冲它大喊),凭感觉一路摸索着解决问题,直到上下文耗尽、你选择放弃,或者智能体开始道歉。
稍微聪明一点的做法,是在偏离正轨时直接重新开始,丢弃当前会话并开启一个新会话,也许还会在提示词里多加一点引导:
[original prompt], but make sure you use XYZ approach, because ABC approach won't work
稍微聪明一些:有意压缩
你可能已经做过一种我称为“有意压缩”的事情。无论当前是否仍在正确轨道上,当上下文开始被填满时,你大概都应该暂停工作,换一个全新的上下文窗口重新开始。为此,你可能会使用这样的提示词:
"Write everything we did so far to progress.md, ensure to note the end goal, the approach we're taking, the steps we've done so far, and the current failure we're working on"
你也可以使用提交消息来进行有意压缩。
我们究竟在压缩什么?
什么会吞噬上下文?
理解代码流程
工具返回的巨大 JSON 数据块
所有这些都可能淹没上下文窗口。压缩只是把它们提炼成结构化产物。
一次良好的有意压缩输出可能包含如下内容:
为什么要如此执着于上下文?
正如我们在 12-factor agents 中深入讨论过的那样,LLM 是无状态函数。在不训练或微调模型本身的情况下,唯一会影响输出质量的因素,就是输入的质量。
这既适用于驾驭编程智能体,也适用于一般的智能体设计。只不过前者的问题空间更小,而且我们讨论的是使用智能体,而不是构建智能体。
在任意时刻,claude code 这类智能体中的一轮交互,都是一次无状态函数调用:输入上下文窗口,输出下一步操作。
也就是说,上下文窗口中的内容,是你影响输出质量的唯一杠杆。所以,没错,它值得你如此执着。
你应该针对以下目标优化上下文窗口:
换一种说法,可能发生在上下文窗口中的最糟糕情况,按严重程度排序如下:
错误信息
如果你喜欢公式,可以参考下面这个愚蠢的公式:
正如 Geoff Huntley 所说:
这场游戏的关键在于,你只有大约 17 万 token 的上下文窗口可以使用。因此,尽可能少地使用它至关重要。你使用的上下文窗口越多,得到的结果就越差。
Geoff 针对这一工程约束提出的解决方案,是一种他称为“Ralph Wiggum 作为软件工程师”的技术,其基本做法是使用一条简单提示词,把智能体放在 while 循环中永远运行下去。
while :; do
cat PROMPT.md | npx --yes @sourcegraph/amp
done
如果你想了解更多关于 ralph 或 PROMPT.md 里的内容,可以看看 Geoff 的文章,或者深入了解 @simonfarshid、@lantos1618、@AVGVSTVS96 和我在上个周末 YC Agents Hackathon 建的项目——这个项目基本上在一夜之间把 BrowserUse 移植到了 TypeScript。
Geoff 把 ralph 称为一个"荒唐地愚蠢"的上下文窗口问题解决方案。我不太确定它是否真的愚蠢。
子智能体是管理上下文的另一种方式,通用子智能体(即非自定义的)从 Claude Code 和许多编程 CLI 早期就开始支持了。
子智能体不是关于角色扮演和拟人化。子智能体是关于上下文控制。
子智能体最常见、最直接的用例是让你用一个新鲜的上下文窗口来进行查找、搜索、总结工作,这样父智能体可以直接开始工作,而不会被 Glob、Grep、Read 等调用污染上下文窗口。
理想的子智能体响应可能看起来类似于上面介绍的理想临时压缩方案。
让子智能体返回这样的结果并不是件容易的事。
我想讨论的、以及我们在过去几个月采用的技术都属于我所说的"频繁有意压缩"。
本质上,这意味着围绕上下文管理来设计你的整个工作流,并将利用率保持在 40%-60% 范围内(取决于问题的复杂性)。
我们的做法是分成大约三个步骤。
我说"大约"是因为有时我们跳过研究阶段直接进入规划,有时我们在准备实现之前会进行多轮压缩研究。
我会在下面的具体例子中分享每个步骤的示例输出。对于一个给定的功能或 bug,我们通常会做:
理解代码库、与问题相关的文件,以及信息如何流动,也许还有问题的潜在原因。
这是我们的研究提示。它目前使用自定义子智能体,但在其他仓库中,我使用一个更通用的版本,它通过 Claude Code 的 Task() 工具和 general-agent。通用版本的效果也差不多。
制定我们将采取的确切步骤的大纲,以及我们需要编辑的文件和方式,对测试和验证步骤要非常精确。
这是我们用于规划的提示。
逐步执行计划的每个阶段。对于复杂的工作,我经常在验证每个实现阶段后将当前状态压缩回原始计划文件中。
这是我们使用的实现提示。
旁注 —— 如果你一直听说很多关于 git worktrees 的事,这是唯一需要在 worktree 中完成的步骤。我们倾向于在 main 分支上做其他所有事情。
为了简洁起见,我会跳过这部分,但欢迎你在 humanlayer/humanlayer 启动一个 Claude 会话并询问"thoughts tool"是如何工作的。
我每周都与 @vaibhav 进行一次直播编程会议,我们进行头脑风暴和编码,解决高级 AI 工程问题。这是我一周中最精彩的部分。
几周前,我决定分享更多关于这个过程的信息,想知道我们内部的技术是否能一次性修复一个 BAML(一种用于 LLM 工作的编程语言)的 300k LOC 的 Rust 代码库中的 bug。我从 @BoundaryML 仓库中挑选了一个(相对来说比较小的)bug,然后开始工作。
你可以看看这一期来了解更多关于这个过程的信息,但简要概括一下:
值得注意的是:我最多只是一个业余 Rust 开发者,我从未在 BAML 代码库中工作过。
我进行了一项研究,我读了它。Claude 判定这个 bug 是无效的,代码库是正确的。
我扔掉了那份研究,用更多的方向指导进行了新的研究。
这是我最终使用的研究文档。
在研究进行的同时,我不耐烦地启动了一个没有研究的计划,看看 Claude 是否能直接跳到实现计划——你可以在这里看到它。
当研究完成后,我启动了另一个使用研究结果的实现计划——你可以在这里看到它。
这两个计划都相当短,但它们差异很大。它们以不同的方式修复问题,并有不同的测试方法。不详细讨论,这两个都"本来会工作",但通过研究构建的那个在最佳位置修复了问题,并规定了与代码库约定一致的测试。
这一切都在播客录制的前一晚进行。我并行运行了两个计划,并在签离前将两个都作为 PR 提交了。
到第二天早上 10 点我们上节目时,来自带有研究的计划的 PR 已经被 @aaron 批准了,他甚至不知道我在为播客做东西 🙂。我们关闭了另一个。
所以在我们原来的 4 个目标中,我们达成了:
✅ 在棕地代码库中有效(300k LOC rust 项目)
✅ 无废话(PR 已合并)
解决复杂问题
保持思想对齐
Vaibhav 仍然持怀疑态度,我想看看我们是否能解决一个更复杂的问题。
所以几周后,我和 Vaibhav 花了 7 小时(3 小时研究/规划,4 小时实现),为 BAML 增加了取消和 wasm 支持,并发布了 35k LOC 的代码。取消 PR 上周刚刚合并。WASM 的仍然开放,但有一个从 JS 应用在浏览器中调用 wasm 编译的 rust 运行时的工作演示。
虽然取消 PR 需要一些额外的工作才能推过终点线,但我们在短短一天内取得了令人难以置信的进展。Vaibhav 估计,对于 BAML 团队中的一名高级工程师来说,每个 PR 需要 3-5 天的工作时间才能完成。
✅ 所以我们也能解决复杂问题。
还记得例子中我读了研究然后因为它是错的就扔掉它的那部分吗?或者我和 Vaibhav 深度投入 7 小时的那部分?如果你不投入到你的任务中,这是行不通的。
有一种人总是在寻找能解决他们所有问题的一个神奇提示。它不存在。
通过研究/规划/实现流程进行频繁有意压缩会提高你的性能,但使它足够好去处理难题的是你在管道中构建高杠杆的人工审查。
几周前,@blakesmith 和我坐了 7 小时,试图从 parquet java 中移除 hadoop 依赖——关于所有出错的东西和我关于为什么的理论,我会留到另一篇文章,只需说它进展不顺利。总结就是研究步骤没有深入足够的依赖树,并假设可以将类移到上游而不引入深层嵌套的 hadoop 依赖。
有些大的难题你不能仅通过提示在 7 小时内完成,我们仍在好奇且兴奋地与朋友和合作伙伴一起探索推动边界。我认为这里的另一个教训是你可能需要至少一个是代码库专家的人,在这个案例中,我们两个都不是。
如果你只能记住一件事,那就是这个:
一行坏代码就是……一行坏代码。但计划中的一行坏代码可能导致数百行坏代码。而研究中的一行坏代码、对代码库如何工作或某些功能位置的误解,可能导致你有数千行坏代码。
所以你想把人力和关注力聚焦在管道的高杠杆部分。
当你审查研究和计划时,你获得比审查代码时更多的杠杆。(顺便说一句,我们在 humanlayer 的主要关注点之一是帮助团队构建和利用高质量的工作流提示,以及为 AI 生成的代码和规范制定出色的协作工作流)。
人们对代码审查的目的有很多不同的看法。
我更喜欢 Blake Smith 在《Code Review Essentials for Software Teams》中的框架,他说代码审查最重要的部分是思想对齐——保持团队成员在代码如何变化和为什么变化上步调一致。
还记得那些 2k 行的 golang PR 吗?我关心它们的正确性和好的设计,但团队内部不安和挫折的最大来源是缺乏思想对齐。我开始与我们的产品是什么以及它如何工作失去联系。
我预期任何与高效 AI 编码员合作过的人都经历过这种情况。
这实际上对我们来说是研究/规划/实现最重要的部分。所有人运送更多代码的一个必然副作用是,你的代码库中更大比例的代码对于任何时间点的任何工程师来说都将是陌生的。
我甚至不打算说服你“研究/规划/实现”是适合大多数团队的正确方法——它很可能并不是。但你绝对需要一套工程流程,能够:
对大多数团队来说,这套流程是 Pull Request 和内部文档。对我们来说,现在则是规格、计划和研究。
我不可能每天阅读 2000 行 Go 代码,但我可以阅读 200 行写得很好的实现计划。
当某个地方出问题时,我没法花一个多小时深入翻查 40 多个守护进程代码文件(好吧,其实可以,但我不想)。我可以引导一个研究提示词,让它快速告诉我应该查看哪里,以及为什么。
基本上,我们得到了需要的一切。
✅ 适用于棕地代码库
✅ 能解决复杂问题
✅ 能维持思维上的一致性
(哦,对了,我们三个人的团队现在平均每个月在 Opus 上花费约 1.2 万美元。)
为了避免你觉得我只是另一个过度炒作、留着小胡子的销售,我得说明,这种方法并不能完美解决所有问题(我们还会回来再战一轮的,sound、parquet-java)。
8 月份,整个团队花了两周时间原地打转,试图解决一个极其棘手的竞态条件,结果一路钻进兔子洞,牵扯出 Go 中 MCP sHTTP keepalive 的问题,以及一大堆其他死胡同。
但现在,这已经是例外了。总体而言,这套方法对我们非常有效。我们的实习生入职第一天就提交了 2 个 PR,到第 8 天时提交了 10 个。说实话,我原本很怀疑它是否对其他人也有效,但我和 Vaibhav 在 7 小时内交付了 3.5 万行可运行的 BAML 代码。(如果你还没见过 Vaibhav,他是我认识的工程师中,在代码设计和质量方面最一丝不苟的人之一。)
我相当确信,编码智能体最终会商品化。
真正困难的是团队和工作流的转型。在一个由 AI 编写 99% 代码的世界里,协作的一切都会发生变化。
而且我非常坚信,如果你搞不定这件事,就会被那些搞定了的人远远甩在身后。
我们非常看好规格优先、由智能体驱动的工作流,因此正在构建工具,让这套流程更容易落地。在诸多问题中,我尤其痴迷于如何让这些“频繁、有意的压缩”工作流在大型团队中以协作方式扩展。
今天,我们推出了全新的“后 IDE 时代 IDE” CodeLayer,目前处于私有测试阶段——可以把它理解成“Claude Code 版的 Superhuman”。如果你喜欢 Superhuman 和/或 Vim 模式,并且已经准备好超越“凭感觉编程”,开始认真使用智能体进行构建,我们非常欢迎你加入候补名单。
请前往 https://humanlayer.dev 注册。
如果你是某个复杂开源项目的维护者,并且人在湾区,我有一个长期有效的公开提议:我会在某个周六与你在旧金山线下结对工作 7 小时,看看我们能否交付一个重量级成果。
我可以借此深入了解这些技术的局限性,以及它们在哪些地方会失效(如果运气好的话,还能产出一个可运行、已合并、创造大量价值,并且可以作为案例展示的 PR)。而你则可以通过我目前发现唯一真正有效的方式学习这套工作流——直接一对一结对。
如果你或你认识的人是一位希望借助 AI 将团队生产力提升 10 倍的工程负责人,我们可以深入各类规模的团队,与他们并肩推进,帮助完成迈向 AI 优先编码世界所需的文化、流程和技术转型。
感谢所有听过这篇文章早期那些漫无边际版本的朋友和创始人——Adam、Josh、Andrew,以及许许多多其他人。
感谢 Sundeep 陪我们经受住这场疯狂的风暴。
感谢 Allison、Geoff 和 Gerred,连拖带拽地把我们带进未来。