• 已删除用户
陈永强
陈永强
发布于 2026-06-03 / 1 阅读
0

SpringBoot LangChain4j RAG知识库(二)

SpringBoot LangChain4j RAG知识库(二)

一、向量数据Milvus安装使用

使用docker 安装(milvus 官网地址: https://milvus.io/docs/install_standalone-docker.md)

官网安装命令如下,从地址中下载安装脚本,执行脚本会下载milvus的docker镜像,下载的镜像是最新的版本。

curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh
bash standalone_embed.sh start

docker的映射文件会新建生成在standalone_embed.sh文件所在的目录下,如下图。注:如果启动失败,尝试将volumesd设置成 777(最高权限)

standalone_embed.sh 文件,可以修改端口映射,docker 镜像

#!/usr/bin/env bash

# Licensed to the LF AI & Data foundation under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

run_embed() {
    cat << EOF > embedEtcd.yaml
listen-client-urls: http://0.0.0.0:2379
advertise-client-urls: http://0.0.0.0:2379
quota-backend-bytes: 4294967296
auto-compaction-mode: revision
auto-compaction-retention: '1000'
EOF

    cat << EOF > user.yaml
# Extra config to override default milvus.yaml
EOF
    if [ ! -f "./embedEtcd.yaml" ]
    then
        echo "embedEtcd.yaml file does not exist. Please try to create it in the current directory."
        exit 1
    fi

    if [ ! -f "./user.yaml" ]
    then
        echo "user.yaml file does not exist. Please try to create it in the current directory."
        exit 1
    fi
    
    sudo docker run -d \
        --name milvus-standalone \
        --security-opt seccomp:unconfined \
        -e ETCD_USE_EMBED=true \
        -e ETCD_DATA_DIR=/var/lib/milvus/etcd \
        -e ETCD_CONFIG_PATH=/milvus/configs/embedEtcd.yaml \
        -e COMMON_STORAGETYPE=local \
        -e DEPLOY_MODE=STANDALONE \
        -v $(pwd)/volumes/milvus:/var/lib/milvus \
        -v $(pwd)/embedEtcd.yaml:/milvus/configs/embedEtcd.yaml \
        -v $(pwd)/user.yaml:/milvus/configs/user.yaml \
        -p 19530:19530 \
        -p 9091:9091 \
        -p 2379:2379 \
        --health-cmd="curl -f http://localhost:9091/healthz" \
        --health-interval=30s \
        --health-start-period=90s \
        --health-timeout=20s \
        --health-retries=3 \
        milvusdb/milvus:v2.6.8 \
        milvus run standalone  1> /dev/null
}

wait_for_milvus_running() {
    echo "Wait for Milvus Starting..."
    while true
    do
        res=`sudo docker ps|grep milvus-standalone|grep healthy|wc -l`
        if [ $res -eq 1 ]
        then
            echo "Start successfully."
            echo "To change the default Milvus configuration, add your settings to the user.yaml file and then restart the service."
            break
        fi
        sleep 1
    done
}

start() {
    res=`sudo docker ps|grep milvus-standalone|grep healthy|wc -l`
    if [ $res -eq 1 ]
    then
        echo "Milvus is running."
        exit 0
    fi

    res=`sudo docker ps -a|grep milvus-standalone|wc -l`
    if [ $res -eq 1 ]
    then
        sudo docker start milvus-standalone 1> /dev/null
    else
        run_embed
    fi

    if [ $? -ne 0 ]
    then
        echo "Start failed."
        exit 1
    fi

    wait_for_milvus_running
}

stop() {
    sudo docker stop milvus-standalone 1> /dev/null

    if [ $? -ne 0 ]
    then
        echo "Stop failed."
        exit 1
    fi
    echo "Stop successfully."

}

delete_container() {
    res=`sudo docker ps|grep milvus-standalone|wc -l`
    if [ $res -eq 1 ]
    then
        echo "Please stop Milvus service before delete."
        exit 1
    fi
    sudo docker rm milvus-standalone 1> /dev/null
    if [ $? -ne 0 ]
    then
        echo "Delete milvus container failed."
        exit 1
    fi
    echo "Delete milvus container successfully."
}

delete() {
    read -p "Please confirm if you'd like to proceed with the delete. This operation will delete the container and data. Confirm with 'y' for yes or 'n' for no. > " check
    if [ "$check" == "y" ] ||[ "$check" == "Y" ];then
        delete_container
        sudo rm -rf $(pwd)/volumes
        sudo rm -rf $(pwd)/embedEtcd.yaml
        sudo rm -rf $(pwd)/user.yaml
        echo "Delete successfully."
    else
        echo "Exit delete"
        exit 0
    fi
}

upgrade() {
    read -p "Please confirm if you'd like to proceed with the upgrade. The default will be to the latest version. Confirm with 'y' for yes or 'n' for no. > " check
    if [ "$check" == "y" ] ||[ "$check" == "Y" ];then
        res=`sudo docker ps -a|grep milvus-standalone|wc -l`
        if [ $res -eq 1 ]
        then
            stop
            delete_container
        fi

        curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed_latest.sh && \
        bash standalone_embed_latest.sh start 1> /dev/null && \
        echo "Upgrade successfully."
    else
        echo "Exit upgrade"
        exit 0
    fi
}

case $1 in
    restart)
        stop
        start
        ;;
    start)
        start
        ;;
    stop)
        stop
        ;;
    upgrade)
        upgrade
        ;;
    delete)
        delete
        ;;
    *)
        echo "please use bash standalone_embed.sh restart|start|stop|upgrade|delete"
        ;;
