如何让AI编程助手做更多工作?

527 阅读10分钟

AI 编码助手 2022 年 6 月上线,2023年走进了大家的日常工作中。在一年多的使用时间里,大家最经常用的功能有哪些?

就我个人而言,用得更多的是代码补全功能和代码解释功能、问答助手功能。至于通过写注释来获取编码,真的用的很少。一来常见的代码已经封装到公共库里,二来复杂的业务代码成功率并不高。

现在市面上,都在吹AI能自己写完整个项目,然而那水平也就约等于会写 Demo 的程序员吧。2024 年华为开发者大会中,给出了类似于 AI 自动驾驶的 AI Agent(智能体)的五个级别。要能完整写完项目,起码都是 L3 以上。

Screenshot_20240702_132509_tv.danmaku.bili.jpg

最近百度的无人驾驶出租车萝卜快跑在武汉落地了,据说是 L4 级别的。百度从 2017 年的All in AI,到 2024 年,足足用了 6 年。AI 编码目前应该在 L1 和 L2 级别之间,如果要到 L 4 是否也需要相同的时间才能获到相同的成就?

我觉得是要的,理由有几点:

  1. AI 驾驶需要更多的是图片处理能力,线路规划等推理能力是较弱的;然而 AI 编码需要更多的是推理能力,特别是后端的业务逻辑部分。
  2. AI 驾驶代替的是一个人的工作;AI 编码要产生成品,至少是 3 - 5 个人的工作,前端、后端、设计、产品和测试,其复杂程度剔除人员的沟通之外,仍然是高于 AI 驾驶的。
  3. 现在一个系统至少能达到 99% 以上的稳定性才能上线长期运行的,然而现在 AI 估计 80% 都没有。AI 从推理模型理解语义 90% 的准确率到大语言模型涌现到 99%,也至少用了 5 年。
  4. AI 智能体对算力的要求太高,目前大部分公司无法私有化部署,需要时间把这些成本降下来

既然AI智能体短时间内无法达到理想的状态,那在接下来的时间里,AI 辅助编码仍将是主流,脏活累活还是交到我们一线的代码仔手中,我们能做哪些事情,让AI帮我们做更多呢?

现在 AI 编码有以下两点基本的特点:

  1. AI 也需要读懂你的代码
  2. AI 基于项目的全局记忆能力、全局推理能力需要耗费大量的计算资源,短时间内无法解决。

基于这两点给出以下判断:

命名规范更重要了

“代码是写给人看的,顺便给机器运行”,这个话要更新了。你的代码除了被人阅读,现在还多了一个对象——AI。

我们来看两段代码,一段是从老旧代码库里来的,命名比较随意;一段是修改后的代码,让AI分别对其解读及添加注释。

修改前

function addNew() {
  const menu = getFunc();
  if (menu == null) {
    return false;
  }
​
  const dataId = newGuid();
  const dataUrl = menu.path + menu.module + 'Form.html';
  const tabName = menu.name + '-新增';
  openBtnTab(dataId, dataUrl, tabName);
}

AI对其的解释是:

这段 JavaScript 代码定义了一个名为 addNew 的函数,该函数的目的是根据某种菜单配置来打开一个带有特定名称和 URL 的新标签页(可能是在一个标签页管理系统或类似的界面中)。下面是对这段代码的逐行解释:

...

总结:这段代码定义了一个函数,该函数旨在根据从某个地方(可能是外部定义的 getFunc 函数)获取的菜单配置来打开一个具有特定名称和 URL 的新标签页。这个新标签页可能是用于添加或编辑某种数据的表单。不过,为了完全理解这段代码的目的和行为,你可能还需要查看 getFuncnewGuidopenBtnTab 这三个函数的定义和实现

加注释的话是这样的:

/**
 * 添加新内容
 *
 * @returns 如果添加失败则返回false,否则无返回值
 */

很显然,这里的解释和注释都是比较含糊的。

修改后

我们把 addNewgetFunc 改成了 addNewTabgetMenuInfo

function addNewTab() {
  const menu = getMenuInfo();
  ...;
  openBtnTab(dataId, dataUrl, tabName);
}

AI 对这段代码的解释是:

这段JavaScript代码定义了一个名为addNewTab的函数,该函数主要用于在某种界面(可能是网页或应用程序)上添加一个新的选项卡(tab)。下面是对这段代码的详细解释:

...

总结:这个addNewTab函数的主要目的是在界面上打开一个新的选项卡,该选项卡可能与某个菜单项相关,并用于添加新的项目或数据。它依赖于其他几个函数(如getMenuInfonewGuidopenBtnTab)来完成其任务,但这些函数在给出的代码段中没有定义。

加注释的话是这样的:

/**
 * 添加新标签页
 *
 * @returns 如果添加成功返回true,否则返回false
 */

这一段,AI 给出了更简短并更准确的回复。

可见,AI 并不比人聪明多少,他只能减少你读代码的时间,如果代码本身含糊不清,AI 也只能靠猜,回答会带上很多不确定的词。

所以给予更明确的命名还是很有必要的。如果AI猜中了其中意思,也建议及时改名字。

