自定义RAG工作流:在IDE中结合RAG编排,构建可信的编码智能体

代码为聘礼 2024-07-26 12:00:40

构建编码智能体并非一件容易的事。结合我们在 AutoDev、ArchGuard Co-mate、ChocoBuilder 等智能体项目的经验,我们开始思考在 Shire 语言中提供一种新的 RAG 工作流。结合我们先前构建的 IDE 基础设施(代码生成、代码校验、代码执行等接口),现在你可以构建出更可信的编码智能体。

TL;DR(太长不看)版

现在,你可以使用 Shire + 自定义的 RAG 流程智能体编排。如下代码所示,你可以

使用自己编写的 prompt 与 IDE 接口来获取代码数据

对代码进行向量化、检索与普通的代码搜索

将参数传递给下一个流程( execute 函数)

---

name: "Search"

variables:

"placeholder": /.*.java/ { splitting | embedding }

"input": "博客创建流程"

afterStreaming: {

case condition {

default { searching($output) | execute("SummaryQuestion.shire", $output, $input) }

}

}

---

xxx

User: $input

Response:

再结合我们的代码校验、代码执行等功能,你可以构建出一个完整、可信的编码智能体。

详细见:https://shire.phodal.com/workflow/rag-flow.html

基础 Shire 能力:Pattern Action 与代码可信函数

Shire 提供了一种简便 AI 编码智能体语言,能够让大型语言模型(LLM)与控制集成开发环境(IDE)之间自由对话,以实现自动化编程。

简单来说,你可以通过 Shire 去:

调用封装的 IDE API,以生成 prompt 所需的数据。在 Shire 中,数据在 prompt 中以变量的形式存在。

定义在 IDE 中的行为,如何触发、如何执行,以及如何处理结果。

定义简单的数据流处理,如何处理数据、如何存储数据。

因此,你可以通过 Shire 作为中间语言,访问自己的 IDE 数据,生成与 AI 模型对话的 prompt,以实现自动化编程。

Shire RAG 基础:Pattern Action 构建数据流

在先前的 Shire 中,你可以通过 variables 来自定义你的 Pattern Action,以从 IDE 中获取数据。如下所示:

---

variables:

"logContent": /.*.java/ { grep("error.log") | head }

---

检查用户的代码是否有问题:$logContent

在这个例子中,我们定义了一个变量 logContent,它的值是从所有 *.java 文件中检索 error.log 的结果。最后,将结果发送给 LLM,由 AI 来进行对应的处理。

详细见:https://shire.phodal.com/shire/shire-custom-variable.html#variable-pattern-action

Shire RAG 基础:代码可信校验

Shire 的代码校验是在 Shire 生命周期的 onStreamingDone 中执行的,即在 Streaming 完成后通过一系列的后处理器对生成的内容进行处理。在现有的版本中,支持三个函数:

parseCode 将文本解析为代码块。

verifyCode 检查代码错误或 PSI 问题。

runCode 运行生成的文本代码。

因此,你可以采用如下的方式来处理 LLM 生成的代码:

---

onStreamingEnd: { parseCode | saveFile | openFile | verifyCode | runCode }

---

生成一个 python hello world,使用 markdown block 返回

当你启动 Shire 指令的那一刻,一场精心编排的编码舞蹈便悄然展开。首先,Shire RAG 工作流会调用 Language Model(LLM),这个强大的语言模型迅速进入状态,开始生成一段 Python 语言的经典之作——Hello World 代码块。

生成的代码块接下来会通过 saveFile 功能,被小心翼翼地保存到指定的文件中。

为了确保这段代码的准确性和可靠性,Shire RAG 工作流会启动 verifyCode 函数,进行严格的语法校验。

一旦通过语法校验,接下来就是激动人心的时刻——通过 runCode 函数来运行这段代码。

这一刻,代码仿佛被赋予了生命,它将在 IDE 中绽放出耀眼的光芒,将 "Hello, World!" 这句问候语,优雅地展现在我们的眼前。

详细见:https://shire.phodal.com/lifecycle/on-streaming-done.html

Shire RAG 基础:Index 与 Query

结合我们先前的 RAGScript 与 RAG 项目经验,只需要通过简单的函数,就可以实现代码的检索与查询。如下所示:

---

name: "Search"

variables:

"testTemplate": /.*.kt/ { splitting | embedding | searching("blog") }

---

$testTemplate

