原文:https://harper.blog/2025/02/16/my-llm-codegen-workflow-atm/
作者:Harper Reed
译者:ChatGPT 4 Turbo
编者注:这篇文章介绍了作者使用 LLM 进行代码生成的工作流程。主要包含两种场景:1) 全新项目开发:先用 ChatGPT 等工具进行头脑风暴形成详细规范,然后用推理模型制定执行计划,最后通过 claude.ai 或 aider 等工具执行代码生成。2) 已有项目迭代:使用 repomix 等工具获取代码上下文,再通过 LLM 进行代码审查、生成测试用例等工作。作者认为这种方法效率很高,但也提到了一些局限性,比如目前主要适合单人开发,团队协作时可能会遇到冲突。在等待 LLM 生成代码的过程中,作者会通过听音乐、玩游戏等方式打发时间。对于对 AI 持怀疑态度的人,作者建议阅读 Ethan Mollick 的《Co-Intelligence》一书来了解 LLM 的实际应用价值。
简而言之:构思规格,然后规划计划,接着使用 LLM codegen 执行。离散循环。然后就是魔法。✩₊˚.⋆☾⋆⁺₊✧
我一直在使用 LLMs 构建许多小型产品。这既有趣又有用。然而,也存在一些陷阱,可能会浪费大量时间。不久前,一个朋友问我如何使用 LLMs 编写软件。我想“哦,天哪。你有多少时间!”因此就有了这篇文章。
(附言:如果你讨厌 AI – 滚动到最后)
我与许多开发者朋友讨论了这个话题,我们都有类似的方法,但在某些方面会有各种调整。
这是我的工作流程。它建立在我自己的工作、与朋友们的交谈(感谢 Nikete、Kanno、Obra、Kris 和 Erik)之上,以及遵循在各种糟糕的互联网坏地方地方上分享的许多最佳实践。
这个方法现在运行良好,可能在 2 周后不再适用,或者效果会好两倍。¯\_(ツ)_/¯
开始吧
我总是觉得这些 AI 生成的图像很可疑。向我的 juggalo 编码机器人天使打个招呼吧!
进行开发有许多路径,但我的情况通常是以下两种之一:
- 绿地代码
- 传统现代代码
我将向你展示我对这两条路径的处理过程
绿地
我发现以下流程适用于绿地开发。它提供了一个健全的规划和文档方法,并允许你轻松地以小步骤执行。
技术上,右边有一片绿地。Leica Q,2016 年 5 月 14 日
第 1 步:理念打磨
使用对话式 LLM 来锁定一个想法(我使用 ChatGPT 4o / o3 来做这件事):
一次问我一个问题,这样我们可以为这个想法开发一个彻底的、逐步的规格说明。每个问题都应该基于我之前的回答,并且我们的最终目标是拥有一个详细的规格说明,我可以交给开发者。让我们迭代地做这件事,并深入探讨每一个相关的细节。记住,一次只能问一个问题。
这就是想法:
<IDEA>
在头脑风暴结束时(它会自然而然地结束):
既然我们已经完成了头脑风暴过程,你能将我们的发现编译成一个全面的、开发者准备好的规格说明吗?包括所有相关的要求、架构选择、数据处理细节、错误处理策略和测试计划,以便开发者可以立即开始实施。
这将输出一个相当坚实和直接的规格说明,可以交给计划步骤。
你可以将这个规格说明用于许多事情。我们在这里做代码生成,但我已经使用它来通过要求一个推理模型找出想法中的漏洞(必须更深入!),来生成白皮书,或者生成商业模型。你可以将其投入深入研究,并获得一个 10000 字的支持文档作为回报。
第 2 步:计划
将规格说明传递给一个合适的推理模型(o1*
、o3*
、r1
):
(这是 TDD 提示)
为构建这个项目草拟一个详细的、逐步的蓝图。然后,一旦你有了一个坚实的计划,将其分解成小的、迭代的块,这些块相互构建。查看这些块,然后再进行一轮分解成小步骤。审查结果,确保步骤足够小,可以安全地实施,具有强大的测试,但又足够大,可以推动项目向前发展。迭代,直到你觉得这些步骤的大小适合这个项目。
从这里开始,你应该有了为代码生成 LLM 提供一系列提示的基础,这些提示将以测试驱动的方式实现每个步骤。优先考虑最佳实践、渐进式进展和早期测试,确保在任何阶段都没有大的复杂性跳跃。确保每个提示都基于前一个提示,并以将事物连接在一起结束。不应该有悬而未决或孤立的代码,没有集成到前一个步骤中。
确保并分隔每个提示部分。使用 markdown。每个提示都应该使用代码标签标记为文本。目标是输出提示,但上下文等也很重要。
<SPEC>
为构建此项目,起草一份详细的、步骤-by-步骤的蓝图。然后,一旦你有了一个坚实的计划,将其分解成小的、迭代的块,这些块相互构建。查看这些块,然后再进行一轮分解成小步骤。审查结果,确保步骤足够小,可以安全实施,但又足够大,可以推动项目向前发展。迭代,直到你感觉这些步骤对于这个项目来说大小合适。
从这里开始,你应该有了为代码生成 LLM 提供一系列提示的基础,这些提示将实施每个步骤。优先考虑最佳实践和渐进式进展,确保在任何阶段都没有大的复杂性跳跃。确保每个提示都建立在前一个提示之上,并以将事物连接在一起结束。不应该有悬而未决或孤立的代码,它没有集成到前一个步骤中。
确保并分隔每个提示部分。使用 markdown。每个提示应该使用代码标签标记为文本。目标是输出提示,但上下文等也很重要。
它应该输出一个你可以用 aider、cursor 等执行的提示计划。我喜欢将其保存为 prompt_plan.md
在仓库中。
然后,它会输出一个可以作为清单的 todo.md
。
你能制作一个我可以用作清单的 `todo.md` 吗?要详尽。
你可以将其保存为仓库中的 todo.md
。
你的代码生成工具应该能够在处理时勾选 todo.md
。这对于跨会话保持状态很有帮助。
太好了。计划!
现在你有了一个健壮的计划和文档,这将帮助你执行和构建你的项目。
整个过程可能需要 15 分钟。这是相当快的。真是太疯狂了。
第 3 步:执行
有很多可用的执行选项。成功真的取决于第 2 步进行得如何。
我已经在 github 工作区、aider、cursor、claude engineer、sweep.dev、chatgpt、claude.ai 等工具上使用了这个工作流程。它与我尝试的所有工具都相当好用,我想它会与任何代码生成工具都很好地工作。
我个人更喜欢使用 原生 的 Claude 和 Aider:
Claude
我基本上是与 claude.ai 进行配对编程,逐个迭代地输入提示。我发现这样做效果相当不错。虽然来回操作有些烦人,但大体上是可行的。
我负责初始的样板代码,以及确保工具设置正确。这在开始时提供了一定的自由、选择和指导。Claude 有倾向于只输出 React 代码 – 拥有对你选择的语言、风格和工具的坚实基础将会非常有帮助。
然后,我会使用像 repomix 这样的工具在遇到困难时进行迭代(稍后会详细介绍)。
工作流程如下:
- 设置仓库(样板代码,uv init,cargo init 等)
- 将提示粘贴到 Claude 中
- 将代码从 claude.ai 复制并粘贴到 IDE 中
- 运行代码,运行测试等
- …
- 如果成功,继续下一个提示
- 如果不成功,使用 repomix 将代码库传递给 Claude 进行调试
- 重复操作 ✩₊˚.⋆☾⋆⁺₊✧
Aider
使用 Aider 既有趣又怪异。我发现它很好地融入了第二步的输出。我可以用很少的工作量走得很远。
工作流程基本上与上述相同,但不是将提示粘贴到 Claude,我是将提示粘贴到 Aider 中。
然后 Aider 会“直接处理”,我就可以玩 cookie clicker 了。
旁注:Aider 在他们的 LLM 排行榜 中对新模型进行基准测试做得非常好。我发现这是一个查看新模型有效性的非常好的资源。
使用 Aider 进行测试很方便,因为它可以更加自动化,Aider 会运行测试套件并为你调试问题。
工作流程如下:
- 设置仓库(样板代码,uv init,cargo init 等)
- 启动 Aider
- 将提示粘贴到 Aider 中
- 观看 Aider 跳舞 ♪┏(・o・)┛♪
- Aider 将运行测试,或者你可以运行应用程序进行验证
- 如果成功,继续下一个提示
- 如果不起作用,与助手进行问答以修复
- 清洗重复 ✩₊˚.⋆☾⋆⁺₊✧
结果
我使用这个工作流构建了许多东西:脚本、expo 应用、rust 命令行工具等。它跨编程语言和上下文都有效。我确实喜欢它。
如果你有一个小型或大型项目正在拖延,我会推荐你尝试一下。你会惊讶于在短时间内你能取得多远的进展。
我的黑客待办列表是空的,因为我构建了一切。我一边看电影一边不断想出新东西并完成它们。多年来我第一次花时间学习新的编程语言和工具。这在推动我扩展我的编程视野。
非绿地:迭代,逐步
有时你没有绿地,而是需要在一个已建立的代码库上进行迭代或增量工作。
这不是一片绿地。我祖父相机里的一张随机照片 – 60 年代的乌干达某处
对此我有一个略有不同的方法。它类似于上面,但是“计划基础”稍微少一些。计划是按任务进行的,而不是针对整个项目。
获取上下文
我认为每个深陷 AI 开发的人都有一个不同的工具来做这件事,但你需要某样东西来抓取你的源代码并高效地将其输入到 LLM 中。
我目前使用一个叫做 repomix 的工具。我在我的全局 ~/.config/mise/config.toml
中定义了一个任务集合,允许我对我的代码库做各种事情(mise 规则)。
这是 LLM 任务列表:
LLM:clean_bundles 使用 repomix 生成 LLM 包输出文件
LLM:copy_buffer_bundle 将生成的 LLM 包从 output.txt 复制到系统剪贴板以供外部使用
LLM:generate_code_review 使用 LLM 生成从存储在 output.txt 中的仓库内容生成代码审查输出
LLM:generate_github_issues 使用 LLM 生成从存储在 output.txt 中的仓库内容生成 GitHub 问题
LLM:generate_issue_prompts 使用 LLM 生成从存储在 output.txt 中的仓库内容生成问题提示
LLM:generate_missing_tests 使用 LLM 生成从存储在 output.txt 中的仓库内容生成缺失的测试
LLM:generate_readme 使用 LLM 生成从存储在 output.txt 中的仓库内容生成 README.md
我会生成一个 output.txt
文件,它包含了我的代码库中的上下文。如果我正在快速消耗令牌,并且文件太大 – 我会编辑生成命令,忽略与这个任务不相关的代码库部分。
关于
mise
真正好的一点是,任务可以在工作目录的.mise.toml
中重新定义和重载。我可以使用不同的工具来转储 / 打包代码,只要它生成了一个output.txt
,我就可以使用我的 LLM 任务。当各种代码库差异很大时,这很有帮助。我经常重写repomix
步骤,以包含更广泛的忽略模式,或者只是使用一个更有效的工具来进行打包。
一旦生成了 output.txt,我就将它传递给 LLM 命令来进行各种转换,然后将这些保存为 markdown 文件。
最终,mise 任务正在运行这个:cat output.txt | LLM -t readme-gen > README.md
或 cat output.txt | LLM -m claude-3.5-sonnet -t code-review-gen > code-review.md
。这并不复杂。LLM
命令正在做繁重的工作(支持不同的模型,保存键,并使用提示模板)。
例如,如果我需要快速审查和修复测试覆盖率,我会做以下操作:
Claude
- 前往代码所在的目录
- 运行
mise run LLM:generate_missing_tests
- 查看生成的 markdown 文件(
issue-prompts.md
) - 获取代码的完整上下文:
mise run LLM:copy_buffer_bundle
- 将其粘贴到 claude 中,连同第一个缺失的测试 “问题”
- 将从 claude 生成的代码复制到我的 ide 中。
- …
- 运行测试
- 清洗重复 ✩₊˚.⋆☾⋆⁺₊✧
Aider
- 前往代码所在的目录
- 运行 aider(始终确保你在 aider 工作的新分支上)
- 运行
mise run LLM:generate_missing_tests
- 查看生成的 markdown 文件(
issue-prompts.md
) - 将第一个缺失的测试 “问题” 粘贴到 aider 中
- 观看 aider 跳舞 ♪┏(・o・)┛♪
- …
- 运行测试
- 清洗重复 ✩₊˚.⋆☾⋆⁺₊✧
这是逐步改进代码库的一个非常好的方式。在大型代码库中做少量工作时,这非常有帮助。我发现我可以用这种方法完成任何大小的任务。
提示魔法
这些快速技巧非常适合深入挖掘我们可以使项目更加健壮的地方。它非常快速且有效。
以下是我用来深入已有代码库的一些提示:
代码审查
你是一名高级开发者。你的工作是对这段代码进行彻底的代码审查。你应该撰写并输出 markdown 格式。包括行号和上下文信息。你的代码审查将会传递给另一名团队成员,所以要彻底。在写代码审查之前深思熟虑。审查每一个部分,不要臆想。
GitHub 问题生成
(我需要自动化实际的问题发布!)
你是一名高级开发者。你的工作是审查这段代码,并写出你看到的代码的主要问题。可能是 bug、设计选择或代码清洁度问题。你应该具体,并且非常优秀。不要臆想。静静地思考,然后行动 - 写下问题。这些问题将会交给一名开发者执行,所以它们应该与 github 问题兼容的格式。
缺失的测试
你是一名高级开发者。你的工作是审查这段代码,并写出缺失的测试用例列表,以及应该存在的代码测试。你应该具体,并且非常优秀。不要臆想。静静地思考,然后行动 - 写下问题。这些问题将会交给一名开发者执行,所以它们应该与 github 问题兼容的格式。
这些提示相当于 旧的和破损的(如果我可以这么说的话,就是“boomer 提示”)。它们需要一些重构。如果你有使它们变得更好的想法,请告诉我。
滑雪 ᨒ↟ 𖠰ᨒ↟ 𖠰
当我向人们描述这个过程时,我会说“你必须积极地跟踪正在发生的事情,因为你很容易超前于自己。”
不知为何,当谈论 LLMs 时,我经常说“超出我的滑雪范围”。我不知道为什么。这对我来说很有共鸣。也许是因为它是美丽的平滑粉雪滑雪,然后突然你会像“到底发生了什么!”一样,完全迷失方向,突然从悬崖上掉下来。
我发现使用规划步骤(类似于上述的 Greenfield 过程)可以帮助保持事情的控制。至少你会有一个文档可以对照检查。我也确实相信测试是有帮助的 – 尤其是如果你在进行风格狂野的辅助编码。帮助保持事物良好且紧凑。
无论如何,我仍然发现自己经常超出我的技能范围。有时候,快速休息或短暂散步会有所帮助。在这方面,这是一个正常的问题解决过程,但速度加快到了极致。
我们经常会要求 LLM 在我们并不非常荒谬的代码中包含荒谬的东西。例如,我们要求它创建一个传说文件,然后在用户界面中引用这个传说。这是针对 python cli 工具的。突然之间有了传说,界面出现故障等等。所有这些都是为了管理你的云函数、你的待办事项列表或其他任何东西。天空是极限。
我如此孤独 (。•́︿•̀。)
我对这些工作流的主要抱怨是,它在很大程度上是一项单独的努力 – 也就是说,界面都是_单人模式_。
我花了多年时间独自编码,多年时间作为一对进行编码,以及多年时间在团队中编码。和人在一起总是更好的。这些工作流不容易作为一个团队使用。机器人相互冲突,合并是可怕的,上下文复杂。
我真的希望有人能以一种使得与 LLM 一起编码成为多人游戏的方式解决这个问题。不是单打独斗的黑客体验。有很多机会来解决这个问题并使其变得惊人。
开始工作吧!
ⴵ 时间 ⴵ
所有这些代码生成加速了我作为一个人能够生成的代码量。然而,有一个奇怪的副作用。我发现自己有大量的“空闲时间”,在等待 LLM 完成它的令牌燃烧时。
我记得这就像是昨天发生的事
我已经改变了我的工作方式,足以开始融入一些实践,这将尝试消耗等待时间:
- 我开始了另一个项目的“头脑风暴”过程
- 我听唱片
- 我玩 cookie clicker
- 我和朋友还有机器人聊天
能够这样 hack 真是太棒了。Hack Hack Hack。我想不出还有什么时候我在编码上如此高产。
Haterade ╭∩╮( •̀_•́ )╭∩╮
我的很多朋友都像是“去他的 LLMs。它们在所有事情上都很糟糕。”我不介意这种观点。我不同意,但我认为保持怀疑是重要的。有很多理由去讨厌 AI。我主要担心的是能源消耗和环境影响。但是……代码必须流动。对吧……叹气。
如果你愿意了解更多,但不想深入成为一个赛博程序员 – 我的建议不是改变你的观点,而是去读 Ethan Mollick 关于 LLMs 以及它们如何被使用的书:共智:与 AI 生活和工作。
它很好地解释了好处,而不是成为一个技术无政府资本主义兄弟类型的读物。我发现它非常有帮助,并且和读过它的朋友们进行了很多好的、细腻的对话。强烈推荐。
如果你持怀疑态度,但又有点好奇 – 随时找我,让我们一起讨论这一切疯狂。我可以向你展示我们如何使用 LLMs,也许我们可以一起构建一些东西。