🔥 导读:标准的大语言模型知道天下事,但唯独不知道你的"私房事"——公司的内部文档、产品的技术规格、项目的代码库…如何让AI精通这些私有知识?本章将带你深入Spring AI的高级核心,揭开检索增强生成(RAG)的神秘面纱。你将学会使用EmbeddingClient将任何文档转化为AI能理解的"向量",并借助向量数据库,构建一个能基于你的私有数据进行精准问答的智能知识库系统。


🔍 1. RAG:让大模型"开卷考试"

想象一个场景:你想让AI回答关于你公司最新产品"Phoenix v2.0"的技术问题。但无论你怎么问,ChatGPT或任何通用大模型(LLM)都只会回答:“对不起,我的知识库截止到XXX年,我并不知道关于’Phoenix v2.0’的信息。”

这是因为LLM的知识是预训练的,是静态的。为了解决这个问题,业界提出了**RAG (Retrieval-Augmented Generation,检索增强生成)**架构。

💡 RAG的核心思想:让AI"开卷考试"而不是"闭卷考试"

RAG的工作流程非常直观:

  1. 📚 “开卷” - 准备资料 (Ingestion):在提问之前,我们先把所有相关的私有文档(如产品手册.pdf, 技术白皮书.docx)全部处理好,放进一个"资料库"里。

  2. 🔎 “审题” - 检索 (Retrieval):当用户提出问题时(例如:“Phoenix v2.0的新特性是什么?”),系统不会直接把问题扔给LLM。而是先拿着这个问题,去刚才的"资料库"里,快速找到最相关的那几段内容。

  3. ✍️ “作答” - 生成 (Generation):系统将用户原始的问题和从资料库中检索到的相关内容,一起打包发给LLM,并对LLM说:“请根据我提供的这些参考资料,回答这个问题。”

🌟 RAG的优势:

  • 解决了LLM知识时效性问题
  • 让AI能够访问私有数据
  • 减少"幻觉"(虚构信息)
  • 提高回答的可靠性和准确性

🧠 2. Embedding:AI世界的通用语言

RAG流程中最关键的一步是"检索":如何快速从成千上万份文档中,找到与问题最相关的片段?

答案就是Embedding。

你可以将Embedding理解为一种"降维打击"技术。它通过一个特殊的模型(Embedding Model),将任何一段文本(一个词、一句话、一个文档)转换成一个由数字组成的"向量"(Vector)。

例如:

  • "猫" → [0.1, 0.8, -0.3, ...]
  • "小猫" → [0.12, 0.78, -0.29, ...]
  • "狗" → [0.6, -0.2, 0.5, ...]
  • "汽车" → [-0.9, 0.05, 0.1, ...]

这些向量在多维空间中的距离,代表了原始文本在语义上的相似度。"猫"和"小猫"的向量会非常接近,而它们与"汽车"的向量则会相距甚远。

🔬 技术细节:大多数Embedding模型会生成数百到数千维的向量。例如,OpenAI的text-embedding-ada-002生成1536维的向量。

在Spring AI中,EmbeddingClient就是负责执行这个转换任务的核心组件。

💾 3. 向量数据库:Embedding的"专属豪宅"

当我们将所有私有文档都转换成大量的向量后,需要一个地方来高效地存储和检索它们。这个地方就是向量数据库(Vector Database)。

与传统的关系型数据库不同,向量数据库专门为高维向量的存储和"相似性搜索"进行了优化。你可以用一个"问题"向量,在数百万甚至数十亿的"文档"向量中,毫秒级地找出距离最近(即语义最相似)的Top K个结果。

🛠️ Spring AI支持的向量数据库:

  • Chroma (轻量级,适合开发)
  • PostgreSQL (with pgvector)
  • Redis
  • Milvus
  • Elasticsearch
  • Pinecone
  • Weaviate

对于本地开发和快速原型验证,Chroma是一个非常好的选择,因为它轻量且可以嵌入到应用中。

🚀 4. 实战:构建一个基于文档的问答系统

我们的目标是:

  1. 读取一个本地的.txt文件作为我们的私有知识库。
  2. 将文件内容分割、向量化,并存入向量数据库。
  3. 提供一个API,接收用户问题,通过RAG流程生成答案。

4.1. 增加依赖

