《史上最简单的SpringAI+Llama3.x教程》-04-RAG核心Embedding及向量检索Retrieval

上一节咱们顺利从本地读取了文件内容,并且可以使用transform工具对文件进行内容处理,下面咱们继续看看如何将文件进行向量化,并且存储到向量数据库中。

Embedding 知识扩展

Embeddings是一种将高维数据映射到低维空间的技术,它能够捕捉数据之间的语义关系和相似性,使得模型能够更好地理解和处理这些数据。

在自然语言处理(NLP)中,Embeddings通常用于将文本转换为连续向量,基于分布式假设捕捉语义信息。

例如,Word2Vec、GloVe和BERT等模型通过学习上下文和语义信息,将单词映射到连续的向量空间。

Embeddings在多个领域都有广泛的应用,包括但不限于:

  • 自然语言处理:Embeddings可以帮助计算机更好地理解单词之间的语义关系,这对于机器翻译、情感分析等任务非常有益.
  • 图像处理:在计算机视觉领域,图像Embeddings被用于图像分类、相似性匹配等任务。通过将图像映射到低维向量空间,我们可以比较和分析图像之间的相似性.
  • 推荐系统:在推荐系统中,Embeddings被用于表示用户和商品。这种表示能够捕捉用户和商品之间的潜在关系,从而提高推荐的准确性.

简单来说,embedding向量就是一个N维的实值向量,它将输入的数据表示成一个连续的数值空间中的点。

在这里插入图片描述

如图 通俗易懂的描述:嵌入就相当于给文本穿上了“数字化”的外衣,目的是让机器更好的理解和处理。

Embedding 起源于 Word Embedding,从横向发展上看: Word Embedding -> Item Embedding -> Entity Embedding -> Graph Embedding -> Position Embedding -> Segment Embedding

从纵向发展看:

  • 由静态的Word Embedding(如Word2Vec、GloVe和FastText)
  • 动态预训练模型(如ELMo、BERT、GPT、GPT-2、GPT-3、ALBERT、XLNet等)。

大型语言模型可以生成上下文相关的 embedding 表示,可以更好地捕捉单词的语义和上下文信息。

Spring AI是如何支持Embedding

在 Spring AI中通过EmbeddingModel来实现,EmbeddingModel接口旨在简化AI和机器学习中的嵌入模型的集成。

其主要作用是将文本转换为数值向量,即嵌入。这些嵌入对于执行语义分析和文本分类等任务至关重要。EmbeddingModel接口的设计主要追求两个目标:

  • 可移植性**:**确保在不同嵌入模型间的高度适应性。开发者可以轻松地在各种嵌入技术或模型之间进行切换,只需进行极小的代码更改。这与Spring框架强调的模块化和可互换性原则一致。
  • 简洁性:EmbeddingModel使得文本到嵌入的转换过程更为简单。通过提供embed(String text)embed(Document document)等直观方法,它减少了处理原始文本和嵌入算法的复杂性。这样的设计让开发者,尤其是AI领域的新手,能够更容易地在他们的应用中使用嵌入技术,无需深入了解其背后的工作原理。

实现设计

EmbeddingModel API基于Spring AI库中的通用AI模型API构建。因此,EmbeddingModel接口继承了Model接口,后者提供了一系列与AI模型交互的标准方法。EmbeddingRequestEmbeddingResponse类分别继承自ModelRequestModelResponse类,用于封装嵌入模型的输入和输出数据。

嵌入API随后被用于实现特定嵌入模型的高级组件,例如OpenAITitanAzure OpenAIOllama等。

下图展示了Embedding API与Spring AI模型API以及嵌入模型之间的关系:

在这里插入图片描述

现在Spring AI 已经支持了很多Embedding模型,如下:

文本向量化(使用Ollama Embedding)

要计算向量数据库的嵌入向量,需要选择与 AI 模型匹配的嵌入模型,比如,openai的模型text-embedding-ada-002,咱们这次使用的Embedding是llama3.1模型进行数据向量化。

通过Ollama,可以在本地运行多种大型语言模型(LLMs),并利用这些模型生成文本嵌入。Spring AI通过OllamaEmbeddingModel支持Ollama文本嵌入功能。

