前言
分享了利用 AI 生成中后台前端代码的实践经验,讨论了 AI 生成代码的优缺点,提出了按需生成代码的方案,并展示了 AI 代码生成方案的优化。今日前端早读课文章由 @waldon 分享,公号:三七互娱技术团队授权。
正文从这开始~~
背景
部门的中后台项目使用 AI 生成中后台前端代码也有大半年的时间了,已应用到 4 个业务后台,累计 78 个页面。
AI 生成的代码中,只有对接的 api 接口文件以及 typescript 类型声明是 100% 准确的,每次生成能节省 10 几分钟的对接时间,不过生成的页面功能、组件、交互逻辑还是差强人意。本文就针对 “差强人意” 的这部分内容进行讨论:为什么会导致这样的结果?未来可以通过什么方式可以去解决?
中后台页面结构
以一个通用的中后台页面为例,大概可以分开 3 个部分,查询区域、表格区域、表单区域。
这里可以看一下实际对应的页面:
如果是这样一个最基础【增删改查】页面,那么生成出来基本上 90% 的内容都是符合我们规范且可用的代码。这样简单的页面,在不同系统的数量占比大概是 40% - 70%。
虽然中后台的页面基本都长一个样,但是不同的需求,页面逻辑还是有差异的,这部分差异,就是生成的一个复杂点。
生成了一堆无用的代码
目前生成的代码大概可以分为接口、类型声明、组件、配置文件、展示页面,结构大概如下图所示(使用 tcf 开发过项目的小伙伴应该都比较熟悉)。
重点关注一下 index.vue 这个文件,它包含了查询和删除的逻辑以及新增 / 编辑的入口。熟悉 vue3 的同学都知道,一个.vue
文件大概可以分为 3 大块,【script setup】、【template】、【style】。下图是我按查询、新增 & 编辑、删除划分的代码区域分布图。
第一版的 AI 生成代码,是还没有去掉无用的代码的。假设用户只需要开发一个报表(无增删功能),但实际上还生成了无用的增删改的代码,用户需要手动删掉 6、7 处的代码块。对于熟悉的同学,可能 2 - 3 分钟就删掉了,但还是会感觉体验很差。
按需生成代码
现阶段最简单的处理方式是,按【查询】、【删除】、【新增 & 编辑】这几个维度去划分代码块,然后给【删除】、【新增 & 编辑】打上标识。如果用户只希望生成【查询】的代码,就正则匹配把其他无用的代码块删掉。
最优处理方案
因为后续还要增加更多组件和功能,比如上传组件、图表组件、tab 组件等。这种情况下,代码 “做减法” 涉及到的逻辑很多,而且不够直观,更别谈有些逻辑还是互斥的了。
换一个思路,从零开始 “做加法”,把每个功能的代码块,用一个唯一的 key 做标识。比如,
接着把所有的 key 放到一个集合中,当 AI 识别出功能或者用户手动选择对应的功能时,就从大的集合中去匹配 key,生成一个小的集合。
比如,最终页面需要的功能是【查询】、【折线图】,那对应的 key 集合就为:query_import_xxx、query_logic_xxx、query_template_xxx、line_template_xxx。
最后,再把匹配集合中的 key 剔除掉,得到的就是 “纯净版” 的代码了。
模块化 & 组件化
或许大家有听说过一些网站,输入 url 或者提供截图,就能生成一个 “一模一样” 的网站。各大营销号纷纷贩卖焦虑,前端已死。但就目前而言,这些所谓的生成式的网站,生成的代码和真正项目代码之间的区别就是像是手机模型和手机的区别。看上去一模一样,但其实生成的网站既没有逻辑,也很难进行二次开发,只能用于纯展示。
但我们要生成的代码,是要和我们规范的代码是要完全一致的。所以在我们的 AI 工具中,AI 承担的更多是匹配转换的工作,而不是基于它本身的理解去生成。
举个例子,你给 AI 设定一个精通 ant design vue 和 typescript 的前端专家角色,然后让他去生成一个日期范围选择组件,那么就会得到以下的代码。
const queryDate = ref([])
<a-range-picker v-model:value="queryDate"/>
渲染的出来的效果为:
看起来没有问题。但是!会有 3 个局限性。
1、我们日期组件规范中是带有快捷选择的。
2、我们默认输入和输出是 YYYY-MM-DD 的格式,而 <a-range-picker v-model:value="queryDate"/>
是带时区的日期对象。
3、<a-range-picker v-model:value="queryDate"/>
渲染输出的是一个数组,而我们要传给后端的,是起始时间和结束时间这 2 个字符串。
基于以上 3 点,我们是无法直接使用 antd 的原生组件的,而是基于它再二次封装。
模块化和组件化是提升生成准确率的一大关键。最好只给出不超过 3 种选择,让 AI 在不同场景下做对应的匹配。比如,替换函数或组件种的某个变量或条件。
这种匹配替换使用正则或者 AST 也可以实现,但是逻辑的复杂度、考虑的边界条件、代码量都会很庞大(项目中也有用到 AST 做一部分简单的操作,后面会提到)。
而使用 AI 的 prompt 只需几句就可以达到一样的效果。
AI 出码 2.0 版本
代码生成方案优化
总结了以上各个生成方案的优缺点之后,梳理了第 2 版的代码生成时序图。
总共分为 2 步:
1、爬取 api 文档生成 typescript 类型声明和 api 接口函数。
2、选择要生成的页面模板(图表、列表)和组件。
步骤一,爬取 api 文档生成 typescript 类型声明和 api 接口对接。
相对 1.0 版本改善的点:
1、做了一个便捷化的操作,预设了我们中后台所有的地址,不需要开发每次生成的时候再去找了。
2、左侧加了预览代码的窗口,可以预览生成的文件。当后端接口和字段改动较为大时,可以重新生成整块替换,不需要再一个个字段复制和对比了。
步骤二,选择要生成的页面模板(图表、列表)和组件
对 1.0 版本改善的点:
1、自动识别需不需要勾选【增改】、【删】的功能。如果识别不准确,用户也可以手动处理。
2、文件可以直接保存到项目目录下,无需解压和复制。
如何处理生成不准确的结果
“不准确” 的场景分为以下几种:
1、返回的内容格式不固定
之前测试效果的时候,前后换过几种大模型,如 gpt3.5-turbo、gpt4、kimi-v1-32k。同样的 prompt 会因为用的模型不一样,有些会生成带 markdown 标签的代码,有些则生成纯代码。有时候还会因为传入的上下文内容和 prompt 示例差距过大,导致生成不一样的 markdown 标签。
所以,对于 AI 返回的代码,最后输出时,都要去掉这些 markdown 标签。目前处理方式比较简单,直接匹配 typescript、html、vue 等 markdown 标签,实现过程就不展开说了。
2、返回的代码不按照示例来
在给的示例模板内容过多时,AI 很难每一项都精确识别。
以上的对比图是为了大家更好地理解而截取出来的一小部分内容。实际上,生成的内容这么简短的话,AI 是可以准确地识别的。但是一个页面那么多,如果拆成很细的模块的去调 AI,不仅要写的逻辑多,而且调 api 的费用也会高很多。
这种小修小改就可以结合 AST 处理,目前用的库是【ts-morph】。
这样就可以拿到代码片段中所有的函数名,然后再将它重命名插入对应的位置即可。
3、无法处理逻辑分开多段代码的组件
再以我们之前提到的日期组件为例。前面也说到,antd 的日期组件入参是一个数组,但是后端要求的是开始时间和结束时间 2 个字符串。
总结 & 规划
总的来说,以目前的 AI 技术,让它自主创造生产可用的业务代码还是比较难实现的。但是,让 AI 基于我们封装好的组件再根据不同业务场景进行匹配和转换,是能稳定产出符合规范的代码的。
后续也会把一些流程固定的业务场景抽成对应的模板,将以前手动复制页面 / 模块代码的模式逐步替换成 AI 匹配替换。
关于本文
作者:@waldon
原文:https://mp.weixin.qq.com/s/Rf_dJ5UKmEu9QaGG_P-9OQ
这期前端早读课
对你有帮助,帮” 赞 “一下,
期待下一期,帮” 在看” 一下 。