esac

二、RAG 检索增强生成

简单来说,RAG 是在将提示发送给 LLM 之前,从您的数据中找到并注入相关信息片段的方法。

通过这种方式,LLM 将获得(希望是)相关信息,并能够利用这些信息进行回复,从而降低幻觉的发生概率。

您可以使用各种信息检索方法来查找相关信息。最流行的方法有:

  • 全文(关键词)搜索:此方法使用 TF-IDF 和 BM25 等技术,通过将查询(例如用户的提问)中的关键词与文档数据库进行匹配来搜索文档。它根据关键词在每个文档中的频率和相关性对结果进行排名。

  • 向量搜索,也称为“语义搜索”:使用嵌入模型将文本文档转换为数字向量。然后,它根据查询向量和文档向量之间的余弦相似度或其他相似度/距离度量来查找和排名文档,从而捕捉更深层次的语义含义。

  • 混合搜索:结合多种搜索方法(例如全文 + 向量)通常可以提高搜索的有效性。

Easy RAG:简单的RAG搭建,不需要嵌入模型,向量数据库等配置就可以搭建知识库,过大的知识库文件检索性能不好。

Naive RAG:支持向量模型的检索增强

Advance RAG:一个模块化的 RAG 框架,允许进行额外的步骤,例如查询转换、从多个来源检索和重新排名

RAG 组件:

document(文档包含html、txt、xlsx、docx、pdf等格式)、

Metadata(它存储关于 Document 的元信息,例如其名称、来源、上次更新日期、所有者或任何其他相关细节。

Metadata 以键值对映射的形式存储,其中键的类型为 String,值的类型可以是以下之一:String、Integer、Long、Float、Double、UUID。)

document loader(文档加载器)

document parser(文档解析 将不同的文档进行解析)

document transformer(文档转换 文档格式之间的转换)

Graph Transformer 是一个接口,通过提取语义图元素(例如节点和关系),将非结构化的 Document 对象转换为结构化的 GraphDocument。它非常适合将原始文本转换为结构化语义图。

Text Segment

一旦您的 Document 被加载,就该将它们分割(分块)成更小的片段了。LangChain4j 的领域模型包含一个 TextSegment 类,它表示 Document 的一个片段。顾名思义,TextSegment 只能表示文本信息。

