一、前端开发实例

今天主要想分享一些关于大模型如何协助我们进行前端编码的实践。首先,让我们以一个前端开发的实例开始。通常,当需要实现一个新的前端功能时,我们会收到相关的背景和需求描述。我的期望是,大模型能够直接使用这些描述来实现需求。例如,如果我们需要在人员信息中添加增删改查的方法,我希望只需提供需求描述,大模型就能细化需求并检索相关的代码。这正是大模型的强项,即能够规划和执行任务。

最终生成这个需求实现可能涉及到多个文件的修改或工程级别的修改,这就需要进行 repo level 的代码生成。在进行问答时,我们用户实际上就是在做“提示词工程”。

设计提示词工程其实非常简单。我们对生成的代码有技术栈的要求,需采用 React 或 Vue 架构,并明确组件库是采用 AntD 组件库或其他。从 PRD 中复制需求后,即可开始生成业务代码。由于需求内容较多,字段繁多,形成了一个长表单,因此生成的代码也较长,可以清楚地看到效果,这个需求的表单项很多。如果是程序员手动编写代码,需要逐个敲入 form item 并确认类型。

在前端开发中,重复性劳动是普遍存在的,需要反复确认并一行行地敲代码。尽管现在有低代码或组件化的方法来提高开发效率,但编写一段简单的代码仍需花费几分钟。这样繁琐的过程无疑让人厌烦,而 AI 代码助手的出现则能帮助我们快速完成这些任务,从而有更多时间和精力专注于那些真正需要创造力和深度思考的问题。让编程更有效率,让我们能够更快地得到想要的结果。

二、提升开发效率:自然语言生成代码实践

目前,通过通义灵码,我们可以简单描述并快速生成一个复杂的代码实现,从而显著提高开发效率。它最终会生成多个文件的代码,和它们之间的调用关系。例如,第二步是创建一个名为 Personal form 的组件,生成了一个代码文件。接下来肯定是要去调用附件,怎么在主应用中引入这个组件,每个文件需要修改什么都会呈现出来。这其实是一个非常端到端的从描述生成代码的过程。更复杂的增删改查操作需要具备 repo level 的代码生成能力,即库级别的生成能力,这要求更高。

我们仔细查看生成的结果,我本希望可以直接复制粘贴使用这段结果。然而,遗憾的是,生成的代码在很多情况下无法一次性满足我们的需求。原因在于,这段代码过于冗长,模型认为一次性生成全部内容过于繁琐,因此对返回的内容进行了必要的省略,未能一次性提供我们期望的答案。尽管如此,生成的代码已经非常接近最终版本,接下来,我们将分析为何它未能给出正确的答案。

那么我们该如何应对呢?最重要的是要明确问题。接下来的步骤是将问题转化为模型可以理解的形式,或者以更详细的方式传递给模型,或者纠正和补充信息以帮助回答。因此,我们可以在前一个问题的基础上继续追问:“能否将省略或补充的字段补充完整?”并使用 AntD5 组件库这种更细化的版本要求,在追问中提出细节要求。

这就是问答提示词,大家能够理解如何去提问,这是我们能做的一个事情。理解了问答提示词,实际上就很好地理解了代码补全的基本原理。我们再来看代码补全的提示词,想一想应该是什么呢?可能就是代码的大模型。

它不是通过网络搜索资料,而是基于已学习的参数,根据上下文的提示词来生成内容。例如,假设提示词为“补全这段 time script 代码,上文是什么,下文是什么”,这是一个最简单的代码补全提示词示例。通过这样的提示词,可以与任何模型服务进行交互,进而生成一个代码编辑助手。

三、代码生成模型的质量影响因素与上下文作用

那么,模型生成代码的效果或质量受到哪些因素的影响呢?当前开发文件的内容质量是关键,它能同时感受到编码风格、语言框架以及代码中的自然语言,如注释、伪代码等的影响。如果代码需求表述清晰,上下文完整,生成的代码将更符合预期。反之,如果缺乏上下文或表述模糊,生成的代码可能不够准确,需要人工进一步调试。这意味着在业务逻辑实现过程中,人工智能无法完全理解我们所需的清晰业务逻辑。代码生成推荐以后,人与 AI 协同编程的过程中,良好的代码风格和规范可以提供更好的上下文,有助于生成更精准的代码,也离不开程序员自身对完整需求的理解。