嵌入实质上是浮点数构成的向量。两个向量之间的距离可以反映它们之间的相关性:

  • 距离越近,相关性越高;
  • 距离越远,相关性越低。

以下案例通过llama3.1模型实现。

项目embedding模型配置信息

spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      embedding:
        model: llama3.1

将文本进行向量化实现

@RestController
@AllArgsConstructor
@RequestMapping("/embedding")
public class EmbeddingController {

    private final OllamaEmbeddingModel ollamaEmbeddingModel;

    /**
     * 将文本内容向量化
     *
     * @param message 文本
     * @return 向量化数据
     */
    @GetMapping("/text")
    public Map<String, ?> embed(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        EmbeddingResponse embeddingResponse = 
            ollamaEmbeddingModel.embedForResponse(List.of(message));
        return Map.of("embedding", embeddingResponse);
    }
}

关于向量数据库

向量数据库技术是一种专门用于存储和处理向量数据的数据库系统,它以向量为基本数据类型,旨在处理和存储大规模向量数据。

向量数据库和传统关系型数据库在数据模型上的主要区别体现在数据的表示和组织方式上。

  • 向量数据库将数据表示为多维空间中的矢量,强调数据之间的相似性和距离关系,这种模型适合处理大规模的非结构化数据,侧重于数据的相似性搜索和模式匹配。
  • 传统关系型数据库基于表格形式,数据以行和列的结构组织,通过明确的关系和约束来关联不同的表,更适用于结构化数据,重点在于精确的数据查询、更新和事务处理。

向量数据库由于其在处理高维数据和相似性搜索方面的优势,常被用于图像识别、自然语言处理、推荐系统等领域,而关系型数据库则广泛应用于企业资源规划(ERP)、客户关系管理(CRM)等具有结构化数据和事务处理需求的系统。

文本向量存储(基于Chroma DB)

SpringAI支持了很多向量数据接入,如下:

本次案例使用 Chroma VectorStore 来存储文档嵌入并执行相似性搜索。

Chroma 是开源嵌入数据库。它为您提供了用于存储文档嵌入、内容和元数据以及搜索这些嵌入(包括元数据过滤)的工具。

使用docker安装Chroma

# 加载镜像
docker pull chromadb/chroma
# 启动container
docker run -d --rm --name chromadb -p 8000:8000 chromadb/chroma:latest

Chroma项目配置

spring:
  ai:
    ollama:
      chat:
        options:
          model: llama3.1
          temperature: 0.5
      base-url: http://localhost:11434
      embedding:
        model: llama3.1
    vectorstore:
      chroma:
        client:
          host: http://localhost
          port: 8000
        collection-name: "jingyu-spring-ai"
        initialize-schema: true     # 如果chromadb中没有collection-name,那么此处需要设置为true,否者会404报错

pom配置

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

向量化的代码很简单如下:

@RestController
@RequestMapping("/vector")
@AllArgsConstructor
public class VectorController {

    private final VectorStore vectorStore;

    /**
     * 将向量化数据存储到向量数据库
     *
     * @param message 文本内容
     * @return 向量化存储结果
     */
    @GetMapping("/msg/vector")
    public Boolean embedAndOptions(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {

        // 将文本内容向量化到chromaDB中
        vectorStore.add(List.of(new Document(message)));

        return Boolean.TRUE;
    }
}

第一次使用向量化存储的API时,很诧异,为啥这么简单,竟然向量化也不需要配置,直接add()就可以实现了。

打开其源码才发现,大善人在add()都已经完成了,咱们来一起看一下ChromaVectorStore的实现:

public class ChromaVectorStore implements VectorStore, InitializingBean {

    // 其他代码省略
    
    // 构造方法中自动注入了一个Embedding模型
    public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, String collectionName, boolean initializeSchema) {
        this.embeddingModel = embeddingModel;
        this.chromaApi = chromaApi;
        this.collectionName = collectionName;
        this.initializeSchema = initializeSchema;
        this.filterExpressionConverter = new ChromaFilterExpressionConverter();
    }