Document Splitter

LangChain4j 有一个 DocumentSplitter 接口,并提供了一些开箱即用的实现:

DocumentByParagraphSplitter、DocumentByLineSplitter、DocumentBySentenceSplitter、DocumentByWordSplitter、DocumentByCharacterSplitter、DocumentByRegexSplitter

Text Segment Transformer

TextSegmentTransformer 与 DocumentTransformer(如上所述)类似,但它转换的是 TextSegment。与 DocumentTransformer 一样,没有一刀切的解决方案,因此我们建议根据您的独特数据实施您自己的 TextSegmentTransformer。一种在改进检索方面效果很好的技术是将 Document 标题或简短摘要包含在每个 TextSegment 中。

Embedding 类封装了一个数值向量,它代表了已被嵌入的内容(通常是文本,例如 TextSegment)的“语义含义”。

Embedding Model

EmbeddingModel 接口表示一种特殊的模型,可将文本转换为 Embedding。

嵌入存储(Embedding Store)

EmbeddingSearchRequest 代表一个在 EmbeddingStore 中进行搜索的请求。它有以下属性:

  • Embedding queryEmbedding:用作参考的嵌入。

  • int maxResults:返回的最大结果数。这是一个可选参数。默认值:3。

  • double minScore:最小分数,范围为 0 到 1(包含)。只有分数 >= minScore 的嵌入才会被返回。这是一个可选参数。默认值:0。

  • Filter filter:在搜索过程中应用于 Metadata 的过滤器。只有 Metadata 与 Filter 匹配的 TextSegment 才会被返回。

三、具体实现

需要导入相关的文档解析依赖

嵌入模型、文档解析依赖

<langchain.version>1.15.0-beta25</langchain.version> 有些依赖需要到maven仓库找到对应的版本

<!-- 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--        Amazon Bedrock 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-bedrock</artifactId>
    <version>1.15.1</version>
</dependency>
<!--        Azure OpenAI 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-azure-open-ai</artifactId>
    <version>1.15.1</version>
</dependency>
<!-- ollama 嵌入模型-->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-ollama</artifactId>
    <version>1.15.1</version>
    <exclusions>
        <exclusion>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-http-client-jdk</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--        Cohere 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-cohere</artifactId>
    <version>${langchain.version}</version>
</dependency>

<!--        DashScope 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-dashscope</artifactId>
    <version>${langchain.version}</version>
</dependency>

<!--        GitHub Models  嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-github-models</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--        Google Vertex AI  嵌入模型  -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-vertex-ai</artifactId>
    <version>${langchain.version}</version>
    <!--            排除和Milvus 的冲突-->
    <exclusions>
        <exclusion>
            <groupId>io.grpc</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.google.protobuf</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>

</dependency>
<!--        Hugging Face  嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-hugging-face</artifactId>
    <version>${langchain.version}</version>
</dependency>


<!--        Jina  嵌入模型 -->

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-jina</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--        Jlama  嵌入模型 java 20+ -->
<!--        <dependency>-->
<!--            <groupId>dev.langchain4j</groupId>-->
<!--            <artifactId>langchain4j-jlama</artifactId>-->
<!--            <version>1.10.0-beta18</version>-->
<!--        </dependency>-->


<!--        LocalAI  嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-local-ai</artifactId>
    <version>${langchain.version}</version>
</dependency>


<!--        Mistral AI 嵌入模型 -->

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-mistral-ai</artifactId>
    <version>1.15.1</version>
    <exclusions>
        <exclusion>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-http-client-jdk</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!--        Nomic 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-nomic</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--        OpenAI Official SDK 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai-official</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--        OVHcloud AI Endpoints 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-ovh-ai</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--       Qianfan 嵌入模型 -->

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-qianfan</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--       Voyage AI 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-voyage-ai</artifactId>
    <version>${langchain.version}</version>
    <exclusions>
        <exclusion>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-http-client-jdk</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--      Cloudflare Workers AI嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-workers-ai</artifactId>
    <version>${langchain.version}</version>
