LangChain4j实战之十六:RAG (检索增强生成),Naive RAG

欢迎访问我的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
  16. RAG (检索增强生成),Naive RAG

本篇概览

  • 本文是RAG系列的第二篇,前文体验了LangChain4j提供的最简版本RAG,知道了RAG的作用,但由于Easy RAG强调的是简洁,所以当时未能了解RAG细节
  • 所以今天继续深入学习RAG,目标是Naive RAG,即通过LangChain4j提供的API来实现RAG索引功能
  • 具体要写什么代码才能实现RAG索引呢?为了便于理解,这里整理出详细的时序图

无 EasyRAG 的"一键魔法",全程手动:加载 → 解析 → 切分 → 嵌入 → 存库。
控制台 EmbeddingStore (InMemory/Qdrant) EmbeddingStoreIngestor EmbeddingModel (AllMiniLm) DocumentSplitter (Recursive) DocumentParser (ApacheTika) FileSystemDocumentLoader 应用启动代码 控制台 EmbeddingStore (InMemory/Qdrant) EmbeddingStoreIngestor EmbeddingModel (AllMiniLm) DocumentSplitter (Recursive) DocumentParser (ApacheTika) FileSystemDocumentLoader 应用启动代码 loop [每个文件] loop [每批 segment] 1. 手动创建各组件 1 2. loadDocuments(path, parser) 2 3. 解析为Document 3 4. 返回Document 4 5. List<Document> 5 6. splitAll(documents) 6 7. List<TextSegment> 7 8. ingest(segments) 8 9. 生成Embedding 9 10. List<Embedding> 10 11. 写入(segment, embedding) 11 12. 打印进度 12 13. 索引完成 13

  • 由上可见,Naive RAG的重点是索引,至于检索并没有什么要关注的地方,依旧是高级API的调用
  • 好了,开始编码吧,注意重点是配置类中的索引部分,另外本次实战所用数据与前文相同,依旧是基于维基百科大幅度删减的文本文件,内容如下图

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

名称 链接 备注
项目主页 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. 增加一个参数定义,这是后面文本转向量时要用到的模型版本

  2. 增加上述模型库的依赖

xml 复制代码
      <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-embeddings-bge-small-zh-v15-q</artifactId>
        <version>${bge-small-zh-v15-q.version}</version>
      </dependency>
  1. modules中增加一个子工程,如下图黄框所示

编码:新增子工程

  • 新增名为rag-naive的子工程
  1. langchain4j-totorials目录下新增名为rag-naive的文件夹
  2. rag-naive文件夹下新增pom.xml,内容如下
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-naive</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>

        <dependency>
          <groupId>dev.langchain4j</groupId>
          <artifactId>langchain4j-embeddings-bge-small-zh-v15-q</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-naive/src/main/resources新增配置文件application.properties,内容如下,主要是三个模型的配置信息,记得把your-api-key换成您自己的apikey,rag.file.path是存放本地文档的目录(就是前面维基百科那个文件)
properties 复制代码
# 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-naive

# rag文件路径
rag.file.path=/home/will/temp/202601/15/zhwiki_txt
  1. 新增启动类,依旧平平无奇
java 复制代码
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,所以增加一个自定义接口用于对话
java 复制代码
package com.bolingcavalry.service;

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

import java.util.ArrayList;
import java.util.List;

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;

import com.bolingcavalry.service.Assistant;

import dev.langchain4j.agent.tool.ToolExecutionRequest;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
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 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.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallenv15q.BgeSmallEnV15QuantizedEmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallzhv15q.BgeSmallZhV15QuantizedEmbeddingModel;
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.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;

