Spring AI 系列之二十一 - EmbeddingModel

之前做个几个大模型的应用,都是使用Python语言,后来有一个项目使用了Java,并使用了Spring AI框架。随着Spring AI不断地完善,最近它发布了1.0正式版,意味着它已经能很好的作为企业级生产环境的使用。对于Java开发者来说真是一个福音,其功能已经能满足基于大模型开发企业级应用。借着这次机会,给大家分享一下Spring AI框架。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 Spring AI-1.0.0,JDK版本使用的是19
代码参考: https://github.com/forever1986/springai-study

目录

  • 1 Embedding
    • 1.1 什么是Embedding
    • 1.2 嵌入模型(Embeddings Model)
  • 2 Spring AI 中的Embeddings Model
  • 2 示例演示
  • 3 加载本地模型

前面几乎将Spring AI的聊天模型的功能都讲了一遍,接下来开始几章将会讲解其它类型的大模型。在聊天模型中Spring AI提供了ChatClient做了一层常用的功能性封装,比如聊天记忆、RAG、MCP等应用场景。很遗憾其它类型的大模型并没有提供再次封装的上层API,不过通过前面对聊天模型ChatModel的使用,也知道可以直接使用类似ChatModel对模型的操作,在Spring AI中一样对各类大模型进行了类似ChatModel的封装。这一章先从嵌入模型(Embeddings Model)开始。

1 Embedding

使用嵌入模型(Embeddings Model)之前,需要了解Embedding是什么?为什么要使用Embedding?

1.1 什么是Embedding

首先在人类社会中使用的文字、图片、音频、视频等数据,如何让大模型识别。这里拿文字来说明这个过程:
1)编码: 计算机只会识别0和1,那么这时候要让计算机识别文字,就需要把所有文字进行编码,以中文为例比如00001代表男,00002代表女,这样每个字都有一个编码。
在这里插入图片描述

虽然编码可以让计算机识别,但是还是有缺点的。最大的缺点就是文字之间是有一定的关联关系,也就是说每个字独立编码,那么机器是不理解文字之间的关系,为了解决这个问题,分词就出现了。

2)Tokenizer : 为了解决文字之间的关系。这时候就有人想到使用Tokenizer 分词器。在每个语言体系中,并不是所有的字都要独立编码,有些文字他们的语言体系中就是一直连在一起使用的,他们之间是有一定的含义,这样可能只需要对子词进行编码即可。这样就可以通过一定数据训练得到合理的分词表,这个过程就是Tokenizer做的事情。
在这里插入图片描述

Tokenizer 虽然解决了一定的语义关系,但也造成一个问题,就是过于稀疏,占用过多资源。因为在底层都是2进制表示,那么10万个子词需要一个17维度(2的17次方)才能描述完,但是实际上很多位置上都是0。那么有没有一种办法使用更少的维度来表示更多的子词,这时候就出现了Embedding。子词之间的语义上关系,可能可以通过一个向量维度来表示,一个768维的就能表示768种语义关系可能就已经足够描述所有关系。

3)Embedding: Embeding就是将每个子词ID映射为n维向量,并与位置编码、段落编码相加。这个维度可以简单理解就是相关性。比如其中一个维度表示性别,那么男人和国王在这个维度上面应该是相等的,而女人和皇后在这个维度应该也是相等的。这种通过多维度表示其实就是向量化,而且向量化之后的子词还可以做运算,比如:国王-男=皇后-女 ,其结果在性别这个维度是相等的。
在这里插入图片描述

上图示例中就是一个3维来表示,其中中间那个维度表示性别,那么国王-男和皇后-女的向量运算结果在这个性别维度上都是0。当然实际上可能会很多维,比如512、768、1024等,越多维度表示的语义更为准确,但是造成的效果就是需要更多计算量。

通过Embedding技术将文本、图像和视频转换为一系列浮点数数组(即向量),能够捕捉输入之间的关系。这些向量旨在捕捉文本、图像和视频的含义。Embedding数组的长度被称为向量的维度。通过计算两段文本的向量表示之间的数值距离,应用程序能够确定用于生成嵌入向量的两个对象之间的相似度。这就是Embedding的意义。

1.2 嵌入模型(Embeddings Model)

Embeddings Model模型经过这些年的不断改进,出现了各种各样的Embeddings Model。这里需要注意的是Embeddings Model也是一个训练好的模型,这里不详细讲述,大家有兴趣可以去了解更深入。这个主要给大家讲述几个重要选择Embeddings Model的实战参考。在之前我写的《RAG实践系列》中的这一章《检索增强生成RAG系列3–RAG优化之文档处理》已经提到过。

