LangChain4j开发RAG入门示例

23 阅读5分钟

本文将详细介绍如何基于Java语言,使用Langchain4j开源框架、Milvus向量数据、阿里Qwen大模型,开发一个RAG入门级简单示例。本示例虽然简单,但涉及到多个知识点,包括:Milvus初始化、Embedding模型、文档切片、Springboot集成Langchain4j、Langchain4j调用Qwen大模型等。

1、前提条件

  • JDK为17以上版本,本人使用的jdk21版本;
  • SpringBoot版本为3.x以上,本项目使用的是SpringBoot 3.4.0版本;
  • 本文采用了阿里巴巴的Qwen大模型进行实验与验证,但您同样可以选择使用DeepSeek大模型作为替代方案。若选用阿里巴巴的AI服务,则需首先在阿里云平台上开通相应的大型模型服务,并获取所需的API密钥,以便在后续代码中调用。
  • 提前安装部署好Milvus数据库,本文示例使用的Milvus2.5.4版本

2、创建springboot工程

本示例的springboot工程结构如下:

00-springboot工程结构

其中,Langchain4jRagApplication启动类代码如下:

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.core.env.Environment;

@SpringBootApplication

public class Langchain4jRagApplication {

private static final Logger log = LoggerFactory.getLogger(Langchain4jRagApplication.class);

public static void main(String[] args) {

ConfigurableApplicationContext application = SpringApplication.run(Langchain4jRagApplication.class, args);

Environment env = application.getEnvironment();

String port = env.getProperty("server.port");

log.info("Application启动成功,服务端口为:" + port);

}

}

3、添加maven依赖

创建springboot工程后,在pom.xml文件里引入langchain4j、milvus、dashscope、tika相关Jar包。

\ 4.0.0\ \ org.springframework.boot\ spring-boot-starter-parent\ 3.4.0\

com.yuncheng\ langchain4j-rag-demo\ 1.0-SNAPSHOT

21 21 UTF-8 1.0.0-beta1 org.springframework.boot spring-boot-starter-webflux dev.langchain4j langchain4j-spring-boot-starter ${langchain4j.version} dev.langchain4j langchain4j-community-dashscope-spring-boot-starter ${langchain4j.version} org.slf4j slf4j-simple dev.langchain4j langchain4j-milvus ${langchain4j.version} dev.langchain4j langchain4j-document-parser-apache-tika ${langchain4j.version} dev.langchain4j langchain4j-reactor ${langchain4j.version}

4、配置yml文件

#配置milvus向量数据库的IP和端口、模型名称、api-key

server:

port: 8099

milvus:

host: 192.168.3.17

port: 19530

langchain4j:

community:

dashscope:

chat-model:

model-name: qwen-plus

api-key: sk-4d6e6db446014411ad92c0e8fa143964

streaming-chat-model:

model-name: qwen-plus

api-key: sk-4d6e6db446014411ad92c0e8fa143964

embedding-model:

api-key: sk-4d6e6db446014411ad92c0e8fa143964

model-name: text-embedding-v2

5、创建EmbeddingStore

以下源代码定义了一个Spring自动装配类 RagConfig ,用于初始化创建ChatMemoryStore 对象和基于Milvus向量数据库的EmbeddingStore对象。

import dev.langchain4j.store.embedding.EmbeddingStore;

import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;

import dev.langchain4j.store.memory.chat.ChatMemoryStore;

import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;

import io.milvus.common.clientenum.ConsistencyLevelEnum;

import io.milvus.param.IndexType;