</dependency>

<!--      Zhipu AI 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-zhipu-ai</artifactId>
    <version>${langchain.version}</version>
    <exclusions>
        <exclusion>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-http-client-jdk</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--      Xinference 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-xinference</artifactId>
    <version>${langchain.version}</version>
</dependency>
<!--      Google AI Gemini Embeddings 嵌入模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-google-ai-gemini</artifactId>
    <version>1.15.1</version>
    <exclusions>
        <exclusion>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-http-client-jdk</artifactId>
        </exclusion>
    </exclusions>
</dependency>文档解析
 <!-- 文档解析器 -->
            <dependency>
                <groupId>dev.langchain4j</groupId>
                <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
                <version>${langchain.version}</version>
            </dependency>
            <dependency>
                <groupId>dev.langchain4j</groupId>
                <artifactId>langchain4j-document-parser-apache-poi</artifactId>
                <version>${langchain.version}</version>
            </dependency>
            <dependency>
                <groupId>dev.langchain4j</groupId>
                <artifactId>langchain4j-document-parser-markdown</artifactId>
                <version>${langchain.version}</version>
            </dependency>
            <dependency>
                <groupId>dev.langchain4j</groupId>
                <artifactId>langchain4j-document-parser-yaml</artifactId>
                <version>${langchain.version}</version>
            </dependency>

            <!-- easy rag 知识库 -->
            <dependency>
                <groupId>dev.langchain4j</groupId>
                <artifactId>langchain4j-easy-rag</artifactId>
                <version>${langchain.version}</version>
            </dependency>

1、使用milvus 向量数据库(数据库中进行向量数据库配置)

向量数据库配置表结构 rag_config.sql

通过数据库获取指定的向量数据库连接参数,作为RAG的提供方

Milvus配置工具

//milvus 连接配置
@Slf4j
public class RagConfigTool {
    //创建连接
    public static MilvusServiceClient getClient(RagConfig ragConfig) {
        ConnectParam.Builder builder = ConnectParam.newBuilder()
            .withHost(ragConfig.getHost())
            .withPort(Integer.valueOf(String.valueOf(ragConfig.getPort())));
        //用户名 密码登录
        if (StringUtils.isNotEmpty(ragConfig.getUsername()) && StringUtils.isNotEmpty(ragConfig.getPassword())) {
            builder.withAuthorization(ragConfig.getUsername(), ragConfig.getPassword());

        }
        MilvusServiceClient milvusServiceClient = new MilvusServiceClient(builder.build());
        return milvusServiceClient;
    }



