欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

LangChain4j实战全系列链接

  1. 准备工作
  2. 极速开发体验
  3. 细说聊天API
  4. 集成到spring-boot
  5. 图像模型
  6. 聊天记忆,低级API版
  7. 聊天记忆,高级API版
  8. 响应流式传输
  9. 高级API(AI Services)实例的创建方式
  10. 结构化输出之一,用提示词指定输出格式
  11. 结构化输出之二,function call
  12. 结构化输出之三,json模式
  13. 函数调用,低级API版本
  14. 函数调用,低级API版本
  15. RAG (检索增强生成),Easy RAG

关于RAG(检索增强生成)

  • 简单来说,RAG 是一种在发送给 LLM 之前,从你提供的数据中找到并注入相关信息片段到提示词中的方法,如果您看过前面函数调用的文章就很容易理解了,函数调用是把本地函数的结果给LLM,而RAG是基于本地资料搜索一些结果给LLM
  • RAG 过程分为两个不同的阶段:索引和检索。 LangChain4j 为这两个阶段提供了工具
  • 对于向量搜索,索引阶段涉及到文档分割和存储,以下是索引阶段的简化图表

在这里插入图片描述

  • 当用户提交一个应该使用索引文档回答的问题时触发检索逻辑,对于向量搜索,这通常涉及嵌入用户的查询(问题) 并在嵌入存储中执行相似度搜索。 然后将相关片段(原始文档的片段)注入到提示中并发送给 LLM
  • 以下是检索阶段的简化图表
    在这里插入图片描述
  • 涉及到的核心概念整理如下,希望能加速您的理解
    在这里插入图片描述

LangChain4j对RAG的支持

  • LangChain4j提供了三种方式来支持RAG
  1. Easy RAG:开始使用 RAG 的最简单方式,细节被LangChain4j封装
  2. Naive RAG:使用向量搜索的基本 RAG 实现
  3. Advanced RAG:一个模块化的 RAG 框架,允许额外的步骤,如 查询转换、从多个来源检索和重新排序
  • 上述内容都会逐个实战学习,又是一次深度之旅,不过LangChain4j的大部分核心知识点咱们都已经掌握了,胜利的曙光已经不远啦

本篇概览

  • 本篇从最简单的开始学习,也就是Easy RAG
  • 使用Easy RAG无需了解嵌入、向量存储、嵌入模型、 解析分割等等RAG的重要功能点,只需指向文档所在目录,其他复杂的事情都交给LangChain4j来完成即可,所以本篇只需要写少量代码就能完成
  • Easy RAG有三个关键点,如下
  1. 加载文本、分割段落、转为向量、存储向量
  2. 创建向量查询服务类,并关联步骤1存储的向量
  3. 把向量查询服务类绑定到高级API服务,这样对话的时候就会执行RAG
  • 这里再给出一次用户提问的完整时序图
LLM (OpenAI) EmbeddingStore (InMemory) EmbeddingModel (AllMiniLm) EasyRAG 自动装配 Assistant (@AiService) Controller (REST) 用户 LLM (OpenAI) EmbeddingStore (InMemory) EmbeddingModel (AllMiniLm) EasyRAG 自动装配 Assistant (@AiService) Controller (REST) 用户 GET /chat?q=Java谁发明的? 1 chat("Java谁发明的?") 2 1. 调用EasyRAG 3 2. 把问题→TextSegment 4 3. 生成embedding 5 4. 返回向量 6 5. 相似度搜索Top-K 7 6. 返回相关段落 8 7. 按模板拼成context 9 8. 带回增强后Prompt 10 9. 发送Prompt+context 11 10. 生成答案 12 11. 答案文本 13 12. 响应浏览器 14

准备工作

  • 体验RAG功能要用到本地文档,所以咱们要去找些能用的资料文档,我这里打算用维基百科的内容,您也可以按需要自己去准备
  • 完整纯文本维基百科的下载地址如下
https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles.xml.bz2
  • 执行以下命令,就把zhwiki-latest-pages-articles.xml.bz2能解压成三个文件wiki_00、wiki_01、wiki_02:,这三个文件内部其实已经是一份一份纯文本条目,只是被“合并”到同一个文件里而已