import io.milvus.param.MetricType;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class RagConfig {

private static final Logger log = LoggerFactory.getLogger(RagConfig.class);

@Value("${milvus.host}")

private String host;

@Value("${milvus.port}")

private Integer port;

 

@Bean

public ChatMemoryStore chatMemoryStore() {

log.info("==========初始化ChatMemoryStore");

return new InMemoryChatMemoryStore();

}

@Bean

public EmbeddingStore createEmbeddingStore() {

log.info("==========开始创建Milvus的Collection");

MilvusEmbeddingStore store = MilvusEmbeddingStore.builder()

.host(host)

.port(port)

.collectionName("langchain_01")

.dimension(1536)

.indexType(IndexType.FLAT)

.metricType(MetricType.COSINE)

// .username("username")

// .password("password")

.consistencyLevel(ConsistencyLevelEnum.EVENTUALLY)

.autoFlushOnInsert(true)

.idFieldName("id")

.textFieldName("text")

.metadataFieldName("metadata")

.vectorFieldName("vector")

.build();

log.info("==========创建Milvus的Collection完成");

return store;

}

}

6、创建RagService

这个类RAG逻辑实现的核心类,用于处理文档向量存储,以及RAG过程。

import dev.langchain4j.data.document.Document;

import dev.langchain4j.data.document.DocumentSplitter;

import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;

import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;

import dev.langchain4j.data.document.splitter.DocumentByParagraphSplitter;

import dev.langchain4j.data.embedding.Embedding;

import dev.langchain4j.data.segment.TextSegment;

import dev.langchain4j.memory.chat.MessageWindowChatMemory;

import dev.langchain4j.model.chat.ChatLanguageModel;

import dev.langchain4j.model.chat.StreamingChatLanguageModel;

import dev.langchain4j.model.embedding.EmbeddingModel;

import dev.langchain4j.rag.DefaultRetrievalAugmentor;

import dev.langchain4j.rag.content.retriever.ContentRetriever;

import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;

import dev.langchain4j.rag.query.transformer.CompressingQueryTransformer;

import dev.langchain4j.rag.query.transformer.QueryTransformer;

import dev.langchain4j.service.AiServices;

import dev.langchain4j.store.embedding.EmbeddingStore;

import dev.langchain4j.store.memory.chat.ChatMemoryStore;

import jakarta.annotation.Resource;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.core.io.support.ResourcePatternResolver;

import org.springframework.stereotype.Service;

import reactor.core.publisher.Flux;

import java.io.File;

import java.util.List;

@Service

public class RagService {

private static final Logger log = LoggerFactory.getLogger(RagService.class);

private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

@Resource

private StreamingChatLanguageModel streamingChatLanguageModel;

@Resource

private ChatLanguageModel chatLanguageModel;

@Resource

private EmbeddingModel embeddingModel;

@Resource

private EmbeddingStore embeddingStore;

@Resource

private ChatMemoryStore chatmemoryStore;

/**

  • RAG主要实现逻辑

  • @param chatId 对话ID

  • @param message 用户提问的内容

  • @return 返回检索增强生成的内容

*/

public Flux chatStream(String chatId,String message) {

AiServices aiServices = AiServices.builder(Customer.class)

.chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder()

.id(chatId)

.chatMemoryStore(chatmemoryStore)

.maxMessages(50)

.build());

aiServices.streamingChatLanguageModel(streamingChatLanguageModel);

aiServices.chatLanguageModel(chatLanguageModel);

// 先进行知识库检索

ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()

.embeddingModel(embeddingModel)

.embeddingStore(embeddingStore)

.maxResults(10)

.minScore(0.5)

.build();

//将用户的查询和前面的对话压缩到一个独立的查询中。可以显著提高检索质量。

QueryTransformer queryTransformer = new CompressingQueryTransformer(chatLanguageModel);

//检索增强生成

aiServices.retrievalAugmentor(DefaultRetrievalAugmentor

.builder()

.queryTransformer(queryTransformer)

.contentRetriever(contentRetriever)

.build());

Customer customer = aiServices.build();

return customer.stream(chatId, message);

}

/**

  • 解析文档、切片、embedding、并保存到向量数据库

*/