    public void add(List<Document> documents) {
        Assert.notNull(documents, "Documents must not be null");
        if (!CollectionUtils.isEmpty(documents)) {
            List<String> ids = new ArrayList();
            List<Map<String, Object>> metadatas = new ArrayList();
            List<String> contents = new ArrayList();
            List<float[]> embeddings = new ArrayList();
            Iterator var6 = documents.iterator();
    
            while(var6.hasNext()) {
                Document document = (Document)var6.next();
                ids.add(document.getId());
                metadatas.add(document.getMetadata());
                contents.add(document.getContent());
                document.setEmbedding(this.embeddingModel.embed(document));
                embeddings.add(JsonUtils.toFloatArray(document.getEmbedding()));
            }
    
            this.chromaApi.upsertEmbeddings(this.collectionId, new ChromaApi.AddEmbeddingsRequest(ids, embeddings, metadatas, contents));
        }
    }
}

向量检索

存储数据只是咱们得第一步,目的还是为了咱们能够更好的根据语义去检索到咱们得数据。

向量数据库的检索也挺简单,咱们可以只需要设置部分参数,底层会自动帮助我们做问题的Embedding,然后再到向量数据库中进行匹配查询。

向量化检索

@GetMapping("/retrieval")
public Object queryVector(@RequestParam("query") String query) {
    SearchRequest searchRequest = SearchRequest.defaults()
            .withQuery(query)
            .withTopK(5)
            .withSimilarityThreshold(SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL);
//           .withFilterExpression();

    return vectorStore.similaritySearch(searchRequest);
}

这里需要注意的有两点:

  1. SearchRequest中设置的参数:
    1. query:用于嵌入相似性比较的文本。
    2. topK:指定要返回的相似文档的最大数量。这通常被称为“前 K”搜索,或“K 最近邻”(KNN)。
    3. similarityThreshold:相似度检索阈值。阈值值为0.0表示接受任何相似度或禁用相似度阈值过滤。阈值值为1.0表示需要完全匹配。例如,默认情况下,如果将阈值设置为 0.75,则仅返回相似度高于此值的文档。
    4. filterExpression:基于 ANTLR4 的外部 DSL,接受过滤器表达式作为字符串。例如,对于 country、year 和 等元数据键,可以使用如下表达式:isActivecountry == 'UK' && year >= 2020 && isActive == true.
  2. Chroma查询过滤语法:🧪 Chromadb Querying a Collection

以上就是本节所有的内容了,下面我将继续研究一下,在数据有限的情况下,如何通过Function Calling来获取外部数据。

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用信息,你遇到的问题是在编译过程中出现了错误。具体来说,错误信息是"\k_quants.h(145): error C2059: 语法错误:“)”"。根据提供的引用,这个错误可能是在编译GPU版本的llama.cpp文件时出现的,并且与选项'gpu-architecture'的值为'native'有关。 解决这个问题的步骤如下: 1. 首先,查看编译错误的具体位置,即\k_quants.h文件的第145行。 2. 在该行附近检查代码,查找是否有语法错误,例如缺少分号或括号不匹配等。 3. 如果代码没有明显的语法错误,可以考虑检查编译选项和环境设置是否正确。特别是关于选项'gpu-architecture'的值,确保它被正确定义和使用。 4. 如果是Makefile文件导致的问题,则需要修改Makefile源码,确保编译选项被正确设置。 5. 重新编译代码并进行测试,确保问题已经解决。 请注意,以上步骤仅供参考,具体解决方法可能因个人环境和代码情况而异。建议仔细检查错误信息和相关代码,结合实际情况采取相应的解决措施。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【AI实战】llama.cpp量化cuBLAS编译;nvcc fatal:Value ‘native‘ is not defined for option ‘gpu-...](https://blog.csdn.net/zengNLP/article/details/131576986)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [ubuntu下编译时遇到的错误及解决方式](https://blog.csdn.net/weixin_30267691/article/details/94986381)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

静愚 AGI

你的善意终将流回自己,加油!

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

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

打赏作者

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

抵扣说明:

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

余额充值