python3 -m wikiextractor.WikiExtractor \
       --no-templates \
       -b 1024M \
       -o zhwiki_txt \
       zhwiki-latest-pages-articles.xml.bz2
  • 上面的命令生成的文件大小是1G,如果您觉得太大,可以调整参数-b 1024M,让每个文件小一些,不过文件数量会变多
  • 这里要注意:上面得到的是完整维基百科内容,数据量太大,咱们接下来写的代码要想加载这些信息要消耗大量时间和电脑资源,这显然不是本篇的目标,所以我这里做了简化:只留一个文件,并把这个文件中的内容删掉大部分,最后这个文件只有141KB,如下图
    在这里插入图片描述
  • 准备完毕,开始编码吧

源码下载(觉得作者啰嗦的,直接在这里下载)

  • 如果您只想快速浏览完整源码,可以在GitHub下载代码直接运行,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在langchain4j-tutorials文件夹下,如下图红色箭头所示:
    在这里插入图片描述

编码:父工程调整

  • 《准备工作》中创建了整个《LangChain4j实战》系列代码的父工程,本篇实战会在父工程下新建一个子工程,所以这里要对父工程的pom.xml做少量修改
  1. modules中增加一个子工程,如下图黄框所示
    在这里插入图片描述

编码:新增子工程

  • 新增名为rag-easy的子工程
  1. langchain4j-totorials目录下新增名rag-easy为的文件夹
  2. rag-easy文件夹下新增pom.xml,内容如下
<?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>com.bolingcavalry</groupId>
        <artifactId>langchain4j-totorials</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    <!-- 配置编译编码 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    </properties>

    <artifactId>rag-easy</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- JUnit Jupiter Engine -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- Mockito Core -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- Mockito JUnit Jupiter -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- LangChain4j Core -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-core</artifactId>
        </dependency>
        
        <!-- LangChain4j OpenAI支持(用于通义千问的OpenAI兼容接口) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>

        <!-- 官方 langchain4j(包含 AiServices 等服务类) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-community-dashscope</artifactId>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-easy-rag</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Spring Boot Maven Plugin -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.3.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <jvmArguments>-Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8</jvmArguments>
                </configuration>
            </plugin>
            
            <!-- Maven Resources Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <propertiesEncoding>UTF-8</propertiesEncoding>
                </configuration>
            </plugin>
            
            <!-- Maven Compiler Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        
        <!-- 确保资源文件使用UTF-8编码 -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>
  1. langchain4j-totorials/rag-easy/src/main/resources新增配置文件application.properties,内容如下,主要是三个模型的配置信息,记得把your-api-key换成您自己的apikey,rag.file.path是存放本地文档的目录(就是前面维基百科那个文件)
# Spring Boot 应用配置
server.port=8080
server.servlet.context-path=/

# LangChain4j 使用OpenAI兼容模式配置通义千问模型
# 注意:请将your-api-key替换为您实际的通义千问API密钥
langchain4j.open-ai.chat-model.api-key=your-api-key
# 通义千问模型名称
langchain4j.open-ai.chat-model.model-name=qwen3-max
# 阿里云百炼OpenAI兼容接口地址
langchain4j.open-ai.chat-model.base-url=https://dashscope.aliyuncs.com/compatible-mode/v1

# 日志配置
logging.level.root=INFO
logging.level.com.bolingcavalry=DEBUG
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
# 日志编码配置,解决中文乱码问题
logging.charset.console=UTF-8
logging.charset.file=UTF-8
# 应用名称
spring.application.name=rag-easy

# rag文件路径
rag.file.path=/home/will/temp/202601/15/zhwiki_txt

  1. 新增启动类,依旧平平无奇
package com.bolingcavalry;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring Boot应用程序的主类
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  • 由于本篇是高级API,所以增加一个自定义接口用于对话
package com.bolingcavalry.service;

public interface Assistant {
    /**
     * 通过提示词range大模型返回JSON格式的内容
     * 
     * @param userMessage 用户消息
     * @return 助手生成的回答
     */
    String byRagEasy(String userMessage);
}
  • 接着是本篇的重点代码:配置类,有几处重点稍后会说明
package com.bolingcavalry.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.bolingcavalry.service.Assistant;

import dev.langchain4j.agent.tool.ToolExecutionRequest;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.model.chat.listener.ChatModelErrorContext;
import dev.langchain4j.model.chat.listener.ChatModelListener;
import dev.langchain4j.model.chat.listener.ChatModelRequestContext;
import dev.langchain4j.model.chat.listener.ChatModelResponseContext;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Configuration
public class LangChain4jConfig {

    private static final Logger logger = LoggerFactory.getLogger(LangChain4jConfig.class);

