侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 133 篇文章
  • 累计创建 13 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

RAG(检索增强生成)

秋之牧云
2026-03-17 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

1. 什么是 RAG

RAG(Retrieval-Augmented Generation,检索增强生成) 并非颠覆大模型,而是为其加装了一个智能 “知识雷达”,核心思想直击痛点:“不懂就问,现查现用”。

  • 传统大模型瓶颈:依赖训练时的静态知识,无法获取训练截止日期后的新信息,对特定领域细节(如企业专有文档)掌握不足,易产生 “幻觉”(编造答案)。

  • RAG 的革新:将大模型的强大语言理解与生成能力,与实时、精准的外部知识检索相结合。回答问题时,先自动从企业专属知识库中查找最相关资料,再基于这些资料生成可靠回答。

2. 为什么需要 RAG

  1. 解决大模型“静态知识瓶颈”: 通用大模型(如 DeepSeek)的训练数据截止于某个时间点,无法获取后续新知识。有了 RAG 技术,能够实时检索最新企业文档,动态注入知识。

  2. 消除“幻觉”,保障答案准确性:大模型对专业细节不熟悉时,可能编造错误答案(如虚构产品功能)。有了 RAG 技术,答案严格基于检索到的权威文档生成,源头可追溯,大幅降低错误率。

  3. 保护私有知识资产,杜绝数据泄露:知识库与检索引擎可完全部署在企业内网,避免上传到公有云,用户提问题、检索内容、生成答案全流程在私有环境闭环运行,保证数据安全性;

  4. 降低成本,快速落地:训练专属大模型需百万级标注数据和算力,中小企业难以承受。有了 RAG 技术,可直接复用开源/商用 AI 大模型能力,企业只需聚焦知识库建设(成本<5%);

  5. 提升知识利用效率:80%的企业知识散落在邮件、PDF、数据库,员工难以高效检索。有了 RAG 技术,统一接入非结构化数据,实现自然语言一键直达目标信息(如“调取 2023 年华东区退货率最高的产品报告”);

3. 处理流程

  • 文档预先向量化

将企业内部的产品说明书、技术文档等,提前通过向量化模型,进行结构化处理(分块、清洗),存储到向量数据库中;

  • 提出问题: 用户提出自然语言问题(例:“XX冰箱的 ‘瞬冷冻’ 功能最低能达到多少度?如何开启?”)

  • 知识检索

  • 向量化模型处理:将用户问题转化为数学向量(Embedding)

  • 查询向量数据库:在预先构建并向量化的企业知识数据库(产品说明书、技术文档、客服QA记录等)中,快速查找语义最相关的文本片段(通常使用相似度计算,如余弦相似度)

  • 知识增强:将检索到的相关文本片段(Context)与原始用户问题组合,形成增强后的提示词(Prompt),类似下面这样

“基于以下产品文档信息:[检索到的冰箱说明书段落]... 请回答用户问题:[用户原问题]。确保答案严格依据提供信息。”

  • 答案生成:AI 大模型接收 “增强版 Prompt 提示词”,融合自身通用理解力与提供的专属知识,生成精准、可靠、符合企业语境的答案,输出示例如下:

“根据XX冰箱最新产品手册(2025版),‘瞬冷冻’功能最低可达 -32°C。开启方法:1. 在主界面选择‘速冻模式’;2. 点击‘瞬冷冻’图标;3. 设定时长(最长6小时)。具体操作示意图请参考手册第15页。”

4. 文档向量化存储与检索

4.1. 搭建项目

!-- Spring AI 依赖管理   -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

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

4.2. 选择向量模型

我们需要先挑选一个 “向量模型”,它够将文本、图像、视频等数据转换为数学空间中的向量。通过计算向量之间的距离或夹角,可以量化数据的相似度,从而作用于精准搜索、智能推荐、自动分类及异常检测等任务。

阿里百炼” 的模型广场,筛选 “向量模型” 分类下所有大模型,选择最新的 “通用文本向量-v4” 模型

4.3. 依赖

<!-- OpenAI -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

<!-- 整合向量数据库 Redis -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>

4.4. 配置

server:
  port: 8090 # 项目启动端口

spring:
  data:
    redis:
      host: localhost # Redis URL 链接
      port: 6379 # Redis 端口
  ai:
    openai:
      base-url: https://dashscope.aliyuncs.com/compatible-mode # OpenAI 服务的访问地址,这里使用的是阿里云百炼
      api-key: xxx  # 填写阿里百炼的 API Key, 改成你自己的
      embedding:
        options:
          model: text-embedding-v4 # 向量模型
    vectorstore:
      redis:
        initialize-schema: true # 是否初始化模式
        index-name: xiaoha-ai-index # 自定义索引名称
        prefix: embedding # 自定义键名前缀

