AI Services:检索增强生成(RAG)

检索增强生成(RAG)简单来说就是AI 回答问题前,先去查资料,再根据资料回答你。

下面我们以考试为例,来比喻 RAG,让你秒懂 RAG:

  • 普通大模型 = 闭卷考试

        只靠自己脑子里记住的知识

        容易胡说八道、过时、说错细节

  • RAG 大模型 = 开卷考试

        先去翻指定的书 / 文档 / 资料

        找到相关内容

        再整理成通顺的话回答你

RAG 的简单流程:

  1. 你上传资料(文档、表格、知识库、小说、合同等)

  2. AI 把资料存起来,建好 “快速查找索引”

  3. 你提问:

    • AI 先检索:去资料里找相关内容

    • 再生成:把找到的内容整理成人话回答

AI 服务对 RAG 支持

在 LangChain4j 中,可以为 AI服务(AI Services)配置一个 ContentRetriever(内容检索器),以启用简单的RAG(检索增强生成)。

可以这样做:

// 初始化向量存储(用于存储文档的向量数据)
EmbeddingStore embeddingStore  = ...
// 初始化嵌入模型(用于将文本转换为向量)
EmbeddingModel embeddingModel = ...

// 创建基于向量存储的内容检索器(负责从向量库中检索与问题相关的内容)
ContentRetriever contentRetriever = 
    new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);

// 构建具备RAG能力的AI助手
Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model) // 绑定大模型
    .contentRetriever(contentRetriever) // 注入检索器,开启RAG能力
    .build();

配置 RetrievalAugmentor 能提供更大的灵活性,可启用高级 RAG 功能,如查询转换、重新排序等:

// 构建自定义检索增强器(精细化控制RAG全流程)
RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
        .queryTransformer(...) // 设置查询转换器(处理用户提问:如重写、优化问题)
        .queryRouter(...) // 设置查询路由器(将问题路由到对应数据源/检索器)
        .contentAggregator(...) // 设置内容聚合器(合并多个检索结果)
        .contentInjector(...) // 设置内容注入器(将检索结果注入到对话上下文)
        .executor(...) // 设置执行器(控制检索流程的异步/同步执行)
        .build();

// 构建具备自定义RAG流程的AI助手
Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model) // 绑定大模型
    .retrievalAugmentor(retrievalAugmentor) // 注入自定义检索增强器,替代默认RAG逻辑
    .build();

完整示例

下面通过一个完整的示例介绍如何通过 AI 服务使用 RAG 功能。

该示例通过提供虚构的产品手册和员工月度补贴标准细则(product.txt 和 subsidy_standard.md)作为 RAG 的输入文档,然后通过嵌入模型将文档向量化,存入到内存中。AI 服务回答问题时先从该 RAG 库中召回数据,然后进行回答。

完整代码如下:

package com.hxstrive.langchain4j.aiServices;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
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 java.util.List;
import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocuments;

public class SimpleRAGDemo {
    // 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
    // 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
    private static final String API_KEY = System.getenv("OPEN_API_KEY");

    // 定义业务接口
    interface Assistant {
        // userMessage 是用户输入的消息
        // 返回值是 AI 回复的内容呢
        String chat(String userMessage);
    }

    public static void main(String[] args) {
        // 第一步:加载用于RAG的本地文档(支持多个txt文件)
        List<Document> documents = loadDocuments("E:\\langchain4j\\document");

        // 创建 ChatModel 实现类(OpenAI 为例)
        ChatModel chatModel = OpenAiChatModel.builder()
                .baseUrl("https://api.xty.app/v1")
                .apiKey(API_KEY)
                .modelName("gpt-4.1-mini")
                .logRequests(true)
                .logResponses(true)
                .build();

        // 使用 AiServices 创建服务
        Assistant assistant = AiServices.builder(Assistant.class)
                .chatModel(chatModel)
                // 绑定文档检索器(关联本地文档)
                .contentRetriever(createContentRetriever(documents))
                .build();

        // 发起对话
        String answer = assistant.chat("随心变色手机壳的主要参数有哪些?通过key=value的格式输出");
        System.out.println(answer);
    }