对于我们如何选择一个embedding,我根据一些实战中的经验总结如下:

  • 排行榜:首先要知道有哪些embedding模型,一般可以去hugging face的排行版上找:https://huggingface.co/spaces/mteb/leaderboard
  • 语言:在排行榜中,你可以根据你的业务选择语言
  • embedding维度:这个需要根据你的业务,如果你业务语义丰富,那么选择维度更高更好,如果语义不丰富,其实选择维度更低会更好。
  • sequence length:不同embedding模型支持不同sequence length,因此需要根据你的业务选择不同的模型
  • 模型大小:这个会根据实际你有多少资源作为选择标准
  • 业务效果:以上几个标准可能只是基本维度,最终还是需要看看业务效果,因此你可能需要选择几个比较合适的模型,然后再逐一的去测试一下其效果相对于你的业务结果如何

2 Spring AI 中的Embeddings Model

在Spring AI中,定义了一个EmbeddingModel接口,旨在便于与人工智能和机器学习中的嵌入模型进行集成。其主要功能是将文本转换为数值向量,通常称为“嵌入”。这些嵌入对于诸如语义分析和文本分类等任务至关重要。下面是其源代码:

public interface EmbeddingModel extends Model<EmbeddingRequest, EmbeddingResponse> {/*** 需要各个模型厂家实现调用call方法 */@OverrideEmbeddingResponse call(EmbeddingRequest request);/*** 将一个text进行embedding,返回结果向量*/default float[] embed(String text) {Assert.notNull(text, "Text must not be null");List<float[]> response = this.embed(List.of(text));return response.iterator().next();}/*** 将一个文档进行embedding,返回结果向量*/float[] embed(Document document);/*** 将多个text进行embedding,返回结果向量*/default List<float[]> embed(List<String> texts) {Assert.notNull(texts, "Texts must not be null");return this.call(new EmbeddingRequest(texts, EmbeddingOptionsBuilder.builder().build())).getResults().stream().map(Embedding::getOutput).toList();}/*** 将多个文档进行embedding,返回结果向量*/default List<float[]> embed(List<Document> documents, EmbeddingOptions options, BatchingStrategy batchingStrategy) {Assert.notNull(documents, "Documents must not be null");List<float[]> embeddings = new ArrayList<>(documents.size());List<List<Document>> batch = batchingStrategy.batch(documents);for (List<Document> subBatch : batch) {List<String> texts = subBatch.stream().map(Document::getText).toList();EmbeddingRequest request = new EmbeddingRequest(texts, options);EmbeddingResponse response = this.call(request);for (int i = 0; i < subBatch.size(); i++) {embeddings.add(response.getResults().get(i).getOutput());}}Assert.isTrue(embeddings.size() == documents.size(),"Embeddings must have the same number as that of the documents");return embeddings;}/*** 将多个text进行embedding,但返回请求的结果Response */default EmbeddingResponse embedForResponse(List<String> texts) {Assert.notNull(texts, "Texts must not be null");return this.call(new EmbeddingRequest(texts, EmbeddingOptionsBuilder.builder().build()));}/*** 获取嵌入向量的维度数量。请注意,通常情况下,此操作默认会执行。*/default int dimensions() {return embed("Test String").length;}}

EmbeddingModel接口设计围绕着两个主要目标展开:

  • 可移植性:此接口确保了在各种嵌入式模型之间能够轻松实现适应性。它使开发人员能够通过最少的代码更改来切换不同的嵌入技术或模型。这种设计符合 Spring 的模块化和可互换性理念。
  • 简洁性:EmbeddingModel 简化了将文本转换为嵌入的流程。通过提供诸如 embed(String text) 和 embed(Document document) 这样简单的方法,它消除了处理原始文本数据和嵌入算法的复杂性。这一设计选择使得开发人员,尤其是那些对人工智能不熟悉的人,能够更轻松地在其应用程序中使用嵌入,而无需深入研究底层机制。

2 示例演示

代码参考lesson17子模块

示例说明:本示例使用智谱的线上embedding模型进行嵌入(由于智谱的embedding模式是付费的,请保证账号有钱!)

1)新建lesson17子模块,其pom引入如下:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-zhipuai</artifactId></dependency>
</dependencies>

2)配置application.properties文件

## API KEY
spring.ai.zhipuai.api-key=你的智谱模型的API KEY

3)创建演示类EmbeddingController:

import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class EmbeddingController {private final EmbeddingModel embeddingModel;public EmbeddingController(EmbeddingModel embeddingModel) {// 自动注入智谱的EmbeddingModel模型this.embeddingModel = embeddingModel;}@GetMapping("/ai/embeded")public float[] embeded(@RequestParam(value = "message", required = true, defaultValue = "测试进行嵌入") String message) {float[] embed = embeddingModel.embed(message);System.out.println("输出的嵌入向量维度:"+embed.length);return embed;}
}

4)创建启动类Lesson17Application:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Lesson17Application {public static void main(String[] args) {SpringApplication.run(Lesson17Application.class, args);}}