在这个例子中,我们定义了一个变量 testTemplate,它的值是从所有 *.kt 文件中检索 blog 的结果。随后,你就可以将结果发送给 LLM,由 AI 来进行对应的处理。

Shire RAG Flow:解释代码示例

当我们使用领先 AI IDE (如 AutoDev VSCode 版本)的业务知识解释功能时,通常会分为 3~5 个步骤:

查询转换。将用户的问题,转换或者扩展(query expansion)为某种形式的查询语句。有的是关键词、有的是是假设性代码。

信息检索。随后,将查询的结果结合本地的数据(文本、向量等)进行检索,以获取到相关的信息。

重新排序。对检索到的信息进行排序、解释等处理,以生成对应的结果。

内容总结。最后,将结果发给 LLM,由 AI 来进行对应的处理。

根据不同的上下文或者业务需求,这个流程可能会有所不同。但是,基本的流程是一样的。而在使用 Shire 开发时,由于我们只需要和 LLM 交互两次,所以只需要两步:

将用户的问题发给 LLM,并进行检索

由 LLM 来总结上一步的结果

尽管过程简化,但是如何抽象中这种原子能力,对 Shire 提出了更高的要求。因此,在这里我们也是作为一个 PoC 来进行展示,我们将在后续的版本中,提供更多的能力。

步骤 1:使用 Shire 自定义代码检索

有了上述的基础,我们可以开始构建一个 RAG 流程。如下所示,我们可以:

---

name: "Search"

variables:

"placeholder": /.*.java/ { splitting | embedding }

"lang": "java"

"input": "博客创建流程"

afterStreaming: {

case condition {

default { searching($output) | execute("summary.shire", $input, $output) }

}

}

---

[]: 这里写一些 CoT 相关的指令

在这个例子中,我们定义了一个变量 placeholder,它的值是从所有 *.java 文件中检索 博客创建流程 的结果。由于,默认情况下,会将 embedding 的结果存储在内存中,所以在 afterStreaming 时,我们就可以直接拿来使用。

afterStreaming 会在 Streaming 完成后执行,这里我们使用 searching 函数结合上一步的结果,来进行检索。最后,将结果发送给下一个流程。

步骤 2:使用 LLM 进行总结

在第一步中,我们决定了下一个指令的名称为 summary.shire,并且传递了两个参数: $input 和 $output。在这个流程中,我们可以直接使用这两个参数:

[]: 这里写一些 prompt

代码信息如下:

$output

用户的问题: $input

随后,Shire 会自动执行这个指令,并将结果返回给用户,即对问题的总结。

详细见:https://shire.phodal.com/workflow/rag-flow.html

Shire RAG 工作流的实现

实现 Shire RAG 工作流,并非一件容易的事。我们在人力有限的情况下,需要经过大量的调研和试验,以及场景验证。我们调研了被广泛采用的编码 RAG 工具, 以探索更多的可能性。我们还尝试了不同的编码智能体的实现方式,以及不同的编码智能体的实现方式。

Shire RAG 技术栈

Shire RAG 工作流主要使用的技术栈如下:

推理框架:ONNX Runtime

Embedding 模型:Sentence Transformers all-MiniLM-L6-v2

相似度算法:Jaccard similarity(默认)

数据存储:内存(默认)、本地文件(项目目录)、未来:SQLite

Tokenizer:HF Tokenizer

而除了 RAG 部分,基于 NLP 与搜索的传统检索方式也是支持的,诸如于:

similarCode 变量:通过 Jaccard 等算法,来检索相似的代码。

similarTestCase 变量:通过 TF-IDF 来检索相似的测试用例。

我们尝试将更多的算法与技术集成到 Shire RAG 工作流中,以提供更多的能力。

文档支持

基于我们构建的 LLM 开发框架 ChocoBuilder,现在可以支持:

Office 文档:docx, pptx, xlsx 文件

PDF 文档

非二进制文件

IDE 支持语言代码文件

IDE 不支持语言代码文件

当然,现有版本的代码拆分机制还不够完善,我们会在后续版本中提供更多的支持。

下一步

我们现在的版本只能满足一些简单的需求,但是在实际的开发中,我们还需要更多的能力。因此,我们会在后续版本中提供更多的能力:

支持更多的存储方式,如向量数据库。

支持对结果进行重排,如 LIM、LLM Rerank 等。

支持更多的检索方式,如 BM25+、BM42 等。

……

详细见:https://github.com/phodal/shire

0 阅读:0

代码为聘礼

简介:感谢大家的关注