    //创建数据库 和 表
    public static Boolean createRagDatabase(RagConfig ragConfig, MilvusServiceClient client) {
        try {
            //只创建向量数据库
            CreateDatabaseParam.Builder builder = CreateDatabaseParam.newBuilder();
            builder.withDatabaseName(ragConfig.getRagDatabase());
            client.createDatabase(builder.build());

            return true;

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    //删除数据库
    public static Boolean deleteRagDatabase(RagConfig ragConfig) {
        DropCollectionParam dropCollectionParam = DropCollectionParam.newBuilder()
            .withDatabaseName(ragConfig.getRagDatabase())
            .withCollectionName(ragConfig.getCollectionName())
            .build();
//        DropDatabaseParam dropDatabaseParam = DropDatabaseParam.newBuilder().withDatabaseName(ragConfig.getRagDatabase()).build();
        RagConfig bo = new RagConfig();
        BeanUtils.copyProperties(ragConfig, bo);
        getClient(bo).dropCollection(dropCollectionParam);
        return true;
    }

    /**
     * 获取向量对象
     *
     * @param ragConfig
     * @return
     */
    public static ContentRetriever getContentRetriever(RagConfig ragConfig) {
        //1.调用嵌入模型 type
        //2.配置向量数控
        //3.返回
        if(StringUtils.isNull(ragConfig)) {
            return null;

        }
        EmbeddingModel embeddingModel = embeddingModelRag(ragConfig);
        ragConfig.setDimension(String.valueOf(embeddingModel.dimension()));
        EmbeddingStore<TextSegment> embeddingStore = milvusEmbeddingStoreRag(ragConfig);
        return contentRetriever(embeddingModel,embeddingStore);
    }

    /**
     * 文件写入向量库
     *
     * @param ragConfig
     * @return
     */
    public static EmbeddingStoreIngestor getEmbeddingStoreIngestor(RagConfig ragConfig) {
        //1.调用嵌入模型 type
        //2.配置向量数控
        //3.加载数据
        //从模型中获取向量维度
        EmbeddingModel embeddingModel = embeddingModelRag(ragConfig);
        ragConfig.setDimension(String.valueOf(embeddingModel.dimension()));
        return embeddingStoreIngestorRag(embeddingModel, milvusEmbeddingStoreRag(ragConfig),ragConfig);
    }
    /**
     * 文件写入向量库
     *
     * @param ragConfig
     * @return
     */
    public static EmbeddingStoreIngestor getEmbeddingStoreIngestorFile(RagConfig ragConfig, List<Document> documents) {
        //1.调用嵌入模型 type
        //2.配置向量数控
        //3.加载数据
        //从模型中获取模型所属的向量维度
        EmbeddingModel embeddingModel = embeddingModelRag(ragConfig);
        ragConfig.setDimension(String.valueOf(embeddingModel.dimension()));
        EmbeddingStoreIngestor embeddingStoreIngestor = embeddingStoreIngestorRag(embeddingModel, milvusEmbeddingStoreRag(ragConfig), ragConfig);
        embeddingStoreIngestor.ingest(documents);
        return embeddingStoreIngestor;
    }



    /**
     * MiniLM 嵌入模型
     */
    public static EmbeddingModel embeddingModelRag(RagConfig ragConfig) {
        //为空返回默认模型
        if(StringUtils.isNull(ragConfig.getEmbeddingUseConfigId())) {
            return new AllMiniLmL6V2EmbeddingModel();
        }
        RagEmbeddingUseConfig ragEmbeddingUseConfigVo = ragConfig.getRagEmbeddingUseConfig();
        RagEmbeddingConfig ragEmbeddingConfigVo = ragConfig.getRagEmbeddingConfig();
        EmbeddingModelFactory embeddingModelFactory = new EmbeddingModelFactory();
        return embeddingModelFactory.getEmbeddingModel(ragEmbeddingConfigVo.getType(), ragEmbeddingUseConfigVo);

    }

    /**
     * Milvus向量数据库配置
     */
    public static EmbeddingStore<TextSegment> milvusEmbeddingStoreRag(RagConfig ragConfig) {
        return MilvusEmbeddingStore.builder()
            .host(ragConfig.getHost())
            .port(Integer.valueOf(String.valueOf(ragConfig.getPort())))
            .databaseName(ragConfig.getRagDatabase())
            .collectionName(ragConfig.getCollectionName())
            .dimension(Integer.valueOf(ragConfig.getDimension()))
            .build();
    }

    /**
     * 文档注入器
     * TODO 后续需要优化
     */
    public static EmbeddingStoreIngestor embeddingStoreIngestorRag(EmbeddingModel embeddingModel,
                                                                   EmbeddingStore<TextSegment> embeddingStore, RagConfig ragConfigVo) {
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
            .documentSplitter(DocumentSplitters.recursive(500, 50))
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build();
        return ingestor;
    }

    /**
     * 文档注入器
     * TODO 后续需要优化
     */
    public static EmbeddingStoreIngestor embeddingStoreIngestorRagFile(EmbeddingModel embeddingModel,
                                                                   EmbeddingStore<TextSegment> embeddingStore, RagConfig ragConfigVo) {
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
            .documentSplitter(DocumentSplitters.recursive(500, 50))
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build();
        // 1、加载知识库
        List<Document> documents = new ArrayList<>();
        ragConfigVo.getRagConfigFiles().forEach(ragConfigFileVo -> {
            //写入
            DocumentParser documentParser = getDocumentParser(ragConfigFileVo.getFileSuffix().replace(".", ""));
            Document load = UrlDocumentLoader.load(ragConfigFileVo.getUrl(), documentParser);
            documents.add(load);
        });
        ingestor.ingest(documents);
        return ingestor;
    }

    /**
     * 构建向量数据库检索对象
     *
     * @return
     */
    public static ContentRetriever contentRetriever(EmbeddingModel embeddingModel,
                                                    EmbeddingStore<TextSegment> embeddingStore) {
        return EmbeddingStoreContentRetriever.builder()
            .embeddingStore(embeddingStore)
            .embeddingModel(embeddingModel)
            .minScore(0.5)
            .maxResults(3)
            .build();
    }

    public static DocumentParser getDocumentParser(String documentType) {
        return switch (documentType) {
            case "pdf" -> new ApachePdfBoxDocumentParser();
            case "txt" -> new TextDocumentParser();
            case "html" -> new TextDocumentParser();

            case "md" -> new MarkdownDocumentParser();
            case "yml"-> new YamlDocumentParser();
            case "yaml"-> new YamlDocumentParser();

            //doc, docx, ppt, pptx, xls, xlsx
            case "docx" -> new ApachePoiDocumentParser ();
            case "doc" -> new ApachePoiDocumentParser ();
            case "xls" -> new ApachePoiDocumentParser ();
            case "xlsx" -> new ApachePoiDocumentParser ();
            case "ppt" -> new ApachePoiDocumentParser ();
            case "pptx" -> new ApachePoiDocumentParser ();
            default -> new ApacheTikaDocumentParser();//官网说可以解析几乎所有的文件格式。。。。。。 所以作为默认解析器
        };

    }

    //插入知识库的向量数据
    public static void insertRag(RagConfig ragConfigVo, Class<?> clazz) throws Exception {
        EmbeddingModel embeddingModel = embeddingModelRag(ragConfigVo);
        ragConfigVo.setDimension(String.valueOf(embeddingModel.dimension()));
        Method toTextSegment = clazz.getMethod("toTextSegment");
        Document document = (Document) toTextSegment.invoke(clazz.newInstance());
        List<Document> documents = new ArrayList<>();
        documents.add(document);
        getEmbeddingStoreIngestorFile(ragConfigVo, documents);
    }
    //删除对应的数据
    public static void delRag(RagConfig ragConfigVo, List<Object> bos) throws Exception,NoSuchFieldException {
        EmbeddingModel embeddingModel = embeddingModelRag(ragConfigVo);
        ragConfigVo.setDimension(String.valueOf(embeddingModel.dimension()));
        EmbeddingStore<TextSegment> embeddingStore = milvusEmbeddingStoreRag(ragConfigVo);
        bos.forEach(bo -> {
            Class<?> aClass = bo.getClass();
            long aLong = 0L;
            try {
                Field id = aClass.getDeclaredField("id");
                id.setAccessible(true);
                 aLong = id.getLong(bo);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            Filter filter = metadataKey("id").isEqualTo(String.valueOf(aLong));
            embeddingStore.removeAll(filter);
        });
    }


}

2、嵌入模型配置

基础模型配置:

sql: rag_embedding_config.sql

官网:https://docs.langchain4j.dev/category/embedding-models

数据库

嵌入模型工厂

3、文档解析

Langchain4j 支持的解析文件很多,目前发现excel不是逐行解析,所以需要自定义excel解析方式

pom依赖添加

 			<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>3.3.4</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.poi</groupId>
                        <artifactId>poi-ooxml-schemas</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.2</version>
            </dependency>