4.5. 文档向量化处理,并存入 Redis(Redis Stack)

import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @Description: 将文档通过向量模型,向量化存储到数据库中
 **/
@Component
public class InitEmbeddingIndexRunner implements ApplicationRunner {

    @Resource
    private VectorStore vectorStore;

    @Override
    public void run(ApplicationArguments args) {
        // 定义 3 条文档
        List<Document> documents = List.of(
                new Document("冰箱首次使用指南:拆箱后静置24小时再通电,调节温控器至4℃冷藏室、-18℃冷冻室。清洁内胆时请使用中性洗涤剂。",
                        Map.of("章节", "安全须知", "版本", "2025")),
                new Document("节能技巧:避免频繁开关门,热食冷却后再放入,定期除霜可提升制冷效率。建议每月清洁一次冷凝器。"),
                new Document("故障代码手册:E1温度传感器异常,E2化霜故障,F1通讯错误。遇到E2代码请断电2小时后重启,若持续出现需联系售后。",
                        Map.of("章节", "故障处理", "紧急程度", "高"))
        );

        // 通过向量模型,将文档向量化存储到 Redis 中
        vectorStore.add(documents);
    }
}

4.6. 检索向量数据库

import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 检索向量数据库
 **/
@RestController
@RequestMapping("/vector")
public class VectorSearchController {

    @Resource
    private VectorStore vectorStore;

    /**
     * 检索向量数据库
     * @param key
     * @return
     */
    @GetMapping(value = "/search")
    public List<Document> search(@RequestParam(value = "key") String key) {
        // 检索与查询相似的文档
        List<Document> results = vectorStore.similaritySearch(SearchRequest.builder()
                .query(key) // 查询的关键词
                .topK(2) // 查询相似度最高的 2 条文档
                .build());

        return results;
    }

}

4.7. 提取 txt 文件

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: Txt 文件读取
 **/
@Component
public class MyTextReader {

    @Value("classpath:/document/manual.txt")
    private Resource resource;

    /**
     * 读取 Txt 文档
     * @return
     */
    public List<Document> loadText() {
        // 创建 TextReader 对象,用于读取指定资源 (resource) 的文本内容
        TextReader textReader = new TextReader(resource);
        // 添加自定义元数据,如文件名称
        textReader.getCustomMetadata()
                .put("filename", "manual.txt");
        // 读取并转换为 Document 文档集合
        return textReader.read();
    }

    /**
     * 读取 Txt 文档并分块拆分
     * @return
     */
    public List<Document> loadTextAndSplit() {
        // 创建 TextReader 对象,用于读取指定资源 (resource) 的文本内容
        TextReader textReader = new TextReader(resource);

        // 将资源内容解析为 Document 对象集合
        List<Document> documents = textReader.get();

        // 使用 TokenTextSplitter 对文档列表进行分块处理
        List<Document> splitDocuments = new TokenTextSplitter().apply(documents);

        // 返回拆分后的文档分块集合
        return splitDocuments;
    }
}

import com.quanxiaoha.vector.store.reader.MyTextReader;
import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyTextReader textReader;

    @GetMapping(value = "/txt")
    public List<Document> readText() {
        return textReader.loadText();
    }

    @GetMapping(value = "/txt2")
    public List<Document> readText2() {
        return textReader.loadTextAndSplit();
    }

}

4.8. 读取 Json 文件

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.JsonReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: Json 文件读取
 **/
@Component
public class MyJsonReader {

    @Value("classpath:/document/tv.json")
    private Resource resource;

    /**
     * 读取 Json 文件
     * @return
     */
    public List<Document> loadJson() {
        // 创建 JsonReader 阅读器实例,配置需要读取的字段
        JsonReader jsonReader = new JsonReader(resource, "description", "content", "title");
        // 执行读取操作,并转换为 Document 对象集合
        return jsonReader.get();
    }

}

/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {
	
    @Resource
    private MyJsonReader jsonReader;

    @GetMapping(value = "/json")
    public List<Document> readJson() {
        return jsonReader.loadJson();
    }

}

4.9. 读取 Markdown

<!-- 读取 Markdown -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.markdown.MarkdownDocumentReader;
import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: Markdown 文件读取
 **/
@Component
public class MyMarkdownReader {

    @Value("classpath:/document/code.md")
    private Resource resource;