    @Value("${langchain4j.open-ai.chat-model.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.chat-model.model-name:qwen-turbo}")
    private String modelName;

    @Value("${langchain4j.open-ai.chat-model.base-url}")
    private String baseUrl;

    @Value("${rag.file.path}")
    private String ragFilePath;

    @Bean
    public OpenAiChatModel chatModel() {

        ChatModelListener listener = new ChatModelListener() {
            @Override
            public void onRequest(ChatModelRequestContext reqCtx) {
                // 1. 拿到 List<ChatMessage>
                List<ChatMessage> messages = reqCtx.chatRequest().messages();
                logger.info("发到LLM的请求: {}", messages);

            }

            @Override
            public void onResponse(ChatModelResponseContext respCtx) {
                // 2. 先取 ChatModelResponse
                ChatResponse response = respCtx.chatResponse();
                // 3. 再取 AiMessage
                AiMessage aiMessage = response.aiMessage();

                // 4. 工具调用
                List<ToolExecutionRequest> tools = aiMessage.toolExecutionRequests();
                for (ToolExecutionRequest t : tools) {
                    logger.info("LLM响应, 执行函数[{}], 函数入参 : {}", t.name(), t.arguments());
                }

                // 5. 纯文本
                if (aiMessage.text() != null) {
                    logger.info("LLM响应, 纯文本 : {}", aiMessage.text());
                }
            }

            @Override
            public void onError(ChatModelErrorContext errorCtx) {
                errorCtx.error().printStackTrace();
            }
        };

        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .modelName(modelName)
                .baseUrl(baseUrl)
                .listeners(List.of(listener))
                .build();
    }

    @Bean
    public Assistant assistant() {
        ContentRetriever contentRetriever = createContentRetriever(ragFilePath);
        return AiServices.builder(Assistant.class)
                .chatModel(chatModel())
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .contentRetriever(contentRetriever)
                .build();
    }

    private static ContentRetriever createContentRetriever(String ragFilePath) {
        // 向量数据存储的服务类,这里用的是内存存储,实际场景中可以用数据库或其他存储
        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        long start = System.currentTimeMillis();
        logger.info("开始加载索引文件:{}", ragFilePath);
        List<Document> documents = FileSystemDocumentLoader.loadDocuments(ragFilePath);
        logger.info("加载索引文件完成,耗时: {}秒, 文件数量: {}",
                (System.currentTimeMillis() - start) / 1000, documents.size());

        logger.info("开始索引RAG文件: {},共{}个文档", ragFilePath, documents.size());
        start = System.currentTimeMillis();

        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .embeddingStore(embeddingStore)
                .build();

        int totalDocuments = documents.size();

        // 逐个处理文档,添加进度日志
        for (int i = 0; i < totalDocuments; i++) {
            Document doc = documents.get(i);

            if (i % 10 == 0) {
                logger.info("处理进度: {}/{}", i + 1, totalDocuments);
            }

            ingestor.ingest(doc);
        }

        long end = System.currentTimeMillis();
        logger.info("所有文档索引完成,总耗时:{}秒", (end - start) / 1000);

        return EmbeddingStoreContentRetriever.from(embeddingStore);
    }
}
  • 配置类代码中的重点共有三个
  1. createContentRetriever方法,这里面先加载文件,然后用EmbeddingStoreIngestor.ingest完整向量存储,最后调用EmbeddingStoreContentRetriever.from创建了查询服务类
  2. 在创建高级API服务类的时候,通过调用contentRetriever方法把查询服务类绑定进来
  3. chatModel方法负责创建模型服务类,这里绑定了自定义监听器,使得和LLM的通信内容会通过日志打印出来
  • 其实以上代码就是今天的核心了,可见RAG的索引过程被LangChain4j封装好了,我们并未做太多处理

  • 接下来是服务类,按部就班调用自定义接口即可

package com.bolingcavalry.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 通义千问服务类,用于与通义千问模型进行交互
 */
@Service
public class QwenService {

    private static final Logger logger = LoggerFactory.getLogger(QwenService.class);

    @Autowired
    private Assistant assistant;

    /**
     * 通过提示词range大模型返回JSON格式的内容
     * 
     * @param prompt
     * @return
     */
    public String byRagEasy(String prompt) {
        String answer = assistant.byRagEasy(prompt);
        logger.info("响应:" + answer);
        return answer + "[from byRagEasy]";
    }
}

  • 最后是controller类,这里准备个http接口响应,用来调用前的服务类的功能
package com.bolingcavalry.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.bolingcavalry.service.QwenService;

