上周微软发布了自家的 AI 编程和软件研发智能体框架:AutoDev,其与咱们研发的 IDE 插件 AutoDev 有颇多的类似之处,尤其是有些设计思路,以及在针对辅助软件研发任务的智能体以及有些基本设备上。
稍有区别的是: 交互介质。咱们的 AutoDev 构建基于 IDE API 体系构建的,而微软的 AutoDev 则是构建以 CLI 为主。隔离环境。咱们设计了 DevIns 语言来构建隔离环境,而微软的 AutoDev 则是基于 Docker 隔离环境。
当危,咱们的 AutoDev 研发人数比较有限,因此相比于微软的 AutoDev 成熟度上是相对比较低的。思虑到咱们的 AutoDev 是一年前开源的,而微软的 AutoDev 是近期发布的,她们这取名有点不厚道。
AI 驱动软件研发的本质:“人类—AI—代码”的桥梁
针对 AI 驱动的自动编程来讲,无非便是让 AI 能理解好人类的需要,而后实现 AI 与代码环境的自动交互。更仔细来讲,便是: 人类经过自然语言或交互描述软件研发任务,如解释代码、生成代码、运行测试等。AI 结合智能体与上下文理解人类的需要,并生成对应的指令文本。代码环境接收指令文本,并执行对应的操作,再返回结果给人类或 AI。
亦因此呢,咱们所要构建的上是一个基于 “人类—AI—代码环境” 的沟通桥梁。实现让 AI 能理解人类的需要,并不是一件繁杂的事情,经过额外的需求澄清、展开, 就有初步得到格式化后的需要。而让 AI 与代码环境进行交互,则是一件更繁杂的事情,即怎样经过指令文本来实现的。
方式 1:基于文本的函数调用
函数调用(Function calling)能够让研发人员声名一系列的函数,将其与对应的说明传递给语言模型,让语言模型按照这些说明来生成格式化的结果。随后, 在对应的工具中,调用对应的 API 来实现对应的操作。诸如于 Google AI 中语言模型生成的返回结果示例: {"functionCall": {"name": "find_theaters","args": {"movie": "Barbie","location": "Mountain View, CA"}}}类似的方式,还有让 AI 生成对应的代码,如 shell 等,而后执行对应的代码。
方式 2:语言抽象的研发环境
咱们针对自动化的探索是来自于 AutoDev 第1个需要,针对 Spring 框架的 AutoCRUD。在这个需要中,咱们发掘在繁杂的软件研发任务中,需要动态生成 高质量上下文,以让 AI 能在对应的问题域中生成对应的代码。诸如于,生成 Controller 代码,需要晓得现有 Controller,规范,以及对应的 Service、Repository 等代码。这一系列的信息,寓意着,咱们需要一个更高级别的语言来描述这些信息。
随后,咱们在 AutoDev 中构建了一系列 Auto 功能(针对 React 的 AutoPage、针对鸿蒙操作系统的 AutoArkUI 等),以探索更合适的语言抽象来描述 “人类—AI—代码环境”,即 DevIns 语言。经过语言来做为人机接口,并做为可执行的代码,来实现对代码环境的操作。诸如于: /patch
```patch
// the patch to apply
```
经过形式化的方式来描述对 IDE 的操作,易于让 AI 理解,亦易于让代码环境执行。
设计基于 IDE 的编程智能体研发
在设计 AutoDev 的自动编码功能时,咱们依旧是根据在 Unit Mesh 架构范式下的设计思路来设计的, 即 AI 生成的都是可验证的代码。亦因此呢,在咱们设计 AutoDev 的自动测试功能时,亦是基于这个思路来设计的。当然了,在有了 DevIns 语言后,就能实现 更加多的自动化(理论上)。
接下来,让咱们从实质的需要出发,以三个例子来瞧瞧平常的编码能够怎样设计: 验证生成代码是不是工作?进行安全的代码信息提交?探索自动化问题辅助修复?
当然了,还能够有更加多的区别示例,这儿就不一一列举了。
示例过程 1:经验证可工作的代码
不论是人类,还是 LLM,要验证一段代码是不是工作正确,最简单的方式便是运行它。运行它,一般有多种方式: 直接起步应用。通用 IDE 或 CLI 来起步应用程序,经过交互界面或 API 来验证代码的正确性。单元测实验证代码。即经过生成单元测试,以验证生成业务代码的正确性。构建 REPL 环境。而交互环境针对繁杂应用的依赖管理并非易事,因此并非那样容易。
与起步应用的效率相比,显然经过测试驱动研发(TDD)来验证代码的正确性更加有效。因此呢,在结合 IDE 时,则需要多思虑一步:如何运行测试以验证代码。
于是,咱们设计了一个简单的测试运行指令: /run:src/test/java/cc/unitmesh/MathHelperTest.java这般当咱们生成为了代码后,便能够经过运行测试来验证代码的正确性。因为 Intellij IDEA 支持区别的语言,然则区别的语言运行方式等是区别的。而因为 JetBrains IDE 运用了统一的底层抽象:RunConfiguration,因此呢咱们构建了一个 RunService 来封装区别语言的运行方式: interface RunService {
fun createConfiguration(project: Project, virtualFile:VirtualFile): RunConfiguration? = nullfun
runFile(project: Project, virtualFile: VirtualFile): String? { }
}更仔细能够参见 RunService.kt 代码。
示例过程 2:安全的 Git 操作
既然,咱们生成为了可验证的代码,那样下一步,咱们应该思虑的是结合 VCS 来进行代码提交。为了保证不执行不安全的操作,咱们不直接执行 Git 操作,而 是借助于 IDE 的 VCS API 来执行对应的操作。
于是,咱们设计了 /commit 指令来提交代码: /commit
```commitfeat: add new feature```
而针对需要更繁杂的场景,诸如于远程生成的任务来讲,咱们经过 /patch 指令来
示例过程 3:自动化问题辅助修复
接下来,咱们的挑战便是怎样在 IDE 获取运行结果,并按照结果来进行对应的操作。于是,咱们在 AutoDev 中设计了一个 DevInsProcessProcessor 来 处理 DevIns 指令的执行结果: when {
event.exitCode == 0 -> {
val comment = lookupFlagComment(devInFile!!).firstOrNull() ?: return
///handle flag comments
}
event.exitCode != 0 -> {
project.service<DevInsConversationService>().tryFixWithLlm(scriptPath)
}
}即: 成功。当 exitCode 为 0 时,咱们能够经过 flag comments 来决定怎样处理失败。当 exitCode 不为 0 (如 -1)时,咱们则能够继续经过 AI 来尝试修复对应的问题
在失败的场景时,咱们需要构建完整的上下文:输入、编译输出、 执行结果/LLM 返回结果,以便于 AI 能更好的理解问题,再给出对应的修复方法。
更仔细能够参见 DevInsProcessProcessor.kt 代码。
其它
咱们依旧还在设计适用于 IDE 的自动研发框架与 DevIns 语言,倘若大众有兴趣,能够参与到咱们的研发中来。
GitHub:https://github.com/unit-mesh/auto-dev
|