    public List<Document> loadMarkdown() {
        // MarkdownDocumentReader 阅读器配置类
        MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()
                .withHorizontalRuleCreateDocument(true) // 遇到水平线 ---,则创建新文档
                .withIncludeCodeBlock(false) // 排除代码块(代码块生成单独文档)
                .withIncludeBlockquote(false) // 排除块引用(块引用生成单独文档)
                .withAdditionalMetadata("filename", "code.md") // 添加自定义元数据,如文件名称
                .build();

        // 新建 MarkdownDocumentReader 阅读器
        MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config);
        
        // 读取并转换为 Document 文档集合
        return reader.get();
    }
}
import com.quanxiaoha.vector.store.reader.MyJsonReader;
import com.quanxiaoha.vector.store.reader.MyMarkdownReader;
import com.quanxiaoha.vector.store.reader.MyTextReader;
import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyMarkdownReader markdownReader;

    @GetMapping(value = "/md")
    public List<Document> readMarkdown() {
        return markdownReader.loadMarkdown();
    }

}

4.10. 读取 Html

<!-- 读取 HTML -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-jsoup-document-reader</artifactId>
</dependency>
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.jsoup.JsoupDocumentReader;
import org.springframework.ai.reader.jsoup.config.JsoupDocumentReaderConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: HTML 文件读取
 **/
@Component
public class MyHtmlReader {

    @Value("classpath:/document/my-page.html")
    private Resource resource;

    public List<Document> loadHtml() {
        // JsoupDocumentReader 阅读器配置类
        JsoupDocumentReaderConfig config = JsoupDocumentReaderConfig.builder()
                .selector("article p") // 提取 <article> 标签内的 p 段落
                .charset("UTF-8") // 使用 UTF-8 编码
                .includeLinkUrls(true) // 在元数据中包含链接 URL(绝对链接)
                .metadataTags(List.of("author", "date")) // 提取 author 和 date 元标签
                .additionalMetadata("source", "my-page.html") // 添加自定义元数据
                .build();

        // 新建 JsoupDocumentReader 阅读器
        JsoupDocumentReader reader = new JsoupDocumentReader(resource, config);

        // 读取并转换为 Document 文档集合
        return reader.get();
    }
}
import com.quanxiaoha.vector.store.reader.MyHtmlReader;
import com.quanxiaoha.vector.store.reader.MyJsonReader;
import com.quanxiaoha.vector.store.reader.MyMarkdownReader;
import com.quanxiaoha.vector.store.reader.MyTextReader;
import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyHtmlReader htmlReader;

    @GetMapping(value = "/html")
    public List<Document> readHtml() {
        return htmlReader.loadHtml();
    }

}

4.11. 读取 Pdf

<!-- 读取 PDF -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: PDF 文件读取
 **/
@Component
public class MyPdfReader {

    public List<Document> getDocsFromPdf() {
        // 新建 PagePdfDocumentReader 阅读器
        PagePdfDocumentReader pdfReader = new PagePdfDocumentReader("classpath:/document/profile.pdf", // PDF 文件路径
                PdfDocumentReaderConfig.builder()
                        .withPageTopMargin(0) // 设置页面顶边距为0
                        .withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
                                .withNumberOfTopTextLinesToDelete(0) // 设置删除顶部文本行数为0
                                .build())
                        .withPagesPerDocument(1) // 设置每个文档包含1页
                        .build());

        // 读取并转换为 Document 文档集合
        return pdfReader.read();
    }
}
import com.quanxiaoha.vector.store.reader.*;
import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyPdfReader pdfReader;

    @GetMapping(value = "/pdf")
    public List<Document> readPdf() {
        return pdfReader.getDocsFromPdf();
    }
}

5. Apache Tika 读取 Word、PPT 文档

5.1. Apache Tika 介绍

Apache Tika 是一个开源的 内容检测与分析工具包,用于从各种格式的文件(如 PDF, DOC/DOCX, PPT/PPTX, HTML等)中提取文本内容和元数据。它通过统一的 API 简化了文档解析的复杂性。

5.2. 依赖

<!-- Tika -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

5.3. 读取 word

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: Word 文件读取
 **/
@Component
public class MyTikaWordReader {

    @Value("classpath:/document/55f79946a0964b89bc7ab9b55e4a49ff.docx")
    private Resource resource;

    public List<Document> loadWord() {
        // 新建 TikaDocumentReader 阅读器
        TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(resource);
        // 读取并转换为 Document 文档集合
        List<Document> documents = tikaDocumentReader.get();

        // 文档分块
        TokenTextSplitter splitter = new TokenTextSplitter(); // 不设置任何构造参数,表示使用默认设置
        return splitter.apply(documents);
    }
}
/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyTikaWordReader tikaWordReader;

    @GetMapping(value = "/word")
    public List<Document> readWord() {
        return tikaWordReader.loadWord();
    }
}