在pom.xml中,我们需要添加向量数据库的依赖。我们选用嵌入式的Chroma:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-chroma-store-spring-boot-starter</artifactId>
</dependency>

4.2. 准备私有数据

在src/main/resources/目录下,创建一个名为docs的文件夹,并在其中创建一个faq.txt文件,内容如下:

Q: Spring AI是什么?
A: Spring AI是一个由Spring团队开发的AI应用开发框架,旨在简化将AI技术集成到企业级Java应用中的过程。它提供了对多种大语言模型(LLM)和Embedding模型的统一抽象,并与Spring生态系统无缝集成。

Q: RAG是什么意思?
A: RAG是检索增强生成(Retrieval-Augmented Generation)的缩写。它是一种先进的AI技术,通过在生成答案前从外部知识库中检索相关信息,来增强大语言模型的知识和准确性,解决了模型知识静态、无法访问私有数据的问题。

Q: 我们的旗舰产品"Phoenix v2.0"有哪些新功能?
A: Phoenix v2.0引入了三大革命性新功能:1. 基于AI的智能预测分析引擎。2. 全新的多租户安全架构。3. 对分布式数据库的无缝支持,性能提升了30%。

Q: 如何联系技术支持?
A: 您可以通过发送邮件到support@example.com或拨打400-800-8888联系我们的技术支持团队。

4.3. 实现数据加载与RAG流程

我们将创建一个新的RagController来处理这一切。

// RagController.java
package com.example.ai.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.files.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
public class RagController {

    private static final Logger logger = LoggerFactory.getLogger(RagController.class);
    
    @Autowired
    private ChatClient chatClient;

    @Autowired
    private VectorStore vectorStore;

    @Value("classpath:/docs/faq.txt")
    private Resource faqResource;

    // 应用启动时,自动加载数据到向量数据库
    @PostConstruct
    public void init() {
        logger.info("开始加载私有知识库...");
        // 使用TikaDocumentReader读取文件
        var documentReader = new TikaDocumentReader(faqResource);
        List<Document> documents = documentReader.get();
        
        // 使用TokenTextSplitter进行文本分割
        var textSplitter = new TokenTextSplitter();
        List<Document> splitDocuments = textSplitter.apply(documents);
        
        // 将分割后的文档存入向量数据库
        vectorStore.add(splitDocuments);
        logger.info("私有知识库加载完毕!");
    }

    @GetMapping("/ai/rag")
    public String rag(@RequestParam String query) {
        // 1. 检索:根据用户问题在向量数据库中查找最相似的文档
        logger.info("正在检索相关信息...");
        List<Document> similarDocuments = vectorStore.similaritySearch(query);
        String relevantInfo = similarDocuments.stream()
                .map(Document::getContent)
                .collect(Collectors.joining("\n\n"));
        
        // 2. 生成:构建Prompt,将检索到的信息和用户问题一起发给LLM
        logger.info("正在生成回答...");
        String systemMessage = """
                你是一个专业的AI客服。
                请根据我提供的"参考资料",用中文、礼貌且专业的口吻来回答用户的问题。
                如果"参考资料"中没有相关信息,就直接回答:"抱歉,关于这个问题我暂时无法提供帮助,建议您联系技术支持。"
                
                参考资料:
                ---
                {relevant_info}
                ---
                """;
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemMessage);
        Prompt prompt = systemPromptTemplate.create(Map.of("relevant_info", relevantInfo));
        
        // 我们需要手动将用户的query添加到Prompt的消息列表中
        var chatPrompt = new Prompt(query, prompt.getInstructions());

        return chatClient.call(chatPrompt).getResult().getOutput().getContent();
    }
}

🔍 代码解析:

  1. @PostConstruct: 这个注解让init()方法在RagController被创建并注入所有依赖后自动执行。我们在这里完成"准备资料"的步骤。

  2. TikaDocumentReader: Spring AI提供的强大的文档读取器,能处理各种格式(txt, pdf, docx…)。这意味着你可以轻松扩展到处理PDF、Word等复杂文档!

  3. TokenTextSplitter: 将长文档切分成更小的、适合Embedding的块。这是RAG的关键步骤之一,确保我们能找到最相关的文本片段。

  4. vectorStore.add(...): 将处理好的文档块(Document对象)交给VectorStore,它会自动调用EmbeddingClient进行向量化并存储。

  5. vectorStore.similaritySearch(query): 这是"检索"的核心。它会将用户的query向量化,然后在数据库中执行相似性搜索。

  6. System Prompt: 我们构建了一个复杂的系统指令,告诉LLM它的角色、回答风格,并明确了如果找不到信息该如何应对。这是一种非常重要的Prompt工程技巧。