通过一个简单的例子,我们可以看到上下文是如何影响生成代码的。

在这里,通常新建文件开始,其实大模型都已经开始理解我们,就开始做推测了。我们的文件名是 User.tsx,那这里就有一些暗示了,文件的扩展名其实代表了我们代码语言类型是什么?TSX 这种类型的文件其实都是通常用在 React 框架里面。

文件名通常与组件名相同,代码模型据此进行识别。在输出和输入的 type 中,当需要声明一个类型时,它会推荐使用 UserProps。这是因为模型能够感知文件名与组件名的一致性,这是一种它所学习到的模式,即类型命名与组件名相同。因此,生成代码后,我们只需按 tab 键进行采纳即可。

定义好类型后按 tab 键,然后它会开始补充组件的函数问题。我们按回车键多次,它会继续生成代码。当我引入了 Table 组件后,它自动补全了 Table 符合数据源要求的数据结构。再按 tab 键,它执行采纳操作,从而自然而然地形成了我们整个 return 一个 DOM 元素的逻辑。

四、代码补全技术的局限与优化方法

代码补全的结果并非每次都准确,这可能与上下文的精确度有关,也与代码生成模型的能力相关。在当前上下文信息不足的情况下,可能会有多种生成结果。特别是在前端开发中,由于交互的性质,用户行为难以准确预测。

让我们以一个三方 API 为例,演示在生成代码过程中模型是如何补充相关库的。看起来还是很有道理的。它实际上学到了一种普遍的模式:大驼峰式 API 通常通过小写中划线的包名零引入。然而,在 NBA 官网中并未找到该包,正确的依赖包应为“utrie”。有时,API 的命名比程序员更规范、标准,但并不意味着这些 API 在客观上确实存在。

另一个问题是,通常在 TS 中,代码块始于 import。我很难确定我引入的这个依赖的 former 里面究竟是什么函数。如果仅从模型中看到函数定义,很容易随意生成这个 formatter,甚至函数的 API 参数的定义,这些在编码时都是不确定的。这会导致所谓的“幻觉”,即模型可能编造出不存在的包,这就需要开发者介入识别并干预。

五、大模型代码生成中的幻觉问题及解决策略

在自定义组件库时,许多开发者会基于公共组件库,并针对特定业务需求进行修改。例如,在筛选组件中,我们可能不需要清除按钮。因此,在自定义组件库时,我们会删除这一属性。然而,当大模型学习公共数据时,它通常会学习到“clear”这一属性,并可能推荐出业务组件库中未定义的选项。这是一个普遍现象。后续我们将探讨如何调优,以及如何干扰模型生成结果以优化其输出。

首先,我们需要提供更多信息以帮助模型生成更准确的内容,避免或减少生成的幻觉。这是每个大模型都需要解决的问题。当用户向模型输入内容时,他们应该提供更多信息,使模型能够感知到更多的内部细节,从而避免在生成代码时产生幻觉,导致开发者无法接受结果或影响开发效率。因此,我们会进行更多的调整。

其实我们灵码团队为了避免这个问题,做了很多相关的工作。包括代码的语义分析,代码的引用链、调用链这些跟踪,以及各种推导和相似代码的分析。我们在补全当前上下文这个代码的时候,我们会获取已解析的依赖关系或跨文件签名。将更多的信息融入到代码补全里。这样,在生成当前代码片段时,能够忠实于语言和数据,从而避免乱生成代码。

当然如果你说完全避免,这个也不是完全确定的。因为灵码不会存储用户代码,也不会使用用户的代码。它所有的索引代码、索引内容或检索召回都是在用户的本地完成的,然后再结合大模型的内容进行生成。我们会持续迭代这一部分,包括支持语言的扩展和生成格式。那么,究竟生成的内容是推荐一行代码、一个容器外部,还是一个完整的函数或类,对于我们开发者来说是至关重要的。

六、探讨人工智能大模型生成前端代码的挑战

