使用VoltAgent构建RAG聊天机器人
简介
聊天机器人变得非常有用,不是吗?从客户支持到个人助理,它们都能很好地处理对话。但有时,标准聊天机器人会遇到瓶颈——它们的知识仅限于训练时接触的内容。
如果你想让聊天机器人基于特定文档、最新数据或私有知识库来回答问题,该怎么办呢?
这就是检索增强生成(RAG)的用武之地。
我们将涵盖以下步骤:
- 什么是检索增强生成(RAG,Retrieval-Augmented Generation)以及它为什么有用。
- VoltAgent的检索器系统是如何助力检索增强生成(RAG)的。
- 搭建一个VoltAgent项目。
- 利用一个简单的知识库来实现自定义的基础检索器(BaseRetriever)。
- 创建一个直接使用该检索器的VoltAgent智能体。
- 使用VoltAgent控制台运行并测试这个检索增强生成(RAG)聊天机器人。
什么是RAG,为何要使用它?
从根本上说,RAG(检索增强生成)是一种技术,它通过让大型语言模型(LLMs)(例如驱动聊天机器人的模型)在生成回复前访问外部信息,从而使其变得更智能。
可以这样理解:
-
检索:当你向一个具备RAG功能的聊天机器人提问时,它首先会从预设的数据源(如文档、数据库或网站)中检索出相关的信息片段。
-
增强处理:检索到的信息(即"上下文")随后会被添加到您的原始问题中。
-生成阶段:最终,大语言模型接收到组合提示(您的问题+检索到的上下文),并基于这些特定信息生成一个答案。
结果如何?聊天机器人能够提供更精准、实时且符合语境的答案,突破其内置知识的局限。我认为这对于构建需要了解特定产品文档、企业内部政策或近期新闻的机器人来说极具威力。
认识VoltAgent
在深入构建之前,请允许我简要介绍一下VoltAgent。这是我正在使用的一个TypeScript框架,它能极大地简化构建复杂AI智能体(比如我们的RAG聊天机器人)的过程。该框架处理了大量样板代码,让我能够专注于智能体的核心逻辑,包括它们如何检索和使用信息。
VoltAgent的检索系统
VoltAgent 通过其检索器系统提供了一种简化的 RAG 实现方式。其核心组件是 BaseRetriever 抽象类(您可以在 @voltagent/core 中找到它)。要为您的智能体添加 RAG 功能,本质上需要:
-
创建自定义检索器:继承BaseRetriever并实现retrieve方法。该方法包含根据用户输入从选定数据源获取相关数据的逻辑。
-
连接到代理:VoltAgent 提供了两种主要方式实现此功能,具体操作详见 :
-
直接挂载(agent.retriever):检索器在该智能体的每次LLM调用前自动运行。方案简单,能确保始终获取上下文。
-
作为工具(agent.tools):LLM根据对话内容决定何时调用检索工具。这种方式更为高效灵活,尤其在不总是需要检索的情况下。
在本教程中,为简化操作,我们将采用直接附加法。我们的智能体在回答前会始终尝试从其小型知识库中获取上下文信息。
构建简易RAG聊天机器人
好的,理论固然重要,但实践出真知。下面我将演示如何用VoltAgent构建一个基础的RAG聊天机器人,它能基于一组硬编码的、关于VoltAgent本身的事实来回答问题。
项目搭建
启动新的VoltAgent项目最简单的方法是使用create-voltagent-app命令行工具。在这个示例中,我们将项目命名为with-rag-chatbot。打开终端并运行:
npm create voltagent-app@latest with-rag-chatbot
该命令将引导您完成安装流程。(如需了解CLI使用或手动配置的更多详情,请查阅)。
安装完成后,请进入新创建的项目目录:
cd with-rag-chatbot
CLI 会为你设置一个标准的项目结构:
with-rag-chatbot/
├── src/
│ └── index.ts # Our main agent logic will go here
├── package.json # Project dependencies
├── tsconfig.json # TypeScript config
├── .gitignore # Git ignore rules
└── .env # API keys (important!) - created automatically or you add it
生成的 package.json 将类似于以下内容(尽管版本号可能略有差异):
package.json (Example)
// ... (scripts, name: "with-rag-chatbot", etc.)
"dependencies": {
"@ai-sdk/openai": "...", // Or your chosen LLM SDK
"@voltagent/core": "...",
"@voltagent/vercel-ai": "...", // Or your chosen provider
"zod": "..."
},
// ... (devDependencies)
现在,让我们聚焦于 src/index.ts 中的代码实现。
实现检索器与智能体
这里是魔法发生的地方。在 src/index.ts 中,我定义了一个简单的检索器和一个使用它的智能体。
//src/index.ts
import { VoltAgent, Agent, BaseRetriever, type BaseMessage } from "@voltagent/core";
import { VercelAIProvider } from "@voltagent/vercel-ai";
import { openai } from "@ai-sdk/openai";
// --- Simple Knowledge Base Retriever ---
class KnowledgeBaseRetriever extends BaseRetriever {
// Our tiny "knowledge base"
private documents = [
{
id: "doc1",
content: "What is VoltAgent? VoltAgent is a TypeScript framework for building AI agents.",
},
{
id: "doc2",
content:
"What features does VoltAgent support? VoltAgent supports tools, memory, sub-agents, and retrievers for RAG.",
},
{ id: "doc3", content: "What is RAG? RAG stands for Retrieval-Augmented Generation." },
{
id: "doc4",
content:
"How can I test my agent? You can test VoltAgent agents using the VoltAgent Console.",
},
];
// Reverting to simple retrieve logic
async retrieve(input: string | BaseMessage[]): Promise<string> {
const query = typeof input === "string" ? input : (input[input.length - 1].content as string);
const queryLower = query.toLowerCase();
console.log(`[KnowledgeBaseRetriever] Searching for context related to: "${query}"`);
// Simple includes check
const relevantDocs = this.documents.filter((doc) =>
doc.content.toLowerCase().includes(queryLower)
);
if (relevantDocs.length > 0) {
const contextString = relevantDocs.map((doc) => `- ${doc.content}`).join("\n");
console.log(`[KnowledgeBaseRetriever] Found context:\n${contextString}`);
return `Relevant Information Found:\n${contextString}`;
}
console.log("[KnowledgeBaseRetriever] No relevant context found.");
return "No relevant information found in the knowledge base.";
}
}
// --- Agent Definition ---
// Instantiate the retriever
const knowledgeRetriever = new KnowledgeBaseRetriever();
// Define the agent that uses the retriever directly
const ragAgent = new Agent({
name: "RAG Chatbot",
description: "A chatbot that answers questions based on its internal knowledge base.",
llm: new VercelAIProvider(), // Using Vercel AI SDK Provider
model: openai("gpt-4o-mini"), // Using OpenAI model via Vercel
// Attach the retriever directly
retriever: knowledgeRetriever,
});
// --- VoltAgent Initialization ---
new VoltAgent({
agents: {
// Make the agent available under the key 'ragAgent'
ragAgent,
},
});
代码解析:
-KnowledgeBaseRetriever(知识库检索器):继承自BaseRetriever。它维护一个小型文档数组。其retrieve方法执行简单的非区分大小写搜索。若找到匹配项,则将其格式化为以"找到相关信息:"为前缀的字符串;否则返回"未找到"提示信息。
- ragAgent: 一个代理实例。
我们为其命名并添加描述。
我们配置LLM提供商及模型。
关键在于设置retriever: knowledgeRetriever。这指示VoltAgent在调用LLM前自动运行检索器。
此处的systemPrompt至关重要。它明确要求LLM仅基于"检索到的相关信息"(由检索器提供)作答,并规定未找到信息时的处理方式。这能有效防止LLM回退到通用知识库作答。
- new VoltAgent(…): 初始化VoltAgent服务器并注册我们的ragAgent。
运行智能体
运行前,您需要为您选择的LLM提供商(例如OpenAI)获取API密钥。
-
创建 .env 文件:在您的 with-rag-chatbot 项目根目录下,创建一个名为 .env 的文件。
-
添加API密钥:按以下方式添加您的密钥:
bash title=“.env”
OPENAI_API_KEY=your_openai_api_key_here
(将your_openai_api_key_here替换为您的实际密钥)。
- 安装依赖项:在 with-rag-chatbot 目录内打开终端并运行:
npm install
- 启动代理:运行开发服务器:
npm run dev
您应该能看到VoltAgent服务器的启动消息,其中包含指向开发者控制台的链接:
══════════════════════════════════════════════════
VOLTAGENT SERVER STARTED SUCCESSFULLY
══════════════════════════════════════════════════
✓ HTTP Server: http://localhost:3141
Developer Console: https://console.voltagent.dev
══════════════════════════════════════════════════
在控制台中进行测试
现在开始有趣的部分!
-
打开控制台:在浏览器中访问 https://console.voltagent.dev。
-
查找代理:您应该能看到列出的“RAG聊天机器人”,点击它。
-
聊天:点击聊天图标(通常位于右下角)以打开聊天窗口。
-
提问环节:尝试向我们检索器中的文档提出相关问题:
-
什么是VoltAgent?(应参考doc1)
-
VoltAgent 支持哪些功能?(应使用 doc2)
-
如何测试我的代理?(应使用 doc4)
-
法国的首都是哪里?(根据系统提示及缺乏相关文档,应说明无法基于现有知识库回答此问题。)
观察响应内容。它们应直接基于我们提供的文档数组中的内容!你也可以查看运行npm run dev
的终端——那里会显示来自KnowledgeBaseRetriever的日志,展示每个查询找到的相关上下文(如果有的话)。
结论
如您所见,使用VoltAgent实现基础RAG系统相当简单。通过创建自定义的BaseRetriever并将其附加到Agent,我就能快速构建一个基于特定外部知识的聊天机器人。
这个简单示例使用了硬编码数据,但您可以轻松调整KnowledgeBaseRetriever,使其从真实数据库、API或向量存储中获取数据,从而实现更强大的应用。RAG技术为创建更智能、知识更丰富的AI智能体开辟了许多可能性,而我认为VoltAgent让入门变得格外便捷。