更多地使用公共库

由于 AI 全局推理能力的缺失,所以我们用自己在项目中写的库,并不一定能得到很好的代码片段。除非在你的项目当前文件中出现多次,才有可能被很好的推理出来。

但是使用公共库,AI 学习的知识库本身就包含了这些库,能很方便的帮你完善代码片段。

下面的例子是使用 axios 公共库的截屏,其提示出来除了完整的参数,还有获取到数据后你可能进行的一些操作,弹窗等。

截屏2024-07-13 14.07.23.png

而自己封装之后的 request,只提示一行的参数,还不知道是否准确。

截屏2024-07-13 14.08.23.png

接受更多的冗余代码

同样的,由于 AI 无法从项目全局视角去考虑问题。想实现代码复用,也是很难的事情。

比如一个商城网站,商品的订单页面有一个地址修改弹窗,个人信息页面也有一个地址修改弹窗。两个地方会略有不同:

  1. 订单页面会提示当前用户购买的商品,个人信息仅展示列表即可。
  2. 订单页面修改地址之后需要绑定到当前商品,个人信息页面修改地址后就返回个人信息列表。

在程序员看来,只是两个 if/else 的问题,分别写在展示的时候、提交修改的时候即可。

然而,如果基于AI来开发,更建议你写成两个弹窗。

  1. 分开写之后,逻辑简单了,AI 能更好地帮你生成代码;
  2. 日后维护起来,对功能进行增改删,AI 不需要判断过多的上下文,单功能的组件也比多功能的组件更好维护。
  3. 弹窗组件命名上分开,后续 AI 能更好的理解组件的作用;
  4. 商品页组件跟商品页放在一个文件夹,后续 AI 也能更好地理解当前文件夹的结构。

逐步拆分函数给 AI 填充

在上面的 L2 级别中,AI 执行被分解的任务,那我们人类就要负责把这些分解的任务衔接起来。

在文件内的级别,人类则需要负责好高级函数的书写,并逐步拆分到更细的中低级函数,让AI 完成。

// 入口函数,人类完成
const init = async () => {
  const responseData = await getList();
  if (response.type === ORDER) {
    renderOrderPage(response.addressData, response.orderData);
  } else {
    renderInfoPage(response.addressData);
  }
};
​
// 中低级函数,人类和AI共同完成, 能让AI写则AI写
const getList = async () => {
  // 以下是某AI编码助手真实生成的,修改路径即可
  const response = await fetch('http://localhost:5001/api/address?pageIndex=1&pageSize=20');
  return response.json();
};
const renderOrderPage = async (addressData, orderData) => {
  // 以下是某AI编码助手真实生成的
  if (addressData.length > 0) {
    // 渲染地址列表
  } 
  if (orderData.length > 0) {
    // 渲染订单列表
  }
};
const renderInfoPage = async (addressData) => {
  // 以下是某AI编码助手真实生成的
  if (addressData.length > 0) {
    // 渲染地址列表
  }
};

从上面 AI 生成的代码,可以看到 AI 基本猜对了我的意图。当我敲完 getList,整个函数就完成了;当我敲 if 的时候,渲染地址列表的具体代码没出来,但是框架页基本有了。后续还可以拆出来更细的低级函数,一步步让AI 完成。

由此看来,把函数写小未来会非常有用。

架构能力更重要

要更好地分解任务,在项目方面而言,架构能力会变得更重要。

比如:

  1. 如何划分模块,模块之间的依赖关系如何,模块的颗粒度如何把握,如何保证高聚合、低耦合?
  2. 项目的全局的状态什么时候使用,如何调用,如何同步更新?
  3. 项目整体要规划哪些核心类、函数或组件?如何在各业务场景中复用?

架构做得越好,能让 AI 帮你更好更快地填充更准确的内容。架构没做好,很可能连AI都无法读懂你的项目:

把 AI 当成一个初级程序员,而你要帮他把架子搭好,让他帮你完成重复无趣的工作,另一方面也提高了你的自身的架构能力,可谓一举两得。

WechatIMG16.jpg

总结

离 AI 到智能体自主拆分任务完成任务的日子还远,我们站在前线的代码仔,应该更好地利用 AI 帮我们生成代码。站在 AI 的视角上,我们应该学会把控整体的架构设计、更好地拆分任务、甚至是拆分到函数级别的任务,然后把更多的代码交给 AI 完成。

不管 AI 智能体最后能到哪一步,对于我们打工人更重要的一直都是更准时地下班,存好钱,过更好的生活。

祝大家都有美好的未来!

另外补充一下题外话,老板们期望的一句话实现需求,是无法实现的。模糊的定义最后也只会产生模糊的产品,一句话产生的最终产出物,老板们估计是很难接受的。老板来回的提需求,最终只会消耗他更多的金钱来换取算力。(不过王小川在百川大模型中使用的多轮对答,也许能对解决这个问题有所帮助)

至于 SaaS、低代码转 AI,老板们有多喜欢自定义,这件事就有多难。

以上只是个人对近期 AI 编码方面的一些思考,纯粹个人观点不一定对,有考虑不周的地方也欢迎大家斧正。