@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) {
        // DocumentParser的作用是把磁盘上的文件转为Document对象,以便后面的分块处理,
        // TextDocumentParser处理文本类文件,如txt、md等,如果要处理更多类型,可以用ApacheTikaDocumentParser,代价是包更大,启动更慢
        DocumentParser documentParser = new TextDocumentParser();
        long start = System.currentTimeMillis();
        logger.info("开始加载索引文件:{}", ragFilePath);
        List<Document> documents = FileSystemDocumentLoader.loadDocuments(ragFilePath, documentParser);
        logger.info("加载索引文件完成,耗时: {}毫秒, 文件数量: {}",
                (System.currentTimeMillis() - start), documents.size());

        start = System.currentTimeMillis();    
        logger.info("开始对文档分块,共{}个文档", documents.size());    
        List<TextSegment> segments = new ArrayList<>();

        // 每个文档分块
        for (Document document : documents) {
            // 文档分块, 每个分块300个字符, 重叠0个字符
            DocumentSplitter splitter = DocumentSplitters.recursive(300, 0);
            segments.addAll(splitter.split(document));
        }
        logger.info("文档分块完成,共{}个分块,耗时: {}毫秒", segments.size(), (System.currentTimeMillis() - start));
        
        start = System.currentTimeMillis();    
        logger.info("开始将文档分块转为向量"); 
        // 每个分块创建嵌入向量,模型是智源 bge-small-zh-v1.5 量化版,中文 C-MTEB 第一梯队
        EmbeddingModel embeddingModel = new BgeSmallZhV15QuantizedEmbeddingModel();
        List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
        EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
        embeddingStore.addAll(embeddings, segments);
        logger.info("文档分块转为向量完成,共{}个向量,耗时: {}秒", embeddings.size(), (System.currentTimeMillis() - start) / 1000);

        // 创建内容检索器
        ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .maxResults(2) // 每个查询返回2个最相关的分块
                .minScore(0.5) // 每个分块的相似度阈值
                .build();

        return contentRetriever;
    }
}
  • 建议配合前面的时序图来看配置类代码,重点在createContentRetriever方法:
  1. 用FileSystemDocumentLoader加载文件,对于入参,如果您的文件是txt,markdown这样的文本类,用TextDocumentParser最合适,如果是其他高级文档(例如PDF),那么用ApacheTikaDocumentParser,
  2. 加载后进行分割,也就是所有的文档最终转成了segment对象
  3. 文本转为向量的时候使用了BgeSmallZhV15QuantizedEmbeddingModel,这是智源 bge-small-zh-v1.5 量化版,中文 C-MTEB 第一梯队
  4. 在创建查询工具ContentRetriever的时候,还可以通过maxResults方法设置返回结果的数量,以及minScore方法设置相似度阈值
  • 其实以上代码就是今天的核心了,可见LangChain4j提供了详细的API和参数给我们使用

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

java 复制代码
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 byRagNaive(String prompt) {
        String answer = assistant.byRagNaive(prompt);
        logger.info("响应:" + answer);
        return answer + "[from byRagNaive]";
    }
}
  • 最后是controller类,这里准备个http接口响应,用来调用前的服务类的功能
java 复制代码
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/naive")
    public ResponseEntity<Response> byRagNaive(@RequestBody PromptRequest request) {
        ResponseEntity<Response> checkRlt = check(request);
        if (checkRlt != null) {
            return checkRlt;
        }

        try {
            String response = qwenService.byRagNaive(request.getPrompt());
            return ResponseEntity.ok(new Response(response));
        } catch (Exception e) {
            // 捕获异常并返回错误信息
            return ResponseEntity.status(500).body(new Response("请求处理失败: " + e.getMessage()));
        }
    }
}
  • 至此代码就全部写完了,现在把工程运行起来试试,在rag-easy目录下执行以下命令即可启动服务
bash 复制代码
mvn spring-boot:run
  • 启动日志如下,同一份本地文档,在前文用Easy RAG转向量时用了25秒,而这次只用了12秒,实测发现向量模型对耗时影响较大(改为BgeSmallEnV15QuantizedEmbeddingModel耗时就超过了20秒)
  • 要是用完整维基百科来索引其耗时应该难以接受(真要是索引全部维基百科,就必须用单独的服务将向量数据做持续化存储,而非启动时在内存中存储)