5)演示效果

在这里插入图片描述

在这里插入图片描述

说明:可以看智谱默认的embedding模型的维度是1024维

3 加载本地模型

上面的示例是通过加载线上模型,其实有很多优秀的开源embedding模型,比如BGE-M3、M3E‌等等,很多大厂的embedding也都开源,这个大家可以上网搜一下。但是有个问题,就是很多模型的权重都是基于pytorch或者tensorflow等python框架训练出来的,那么Java中如何加载呢?这部分在前面的RAG中讲过《系列之十 - RAG-加载本地嵌入模型》,大家可以回去看看该示例,这里就不在累述了。

结语:本章先简单浅入的带大家了解了什么是embedding,之后再讲解的Spring AI中的EmbeddingModel,其提供了基础的接口,由各大embedding模型厂商自行实现。最后举例说明如何使用远程和本地的EmbeddingModel。嵌入是大模型的一个基础,它解决了人类社会的内容(文字、图像、视频等)与大模型直接的交互语言,因此了解embedding是非常有必要的。下一章将继续讲解非聊天模型之图像大模型。

Spring AI系列上一章:《Spring AI 系列之二十 - Hugging Face 集成》

Spring AI系列下一章:《Spring AI 系列之二十二 - ImageModel》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92567.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LFU算法及优化

继上一篇的LRU算法的实现和讲解&#xff0c;这一篇来讲述LFU最近使用频率高的数据很大概率将会再次被使用,而最近使用频率低的数据,将来大概率不会再使用。做法&#xff1a;把使用频率最小的数据置换出去。这种算法更多是从使用频率的角度&#xff08;但是当缓存满时&#xff0…

关于原车一键启动升级手机控车的核心信息及注意事项

想知道如何给原车已经有一键启动功能的车辆加装手机远程启动。这是个很实用的汽车改装需求&#xff0c;尤其适合想在冬天提前热车、夏天提前开空调的车主。一、适配方案与核心功能 ‌升级专车专用4G手机控车模块‌&#xff0c;推荐安装「移动管家YD361-3」系统&#xff0c;该方…

数据结构与算法:类C语言有关操作补充

数据结构与算法:类C语言操作补充 作为老师,我将详细讲解类C语言(如C或C++)中的关键操作,包括动态内存分配和参数传递。这些内容在数据结构与算法中至关重要,例如在实现动态数组、链表或高效函数调用时。我会用通俗易懂的语言和代码示例逐步解释,确保你轻松掌握。内容基…

Go 并发(协程,通道,锁,协程控制)

一.协程&#xff08;Goroutine&#xff09;并发&#xff1a;指程序能够同时执行多个任务的能力&#xff0c;多线程程序在一个核的cpu上运行&#xff0c;就是并发。并行&#xff1a;多线程程序在多个核的cpu上运行&#xff0c;就是并行。并发主要由切换时间片来实现"同时&q…

图机器学习(15)——链接预测在社交网络分析中的应用

图机器学习&#xff08;15&#xff09;——链接预测在社交网络分析中的应用0. 链接预测1. 数据处理2. 基于 node2vec 的链路预测3. 基于 GraphSAGE 的链接预测3.1 无特征方法3.2 引入节点特征4. 用于链接预测的手工特征5. 结果对比0. 链接预测 如今&#xff0c;社交媒体已成为…

每日一算:华为-批萨分配问题

题目描述"吃货"和"馋嘴"两人到披萨店点了一份铁盘&#xff08;圆形&#xff09;披萨&#xff0c;并嘱咐店员将披萨按放射状切成大小相同的偶数个小块。但是粗心的服务员将披萨切成了每块大小都完全不同的奇数块&#xff0c;且肉眼能分辨出大小。由于两人都…

Transfusion,Show-o and Show-o2论文解读

目录 一、Transfusion 1、概述 2、方法 二、Show-o 1、概述 2、方法 3、训练 三、Show-o2 1、概述 2、模型架构 3、训练方法 4、实验 一、Transfusion 1、概述 Transfusion模型应该是Show系列&#xff0c;Emu系列的前传&#xff0c;首次将文本和图像生成统一到单…

聊聊 Flutter 在 iOS 真机 Debug 运行出现 Timed out *** to update 的问题

最近刚好有人在问&#xff0c;他的 Flutter 项目在升级之后出现 Error starting debug session in Xcode: Timed out waiting for CONFIGURATION_BUILD_DIR to update 问题&#xff0c;也就是真机 Debug 时始终运行不了的问题&#xff1a; 其实这已经是一个老问题了&#xff0c…

