LangChain4j开发RAG入门示例

news2025/3/10 16:24:13

本文将详细介绍如何基于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密钥,以便在后续代码中调用。具体的开通与配置步骤,请参阅阿里云大模型服务平台“百炼”的相关文档和指南如何获取API Key_大模型服务平台百炼(Model Studio)-阿里云帮助中心。这样可以确保您能够顺利地集成和使用这些先进的AI资源。
  • 提前安装部署好Milvus数据库,本文示例使用的Milvus2.5.4版本

2、创建springboot工程

本示例的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、dashscopetika相关Jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.0</version>
    </parent>

    <groupId>com.yuncheng</groupId>
    <artifactId>langchain4j-rag-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <langchain4j.version>1.0.0-beta1</langchain4j.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
            <version>${langchain4j.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-milvus</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-document-parser-apache-tika</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
        
    </dependencies>
</project>

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<TextSegment> embeddingStore;
    @Resource
    private ChatMemoryStore chatmemoryStore;

    /**
     * RAG主要实现逻辑
     * @param chatId 对话ID
     * @param message 用户提问的内容
     * @return 返回检索增强生成的内容
     */
    public Flux<String> chatStream(String chatId,String message) {

        AiServices<Customer> 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<TextSegment> segments = splitter.split(document);
                log.info("对文档的切片数量为:"+segments.size());
                List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
                embeddingStore.addAll(embeddings, segments);
                log.info("===================导入文档到向量数据库完成");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

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

该文档的在线地址为:https://yunchengxc.yuque.com/staff-kxgs7i/sxhe93/nx1vu6ygryv2bu7f

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<String> 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<String> 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()方法完成的。

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

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

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

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

9.3、RAG检索增强生成测试

浏览器中输入:

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

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

10、RAG执行原理

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

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

11、结束语

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

Langchain4j官方文档:https://docs.langchain4j.dev/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速从C过度C++(一):namespace,C++的输入和输出,缺省参数,函数重载

&#x1f4dd;前言&#xff1a; 本文章适合有一定C语言编程基础的读者浏览&#xff0c;主要介绍从C语言到C过度&#xff0c;我们首先要掌握的一些基础知识&#xff0c;以便于我们快速进入C的学习&#xff0c;为后面的学习打下基础。 这篇文章的主要内容有&#xff1a; 1&#x…

课程《Deep Learning Specialization》

在coursera上&#xff0c;Deep Learning Specialization 课程内容如下图所示&#xff1a;

微服务与消息队列RabbitMQ

简介 同步模式 异步模式 内容 解决方案RabbitMQ 同步调用的优缺点 同步调用的优势是什么&#xff1f; 时效性强&#xff0c;等待到结果后才返回。 同步调用的问题是什么&#xff1f; 拓展性差性能下降级联失败问题

苹果 M3 Ultra 芯片深度解析:AI 时代的性能革命

2025 年 3 月 5 日&#xff0c;苹果正式发布了其史上最强 PC 芯片 ——M3 Ultra。这款基于 UltraFusion 封装技术的旗舰级 SoC&#xff0c;不仅延续了苹果芯片在能效比上的传统优势&#xff0c;更通过架构创新与硬件升级&#xff0c;将 AI 计算能力推向了新高度。本文将从性能突…

通义千问:Qwen2.5-0.5B模型架构解释

通义千问:Qwen2.5-0.5B模型架构解释 1. 模型权重文件 .mdl、.msc:存储模型核心参数,是模型训练后学习到的知识载体,包含神经网络各层权重,加载后模型才能执行推理、生成等任务。 .mdl文件:通常是模型的核心权重数据文件,存储神经网络各层的权重参数、张量等关键数据,是…

【Linux】冯诺依曼体系与操作系统理解

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、冯诺依曼体系结构 二、操作系统 1. 操作系统的概念 2. 操作系统存在的意义 3. 操作系统的管理方式 4. 补充&#xff1a;理解系统调用…

玩转ChatGPT:GPT 深入研究功能

一、写在前面 民间总结&#xff1a; 理科看Claude 3.7 Sonnet 文科看DeepSeek-R1 那么&#xff0c;ChatGPT呢&#xff1f; 看Deep Research&#xff08;深入研究&#xff09;功能。 对于科研狗来说&#xff0c;在这个文章爆炸的时代&#xff0c;如何利用AI准确、高效地收…

虚函数和虚表的原理是什么?

虚函数是一个使用virtual关键字声明的成员函数&#xff0c;在基类中声明虚函数&#xff0c;在子类中可以使用override重写该函数。虚函数根据指针或引用指向的实际对象调用&#xff0c;实现运行时的多态。 虚函数表&#xff08;虚表&#xff09;是一个用于存储虚函数地址的数组…

laravel es 相关代码 ElasticSearch

来源&#xff1a; github <?phpnamespace App\Http\Controllers;use Elastic\Elasticsearch\ClientBuilder; use Illuminate\Support\Facades\DB;class ElasticSearch extends Controller {public $client null;public function __construct(){$this->client ClientB…

字节跳动C++客户端开发实习生内推-抖音基础技术

智能手机爱好者和使用者&#xff0c;追求良好的用户体验&#xff1b; 具有良好的编程习惯&#xff0c;代码结构清晰&#xff0c;命名规范&#xff1b; 熟练掌握数据结构与算法、计算机网络、操作系统、编译原理等课程&#xff1b; 熟练掌握C/C/OC/Swift一种或多种语言&#xff…

C语言_数据结构总结6:链式栈

纯c语言代码&#xff0c;不涉及C 顺序栈的实现&#xff0c;欢迎查看这篇文章&#xff1a;C语言_数据结构总结5&#xff1a;顺序栈-CSDN博客 0. 结构单元 #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct Linknode { ElemType…

基于DeepSeek的智慧医药系统(源码+部署教程)

运行环境 智慧医药系统运行环境如下&#xff1a; 前端&#xff1a; HTMLCSS后端&#xff1a;Java AIGCDeepseekIDE工具&#xff1a;IDEA技术栈&#xff1a;Springboot HTMLCSS MySQL 主要角色 智慧医药系统主要分为两个角色。 游客 尚未进行注册和登录。具备登录注册、…

信奥赛CSP-J复赛集训(模拟算法专题)(6):P6352 [COCI 2007/2008 #3] CETIRI

信奥赛CSP-J复赛集训&#xff08;模拟算法专题&#xff09;&#xff08;6&#xff09;&#xff1a;P6352 [COCI 2007/2008 #3] CETIRI 题目描述 你原本有 4 4 4 个数&#xff0c;它们从小到大排序后构成了等差数列。 但是现在丢失了一个数&#xff0c;并且其余的三个数的顺序…

2025-03-09 学习记录--C/C++-PTA 习题11-1 输出月份英文名

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h>char *getmonth( int n );int main() {int n;char …

linux环保监测4G边缘网关:环境数据的可靠传输者

环保监测工控机&#xff0c;常被称为“环境数据采集器”或“环保数据终端”&#xff0c;是一种专门用于环境监测领域的工业计算机。它具备强大的数据处理能力、稳定的运行性能和多种接口&#xff0c;能够实时采集、处理和传输环境监测数据。这些数据包括空气质量、水质、噪声、…

【哇! C++】类和对象(五) - 赋值运算符重载

目录 ​编辑 一、运算符重载 1.1 运算符重载概念 1.2 全局运算符重载 1.3 运算符重载为成员函数 二、赋值运算符重载的特性 2.1 赋值运算符重载需要注意的点 2.2 赋值运算符重载格式 2.2.1 传值返回 2.2.2 传引用返回 2.2.3 检查自己给自己赋值 三、赋值运算符重载的…

Linux一键安装zsh终端美化插件

zsh应该是很多人第一个用的Linux终端美化软件 但是其安装略微复杂&#xff0c;让人有些困扰 所以我花了两天写了一键安装脚本&#xff0c;实测运行后直接安装好 适用于Ubuntu、Debian、Red Hat、macOS等系统 直接安装好zsh 以及常用插件 autojump 跳转插件 zsh-syntax-highlig…

前端数据模拟 Mock.js 学习笔记(附带详细)

前端数据模拟 Mock.js 学习笔记 在前端开发过程中&#xff0c;数据模拟是一项至关重要的环节。当后端接口尚未完成或者需要独立进行前端开发与测试时&#xff0c;Mock.js 能发挥巨大作用&#xff0c;它可以模拟各种数据场景&#xff0c;助力前端开发高效进行。 一、Mock.js 的…

Web基础:HTML快速入门

HTML基础语法 HTML&#xff08;超文本标记语言&#xff09; 是用于创建网页内容的 标记语言&#xff0c;通过定义页面的 结构和内容 来告诉浏览器如何呈现网页。 超文本&#xff08;Hypertext&#xff09; 是一种通过 链接&#xff08;Hyperlinks&#xff09; 将不同文本、图像…

如何应用大模型 — 大模型使用范式

从OpenAI发布ChatGPT开始&#xff0c;大模型就开始受到大家关注&#xff0c;到DeepSeek-R1出现&#xff0c;大家的关注达到了顶峰&#xff0c;越来越多的企业&#xff0c;机构&#xff0c;学校&#xff0c;政府部门希望接入大模型&#xff0c;希望通过大模型来提升效率&#xf…