摘要
本文介绍了 Spring AI。在 LLM 驱动的应用中,向量数据库是关键存储技术,此前 Spring 结合 Redis 构建 AI 应用选择少,Spring 社区推出 Spring AI 项目来简化开发。检索增强生成(RAG)技术可结合数据与 AI 模型,文中以啤酒数据集为例,详述如何将数据加载进 Redis 实现 RAG 工作流。其代码在 GitHub,依赖 Spring Boot、Azure OpenAI 等,还介绍了负责数据加载、实现 RAG 流程、封装 HTTP 端点的相关类,以及 React 前端与 Spring 后端交互,让 Java 开发者构建 AI 应用更便捷。
一、Spring AI简介
由大型语言模型(LLM)驱动的应用程序中,向量数据库常作为人工智能应用程序的核心存储技术。此类数据库需要支持语义搜索,并为LLM提供相关的上下文环境。
在此之前,通过Spring和Redis来构建人工智能应用程序的选项还相对有限。而最近,Redis作为一种高性能的向量数据库方案,现已引起广泛关注。Spring社区推出了一个名为Spring AI的新项目,旨在简化人工智能应用程序特别是那些涉及向量数据库的应用的开发流程。
下面将介绍如何使用Redis作为向量数据库构建一个Spring AI应用程序,实现检索增强生成(RAG)工作流。
二、检索增强生成
检索增强生成(RAG)是一种结合数据与人工智能模型的技术方法。在RAG工作流中,首先需要将数据加载入向量数据库(例如Redis)。接收到用户查询后,向量数据库会检索出一组与查询相似的文档。这些文档将作为解答用户问题的上下文,并结合用户的查询,通常通过人工智能模型来生成响应。
本例中,我们将利用一个包含各类啤酒信息的数据集进行演示,数据集中包含啤酒的名称、酒精含量(ABV)、国际苦味单位(IBU)和描述等属性。该数据集将被加载到Redis中,以展示RAG工作流的实际应用。
三、代码和依赖关系
可以在GitHub上找到Spring AI和Redis演示的全部代码。
本项目使用了Spring Boot作为Web应用程序的启动依赖项,并结合了Azure OpenAI和Spring AI Redis。
四、数据加载
我们的应用程序将采用提供啤酒信息的JSON文档作为数据来源。每个文档的结构如下:
{
"id": "00gkb9",
"name": "Smoked Porter Ale",
"description": "The Porter Pounder Smoked Porter is a dark rich flavored ale that is made with 5 malts that include smoked and chocolate roasted malts. It has coffee and mocha notes that create a long finish that ends clean with the use of just a bit of dry hopping",
"abv": 8,
"ibu": 36
}
为了将啤酒数据集加载到 Redis 中,我们将使用 RagDataLoader 类。该类包含一个方法,在应用程序启动时执行。在该方法中,我们使用一个 JsonReader 来解析数据集,然后使用自动连接的 VectorStore 将文档插入 Redis。
// Create a JSON reader with fields relevant to our use case
JsonReader loader = new JsonReader(file, "name", "abv", "ibu", "description");
// Use the autowired VectorStore to insert the documents into Redis
vectorStore.add(loader.get());
至此,我们得到了一个包含约 22,000 种啤酒及其相应嵌入的数据集。
五、RAG Service
RagService 类实现了 RAG 工作流程。当收到用户提示时,会调用 retrieve 方法,执行以下步骤:
- 计算用户提示的向量
- 查询 Redis 数据库,检索最相关的文档
- 使用检索到的文档和用户提示构建一个提示信息
- 使用提示调用聊天客户端以生成响应
public Generation retrieve(String message) {
SearchRequest request = SearchRequest.query(message).withTopK(topK);
// Query Redis for the top K documents most relevant to the input message
List<Document> docs = store.similaritySearch(request);
Message systemMessage = getSystemMessage(docs);
UserMessage userMessage = new UserMessage(message);
// Assemble the complete prompt using a template
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
// Call the autowired chat client with the prompt
ChatResponse response = client.call(prompt);
return response.getResult();
}
六、Controller
现在我们已经实现了 RAG 服务,可以将其封装在 HTTP 端点中。
RagController 类将服务作为 POST 端点公开:
@PostMapping("/chat/{chatId}")
@ResponseBody
public Message chatMessage(@PathVariable("chatId") String chatId, @RequestBody Prompt prompt) {
// Extract the user prompt from the body and pass it to the autowired RagService
Generation generation = ragService.retrieve(prompt.getPrompt());
// Reply with the generated message
return Message.of(generation.getOutput().getContent());
}
七、用户界面
在用户界面方面,创建一个简单的 React 前端,允许用户提出有关啤酒的问题。前端通过向 /chat/{chatId} 端点发送 HTTP 请求并显示响应来与 Spring 后端交互。

仅通过简单的几个类,我们就用 Spring AI 和 Redis 实现了一个 RAG 应用程序。
若要更进一步,我们建议您查看 Github 上的示例代码。将 Redis 的高效和易用性与 Spring AI 提供的便捷抽象相结合,Java 开发人员使用 Spring 构建响应式 AI 应用程序将变得更加容易。
有关向量数据库的更多信息,欢迎与我们沟通交流~