shell 复制代码
08:08:00.731 [main] INFO  c.b.config.LangChain4jConfig - 开始加载索引文件:/home/will/temp/202601/15/zhwiki_txt
08:08:00.753 [main] INFO  c.b.config.LangChain4jConfig - 加载索引文件完成,耗时: 22毫秒, 文件数量: 1
08:08:00.754 [main] INFO  c.b.config.LangChain4jConfig - 开始对文档分块,共1个文档
08:08:00.793 [main] INFO  c.b.config.LangChain4jConfig - 文档分块完成,共233个分块,耗时: 39毫秒
08:08:00.793 [main] INFO  c.b.config.LangChain4jConfig - 开始将文档分块转为向量
08:08:05.315 [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
08:08:05.340 [main] WARN  a.d.h.t.HuggingFaceTokenizer - maxLength is not explicitly specified, use modelMaxLength: 512
08:08:13.349 [main] INFO  c.b.config.LangChain4jConfig - 文档分块转为向量完成,共233个向量,耗时: 12秒
  • 用vscode的 REST Client插件发起http请求,参数如下,和前文用提示词指定JSON不同,这里并没有要求LLM返回JSON格式
bash 复制代码
###  用提示词实现json格式的输出
POST http://localhost:8080/api/qwen/rag/naive
Content-Type: application/json
Accept: application/json

{
  "prompt": "一百字介绍完顏陳和尚"
}
  • 收到响应如下,可见LLM的回复内容是基于本地文档整理而成
bash 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 16 Jan 2026 08:07:42 GMT
Connection: close

{
  "result": "完顏陳和尚,本名彝,字良佐,金末名將,豐州(今內蒙古呼和浩特東)人,為蕭王完顏秉德後裔。他通曉《孝經》《左傳》,擅寫細字,有儒將之風。曾於大昌原之役等戰役中屢敗蒙古軍,展現卓越軍事才能。[from byRagNaive]"
}
  • 再看日志,可见这次本地只检索到一条与提示词有关的结果(向量查询,如果把向量模型改为BgeSmallEnV15QuantizedEmbeddingModel就会查出两条),这些结果被送到LLM,再由LLM返回最终结果

  • 至此,Naive RAG就完成了,相比前文,在索引的时候咱们可以根据业务情况做更详细的设置,还有检索工具也能通过API做一些设置,这比Easy RAG就有了更多的自由度

有个问题

  • 至此,咱们可以通过LangChain4j实现RAG业务了,不过聪明的您应该也发现了以下问题:
  1. 五百行的文本,转为向量需要十多秒,那整个维基百科转为向量岂不是要等很久?
  2. 当前的方案是把向量保存在内存中的,文本要是多的话,内存不够用咋办?
  3. 要是进程出问题了向量就丢了,所以每次启动都要重新加载吗?
  • 以上都是很现实的问题,不解决的话如何用在生产环境?所以下一篇文章咱们就来解决这些问题吧

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

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列
相关推荐
Dingdangcat862 小时前
轮胎缺陷检测与分类系统基于solov2_r101_fpn_ms-3x_coco模型实现_fulltyre专项识别_1
人工智能·分类·数据挖掘
Ivanqhz2 小时前
现代异构高性能计算(HPC)集群节点架构
开发语言·人工智能·后端·算法·架构·云计算·边缘计算
weixin_509138342 小时前
探索智能体认知动力学:几何视角下的AI革命(系列博客第二期)
人工智能·机器学习·语义空间
Loo国昌2 小时前
【大模型应用开发】第三阶段:深度解析检索增强生成(RAG)原理
人工智能·后端·深度学习·自然语言处理·transformer
ONLYOFFICE2 小时前
ONLYOFFICE AI 插件新功能:轻松创建专属 AI 助手
人工智能·onlyoffice
audyxiao0012 小时前
AI一周重要会议和活动概览(2.2-2.8)
人工智能·大模型·iclr·ccf·一周会议与活动
柠萌f2 小时前
2026 素材趋势报告:为什么“素材工程能力”,正在决定品牌的投放天花板?
人工智能
莽撞的大地瓜2 小时前
连获国内多行业认可、入选全球AI全景图谱 彰显蜜度智能校对的硬核实力
人工智能·ai·语言模型·新媒体运营·知识图谱
ATM0062 小时前
专其利AI | 专利撰写的救赎:AI工具为何成为知识产权保护的神兵利器
人工智能·大模型·专利撰写