资深程序员的 LLM 高效协作指南
深度文章分析专业开发者如何充分发挥 LLM 辅助编程的效能,介绍高级工作流与 prompt 技巧
深度文章分析专业开发者如何充分发挥 LLM 辅助编程的效能,介绍高级工作流与 prompt 技巧
我懂,你水平太高了,根本不需要凭感觉编程。你是一名有 20 年经验的高级开发者,对整个系统了如指掌。又或许,你是团队里的明星个人贡献者,是唯一一个总能想出办法解决难题的人。再不然,你可能就是你正在实现的那些算法所属学科的开创者。虽然我不了解你,但我知道,你认为自己的水平高到不需要凭感觉编程。可事实是,你大错特错,而且错得彻彻底底。
这是在挖苦人吗?也许吧……但我要把话说得更绝一点。
不,你的水平并没有高到不需要凭感觉编程。事实上,你才是唯一应该凭感觉编程的人。
就在一个月前,我还会觉得这种说法很荒谬,因为“专家”程序员这个标签同样适用于我。为了证明我确实有资格谈论这个话题:我是 200 多个 GitHub 包的维护者,这些包总计获得了超过 23,000 颗星;我是 MIT 一个计算机科学实验室的共同首席研究员;我曾是一家相当成功的科技初创公司的创始架构师,现在则在另一个领域担任副总裁,负责领导 Dyad 的架构设计工作。我显然知道该怎么编程;当学生和实习生的代码明显由 LLM 生成时,我会对他们冷嘲热讽;我也曾相当公开地反对这一切,因为这些机器人蠢得甚至不知道“正确”究竟是什么意思。
但大约一个月前,我开始尝试这种“凭感觉编程”,随后发现,在合适的场景和正确的工作流中,它可以成为一个非常强大的工具。顺便说一句,我现在有大约 32 个 Claude 智能体持续运行在可以通过 ssh 连接的 tmux 窗口中,所以一整天里,我都可以通过笔记本电脑或手机随时查看它们的进展,并不断推进工作。一个月前,这还完全不可想象,但现在它已经成为现实。
这是一份面向专家的凭感觉编程指南,写给那些一边嘲笑不知自己在做什么的小年轻、一边又想以正确方式开始实践的人。
先把那些炒作放到一边。我不是来向你推销 ChatGPT 的,所以不会告诉你它达到了博士水平——任何这辈子真正接触过博士的人,都百分之百、绝对、清楚地知道事实并非如此。但它确实算得上某种东西。那么,它到底是什么?
你可以把 LLM 智能体想象成一名专职实习生,或者一名能力大致相当于大学二年级学生的人。他们知道编程大概是什么样子,可以模仿其他人的思路和架构,知道如何运行单元测试之类的操作,也知道怎样用 Google 搜索。他们上过基础编程课程,或许还在某门高阶课程中深入研究过某个随机主题;但只要你围绕这个主题多问几个问题,就会发现他们其实并没有真正深入地掌握它。这孩子看起来还算聪明,你愿意给他一个机会。
如果真有这样一个人来到你的办公室找工作,你会怎么安排他?通常来说,你会选择两种做法之一。第一种是把他的工作限制在沙箱里。把新学生或实习生的工作放进沙箱,原因其实非常简单:你对某个新主题或工具不够熟悉,想尝试一下,而且——呃,为什么不呢,看看会发生什么吧。如果选择沙箱这条路,你很可能并不关心代码本身(反正如果不在核心仓库中,它大概既无法维护,最终也会逐渐腐化);你真正关心的是拿到产物。你稍微凭感觉编一会儿程,“这个看起来挺酷!”,然后把它塞进演示或 LinkedIn 帖子里,接着转头去做别的事情。这就是你可能已经尝试过、并认为“还不够实用”的那种简单凭感觉编程。它确实有效,但这不是我们在这里要讨论的内容,所以本文无须再多说。
第二条路则完全相反:你会把这名学生或实习生安排进一个你非常熟悉的项目,因为这样你就能轻松审查他的工作。你可以给出明确的反馈,因为他即将犯的前 10 个错误,你自己早就犯过了;你已经知道该如何告诉他下一步做什么;甚至已经替他规划好了项目未来 6 个月的工作,因此管理成本很低。对于大多数你希望长期留下的人,你都会这样培养,对吧?同样,这也是你应该用来对待 LLM 智能体的方式。
接下来,让我们逐步走一遍这个过程。
带领一个程序员团队很难!这需要时间、能力和耐心。我想,每个人小时候大概都想过:“我不想当干活的人,我想当老板,只要坐在椅子上告诉别人该做什么,然后砰的一声,一切就都完成了!”但等你在大学里做完第二次小组项目后,很快就会意识到:如果带团队的方式不对,最终只会变成你一个人干完所有工作,却要背负整个四人团队的交付预期。
出现这种情况有几个原因。尝试建立团队编程时,一个问题可能是你对相关领域本身就不够了解。如果你需要花很长时间才能理解这个领域、理解别人试图做什么,以及理解他们的代码究竟在做什么,那么管理别人根本不值得你投入这些时间。你需要达到这样一种程度:可以非常迅速地看到代码、理解正在发生什么,然后说:“在你为 X 和 Y 添加测试之前,我不能合并这段代码;另外,请给我一张 Z 的图,让我知道这一切之间是如何关联的。”如果你不能立即给出这类反馈,那你可能还没有足够的经验来领导团队。你需要先写过几百万行代码,才能把这种能力变成本能——看到代码就能直接说:“别这么做,这会成为性能瓶颈。”而要让凭感觉编程真正发挥作用,你在代码审查时就必须具备这种反应速度。不过,我还要直截了当地说一句:
有些人更擅长通过指导别人来完成工作。另一些非常聪明的人,却怎么也无法让别人产出优质成果。这并不是一种指责,硅谷创造“个人贡献者”这个角色是有原因的。如果你属于后者,那么凭感觉编程可能并不适合你,因为你对智能体感到厌烦的速度,很可能比对真人还要快(不知怎么回事,它们能记住的信息甚至比最差的实习生还少;至少实习生还记得你最喜欢点什么午餐)。
所以,请抱着这样的心态开始:我必须和智能体开会,需要制订计划并给它们分配任务,还需要审查代码。如果你发现做这些事情比自己写代码还慢,那现在就停下来。但如果你擅长与团队合作,那就继续。接下来,我们该如何让这支团队高效运转?
如果有人向你展示 Claude Code,而你让它尝试解决自己刚刚在处理的问题——这显然是个难题,因为既然它最终落到了你的桌上,就意味着其他人已经没能解决它——那么当 Claude 惨败时,你只会戳着它嘲笑。但你绝不会这样对待一名新来的实习生或学生(希望如此),那为什么要这样对它?还是那句话,你已经知道它实际上有多聪明了,所以别管那些炒作,以同样的方式对待它。这会立刻引出几条工作流原则:
你有一个问题,把它交给智能体,审查它返回的结果,然后向它提供反馈。这与你管理 Scrum 团队或指导学生完成论文的方式完全相同。你不会只是把问题扔给他们,然后期待他们自行解决;你会把问题交给他们,他们带着一个解决方案回来,接着你再告诉他们下一步该做什么。
如果你的资历足够深,你很可能早已通过这种方式完成了大部分工作。每位教授手下参与编码的学生都比自己多,每位高级开发者所带团队产出的代码总量,也远远超过他本人编写的代码。只要把 Claude 想象成你手下那群刚刚入职的新人就好。现在,如果你在想:“但管理一大群新人可能很困难”……没错,这说明你的资历确实足够深,已经理解该如何正确地做这件事。把新实习生或学生派去做一个项目其实相当容易;如果他们的薪水或成绩取决于项目能否完成,他们总会交回一些东西。至于交回来的东西究竟好不好,则取决于你是否妥善拆分了工作,并为他们分配了合适的任务。
但有一件关键的事情是:如果每 10 分钟就必须开一次会,你肯定会发疯,所以别这么做。可以安排 12 到 32 个智能体运行在不同的进程中,最好将它们隔离在其他计算资源的沙箱里(使用沙箱,一方面是为了防止它们破坏机器,另一方面也是为了让它们使用不具备核心读写权限的 GitHub 身份验证。这样,你就可以告诉它启用“dangerously unsafe permissions”,而最坏的结果也不过是它让自己的 Docker 容器发生段错误,并且永远不会创建 PR)。给它一条完整的命令:
"试着解决(这个开源项目中的一个简单问题)。提交一个带有解决方案的 PR,一小时后检查持续集成,看测试是否通过。如果测试没有通过,评估问题是什么,如果只是个快速修复就提交一个 commit 来处理,否则报告问题的核心难点。"
让它清晰,让它简单,让它知道每一步,就让它不断循环一会儿。
如果你看到一个学生作弊,只是从 StackOverflow 复制粘贴了代码但解释不了它做什么,你会丢弃它并告诉他重新尝试。如果你的新实习生没有重用你团队已经写好的扎实代码,反而用一种有 bug 且难以维护的方式重写了某些低层细节,你会丢弃它并告诉他重新尝试。如果他们写了一个 500 行长的函数做 10 件不同的事情,你会丢弃它并告诉他重新尝试。你不会浪费时间去修复它,你只会告诉他重新尝试。
再次强调,对 LLM 也是一样的。我看到很多人跟风凭感觉编程 YouTuber 们制作愚蠢小游戏的心态。"ChatGPT,更努力点!帮我修复!"。想知道一个秘密吗?那些东西比废话更糟。问题在于这些 LLM 被设计用来取悦你,所以如果你告诉它们更努力,它们要么会开始幻觉,要么就开始改你的测试。都别尝试。一旦你看到它开始脱轨,就丢弃它。那个问题对 Claude 来说太难了,现在该你上场了。
在早上 9 点发送一堆命令。中午检查。你可能有 10 个完成了。其中 8 个可能脱轨了,随便吧,丢掉。嘿,两个 PR 成功了,万岁!再发 10 个,下午 3 点回来看。20 个完成,4 个成功,16 个失败。再发几个,也许再发几个清理工作来寻找缺失的文档字符串,或挖掘看是否引入了任何性能回归。到了晚上 6 点,看到另外 4 个成功,停止其他工作。
10 个 PR 被合并了,加上你那天做的任何其他工作(是的,因为你没有把大部分时间花在这上面!)。你可能会想,这就像 10/40 = 25% 的成功率,不太好。但你知道吗?那些都是免费的。你只是完成了大量额外的工作,否则你根本做不了。成功率只是这些东西为其成本提供多少价值的问题。那是 Sam Altman 要担心的事。但如果你订阅了这些 LLM,就尽管烧 token 吧,谁在乎。不要担心成功率,只要追求成功总数。
这导出了一个非常违反直觉的事实,可能会让人有些措手不及,但我是认真的。每个人的第一本能是把它扔到某个他们从未真正贡献过的项目上,然后被禁言(好吧,至少在开源维护者看来是这样)。但真正的问题是,你大部分时间都会花在代码评审上。如果你在不太熟悉的代码上这样做,你将花费很多时间试图理解代码,那么这一点,为什么不自己写代码呢?
这是大多数人似乎就此停止并完全放弃凭感觉编程想法的地方。但相反……如果把它应用到你正在处理的代码库呢?不,不是那些你想的困难问题,而是所有那些小的附带问题呢?你已经推迟了 6 个月的小重构?追踪 Git 提交二分查找,找到一周前出现在 master 上的性能回归的确切原因呢?或者你为 Windows 和 Mac 创建了一个专用版本,但在 Linux 部分留了一个"待做",因为它很简单但需要 4 小时的单调工作?所有这些东西,如果有人带着代码出现,你可以在大约 5 分钟内评审,并知道它是否正确。把这些任务分配给智能体!
以完全相同的方式,给实习生分配工作的最好地方是你已经很熟悉的项目,因为这样评审他们的工作很容易。这是"我没有时间给你,所以试试这个简单任务"的方法。你知道代码,你知道问题,你可以给他们分配一个足够简单的任务,让他们能够完成而不需要太多帮助。这里的原则是一样的。
现在让我们看一下我的机器人账户提交的一些例子。
这是一个快速简单的 PR,非常适合这种情况。如果你不了解 Julia 性能处理或 trim,基本上这是 Julia v1.12 中的新功能,Julia 现在可以构建小型精简二进制文件。为了做到这一点,你需要确保函数完全专门化,这在默认情况下不会发生,因为那样会在许多情况下产生大量额外编译,但对于高阶数值求解器,这正是我们想要的行为。所以我告诉它去专门化包中该函数的所有实例,我可以相当快地检查 PR,看到它坚持了目标并完成了它。这将随后跟进新工具,执行 trim 兼容性的静态检查(仍在开发中),但只是进行这些向后兼容的微小更改,东西在测试版中似乎可以工作,所以现在合并,当我们有一个好的系统时再添加那些测试。
1 分钟写查询,稍后回来 1 分钟评审。
这正是这些工具的设计目的。大多数 PR 的目标都是这样的。
实际上,我最喜欢的一个提示词是"查阅 XXXXXXX 仓库,找到最简单的问题,提交一个解决它的 PR。"这是一个来自那个提示词的 PR 例子。耶,它成功了!已合并。它应该做最少数量的更改,小而容易评审,否则就丢掉,那意味着它可能脱轨了。有大量这样的小"如果你添加了从 float 到 Int 的转换,这个 API 会更容易"(有时你会说"哦,不,那是个坏主意,关闭 PR 和 issue!")。
这个 PR 来自于指向一个事实:我时不时会在一个关于遍历 ODE 微分的文档构建中遇到测试失败,关于其遍历性质。这是一个非常有趣的话题,但通常任何涉及真实数学的东西对 LLM 来说都太难了。在这个例子中,是的,我可以立即看到这个 PR 没有意义……好吧,它确实有。NaN 和 Inf 肯定来自最小二乘阴影代码中的数值问题,这指向的是 Schur 补数正在用 B * Diagonal(wBinv) * B' 这样的东西完成,作为数值分析师,我可以立即看出这会使矩阵的条件数翻倍,但在开源线性代数事物中似乎没有立即的解决方案。所以我关闭了这个,发送了一个便条给 Alan Edelman,试图找出做这个因数分解的更好方式。虽然它没有解决问题,但至少我现在知道问题是什么。
这大概是大多数 PR 会变成的样子。它给了问题所在的提示,然后我接管。
是一个甜蜜而简单的 PR,重构测试以移动一些东西,特别是 Enzyme 自动微分引擎测试,到一个"无预发布"集合。"无预发布"意味着"不在下一个语言版本的预发布版本上运行",因为这些工具涉及编译器中的语言内部,所以它们永远不会提前准备好。这总是在实际测试任何有意义的东西之前导致预发布测试失败,所以我想在它出现的每个仓库中将所有 Enzyme 使用都移到"无预发布"集合。
大约 5 分钟写查询。一些测试套件需要简单的 Github 建议来修复这里或那里的一些细节。大约 5 分钟把它放进 8 个仓库。现在我准备开始使用预发布测试。手工做的话至少需要半小时,只是因为我们之前没有一个简单的系统来做这件事。也许这比完美的正则表达式有点脏,但不管怎样,10 分钟的时间对我来说听起来很划算。
重构通常效果很好,是该工具最主要的用途之一。"让它正确,写好测试,让它重构"通常是一个懒惰的方式,可以让你走到 90% 的目标。
这是一个通过指向它解决这个问题而生成的 pull request。那个问题之所以被选中,主要是因为它在 issue 列表中待了一阵子,看起来不太困难,但我没有时间来追踪一个不是很广泛使用的替代基于 C 的稀疏矩阵求解器扩展中的内存泄漏,但它需要在某个时候完成。所以,把机器人扔在上面。
AI 智能体返回的建议是为另一个库添加一个内存终结器(即告诉 GC 如何移除内存)。我看一眼就能立刻看出这种代码不应该存在于这个库中,而应该存在于求解器与语言绑定的库中。缺少终结器这个事实应该在那里解决。我关闭了 PR,扔掉了代码,找到了仓库中应该处理终结器的滞后讨论,戳了一下作者,搞定了。完成,有人只是需要被提醒一下。
我花的总时间大约 3 分钟。机器人也本可以写出那个修复,但它基本上已经存在了,所以没必要。这更多是关于找出系统中某些东西应该存在的地方。
这是一个不错的 PR,它没有完成(至少在我写这篇文章时),原因是有很多其他清理工作需要完成才能让它工作。还有多远?好吧,它生成了一套测试,清楚地列出了所有 120 个需要解决的事项。很好,这可能是一整周的任务……我知道工作量会很大,但现在相当具体。我可能不会让机器人来完成这个,但现在如果有人问完成需要多少工作量,我可以给出一个相当清楚的估计。问题已经从"有人需要试试,似乎是一大块工作"简化到"困难部分是完成这 120 项事务,这很简单但很乏味,大概需要一周,现在可能不值得花工夫"。这对提前规划很有用。我花的总时间大约 5 分钟,加上向其他人解释结果含义的 PR 讨论时间。
凭感觉编程把任何个人变成领导 20、30、50、60 个实习生团队的首席技术官。你立刻获得了一个庞大的团队。需要时间和经验来正确处理这样一个团队,使其高效工作。确保 60 个实习生不会破坏代码的性能、正确性或可维护性是非常困难的。所以我不推荐给仍在"成长中的程序员"。但如果你已经比较资深,正在扩大团队,那么这就是一种廉价加速的方式。
这意味着,凭感觉编程面向不会编程的人销售,但如果你真的想想,能正确使用它的主要受众其实是专家。
在 Julia Discourse 论坛上,我详细介绍了一些不同的 PR,以展示 AI 往往在哪里成功和失败。但通常任何主要关于"编程"的东西(重构、低效实现等),LLM 做得很好。关于领域或应用的任何东西(微分方程、工程、物理学对我来说),它似乎就是会做一些愚蠢的事情。结果都非常清楚地表明,你应该让它做什么样的 PR,哪些根本不值得努力。
我认识的开源社区中最缺乏同理心的一些人,也恰好是对凭感觉编程最怀疑的人。我强烈怀疑他们与智能体交流的方式和与其他潜在贡献者交流的方式相似,以同样的方式赶走机器人。但对于机器人来说,它总是会试图让你满意,只是通过幻觉和注释掉你的测试。这些人也不希望机器人出现,因为他们声称这就是机器人所做的全部。真是巧合。我想知道这将如何影响编程文化。
在我每月 $200 的 Claude 20x Max 订阅上,我在第一个月用了相当于约 $5,200 计算量的 token。这显然不可持续,但嘿,这是一个初创公司的世界,风投现在为它买单。如果你能完成一些额外功能来获得更多融资,那就值得。如果你是教授,能发表更多论文,那就值得。如果你是大公司的个人贡献者,能推出更多功能来让团队更亮眼,那就值得。等钱没了以后还值得吗?谁知道呢,但趁金子还在时就挖吧。
代码补全的功能相当烦人。真正的力量来自于运行智能体。Claude Code 有简单的设置,能够开始运行代码。只需写一个不错的 Claude.md,告诉它别太客气,只在无法解决问题时告诉我,你就可以了。context7 MCP 很好,Sequential Thinking 也是。
嘿,黑客新闻!看起来成功了。一个有趣的评论是"对我这个真正热爱编程的人来说,凭感觉编程看起来像地狱。"我 100% 同意!我有段时间远离它,因为我想"呃,这不是有趣的部分,我喜欢编码!"。但从这些例子中注意到,我在这上面花的时间我试图保持尽可能少。我喜欢编程,我需要编程,因为我能做困难的东西,而 LLM 不能。目标是用最小的工作量完成尽可能多的简单工作,这样你可以停止担心烦人的/乏味的东西,把更多时间集中在有趣的工作上。
CuriouslyC 的回应切中要害:
我选择技术栈并架构项目。我选择语言模式和代码组织。当智能体陷入困境时,我介入解决困难问题。这有什么地方说明这是中层管理?这只是摆脱了工作中所有低价值的部分。
但话说回来,如果你也真的讨厌参加会议,更喜欢独自编码,那……是的,也许智能体会把你逼疯。它们很吵,会骗你,你必须筛选电子邮件/PR 的垃圾,删除这些东西提出的大部分内容。同样,当这些东西偏离轨道时要快速删除,它会拯救你的理智。
话虽如此,随着来自 LLM 的代码数量增加,我认为会更加需要优秀的个人贡献者来为旧方式辩护并维护代码库的完整性,所以你会有你的位置。你可能会有更多的 PR 向你涌来,可能想更快地关闭其中一些。我不认为