SpringAI+DeepSeek大模型应用开发——7 RAG:知识库 ChatPDF

7 RAG(知识库 ChatPDF)

  • 由于训练大模型非常耗时,再加上训练语料本身比较滞后,所以大模型存在知识限制问题:

    • 知识数据比较落后,往往是几个月之前的;
    • 不包含太过专业领域或者企业私有的数据;
  • 为了解决这些问题,就需要用到RAG了。

7.1 RAG原理

  • 要解决大模型的知识限制问题,其实并不复杂;
    • 解决的思路就是给大模型外挂一个知识库,可以是专业领域知识,也可以是企业私有的数据;
  • 不过,知识库不能简单的直接拼接在提示词中;
    • 因为通常知识库数据量都是非常大的,而大模型的上下文是有大小限制的,早期的GPT上下文不能超过2000token,现在也不到200k token,因此知识库不能直接写在提示词中;
  • 怎么办?
    • 思路很简单,庞大的知识库中与用户问题相关的其实并不多;
    • 所以,只要想办法从庞大的知识库中找到与用户问题相关的一小部分,组装成提示词,发送给大模型就可以了;
  • 那么问题来了,该如何从知识库中找到与用户问题相关的内容呢?
    • 全文检索?但是在这里是不合适的,因为全文检索是文字匹配,而这里要求的是内容上的相似度;
    • 而要从内容相似度来判断,这就不得不提到向量模型的知识了。

7.1.1 向量模型

  • 向量是空间中有方向和长度的量,空间可以是二维,也可以是多维;

  • 向量既然是在空间中,那么两个向量之间就一定能计算距离;

  • 以二维向量为例,向量之间的距离有两种计算方法:

    在这里插入图片描述

  • 通常,两个向量之间欧式距离越近,就认为两个向量的相似度越高(余弦距离相反,越大相似度越高);

  • 所以,如果能把文本转为向量,就可以通过向量距离来判断文本的相似度了;

  • 现在有不少的专门的向量模型,就可以实现将文本向量化。一个好的向量模型,就是要尽可能让文本含义相似的向量,在空间中距离更近

    在这里插入图片描述

  • 阿里云百炼平台就提供了这样的模型,用于将文本向量化:

    在这里插入图片描述

    • 这里选择通用文本向量-v3,这个模型兼容OpenAI,所以我们依然采用OpenAI的配置;
  • 修改application.yaml,添加向量模型配置:

    spring:
      application:
        name: chart-robot
      ai:
        ollama:
          # Ollama服务地址
          base-url: http://localhost:11434
          chat:
            # 模型名称,可更改
            model: deepseek-r1:14b
            options:
              # 模型温度,值越大,输出结果越随机
              temperature: 0.8
        openai:
          base-url: https://dashscope.aliyuncs.com/compatible-mode
          api-key: ${
         
         OPENAI_API_KEY}
          chat:
            options:
              # 可选择的模型列表 https://help.aliyun.com/zh/model-studio/getting-started/models
              model: qwen-max-latest
          embedding:
            options:
              model: text-embedding-v3
              dimensions: 1024
    

7.1.2 向量模型测试

  • 前面说过,文本向量化以后,可以通过向量之间的距离来判断文本相似度;

  • 接下来,就来测试下阿里百炼提供的向量大模型;

  • 在项目中写一个工具类,用以计算向量之间的欧氏距离和**余弦距离。**新建一个com.shisan.ai.util包,在其中新建一个VectorDistanceUtils类:

    package com.shisan.ai.util;
    
    public class VectorDistanceUtils {
         
         
    
        // 防止实例化
        private VectorDistanceUtils() {
         
         }
    
        // 浮点数计算精度阈值
        private static final double EPSILON = 1e-12;
    
        /**
         * 计算欧氏距离
         * @param vectorA 向量A(非空且与B等长)
         * @param vectorB 向量B(非空且与A等长)
         * @return 欧氏距离
         * @throws IllegalArgumentException 参数不合法时抛出
         */
        public static double euclideanDistance(float[] vectorA, float[] vectorB) {
         
         
            validateVectors(vectorA, vectorB);
    
            double sum = 0.0;
            for (int i = 0; i < vectorA.length; i++) {
         
         
                double diff = vectorA[i] - vectorB[i];
                sum += diff * diff;
            }
            return Math.sqrt(sum);
        }
    
        /**
         * 计算余弦距离
         * @param vectorA 向量A(非空且与B等长)
         * @param vectorB 向量B(非空且与A等长)
         * @return 余弦距离,范围[0, 2]
         * @throws IllegalArgumentException 参数不合法或零向量时抛出
         */
        public static double cosineDistance(float[] vectorA, float[] vectorB) {
         
         
            validateVectors(vectorA, vectorB);
    
            double dotProduct = 0.0;
            double normA = 0.0;
            double normB = 0.0;
    
            for (int i = 0; i < vectorA.length; i++) {
         
         
                dotProduct += vectorA[i] * vectorB[i];
                normA += vectorA[i] * vectorA[i];
                normB += vectorB[i] * vectorB[i];
            }
    
            normA = Math.sqrt(normA);
            normB = Math.sqrt(normB);
    
            // 处理零向量情况
            if (normA < EPSILON || normB < EPSILON) {
         
         
                throw new IllegalArgumentException("Vectors cannot be zero vectors");
            }
    
            // 处理浮点误差,确保结果在[-1,1]范围内
            double similarity =  dotProduct / (normA * normB);
            similarity = Math.max(Math.min(similarity, 1.0), -1.0);
    
            return similarity;
        }
    
        // 参数校验统一方法
        private static void validateVectors(float[] a, float[] b) {
         
         
            if (a == null || b == null) {
         
         
                throw new IllegalArgumentException("Vectors cannot be null");
            }
            if (a.length != b.length) {
         
         
                throw new IllegalArgumentException("Vectors must have same dimension");
            }
            if (a.length == 0) {
         
         
                throw new IllegalArgumentException("Vectors cannot be empty");
            }
        }
    }
    
    • 由于SpringBoot的自动装配能力,刚才配置的向量模型可以直接使用;
  • 编写测试类:

    在这里插入图片描述

    package com.shisan.ai;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import com.shisan.ai.util.VectorDistanceUtils;
    import org.springframework.ai.openai.OpenAiEmbeddingModel;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.Arrays;
    import java.util.List;
    
    @SpringBootTest
    class ChatRobotApplicationTests {
         
         
    
        // 自动注入向量模型
        @Autowired
        private OpenAiEmbeddingModel embeddingModel;
    
        @Test
        public void testEmbedding() {
         
         
            // 1.测试数据
            // 1.1.用来查询的文本,国际冲突
            String query = "global conflicts";
    
            // 1.2.用来做比较的文本
            String[] texts = new String[]{
         
         
                    "哈马斯称加沙下阶段停火谈判仍在进行 以方尚未做出承诺",
                    "土耳其、芬兰、瑞典与北约代表将继续就瑞典“入约”问题进行谈判",
                    "日本航空基地水井中检测出有机氟化物超标",
                    "国家游泳中心(水立方):恢复游泳、嬉水乐园等水上项目运营",
                    "我国首次在空间站开展舱外辐射生物学暴露实验",
            };
            // 2.向量化
            // 2.1.先将查询文本向量化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失散13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值