程序员详细分享 LLM 辅助代码生成的完整工作流,涵盖 prompt 设计与集成策略的实践经验。
简述:先做规格头脑风暴,再制定计划,然后用 LLM 代码生成执行。离散循环。然后魔法降临。✩₊˚.⋆☾⋆⁺₊✧
我一直在用 LLM 构建很多小产品。这很有趣,也很有用。但是里面有很多陷阱会浪费大量时间。前段时间一个朋友问我是怎么用 LLM 写软件的。我想「天哪,你有多少时间啊」,所以就有了这篇文章。
(p.s. 如果你是 AI 仇恨者 - 直接滚到文末)
我和很多开发朋友讨论过这个话题,我们都有类似的方法,只是细节上各有微调。
下面是我的工作流。它基于我自己的实践、与朋友的讨论(感谢 Nikete、Kanno、Obra、Kris 和 Erik),以及从互联网各个糟糕的地方学到的最佳实践。
这个方法现在运作得很好,但两周后可能就不适用了,或者会有两倍的效果。¯_(ツ)_/¯
开发有很多种路径,但对我来说通常是以下两种之一:
我会给你展示两种路径各自的流程。
我发现以下流程对新项目开发很有效。它提供了稳健的规划和文档化方法,让你可以轻松分步执行。
使用对话型 LLM 来完善想法(我用 ChatGPT 4o / o3):
请逐个问我问题,这样我们可以为这个想法开发一个彻底的、循序渐进的规格说明。每个问题都应该建立在我之前的答案基础之上,我们的最终目标是有一份详细的规格说明,我可以把它交给开发者。我们要反复迭代,深入探讨每个相关细节。记住,一次只问一个问题。
这是我的想法:
<IDEA>
头脑风暴结束时(它会自然地结束):
既然我们已经完成了头脑风暴过程,你能把我们的发现汇编成一份全面的、可交付给开发者的规格说明吗?包括所有相关的需求、架构选择、数据处理细节、错误处理策略和测试计划,这样开发者可以立即开始实现。
这会输出一份相当扎实直接的规格说明,可以交接给规划步骤。我喜欢把它保存为仓库中的 spec.md。
你可以用这份规格做很多事情。我们这里是做代码生成,但我也用过它来通过让推理模型来戳穿想法的漏洞来强化想法(必须深入!),生成白皮书,或生成商业模式。你也可以把它丢给深度研究,换回一份 1 万字的支持文档。
把规格说明交给一个适当的推理模型(o1*、o3*、r1):
(这是 TDD 提示词)
为这个项目的构建草拟一份详细的、循序渐进的蓝图。然后,一旦你有了扎实的计划,把它分解成相互建立的小的、迭代的块。看看这些块,然后再进行一轮分解成更小的步骤。检查结果并确保这些步骤足够小,可以通过强大的测试安全地实现,但又足够大来推进项目。反复迭代,直到你觉得这些步骤的粒度对这个项目是合适的。
从这里开始,你应该有基础来提供一系列提示词给代码生成 LLM,它将以测试驱动的方式实现每个步骤。优先考虑最佳实践、增量进度和早期测试,确保在任何阶段都没有复杂性的大跳跃。确保每个提示词建立在前一个提示词的基础之上,并以连接各部分结束。不应该有任何未集成到前一步骤中的悬空或孤立的代码。
确保分离每个提示词部分。使用 markdown。每个提示词应该用代码标签标记为文本。目标是输出提示词,但上下文等也很重要。
<SPEC>
(这是非 TDD 提示词)
为这个项目的构建草拟一份详细的、循序渐进的蓝图。然后,一旦你有了扎实的计划,把它分解成相互建立的小的、迭代的块。看看这些块,然后再进行一轮分解成更小的步骤。检查结果并确保这些步骤足够小可以安全地实现,但又足够大来推进项目。反复迭代,直到你觉得这些步骤的粒度对这个项目是合适的。
从这里开始,你应该有基础来提供一系列提示词给代码生成 LLM,它将实现每个步骤。优先考虑最佳实践和增量进度,确保在任何阶段都没有复杂性的大跳跃。确保每个提示词建立在前一个提示词的基础之上,并以连接各部分结束。不应该有任何未集成到前一步骤中的悬空或孤立的代码。
确保分离每个提示词部分。使用 markdown。每个提示词应该用代码标签标记为文本。目标是输出提示词,但上下文等也很重要。
<SPEC>
它应该输出一份提示词计划,你可以用 aider、Cursor 等来执行。我喜欢把它保存为仓库中的 prompt_plan.md。
然后我让它输出一份 todo.md,可以勾选完成。
你能生成一份 `todo.md`,我可以用它作为检查清单吗?要全面。
你可以把它保存为仓库中的 todo.md。
你的代码生成工具应该能在处理时勾选 todo.md。这有助于在不同会话间保持状态。
现在你有了一份稳健的计划和文档,可以帮助你执行和构建项目。
整个过程可能只需要 15 分钟。非常快。说实话有点疯狂。
有很多选项可用于执行。成功真的取决于第 2 步进行得有多好。
我用这个工作流试过 GitHub Copilot Workspace、aider、Cursor、Claude Engineer、Sweep.dev、ChatGPT、Claude.ai 等。它在我试过的所有工具上都运作得相当好,我想它也会与任何代码生成工具配合得很好。
不过,我比较偏好原始的 Claude 和 aider:
我基本上是和 Claude.ai 结对编程,逐个地粘贴每个提示词。我发现这样效果很好。来回反复有时候烦人,但总体上运作得不错。
我负责初始的样板代码和确保工具配置正确。这允许了一些自由度、选择和初期指导。Claude 倾向于只输出 React 代码 - 拥有一份用你选择的语言、风格和工具的扎实基础会很有帮助。
然后当事情卡住时我会用 repomix 这样的工具来迭代(后面会讲更多)。
工作流是这样的:
设置仓库(样板代码、uv init、cargo init 等)
粘贴提示词到 Claude
从 Claude.ai 复制代码到 IDE
运行代码、运行测试等
如果可行,继续下个提示词
如果不行,用 repomix 把代码库传给 Claude 来调试
重复 ✩₊˚.⋆☾⋆⁺₊✧
Aider 用起来很有趣也很奇怪。我发现它很好地契合了第 2 步的输出。用很少的工作量我就能走很远。
工作流本质上和上面一样,只不过不是粘贴到 Claude,而是粘贴提示词到 aider。
然后 Aider 就会「直接做」,我可以去玩点击器游戏。
额外说明:Aider 在他们的 LLM 排行榜上做了真正出色的新模型代码生成基准测试。我发现这是一份很好的资源,可以看到新模型在代码生成方面的有效性。
用 Aider 测试很不错,因为它可以甚至更自动化 - aider 会运行测试套件并为你调试。
工作流是这样的:
设置仓库(样板代码、uv init、cargo init 等)
粘贴提示词到 aider
看 aider 舞动 ♪┏(・o・)┛♪
aider 会运行测试,或你可以运行应用来验证
如果可行,继续下个提示词
如果不行,与 aider 问答来修复
重复 ✩₊˚.⋆☾⋆⁺₊✧
我用这个工作流构建了这么多东西:脚本、Expo 应用、Rust CLI 工具等。它在各种编程语言和环境中都适用。我很喜欢它。
如果你有一个正在拖延的小项目或大项目,我会推荐你试一下。你会惊讶于在短时间内你能走多远。
我的待办清单现在是空的,因为我把所有东西都构建了。我一直在想新的东西,一边看电影一边把它们敲出来。多年来我第一次有时间去接触新的编程语言和工具。这推动了我拓展我的编程视角。
有时你没有新项目,而是需要在已建立的代码库上进行迭代或增量工作。
对此我有一个稍微不同的方法。它与上面的类似,但「规划驱动」的程度略低。规划是按任务进行的,而不是针对整个项目。
我认为任何深入参与 AI 开发的人都有不同的工具来做这件事,但你需要一些东西来抓住你的源代码并有效地塞进 LLM。
我现在用一个叫 repomix 的工具。我在我的全局 ~/.config/mise/config.toml 中定义了一个任务集合,允许我用我的代码库做各种事情(mise 规则)。
这是 LLM 任务列表:
LLM:clean_bundles 使用 repomix 生成 LLM bundle 输出文件
LLM:copy_buffer_bundle 将生成的 LLM bundle 从 output.txt 复制到系统剪贴板供外部使用
LLM:generate_code_review 从存储在 output.txt 中的代码库内容生成代码审查输出
LLM:generate_github_issues 从存储在 output.txt 中的代码库内容生成 GitHub issues
LLM:generate_issue_prompts 从存储在 output.txt 中的代码库内容生成 issue 提示词
LLM:generate_missing_tests 为存储在 output.txt 中的代码库内容生成缺失的测试
LLM:generate_readme 从存储在 output.txt 中的代码库内容生成 README.md
我生成一个包含代码库上下文的 output.txt。如果我的 token 用量激增,文件过大,我会编辑生成命令,忽略与当前任务无关的代码库部分。
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 命令做了大部分工作(支持不同模型、保存密钥和使用提示词模板)。
例如,如果我需要快速审查和修复测试覆盖率,我会做以下步骤:
进入代码所在的目录
运行 mise run LLM:generate_missing_tests
查看生成的 markdown 文件(missing-tests.md)
获取代码的完整上下文:mise run LLM:copy_buffer_bundle
将其粘贴到 Claude 中,同时提供第一个缺失的测试"问题"
从 Claude 复制生成的代码到我的 IDE
重复上述过程 ✩₊˚.⋆☾⋆⁺₊✧
进入代码所在的目录
运行 aider(务必在新分支上进行 aider 工作)
运行 mise run LLM:generate_missing_tests
查看生成的 markdown 文件(missing-tests.md)
将第一个缺失的测试"问题"粘贴到 aider
看 aider 发挥作用 ♪┏(・o・)┛♪
重复上述过程 ✩₊˚.⋆☾⋆⁺₊✧
这是逐步改进代码库的好方法。对于在大型代码库中完成少量工作非常有帮助。我发现使用这种方法可以处理任何规模的任务。
这些快速技巧对于探索能让项目更健壮的地方非常有效。它既快速又高效。
以下是我用来深入了解已有代码库的一些提示词:
You are a senior developer. Your job is to do a thorough code review of this code. You should write it up and output markdown. Include line numbers, and contextual info. Your code review will be passed to another teammate, so be thorough. Think deeply before writing the code review. Review every part, and don't hallucinate.
(我需要自动化实际的 issue 发布!)
You are a senior developer. Your job is to review this code, and write out the top issues that you see with the code. It could be bugs, design choices, or code cleanliness issues. You should be specific, and be very good. Do Not Hallucinate. Think quietly to yourself, then act - write the issues. The issues will be given to a developer to executed on, so they should be in a format that is compatible with github issues
You are a senior developer. Your job is to review this code, and write out a list of missing test cases, and code tests that should exist. You should be specific, and be very good. Do Not Hallucinate. Think quietly to yourself, then act - write the issues. The issues will be given to a developer to executed on, so they should be in a format that is compatible with github issues
这些提示词相当老旧("老一代的提示词"吧)。它们需要重构。如果你有任何改进的想法,告诉我吧。
当我向人们描述这个过程时,我会说"你必须积极跟踪正在发生的事情,因为很容易超前"。
说到 LLM 时,我经常说"过度自信",不知道为什么。这种感受很能引起我的共鸣。也许是因为它就像在光滑的粉雪上滑雪,然后突然你会想"搞什么呢!",完全迷茫,突然从悬崖上摔下来。
我发现使用规划步骤(像上面描述的 Greenfield 流程)可以帮助控制局面。至少你会有一份文件可以用来核对。我也相信测试是有帮助的,特别是如果你在进行疯狂的 aider 编码。有助于保持代码的良好和紧凑。
不管怎样,我还是经常发现自己过度自信。有时候一个短暂的休息或散步会有帮助。在这方面,这是一个正常的问题解决过程,只是加快到了极快的速度。
我们经常会让 LLM 在代码中包含一些荒唐的东西。例如,我们让它创建一个 lore 文件,然后在用户界面中引用这个 lore。这是针对 Python CLI 工具的。突然间就有了 lore、故障界面等等。所有这些都是为了管理你的云函数、待办事项列表或其他什么。天空才是极限。
我感到很孤独 (。•́︿•̀。)
我对这些工作流的主要抱怨是它在很大程度上是一个单人活动,也就是说界面都是单人模式。
我花了多年独自编码,花了多年作为一对编程,花了多年在团队中编程。和人一起总是更好。这些工作流不容易作为团队使用。机器人会碰撞,合并会很恐怖,上下文会变得复杂。
我真的想要有人能够以某种方式解决这个问题,让使用 LLM 编码成为一个多人游戏。而不是一个单独的黑客体验。有很多机会来解决这个问题,并让它变得了不起。
所有这些代码生成加快了我作为一个人能够生成的代码量。但是,有一个奇怪的副作用。当等待 LLM 完成其 token 消耗时,我发现自己有大量的"停机时间"。
我改变了足够多的工作方式,开始融入一些实践来尝试利用等待时间:
我为另一个项目启动了"头脑风暴"过程
我玩 Cookie Clicker
我与朋友和机器人交谈
能够像这样黑客编程是很棒的。Hack hack hack。我想不出另一个我在代码中这么有生产力的时刻。
仇恨 ╭∩╮( •̀_•́ )╭∩╮
我的很多朋友都说"LLM 太糟糕了。它们在任何事情上都很糟糕。"我不介意这个观点。我不同意,但我认为持怀疑态度是重要的。有很多理由去讨厌 AI。我最大的担忧是关于电力消耗和环境影响。但是……代码必须流动。对吧……叹气。
如果你愿意了解更多,但不想深入钻研并成为一个改造人程序员,我的建议不是改变你的观点,而是阅读 Ethan Mollick 关于 LLM 及其使用方法的书:《Co-Intelligence: Living and Working with AI》。
这本书很好地解释了好处,而不是一本技术无政府资本主义兄弟式的书。我发现它非常有帮助,与很多阅读过它的朋友进行了很多很好的、细致的对话。强烈推荐。
如果你很怀疑但有点好奇,可以随时联系我,我们来讨论这所有的疯狂。我可以展示我们如何使用 LLM,也许我们可以一起构建什么东西。
感谢 Derek、Kanno、Obra 和 Erik 查看了这篇文章并提出建议。我很感激。