AI 辅助等级的定义
首先介绍一下这里提到的 L3 是个什么东西。我们根据一个任务 AI 能够介入的程度,将编码任务分为 4 类:
- L0: 不使用 AI
- L1: AI 辅助编程 (续写)
- L2: 人类拆分需求后,将任务交给 AI(agent)完成
- L3: 全栈需求交付:(AI 辅助设计需求) + 前端 + (AI 辅助后端)
我们在 20 年之前应该就是处于 L0 的阶段,当时仅有个别几个 AI 辅助编程工具(比如 tabnine),效果比 LSP 补全强不了多少,而且不是很流行。
在 22 年出现 ChatGPT 之后,我们进入了 L0 到 L1 过渡的阶段,AI 写代码的能力虽然还是不行,但是已经可以帮我们快速生成一些简单页面了,这时候我们都是在网页让 AI 生成内容,然后复制出来使用的;
再到 23 年 cursor 出现,我们半只脚进入 L1 阶段,并在 24 年正式跨入 L1!我是 24 年 9 月第一次使用 cursor,当时他的 tab 让还在手动复制粘贴的我啧啧称奇
到了 25 年,agent 这种形式开始流行,相比纯 chat 对话,这种形式能更积极的与外部环境进行交互,自动获取解决问题所需要的信息,这就到了 L2 的阶段
而现在,我们看到一种趋势,跨角色需求交付逐渐成为常态,为此需要新的研发模式和实践,我这里根据以前开发的经验斗胆总结了一些
优势区间
需求明确的项目
L3 级别开发的特点是全栈,因此明确项目需求,并合理进行拆分模块很重要。需求明确后,我们可以同时对几个模块进行修改(并且是在一个工作空间内),同时不会有修改竞争的问题出现,因为任务从分配的时候就已经确保各自 agent 的关注点不同了
具有良好的可模仿的示例代码
对于类似的需求,我们可以合到一组会话中开发,这样能让整个开发流程加快很多倍。因为我们无需重新设计页面,只需要将这部分代码复制一份,然后在其上进行样式或者是功能的修改。还有就是针对项目中原来不存在的功能,我们可以在本地写一些小 demo 来验证可行性,然后最终让模型参考这部分 demo 代码来填补对应的功能。
之所以让模型去模仿已有例子去写代码,主要是出于两点考虑:
- 模型擅长模仿而不擅长创新:我们写的 demo,以及原项目留下的代码,就类似于一个大号的 skill,可以让模型参考。
- 将大任务拆解为小任务:能够有效降低开发时的验证成本,模型最终只负责集成的任务
已知问题
代码质量恶化
在进行 L3 级别的开发时,我们交付速度是以往的几倍,但是与此同时我们 review 和测试的能力没有变化,导致只通过了 happy path 就认为交付通过,一旦 agent 做出短期奏效但长期脆弱的决策,其后果就会在后续迭代中累积放大,而这最终会花费我们一定的时间去进行修复。
这个问题非常普遍,几乎只要使用 AI coding 都会遇到这个问题,我感觉这对工程师能力提出了更多的要求,除了要能够理解业务上的知识外,还要能够及时有效的去 review 模型产生的代码,除此之外,可能也可以通过一些 coding agent 的使用技巧来减缓这个事情的发生
- 首先是 multi agent 的介入,在编码后,我们可以视情况启动多个 code review 或者 simplify 的 agent,帮助我们事先过滤一遍代码,我们负责花费更多时间在理清项目已有逻辑,清理遗漏的部分
- 然后是维护一个良好的测试集,这里的测试除了单元测试外,还要更多的注重 e2e 测试还有一些回归问题
- 通过 harness 工程尽可能延缓代码质量恶化的问题,这是一个需要持续建设的工程,除了使用 superpowers 等流程辅助工具,还要求工程师对代码库的设计有自己的思考
界面样式难以把控
随着模型能力的增长,我们可以看到模型写出来页面是越来越精致了(比如各种天气卡片或者登录页)。但在我做项目的时候,感觉有一些局促:
单个页面上,模型在局部的设计上做得很好,组件细节能看得下去。但在整体的 layout 方面,可能因为缺乏视觉反馈,或者对 CSS 数值的不敏感,导致整体样式比较别扭。
同时,由于项目不是一蹴而就的,如果拓展到了多个页面,多轮对话中 agent 对整体设计风格的把握程度不同,导致不同页面的风格出现偏移。
针对这个问题,我有两个想法:
- 如果开发先于设计,我们可以使用现成的组件库,而非让模型自己去手写页面。美学设计这部分就拜托专业的设计师,我们只负责布局方面,同时搭配一些已有的 skill,比方说 Vercel 或者布局方面专用的知识
- 如果设计先于开发,可以使用 f2c 等专用的智能体来完成这个任务
技术向的思考
模型友好的日志
我们完成一个编码任务经常是一套循环,编码 -> 测试 -> 发现问题 -> 编码修正……,这个过程发现问题和编码修正应该可以交给模型去做,为此日志需要有类似 tee 的机制,既要重定向到终端,也要分流持久化到一个专门的文件中,不要让我们手动复制,充当 agent 和项目之间的胶水。
后端比较好搞这方面,毕竟日志就在那,前端可能需要通过发送埋点日志或者通过什么其他方案联通后端,将日志放到同一个位置,尽量避免开发时日志散落各处,这点 react router 的设计就蛮有意思的
快速迭代友好的设计
这部分无论是对 agent 还是人类都很有用,主要涉及两点:
- 使用一些比较新的工具链。避免花费太多时间在编译等操作上,最好能够即时反馈
- 对项目中耗时较多的模块进行拆分 Mock 处理,每个任务以及之后的测试流程只关注其中一个模块,将其他不相关的内容屏蔽起来
并行与多 agent 开发
多 agent 开发大致可以分为两种,一种是针对一个任务启动多个任务,一种是针对不同任务,每个任务一个 agent,无论是哪种,在一个仓库同时开发时,都有可能发生并发写入同一个文件的问题,因为各个 agent 之间是没有交流以及锁机制的,在 agent 设计没有专门解决这个问题之前,我们可以使用 worktree 来勉强解决,但同时也有很多痛点:
- worktree 创建和管理比较麻烦:除了执行命令创建 worktree,还要管理该分支下的代码产物,如果没有专用的管理界面,做起来还是比较费心思的
- 空间占用:这点在前端和 rust 开发尤为明显,他们依赖以及构建产物通常都是 GB 级别,多开几个 worktree 磁盘就受不了了。目前有包管理器针对这个问题做出了改进,详情可见 https://pnpm.io/11.x/git-worktrees