前些日子尝试借助 Cursor(主要是 claude-sonnet-4) 写一个五子棋 Web App,想着这是一个挺成熟的项目,应该不太需要干预,直接 Vibe Coding(依靠 LLM 生成代码) 应该就能搞定。一开始挺顺利的,界面经过几轮 Prompt 后,基本符合需求,也可以下棋,但在优化五子棋智能时遇到了严重的问题。我扮演 QA 的角色,不断地下棋,然后反馈五子棋算法的错误落子,AI Code Assistant(以下简称 ACA) 收到反馈后,总是会回复:我找到问题了!我解决问题了!完美!诸如此类,我还真就信了。在尝试了大约 50 次后,我发现事情不对,它好像没有真正地解决问题,只是解决了我那次报给它的问题,而且代码也变得异常臃肿,根本没法维护。
后来我就换了一个思路,先实现一个最最基础的五子棋策略,然后询问多个 AI,把代码发给它们,让它们提供优化思路,再把这些 AI 提到的共通点收集起来,让 ACA 每次只针对其中的一点进行优化,并且让它写对应的测试。如此经过几轮迭代下来,才终于慢慢地提升了五子棋的智能,代码也有了可维护性。
本以为一天可以搞定的需求,结果花了近四天,才基本完工,这其中走了不少弯路,正好总结下自己对于 AI-Assisted Coding(AI 辅助编程,以下简称 AAC) 的思考。
先说结论,我认为:
- 只靠 AAC 是无法做出有竞争力的产品的。
- AAC 是一个 multiplier,要么事半功倍,要么事倍功半。
- 「将 AAC 的价值最大化」,是开发者的必选项。
AAC 的本质是:提供了一个以完成当前任务为最高优先级的初级程序员。这里的 trick 就在于「当前任务」,假设你有一个机器人,然后跟它说:房间太乱了,打扫干净。它可能会:
- 发现桌上的东西很多,如果全部收拾掉,并按它们的属性放到合适的位置会涉及到很大的工作量,且不一定做得好,那么它的解决方案可能是在桌上盖一层毯子,这样看着不乱了,符合「干净」的需求。
- 发现角落里有一双鞋,看起来有点旧,又不知道放哪里,那就索性扔掉,虽然这可能是你最喜欢的一双鞋。
- 一些散落的衣服本来应该挂起来,但它可能会叠起来放进抽屉里。
ACA 也一样,它没有长期目标,也没有「代码质量」、「可维护性」等内在驱动力,它只关心如何最直接地满足当前 Prompt。针对一个任务它可能会:
- 走捷径。如加
if
判断,或引入 Magic Number,看起来好像解决了问题,但其实是在堆积技术债。这个倾向在写测试时体现的淋漓尽致。如果你的 prompt 是:为本次代码改动编写测试。那么它很可能会写好几个测试,结果也都通过了,但测试本身非常敷衍。 - 新增非必要的复杂度。它会尝试在现有结构上打补丁,而不是从根本上优化或简化。这可能是因为「增加代码」是解决问题最直接的方式,而「重构」需要更深层次的理解和抽象能力。这也意味着 AI 可能引入冗余代码、重复逻辑,甚至不必要的依赖。
- 进入死胡同。就好像你给一个 prompt:让这辆车飞起来。那么它会想各种办法,对车进行改造,但每次都失败。它不知道这件事几乎不可能,也不会揣测你背后的意图,跟你讨论其他的可能性。
正是因为这些特性,ACA 的表现看起来像是初级程序员。它们缺少创造性思考和大局观,能生成「看起来合理」的代码,但逻辑正确性、架构合理性、长期可维护性需要人工把关。所以ACA 不是一个完全独立的开发者,它是一个高级工具。如果你只是提需求和报 Bug,会发现它可能会为了解决 Bug 而引入新的 Bug,或者为了实现某个功能而增加不必要的复杂度。AI 并不真正理解代码,它只是模拟理解,如果你告诉它错了,它会立刻道歉并尝试给出另一个答案,但这不代表它真的理解了错误。
但我们可以利用它「以完成当前任务为最高优先级」的这个特点,来发挥它的价值。这就需要我们的 prompt 指令清晰,目标明确,且足够小。比如「实现登录功能」,这个 prompt 太大,太模糊。把它分解成:
- 设计AuthService协议
- 实现MockAuthService
- 实现RealAuthService的网络请求
- 编写LoginViewModel处理逻辑
- 编写LoginView UI
- 编写登录成功/失败的集成测试
然后按顺序提交给 ACA,效果会好得多。这个是 Cloudflare 的工程师通过 Cluade 写的代码,可以看下他们给 Claude 的 prompt:
prompt: Please write tests for this library using vitest. The tests should use a mock or fake KV namespace for storage. Be sure to study README.md and storage-schema.md in addition to oauth-provider.ts to fully understand the functionality. Try to cover all the important logic.
Claude initially wrote a separate mock library.
prompt: Let's just put the whole test including mocks in one file.
Claude spent several minutes thinking and produced the test. It failed immediately due to `cloudflare:workers` not being available.
prompt: Looks like for this test to run under node, we need to mock out the `cloudflare:workers` module. We just need to define the `WorkerEntrypoint` class. Can you do that?
Claude did this. Yay.
Several tests are still failing, but they do run. Will debug in separate commits.
由此可见,prompt 要明确:
- 需要达成的目的
- 能够使用的工具
- 应该遵循的规范
- 需要考虑的要素
必要的话,再提供一些示例。通常需要几轮迭代才能完成一个小 feature 或修复一个 bug。每一轮 prompt,ACA 都会输出它的思考和对应的代码,不要在这个期间切换到社交媒体上刷新闻,这样不仅不容易进入 Flow 状态,也容易忽略 AI 犯的错。如果发现 ACA 无法正确地执行任务,要找到其中的原因或提供自己的思考,反馈给它,这样才能打开思路,避免进入死胡同。一个好的实践是,在把 Prompt 给 ACA 之前,自己先思考下:如果是我来做,大概会怎么实现,然后跟 ACA 的输出做对比。
有了 Prompt 的最佳实践后,接下来要做的就是如何生成这些 Prompt,这个就需要用到高阶程序员的技能了:架构设计、良好的编程习惯、定位问题和目标分解。一个好的架构是基础,它让每个模块职责清晰、数据可以顺畅流转、便于新增 Feature、便于定位 Bug。好的编程习惯可以让代码更容易维护。好的目标分解能力和定位问题能力,可以将产品经理的 Feature、QA 发现的 Bug、技术需求等转化为高质量的 Prompt,借助 ACA 的能力,得到最终想要的结果。
有了高质量的 Prompt 还不够,因为 ACA 依旧可能犯错,因此代码 Review 必不可少。值得考虑的点有:
- 是否需要写单元测试,如果是,需要覆盖哪些场景。
- 是否考虑了边界条件、错误处理、性能、可读性、可维护性。
- 是否符合代码规范。
- 是否有「代码异味」,如魔数、深层嵌套、大量 if、重复代码、命名含糊等。
所以,有了 ACA 并不意味着学习编程基础知识变得不那么重要,程序员的经验变得无足轻重,或者程序员的技能会被 AI 完全取代,恰恰相反,它需要你掌握高阶的编程技能,善于与 ACA 沟通,才能让开发效率事半功倍。
采用 AAC 后,开发范式会发生转变,开发者的角色从以「写代码」为主,慢慢转向「设计架构、分解任务、优化 Prompt、Review 代码」。越早适应这种转变,强迫自己提升对应的能力,越能取得优势。
One More Thing:精通市面上最强的 ACA(如 Cursor),结合最强的 AI 模型,可以大幅提升开发效率。