我们非常关注自动生成代码的质量。如果生成的代码力度过大,可能会导致每次只生成单行代码,这不仅冗余,而且需要多次点击才能完成函数补全。因此,我们会通过自适应的方式生成相关的例子,例如,它可能会生成整个 for 循环或 if 语句。在编写工具函数时,当遇到注释,会更倾向于将整个函数解析出来,以满足开发者习惯并确保生成的代码符合实际需求。在这方面,我们已经进行了大量的优化工作,效果显著,得到了明显的提升。

使用人工智能大模型生成前端代码相较于后端的 Java 或 Python 代码会面临更多的挑战。尽管 Python 和 Java 在后端开发中表现出色,但在前端应用中,其表现并不尽如人意。我们可以通过以下维度来分析原因。编写一个 VUE 文件时,该文件实际上融合了三种不同类型的语言:JS 或 TS 脚本(脚本语言),TS(强类型语言),以及 HTML+TS 等标签(标签语言)。

像 CSS 这类语言,严格来说并不算编程语言。它们更接近于规则级的配置。在前端开发的学习过程中,我们会发现规范的多样性和非标准化。尤其在前端技术的历史演进过程中,出现了许多大版本、小版本和技术分支。前端开发涉及的进展更为多样,如 JavaScript 的动态特性、TypeScript 的强类型系统以及 HTML 和 CSS 的混合使用。实际上,没有一个统一的领域模型存在。而且,HTML 和 CSS 在很多方面并没有统一的标准,各个组件库标签的定义也各不相同。

即便在同一企业内部,也可能存在不同的前端开发团队或个人开发者,他们可能会采用不同的技术栈或编码风格。在前端框架的选择上,我们有 React、Vue 和 Angular 等。在国内,Vue 可能是主流选择,同时也有其他遵循不同最佳实践的团队。相比之下,Java 作为后端语言,尽管有多种框架如 Spring、Hibernate 等,但其核心语法和面向对象的编程原则相对统一。

此外,前端在接收到需求后,前端代码直接影响用户界面呈现和交互体验。需求的变化越接近用户,变化频率越高。这要求前端代码不仅需要保证功能正确性,还需要考虑代码生成的复杂度、美观以及响应式的频繁迭代和变更。而后端更关注业务逻辑和数据处理,抽象程度相对较高。

前端代码还需具备实时性和动态性以处理用户输入并及时给予反馈,这涉及到复杂的事件监听和状态操作。相比之下,后端执行环境通常更加稳定,对外部变化的响应不如前端频繁。此外,还有一些兼容性问题以及提升用户体验的问题。因此,前端代码生成面临的挑战不仅包括交互和交互逻辑,还包括用户体验和兼容性方面,这些都需要 AI 模型具备更高级的理解能力和对细节的精准把握,从而使得前端代码生成成为一个更为复杂的任务。

七、优化前端开发者工作环境与企业级服务的大模型应用

针对前端开发者的优化工作环境,我们进行了深入思考和改进。我们考虑过模型是否存在知识盲点?即使我们优化了提示词并输入了大量上下文,开发者已经完成了所有能做的事情,但模型仍存在不足,无法提供相关知识,从而无法给予开发者必要的帮助。遇到这种情况,正确的做法是清晰地阐述问题,最好能围绕问题展开,全面介绍业务技术、团队编码等相关背景信息,至少要让模型理解问题的背景、场景以及待解决的问题。

在企业级服务方面,我们深入考虑了与企业核心需求相关的方面。主要是将企业的自有代码、第三方库以及特定的内部 API,还有其他问答服务整合到当前大模型服务中。这还包括企业内部文档处理,这些都是对企业至关重要的需求。我们可以通过构建与企业相关的代码和文档的知识库,结合大模型的发展,提供更强大的数据处理和检索召回功能。这是我们的优化重点方向,旨在让生成的代码更贴近开发者自己编写代码和知识。

八、企业知识库与大模型融合的实践策略

在学习大量优质公开数据时,我们的大模型无法直接获取企业的私有知识。这就是 RAG 方案的由来,该方案类似于为企业量身定制增强效果,以满足独特需求。对于大模型的落地应用来说,对我们的企业而言,成本最低且门槛最低的方法就是 RAG 技术。它不仅是一个技术,而且是知识库管理的一种方式。通过 RAG 技术,我们可以将企业的知识和私有化知识库与大模型融合,从而更有效地解决用户和开发者的问题。