    /**
     * 创建文档内容检索器(RAG的核心依赖)
     * @param documents 待导入的本地文档列表
     * @return 可用于检索的ContentRetriever实例
     */
    private static ContentRetriever createContentRetriever(List<Document> documents) {
        // 创建空的内存向量库(存储文档文本片段及其向量表示,程序退出后数据丢失)
        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        // 创建嵌入模型
        OpenAiEmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
                .baseUrl("https://api.xty.app/v1")
                .apiKey(API_KEY)
                .modelName("text-embedding-3-small")
                .build();

        // 将文档导入向量库(底层自动完成:文档拆分 → 文本向量化 → 存入向量库)
        // 注:langchain4j 封装了所有细节,无需手动处理拆分/向量化
        EmbeddingStoreIngestor.builder()
                .embeddingModel(embeddingModel) // 设置嵌入模型
                .embeddingStore(embeddingStore) // 设置向量库,这里使用内存向量库
                .build().ingest(documents);

        // 基于向量库创建检索器(用于后续提问时匹配相关文档片段)
        return EmbeddingStoreContentRetriever.builder()
                .embeddingModel(embeddingModel) // 嵌入模型,用于匹配文档片段,将用户问题向量化
                .embeddingStore(embeddingStore) // 设置向量库,上面我们已经处理了的文档
                .build();
    }

}

运行示例,输出日志如下:

# 对文档进行嵌入处理
14:17:45.906 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Starting to ingest 2 documents
14:17:45.944 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Documents were split into 40 text segments
14:17:45.944 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Starting to embed 40 text segments
14:17:59.052 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Finished embedding 40 text segments
14:17:59.052 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Starting to store 40 text segments into the embedding store
14:17:59.054 [main] DEBUG dev.langchain4j.store.embedding.EmbeddingStoreIngestor -- Finished storing 40 text segments into the embedding store


# 发起对话,其中包含了召回的数据
# Answer using the following information(使用以下信息进行回答): 字符串后面的就是召回的数据
# 注意:召回的内容并不全,少了部分,这就牵涉到文档分片了,RAG部分介绍
14:18:00.420 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP request:
- method: POST
- url: https://api.xty.app/v1/chat/completions
- headers: [Authorization: Beare...00], ...
- body: {
  "model" : "gpt-4.1-mini",
  "messages" : [ {
    "role" : "user",
    "content" : "随心变色手机壳的主要参数有哪些?通过key=value的格式输出\n\nAnswer using the following information:\n随心变色手机壳产品说明书\n\n随心变色手机壳产品说明书\n一、产品简介\n\n随心变色手机壳产品说明书 一、产品简介 本产品为随心变色手机壳,核心功能为根据用户心情自动切换颜色,无需手动操作,使用便捷。外壳采用高分子耐磨材料与食品级记忆橡胶精心打磨制成,质感细腻亲肤,防刮耐摔且韧性出众,无需充电即可实现智能变色功能,广泛适配苹果(iPhone 12-15系列)、小米(小米14系列、Redmi K70系列)、华为(Mate 60系列、Pura"
  } ],
  "stream" : false
}


# AI回复的内容
14:18:03.293 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP response:
- status code: 200
- headers: [:status: 200], [alt-svc: h3=":443"; ma=86400],...
- body: {
    "id": "chatcmpl-D7xpxIps7zeuGPgDWofrPpnzaKoQS",
    "object": "chat.completion",
    "created": 1770790681,
    "model": "gpt-4.1-mini",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "变色技术=智能感应心情自动切换颜色  \n材质=高分子耐磨材料+食品级记忆橡胶  \n质感=细腻亲肤  \n耐用性=防刮耐摔,韧性出众  \n电源需求=无需充电  \n适配机型=苹果iPhone 12-15系列、小米14系列、Redmi K70系列、华为Mate 60系列",
                "refusal": null,
                "annotations": []
            },
            "logprobs": null,
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 199,
        "completion_tokens": 97,
        "total_tokens": 296,
        "prompt_tokens_details": {
            "cached_tokens": 0,
            "audio_tokens": 0
        },
        "completion_tokens_details": {
            "reasoning_tokens": 0,
            "audio_tokens": 0,
            "accepted_prediction_tokens": 0,
            "rejected_prediction_tokens": 0
        }
    },
    "system_fingerprint": "fp_3dcd5944f5"
}

变色技术=智能感应心情自动切换颜色  
材质=高分子耐磨材料+食品级记忆橡胶  
质感=细腻亲肤  
耐用性=防刮耐摔,韧性出众  
电源需求=无需充电  
适配机型=苹果iPhone 12-15系列、小米14系列、Redmi K70系列、华为Mate 60系列

通过观察上面日志输出,已经初步完成 RAG 功能的实现,更深入的需要去研究如何对文档分片,如何提升召回的准确率,如何才能将所需要的数据全部召回。

更多关于 RAG 的知识请学习后续关于 RAG 的教程……

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号