5.4. 读取 ppt

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: PPT 文件读取
 **/
@Component
public class MyTikaPptReader {

    @Value("classpath:/document/XX牌云感变频空调说明书.pptx")
    private Resource resource;

    public List<Document> loadPpt() {
        // 新建 TikaDocumentReader 阅读器
        TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(resource);
        // 读取并转换为 Document 文档集合
        List<Document> documents = tikaDocumentReader.get();

        // 文档分块
        // 使用自定义设置
        TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true);
        return splitter.apply(documents);
    }
}
import com.quanxiaoha.vector.store.reader.*;
import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Description: 文档读取
 **/
@RestController
@RequestMapping("/read")
public class ReaderController {

    @Resource
    private MyTikaPptReader tikaPptReader;

    @GetMapping(value = "/ppt")
    public List<Document> readPpt() {
        return tikaPptReader.loadPpt();
    }
}

6. DeepSeek 整合 RAG 增强检索: 实现与 PDF 对话

6.1. 将 PDF 向量化存储到 Redis 中

import jakarta.annotation.Resource;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Description: 将文档通过向量模型,向量化存储到数据库中
 **/
@Component
public class InitEmbeddingIndexRunner implements ApplicationRunner {

    @Resource
    private VectorStore vectorStore;

    @Override
    public void run(ApplicationArguments args) {
        // 新建 PagePdfDocumentReader 阅读器
        PagePdfDocumentReader pdfReader = new PagePdfDocumentReader("classpath:/document/profile.pdf", // 类路径PDF文件
                PdfDocumentReaderConfig.builder()
                        .withPageTopMargin(0) // 设置页面顶边距为0
                        .withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
                                .withNumberOfTopTextLinesToDelete(0) // 设置删除顶部文本行数为0
                                .build())
                        .withPagesPerDocument(1) // 设置每个文档包含1页
                        .build());

        // 读取并转换为 Document 文档集合
        List<Document> documents = pdfReader.get();

        // 防止重复添加到 Redis 中
        for (Document document : documents) {
            // 从向量数据中,查询当前文档
            List<Document> results = vectorStore.similaritySearch(SearchRequest.builder()
                    .query(document.getText())
                    .topK(1) // 查询一条最高得分的
                    .build());

            // 如果结果不为空,并且得分大于 0.99,则表示文档较高几率重复,直接跳过
            if (!results.isEmpty() && results.get(0).getScore() > 0.99)
                continue;

            // 通过向量模型,将文档向量化存储到 Redis 中
            vectorStore.add(List.of(document));
        }
    }
}

6.2. 整合 DeepSeek

<!-- DeepSeek 模型 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
spring:
  ai:
    deepseek:
      base-url: https://api.deepseek.com # DeepSeek 的请求 URL, 可不填,默认值为 api.deepseek.com
      api-key: xxx # 填写 DeepSeek Api Key,改成你自己的
      chat:
        options:
          model: deepseek-reasoner # 使用哪个模型
          temperature: 0.0 # 温度值 在 RAG 场景下,较低的温度值可降低生成内容的随机性,减少幻觉率(
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: ChatClient 配置
 **/
@Configuration
public class ChatClientConfig {

    /**
     * 初始化 ChatClient 客户端
     * @param chatModel
     * @return
     */
    @Bean
    public ChatClient chatClient(DeepSeekChatModel chatModel) {
        return ChatClient.builder(chatModel)
                .build();
    }
}

6.3. RAG 增强检索

添加向量 Advisor 依赖

    <!-- 向量 Advisor -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-advisors-vector-store</artifactId>
    </dependency>
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;


/**
 * @Description: RAG 增强检索
 **/
@RestController
@RequestMapping("/rag")
public class RAGController {

    @Resource
    private VectorStore vectorStore;
    @Resource
    private ChatClient chatClient;

    /**
     * 流式对话
     * @param message
     * @return
     */
    @GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
    public Flux<String> generateStream(@RequestParam(value = "message") String message) {

        // 流式输出
        return chatClient.prompt()
                .system("请你扮演一名企业客服。从企业内部知识库中查阅相关资料,并回答用户,若内部资料没有相关内容,则回答 “未找到相关资料”")
                .user(message) // 提示词
                .advisors(new QuestionAnswerAdvisor(vectorStore)) // 检索向量库,组合增强提示词,调用 AI 大模型
                .stream()
                .content();

    }

}

0

评论区