在实施过程中,有两个关键角色不可或缺。一个是知识库管理员,负责上传高质量的代码仓库和文档。另一个是我们的企业开发者,他们提出问题并参与编码现场。

其实,核心是一个词库,因此我们需要知识库管理员准备一些文本。这些文本构成了我们的知识库。简而言之,我们将这些文本存储在一个类似数据库的系统中,该系统被称为“向量”。我们针对特定项目进行检索,即在获取一个文本后,希望从库中找到与该文本相似的其他文本,以加速检索过程。

我们将使用一种新型的向量数据库系统。在将文本或代码片段存入数据库之前,需要先进行切分。如何将文章分割成各个段落?我们需要合理地分割不同类型的前端语言代码。例如,标签应从开始标签到结束标签进行分割,而 Java、JavaScript 等语言则需按代码块进行分割。这一过程涉及多种算法,这里不再详细说明。接下来,我们将切分后的每个段落或片段,即窗口,存入向量数据库。在存储之前,需要将它们转化为向量的向量化形式,这一过程称为“Embedding 向量化”。一旦知识库被上传,我们就已经完成了知识的 Embedding 向量化,并将其存放于向量数据库中。

接下来讨论什么呢?用户开始编码,那么我们该如何自动补全代码或者用户开始使用的场景。我们首先将用户的问题转化为一个向量,这个过程我们仍需要使用 Embedding。有了这个问题的向量后,我们还需要在向量数据库中检索包含该问题的答案或段落,或者是相似的代码片段。这个搜索过程实际上是在数据库中检索的过程。检索完成后,我们让数据库返回可能包含问题的几个段落。我们将这些段落放在一起,这个过程我们称之为检索,检索出来的结果也被称为 Context 上下文。这个上下文可以与我们之前提到的所有上下文结合,并整合成一个 Prompt。

因此,让大模型回答这个问题构成了整个流程的核心。如何有效地裁剪代码或加速检索过程呢?在优化过程中,存在多种策略可选。如果用户能够构建一个高质量的代码仓库或知识库,那么召回与用户需求高度相关的代码片段的概率将会显著提升。这意味着,当我编写某段代码时,系统已经在向量数据库中存储了相似或高度相似的代码,从而实现高效的检索。

九、前端组件库文档的重要性及实践案例

以前端组件文档为例,它实际上是一种高质量的文档。当你使用开源组件库时,通常会在官网找到以 markdown 格式呈现的网页。这种网页格式是为了方便开发者的阅读和查询,帮助我们快速了解组件库的 API 及其应用场景。因此,这些文档通常会单独发布为网页形式。

该文档的质量之所以高,是因为它首先用自然语言介绍了组件的功能和应用场景,然后提供了具体的代码实现。因此,它实际上架起了一座桥梁,连接了自然语言与代码。通过专业工具将这些网页转换为markdown 格式后,我们便可以开始进行问答。

前端代码是基于脚本和标签语言的特性生成的,我们来看一下具体效果。我们团队有一个名为 Teamix UI 组件库的资源,它包含了基础和业务组件。当这些组件被上传到知识库后,灵码在生成答案时会自动输出 import 语句,引入 UI 私有库。这一特性带来的好处是生成的代码可以直接复制并粘贴,省去了进一步修改的步骤,极大提高了效率。

十、前端团队代码仓库管理实践

那么,企业如何在前端团队中实现代码仓库的落地呢?在与客户的交流中,我发现他们往往将此事视为门槛很高的事情。因为建立一个高质量的知识库需要投入大量精力,这可能包括文档和代码仓库的管理,或者建立一个模板工程。在此,我想澄清一下,以我们前端团队是如何实施这个过程为例,其实这是一个很简单的过程,不需要过于复杂。我们直接在灵码的后台建立一个名为“云原生前端团队”的私有知识库,并上传代码仓库的压缩包,将其设置为私有知识库成员。

为什么要设置为私有呢?这是因为我们的前端团队负责的产品线多样,各产品间差异较大,技术栈的差异也较大。此外,每个开发人员所管理的仓库各不相同。鉴于此,我们没有按照团队来划分知识库,而是细化到个人层面,以避免不同组件库或 API 之间的混淆,以及潜在的版本冲突问题。例如,由于 VUE2 和 VUE3 的技术栈不同,我们为它们设置了独立的存储空间。那么,如何形成这个独立的知识空间呢?答案是通过设置为私有,并选择私有时,通过成员权限来实现。