《R for Data Science (2e)》免费中文翻译 (第1章) --- Data visualization(2)

写在前面 本系列推文为《R for Data Science (2)》的中文翻译版本。所有内容都通过开源免费的方式上传至Github&#xff0c;欢迎大家参与贡献&#xff0c;详细信息见&#xff1a; Books-zh-cn 项目介绍&#xff1a; Books-zh-cn&#xff1a;开源免费的中文书籍社区 r4ds-zh-cn …

【机器学习【9】】评估算法:数据集划分与算法泛化能力评估

文章目录一、 数据集划分&#xff1a;训练集与评估集二、 K 折交叉验证&#xff1a;提升评估可靠性1. 基本原理1.1. K折交叉验证基本原理1.2. 逻辑回归算法与L22. 基于K折交叉验证L2算法三、弃一交叉验证&#xff08;Leave-One-Out&#xff09;1、基本原理2、代码实现四、Shuff…

CodeBuddy三大利器:Craft智能体、MCP协议和DeepSeek V3,编程效率提升的秘诀:我的CodeBuddy升级体验之旅(个性化推荐微服务系统)

&#x1f31f; 嗨&#xff0c;我是Lethehong&#xff01;&#x1f31f; &#x1f30d; 立志在坚不欲说&#xff0c;成功在久不在速&#x1f30d; &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞⬆️留言收藏&#x1f680; &#x1f340;欢迎使用&#xff1a;小智初学计…

Spring Boot 整合 Redis 实现发布/订阅(含ACK机制 - 事件驱动方案)

Spring Boot整合Redis实现发布/订阅&#xff08;含ACK机制&#xff09;全流程一、整体架构二、实现步骤步骤1&#xff1a;添加Maven依赖<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter…

Sklearn 机器学习 线性回归

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Sklearn 机器学习线性回归实战详解 线性回归是机器学习中最基础也最经典的算法之一,…

AJAX案例合集

案例一&#xff1a;更换网站背景JS核心代码<script>document.querySelector(.bg-ipt).addEventListener(change, e > {//选择图片上传&#xff0c;设置body背景const fd new FormData()fd.append(img, e.target.files[0])axios({url: http://hmajax.itheima.net/api/…

vscode环境下c++的常用快捷键和插件

本文提供一些能够在vscode的环境下&#xff0c;提高c代码书写效率的快捷键&#xff0c;插件以及设置等等。 快捷键ctrlshiftx&#xff1a; 弹出插件菜单ctrlshiftp&#xff1a;弹出命令面板可以快捷执行一些常见命令插件安装这个后&#xff0c;可以按住ctrl跳转到方法的实现&am…

React + ts 中应用 Web Work 中集成 WebSocket

一、Web Work定义useEffect(() > {let webSocketIndex -1const websocketWorker new Worker(new URL(./websocketWorker.worker.ts?worker, import.meta.url),{type: module // 必须声明模块类型});//初始化WEBSOCKET&#xff08;多个服务器选择最快建立连接…

RabbitMQ面试精讲 Day 3:Exchange类型与路由策略详解

【RabbitMQ面试精讲 Day 3】Exchange类型与路由策略详解 文章标签 RabbitMQ,消息队列,Exchange,路由策略,AMQP,面试题,分布式系统 文章简述 本文是"RabbitMQ面试精讲"系列第3天内容&#xff0c;深入解析RabbitMQ的核心组件——Exchange及其路由策略。文章详细剖析…

深入解析Hadoop MapReduce Shuffle过程:从环形缓冲区溢写到Sort与Merge源码

MapReduce与Shuffle过程概述在大数据处理的经典范式MapReduce中&#xff0c;Shuffle过程如同人体血液循环系统般连接着计算框架的各个组件。作为Hadoop最核心的分布式计算模型&#xff0c;MapReduce通过"分而治之"的思想将海量数据处理分解为Map和Reduce两个阶段&…

Kafka MQ 消费者

Kafka MQ 消费者 1 创建消费者 在读取消息之前,需要先创建一个KafkaConsumer对象。创建KafkaConsumer对象与创建KafkaProducer对象非常相似—把想要传给消费者的属性放在Properties对象里。本章后续部分将深入介绍所有的配置属性。为简单起见,这里只提供3个必要的属性:boo…

人工智能——Opencv图像色彩空间转换、灰度实验、图像二值化处理、仿射变化

一、图像色彩空间转换&#xff08;一&#xff09;颜色加法1、直接相加1、直接相加2、调用cv.add()函数进行饱和操作 在OpenCV中进行颜色的加法&#xff0c;我们说图像即数组&#xff0c;所以从数据类型来说我们可以直接用numpy的知识来进行直接相加&#xff0c;但是存在…