import lombok.Data;

/**
 * 通义千问控制器,处理与大模型交互的HTTP请求
 */
@RestController
@RequestMapping("/api/qwen")
public class QwenController {

    private final QwenService qwenService;

    /**
     * 构造函数,通过依赖注入获取QwenService实例
     * 
     * @param qwenService QwenService实例
     */
    public QwenController(QwenService qwenService) {
        this.qwenService = qwenService;
    }

    /**
     * 提示词请求实体类
     */
    @Data
    static class PromptRequest {
        private String prompt;
        private int userId;
    }

    /**
     * 响应实体类
     */
    @Data
    static class Response {
        private String result;

        public Response(String result) {
            this.result = result;
        }
    }

    /**
     * 检查请求体是否有效
     * 
     * @param request 包含提示词的请求体
     * @return 如果有效则返回null,否则返回包含错误信息的ResponseEntity
     */
    private ResponseEntity<Response> check(PromptRequest request) {
        if (request == null || request.getPrompt() == null || request.getPrompt().trim().isEmpty()) {
            return ResponseEntity.badRequest().body(new Response("提示词不能为空"));
        }
        return null;
    }

    @PostMapping("/rag/easy")
    public ResponseEntity<Response> byRagEasy(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            String response = qwenService.byRagEasy(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }
}

  • 至此代码就全部写完了,现在把工程运行起来试试,在rag-easy目录下执行以下命令即可启动服务
mvn spring-boot:run
  • 启动日志如下,可见索引过程是很耗时的,500多行的内容用了25秒,要是用完整维基百科来索引其耗时应该难以接受(真要是索引全部维基百科,就必须用单独的服务将向量数据做持续化存储,而非启动时在内存中存储)
12:33:54.474 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 874 ms
12:33:54.526 [main] INFO  c.b.config.LangChain4jConfig - 开始加载索引文件:/home/will/temp/202601/15/zhwiki_txt
12:33:55.189 [main] INFO  c.b.config.LangChain4jConfig - 加载索引文件完成,耗时: 0秒, 文件数量: 1
12:33:55.190 [main] INFO  c.b.config.LangChain4jConfig - 开始索引RAG文件: /home/will/temp/202601/15/zhwiki_txt,共1个文档
12:33:59.246 [main] INFO  ai.djl.util.Platform - Found matching platform from: jar:file:/home/will/.m2/repository/ai/djl/huggingface/tokenizers/0.31.1/tokenizers-0.31.1.jar!/native/lib/tokenizers.properties
12:34:00.024 [main] WARN  a.d.h.t.HuggingFaceTokenizer - maxLength is not explicitly specified, use modelMaxLength: 512
12:34:00.025 [main] INFO  c.b.config.LangChain4jConfig - 处理进度: 1/1
12:34:20.969 [main] INFO  c.b.config.LangChain4jConfig - 所有文档索引完成,总耗时:25秒
12:34:21.361 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '/'
12:34:21.369 [main] INFO  com.bolingcavalry.Application - Started Application in 28.16 seconds (process running for 28.497)
  • 用vscode的 REST Client插件发起http请求,参数如下,和前文用提示词指定JSON不同,这里并没有要求LLM返回JSON格式
###  用提示词实现json格式的输出
POST http://localhost:8080/api/qwen/rag/easy
Content-Type: application/json
Accept: application/json

{
  "prompt": "一百字介绍完颜陈和尚"
}
  • 收到响应如下,可见LLM的回复内容是基于本地文档整理而成
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 15 Jan 2026 13:11:27 GMT
Connection: close

{
  "result": "完顏陳和尚(本名彝,字良佐),金末名將,豐州人(今內蒙古呼和浩特東),為蕭王完顏秉德後裔。通曉《孝經》《左傳》,擅寫牛毛細字,有儒將之風。曾於大昌原之役等戰役中屢敗蒙古軍,展現卓越軍事才能。[from byRagEasy]"
}
  • 再看日志,可见本地检索到三条与提示词有关的结果(向量查询),这些结果被送到LLM,再由LLM返回最终结果
    在这里插入图片描述
  • 至此,最简单的RAG就完成了,对于LLM没有的内容(例如自己写的从未公开的资料文档),要想得到更准确的结果,RAG方式是最有效的补充手段
  • Easy RAG虽然简单,却由于LangChain4j的高度封装导致灵活性不足,接下来的文章咱们继续深入学习RAG,体验Naive版,这里有更灵活的配置

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