通过让团队成员仅接触与其工作直接相关的代码仓库,可以减少干扰,提高专注度。这就是整个操作过程。有人认为准备仓库很麻烦,需要准备许多模板工程,还要做很多集合,以及搞清楚团队的业务分工。其实,有一种非常简单的方法可以立即启动外的能力,即首先将团队当前编码的仓库上传,建立一个知识库即可。或者,你也可以选择团队中那些代码质量高的几个人的代码仓库,上传这些仓库也能立即发挥作用。如果我上传的代码仓库与实际开发的相似度越高,那么效果就会越好。启用企业知识库能力后,我们团队的 AI 生成占比提升了 5% 到 10% 左右。

为什么数据会有所波动呢?这是因为我们团队的编码活动在不断变化。例如,某个月我们专注于国际化开发,这包含自动化工具与文案的改写,导致 AI 生成内容的占比相对较低。因此,需要根据具体的实际开发活动来分析数据。另外,团队在编码风格上也有一致性的要求,比如前端编码规范,eslint 等,通常我们在配置里面会有清晰的 case 和约定。

十一、探讨 AI 在提升编码工作效率中的应用

那么我们推荐通过知识库上传符合编码规范的文档以校正。例如,我们可以在代码仓库中进行校正。在开发过程中,我们推荐使用最下面这种写法,以确保代码既清晰又高效。通过在灵码知识库中上传符合编码规范的代码,团队成员可以轻松访问并效仿最佳实践。他推荐出来的就是最好的代码,这样就确保了项目代码的一致性和高质量。

另外,我们还提供一键修复报错的功能,当我们在编写代码过程中遇到红色标注的错误时,可以利用这个功能让灵码进行修复并跟进修改结果。这个提示非常好,我们经常用你,这是一个高频的使用场景。

另一个非常推荐大家使用的是 commit message,即提交信息的生成。在进行代码提交时,团队成员经常随意填写提交信息,Code Review 也无法有效管理和验证这些信息。虽然我们可以结合 husky等工具对 commit 做卡点,但这也会降低工作效率,而且开发很容易绕过。灵码能自动生成变更信息,从而直接提交,有效帮助我们提高了工作效率。

通义灵码最近针对开发者进行了一项调研,收集了超过一千份问卷。调研结果显示,72% 的受访者认为编码工作效率得到了显著提升,这是一项相对不错的评估结果。我们之前讨论过人与机器协作的主题,也谈及了前端开发过程中的相关经验。

十二、未来展望

软件如何赋能?从 AI 开始,我们更加依赖于 AI 作为软件工程主力进行代码的整合和开发。随着 AI 智能占比的不断提升,我们不断探索更强大的模型来解决问题,例如 GPT 等更先进的模型,以及克服更前沿的智能体技术。此外,还需要处理多模型间的配合和接口协作。因此,采用先进的软件开发理念是必要的,开发人员需学习如何更好地利用 AI 提升开发效率,拓展自身能力的极限。这其实是一个更先进的软件开发理念,并且它已经发生,甚至将 AI 融入整个软件工程团队的合作中。

没有这些因素,我相信未来将会发生一些质变。例如,四十年前人类开始步入神话时代,意味着我们对团队协作的依赖达到了新的高度,无论是现在还是未来。这包括项目如何划分、人与人之间的协作方式,以及是否可以扩展等都提出了许多问题,并且我们也在寻找解决方案。接下来,人与智能体的交互将变得更为紧密,比如 N 年以后是否可以逐渐过渡。这个逐渐过渡的过程实际上是温和的,从依赖人类到依赖超大规模算力的转变,可能会取代我们的一些职责。这不仅仅是简单的叠加关系。对于AI和超大规模算力,这是否意味着我们可以大幅度提升软件质量,是否可以缩短研发周期并提高效率,还有创造出更优质的软件并持续发展,这无疑是肯定的。

在这一过程中,我们不可避免地会遇到一些挑战。我们希望借助这项技术,提升软件工程的质量或缩短交付周期。这是我们的未来展望。


阿里云云原生
1k 声望306 粉丝