public void importDocuments(){

try {

log.info("===================开始导入文档到向量数据库");

org.springframework.core.io.Resource[] resourceList = resourcePatternResolver.getResources("classpath:documents/*");

for (org.springframework.core.io.Resource resource : resourceList) {

File file = resource.getFile();

log.info("导入文档的名称为:"+file.getName());

Document document = FileSystemDocumentLoader.loadDocument(file.getAbsolutePath(), new ApacheTikaDocumentParser());

document.metadata().put("docsName", file.getName());

DocumentSplitter splitter = new DocumentByParagraphSplitter(1000,0);

List segments = splitter.split(document);

log.info("对文档的切片数量为:"+segments.size());

List embeddings = embeddingModel.embedAll(segments).content();

embeddingStore.addAll(embeddings, segments);

log.info("===================导入文档到向量数据库完成");

}

}catch (Exception e){

e.printStackTrace();

}

}

}

注意:在本示例中,Spring Boot工程的 resources/documents/目录下放置了一个名为“云程低代码平台介绍.docx”文件。该文件将被读取、切片、embedding、向量存储,并基于该文件验证检索增强生成(RAG)。

7、创建Customer

import dev.langchain4j.service.MemoryId;

import dev.langchain4j.service.SystemMessage;

import dev.langchain4j.service.UserMessage;

import reactor.core.publisher.Flux;

public interface Customer {

@SystemMessage("""

你是云程低代码平台客服人员,请你友好、礼貌、简洁回答客户的问题。

你只回答与云程低代码平台相关问题,如果是其它问题,请礼貌拒绝。

""")

Flux stream(@MemoryId String id, @UserMessage String message);

}

其中,系统提示词通过@SystemMessage注释注入。

8、创建RagController

import jakarta.annotation.Resource;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;

@RestController

@RequestMapping("/rag")

public class RagController {

@Resource

private RagService chatService;

@GetMapping(value = "/dbinit")

public String dbInit() {

chatService.importDocuments();

return "OK";

}

@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

public Flux chatStream(@RequestParam(value = "chatId",required = false,defaultValue = "1") String chatId,@RequestParam(value = "message") String message) {

return chatService.chatStream(chatId, message);

}

}

该类中有2个方法,可以通过http调用,一个是初始化向量库方法dbInit,一个是chat对话方法chatStream。

9、验证测试RAG效果

9.1、在Milvus中创建Collection

以上代码编写完成后,启动springboot工程,启动时会在Milvus数据库中自动创建
langchain_01的collection,创建向量表的逻辑是由RagConfig类的createEmbeddingStore()方法完成的。

01-向量表创建

9.2、导入本地word文档到向量库

浏览器中输入:http://localhost:8099/rag/dbinit

执行成功后,也可以通过Milvus自带的webui工具查看。

02-插入数据

说明该文档被划分为2个切片,进行了向量化存储。

9.3、RAG检索增强生成测试

浏览器中输入:

http://localhost:8099/rag/chat?message=云程低代码平台移动端采用什么技术开发

我们期望检索增强生成(RAG)系统能够返回与上传文档语义相关内容,并提供最优结果。通过这一过程,可以验证RAG是否对本地知识库进行相似度检索,最后调用大语言模型输出内容,跟预期内容是否一致。

10、RAG执行原理

RAG 通过结合检索技术和生成模型的强大能力,使智能体能够实时从外部数据源获取信息,并在生成过程中增强其知识深度和推理能力。

03-RAG原理

如上图所示,总体上 RAG 是分为离线和运行时两部分。离线部分是将一些领域特有数据进行向量化的过程,将向量化的数据存入向量数据库。图中后半部分体现的运行时流程,Langchain4j框架在组装 prompt 时,会优先检索向量数据库,连同用户的原始问题组合到一起给到大模型,大模型根据用户问题、上下文以及自己的推理生成响应。

11、结束语

通过本文的详细讲解和实践示例,我们成功展示了如何使用Springboot工程、Langchain4j开源框架、Milvus向量数据、阿里Qwen大模型,搭建一个基于AI大模型的本地知识库系统,实现检索增强生成(RAG)。