4.4. 启动与测试

重启应用。在控制台,你会看到日志显示知识库已开始加载。加载完成后,用curl或浏览器测试:

测试1:问题在知识库中

curl "http://localhost:8080/ai/rag?query=Phoenix%20v2.0%20有什么新功能"

✅ 预期结果:你会得到一个基于faq.txt内容的、非常精准的回答,而不是LLM的凭空想象:

“Phoenix v2.0引入了三大革命性新功能:1. 基于AI的智能预测分析引擎;2. 全新的多租户安全架构;3. 对分布式数据库的无缝支持,性能提升了30%。如果您需要更详细的信息,请随时咨询。”

测试2:问题不在知识库中

curl "http://localhost:8080/ai/rag?query=公司的股价是多少"

✅ 预期结果:AI会礼貌地回答它不知道,并建议你联系技术支持,完美地遵循了我们的指令:

“抱歉,关于这个问题我暂时无法提供帮助,建议您联系技术支持。”

🔧 5. 进阶:优化RAG系统

一个基础的RAG系统已经构建完成,但在实际应用中,我们可以通过以下方式进一步优化:

5.1. 文档分块策略

默认的TokenTextSplitter使用固定的token数量进行分割,但这可能会切断语义完整的段落。考虑使用:

// 自定义分块大小和重叠
var textSplitter = new TokenTextSplitter(500, 50);

或者使用更智能的分割器,如基于段落或语义的分割器。

5.2. 向量检索增强

默认的相似度搜索可以通过多种方式增强:

// 指定返回的最相似文档数量
List<Document> docs = vectorStore.similaritySearch(query, 5);

// 使用过滤器限定搜索范围
Map<String, Object> filter = Map.of("category", "product");
List<Document> docs = vectorStore.similaritySearch(query, 5, filter);

5.3. 混合检索策略

结合关键词搜索和向量搜索,可以获得更好的效果:

// 伪代码:关键词搜索和向量搜索的结果合并
List<Document> keywordResults = keywordSearch(query);
List<Document> vectorResults = vectorStore.similaritySearch(query);
List<Document> hybridResults = mergeAndRank(keywordResults, vectorResults);

🏆 6. 总结

恭喜你,你已经掌握了Spring AI中最强大、最核心的RAG技术!通过结合EmbeddingClient、VectorStore和ChatClient,你现在已经有能力构建出能够学习和利用私有知识的、真正智能的AI应用了。

这为你打开了无数可能性:

  • 🏢 企业内部的智能知识库和客服
  • 💻 能够理解代码库并回答技术问题的编程助手
  • 📝 个人的智能笔记和信息检索系统

🤔 思考题:除了文本文档外,你还能想到哪些类型的私有数据可以通过RAG技术让AI学习?如何将这些数据转化为AI可理解的形式?欢迎在评论区分享你的创意!

在下一章**【神兵利器】**中,我们将探索另一个让AI能力突破天际的功能:函数调用(Function Calling)。我们将赋予AI"手"和"脚",让它不再仅仅是"大脑",而是能够为你调用工具、查询API、执行真实世界的操作。这将是通往智能体(Agent)的第一步,敬请期待!


📚 系列导航:

  • 第1章:破冰启航 - Spring AI横空出世
  • 第2章:初窥门径 - 构建你的第一个AI应用
  • 第3章:Prompt的艺术 - 如何与AI进行高效对话
  • 【当前】第4章:RAG与向量数据库 - 让AI学习你的私有知识
  • 【下一篇】第5章:函数调用 - 赋予AI连接现实世界的能力
  • 第6章:企业级应用挑战 - 部署、监控与最佳实践
  • 第7章:展望未来 - 智能体与多模态

👨‍💻 关于作者:资深Java开发者,Spring生态爱好者,AI应用实践专家。欢迎关注,共同探索Java AI的无限可能!


喜欢这篇文章?点赞+收藏,支持一下作者吧!有任何问题都可以在评论区留言交流~

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