向量和向量化
约 4360 字大约 15 分钟
2025-10-24
数据向量化
“向量化”在大语言模型中是一个重要的概念。向量化使得非数值类型的数据能被计算机有效处理分析,捕捉数据和特征关系,提高计算效率。在大语言模型各环节发挥关键作用,为实现更强语言处理能力提供基础。
自然语言本身是人类易于理解的符号系统(如文字、句子),但计算机无法直接处理这些符号。为了能让计算机“理解”语言并进行计算(比如计算相似度、聚类、检索、作为模型输入等),就需要将这些语言元素转化为数值形式 —— 也就是向量。
向量与向量化
向量化指的是。
在数学和计算机科学中,向量就是一个有序的数字列表,比如:
V=[0.2,−0.5,0.7,1.1,3.2,...]
这个向量可能代表一个词语、一句话或者一段文本在某个高维空间(通常是几百或者几千)中的一个点。

如上图所示,展示的就是二维向量在二维空间的中的表示,很显然的是一个向量可以通过它的方向和的长度来直接进行标定。
在向量化后,每段文本(如一个句子)会被转成一个固定维度的浮点数向量,例如:
我喜欢自然语言处理=[0.12,−0.34,0.56,...,0.78]
这个向量为维度可能是1024,也可能是2048,这取决于使用的是哪个模型来对文本进行的向量化。
向量相似性比较
向量相似性比较是指通过计算两个或多个向量之间的相似度,来判断他们所代表的内容(如词语、句子、文档等)在语义或意义上的相似性。
常用的向量相似性比较方法主要分为两类:相似度和距离,它们的本质是相关的,通常相似度越高意味着距离越小,反之亦然。
余弦相似度:starstar:
余弦相似度是指两个向量夹角的与限度,反向他们的方向的相似性,与向量的长度无关。
cos(A,B)=∣∣A∣∣⋅∣∣B∣∣A⋅B=∑i=1nAi2×∑i=1nBi2∑i=1nAiBi
取值范围:[-1,1],但在文本向量中通常为[0,1]
- 1 —— 表示两个向量方向完全一致,语义非常相似;
- 0 —— 表示两个向量正交,几乎没有语义关联;
- -1 —— 几乎不会出现(除非刻意负采样)
适用场景:语义相似性计算、文本检索、推荐夕同、RAG等。
欧几里得距离😢😢
欧几里得距离是指两个向量之间的直线距离,衡量他们的绝对位置差异。
EuclideanDistance(A,B)=i=1∑n(Ai−Bi)2
数值越小,表示两个向量越近,语义越相似。
与余弦相似度不同,它受向量大小(模长)的影响。一般不如余弦相似度直观,常用于某些特定的任务。
曼哈顿距离
曼哈顿距离与欧几里得距离差不多,但是是各个维绝对差之和。
ManhattanDistance(A,B)=i=1∑n∣Ai−Bi∣
使用相对较少。
点积
DotProduct(A,B)=i=1∑nAi⋅Bi
如果是向量是归一化(单位向量)的,那么点积约等于余弦相似度,否则,点击受向量长度影响较大。
向量化的场景
文本表示
- 将单词、子句或整个句子映射为固定长度的稠密向量,称为词嵌入或句嵌入;
- 常见的词嵌入模型有Word2Vec、Glove、FastText,以及基于Transform的模型(如BERT、Sentence-BERT等)生成的上下文相关的嵌入;
语义信息的捕捉
- 通过向量化,语义相近的词语或者句子,在向量空间中距离会较近。例如,“猫”和“小狗”的向量比“猫”与“汽车”的向量更接近;
- 这种特性使得向量非常适用于语义搜索、问答系统、推荐系统、聚类等任务;
作为大语言模型的输入
- 虽然大语言模型可以直接处理Token ID 序列,但在很多的实际应用中,先对文本进行向量化,再用于检索、过滤、排序或辅助模型理解上下文是一种常见的做法。
- 比如在RAG(Retrieval-Augmented Generation,检索增强生成)中,首先将用户问题向量化,然后再只是库中检索相似的文档,在将这些文档与问题一起输入给大模型;
嵌入式模型(Embeding Model)
向量化的具体实现是借助向量化模型,也称之为嵌入式模型(Embeding Model)来完成的。。
嵌入式模型的核心功能是:输入一段文本,输出一个向量,这个向量通常是一个固定长度的浮点数数组,向量的每个维度没有明确的物理意义,但整体向量编码了输入文本的语义信息。
在百炼平台的官网可以看到文本向量类型的模型,它就是一种嵌入式模型,如下所示:

使用嵌入式模型完成文本向量化
1️⃣添加配置,往Spring中注入一个EmbeddingModel的对象
@Bean
public EmbeddingModel embeddingModel(DashScopeApi dashScopeApi){
return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.NONE, DashScopeEmbeddingOptions.builder()
.withModel("text-embedding-v4")
.build());
}2️⃣使用EmbeddingModel来调用大模型对字符串来进行向量化
/**
*
* @description http://localhost:8854/chat/template6
*/
@GetMapping("/template6")
public float[] embedding() {
EmbeddingRequest request = new EmbeddingRequest(List.of("你好,我爱编程"), DashScopeEmbeddingOptions
.builder().build());
EmbeddingResponse call = embeddingModel.call(request);
Embedding result = call.getResult();
return result.getOutput();
}3️⃣测试结果
返回的结果确实太长了,省略掉中间部分的内容。不用去理解这个向量,其实也没有啥特殊意义。嗯,就是出来了这么个向量😄。
[0.6578311,-0.5013137,4.230573,3.546875,...,0.2946661,-0.012672061,-1.7210287,1.1024576]向量数据库
向量数据库是一类专门用于存储、索引与检索向量数据的数据库系统。它将文本、语音、图像、视频等内容通过嵌入转换为高维向量,并利用相似性搜索(如余弦相似度、欧几里得距离等)与最近邻(ANN)算法,在海量数据中快速找出语义相近的结果。系统通常采用分布式机构以支持水平扩展与高可用,并内置多种索引结构(如KD树,LSH、球树)以在精度与效率间取得平衡。
向量数据库的优势与劣势
- 优势
- 对非结构化数据与高维度向量友好,支持大规模、低延时的相似性检索;
- 分布式与高可用机构,便于容量与性能扩展;
- 支持混合检索与多场景AI应用(搜索、推荐、多模态);
- 劣势
- 事务处理能力较弱,不适合强一致性事务场景;
- 存储于计算成本相对较高(高维度向量与索引开销);
- 查询效率受到维度的影响,需要在精度与性能之间平衡(ANN/索引选型);
- 数据更新与版本管理在部分系统可能比较复杂;
向量数据库的比较
| 向量数据库 | 类型 (开源/商业) | 数据规模支持 | 部署方式 | 优势 | 劣势 |
|---|---|---|---|---|---|
| Milvus | 开源(也可云托管) | 超大规模(亿级~万亿级) | 自托管、Kubernetes、云服务 | - 高性能,支持大规模数据 - 多种索引,灵活调优 - 分布式 & 可扩展 - 活跃社区 | - 架构复杂,部署门槛高 - 学习曲线较陡 |
| FAISS | 开源(Meta) | 中小规模(万级~千万级) | 本地运行(Python/C++) | - 检索速度极快 - 算法丰富,支持 GPU - 易于集成到 Python | - 不是数据库,无持久化/服务化 - 无分布式能力 - 无管理界面 |
| Pinecone | 商业(SaaS 云服务) | 中大规模(依赖套餐) | 全托管(无需部署) | - 全托管,免运维 - 简单易用,API 友好 - 自动扩缩容 | - 商业服务,有使用成本 - 数据不可控,依赖第三方 |
| Weaviate | 开源 + 云服务 | 中等规模(千万级) | 自托管 / 云服务 | - 支持向量 + 结构化联合检索 - 提供 GraphQL 查询 - 开源 + 云托管可选 | - 社区相对小 - 大规模性能略逊于 Milvus |
| Qdrant | 开源 + 商业云 | 中大规模(千万~亿级) | 自托管(Docker/K8s) / 云服务 | - 支持灵活的标量过滤 - Rust 编写,性能优秀 - 易部署,开源免费 | - 大规模(亿级以上)优化略逊 - 生态在成长中 |
| Vespa | 开源(Yahoo) | 超大规模 | 自托管 / 云服务 | - 支持全文 + 向量 + 结构化联合查询 - 企业级稳定 - 支持复杂聚合 | - 架构重,部署复杂 - 学习曲线高 - 社区较小 |
| Redis(+插件) | 开源(RedisSearch / RedisVL) | 中小规模 | 自托管 / 云托管 | - 超低延迟 - 已有广泛用户基础 - 易集成现有系统 | - 原生不支持向量,需插件 - 大规模向量能力有限 |
| Elasticsearch | 开源 + 商业 | 中等规模 | 自托管 / 云服务 | - 成熟稳定,社区大 - 支持全文 + 向量混合 | - 向量能力为后期加入,性能一般 - 配置复杂 |
本次使用的Milvus数据库来存储向量数据
Milvus(向量数据库)
Milvus是鹰科中的一种猛禽,以飞行速度快、视力敏锐、适应性强著称,可以在Milvus数据库的官网地址中进一步了解。
Milvus提供强大的数据建模功能,能够将非结构化(文本、图像和音频)或多模式数据组织称结构化的Collections。它支持多种数据类型,适用于不同的属性模型,包括常见的数字和字符类型、各种向量类型、数组、集合和JSON。
按照官网的实力将Milvus数据库部署后,可以通过http://localhost:9091/webui/端口查看Milvus数据库的UI管理界面。

虽然默认的Milvus-WebUI界面已经可以可视化管理Milvus数据库了,但是缺少了一部分的数据操作的能力,更多的是一种简单的操作。可以通过安装Milvus-CLI工具,然后使用Milvus命令来创建数据,但是这里为了方便还可以直接安装Attu可视化工具。
docker run -d --name attu -p 8000:3000 -e MILVUS_URL=localhost:19530 zilliz/attu:v2.6VectorStore(向量存储组件)
在Spring AI中有一个VectorStore组件,它的作用就是将文本数据向量化后的向量数据存储到对应的向量数据库中。同样的,Spring AI也为我们准备了MilvusVectorStore组件的相关集成。
1️⃣引入对应的依赖
<!--Milvus向量数据库引入-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-milvus</artifactId>
</dependency>2️⃣添加Milvus的配置信息
spring:
vector-store:
milvus:
auto-id: false
client:
host: localhost
port: 19530
databaseName: "default" # 对应的数据库名称
collectionName: "vector_store" # 对应的集合名称
embeddingDimension: 1536 # 向量的维度
indexType: IVF_FLAT # 索引烈性
metricType: COSINE3️⃣向Milvus中添加数据
/**
* @description http://localhost:8854/chat/template7
*/
@GetMapping("/template7")
public String vectorStore() {
String plainText = "你好,我爱编程,我的主要研究语言方向是Java";
vectorStore.add(List.of(new Document(IdUtil.getSnowflakeNextIdStr(), plainText, Map.of("vector", new float[]{}))));
return "success";
}执行上述的测试代码之后,就可以在可视化界面中看到对应的数据

MilvusVectorStore(Milvus向量存储组件)
在引入MilvusVectorStore组件的时候,我们需要预先在Milvus中创建对应的数据库和集合。在Milvus中对应这些信息都有默认值的,也支持我们通过配置文件的方式来进行修改。
// 默认的向量维度,这里需要注意这里的维度与数据库实际上的维度对不上就会报错
public static final int OPENAI_EMBEDDING_DIMENSION_SIZE = 1536;
// 这个就是不限制维度
public static final int INVALID_EMBEDDING_DIMENSION = -1;
// 默认的数据库名称
public static final String DEFAULT_DATABASE_NAME = "default";
// 默认的集合名称
public static final String DEFAULT_COLLECTION_NAME = "vector_store";
// 集合的Schema中,主键字段对应的列名
public static final String DOC_ID_FIELD_NAME = "doc_id";
// 存储实体明文的列名
public static final String CONTENT_FIELD_NAME = "content";
// 存储元数据的列名
public static final String METADATA_FIELD_NAME = "metadata";
// 存储向量的列名
public static final String EMBEDDING_FIELD_NAME = "embedding";
// 存储相似性分数的列名
public static final String SIMILARITY_FIELD_NAME = "score";如果按照默认的配置来的话,就需要在Milvus中配置它的内容的:

Milvus中的Collection目前不支持修改它的Schema的,只能通过删除之后重建。
然后我们在学习如何根据输入的内容查询出Milvus中的相关内容
/**
*
* @description http://localhost:8854/chat/template8
*/
@GetMapping("/template8")
public String template8() {
SearchRequest request = SearchRequest
.builder()
.query("Java")
.build();
// 相似性查找
List<Document> documents = vectorStore.similaritySearch(request);
assert documents != null;
List<String> collect = documents.stream().map(Document::getText).collect(Collectors.toList());
return JSON.toJSONString(collect);
}然后结果返回的内容就是:
["你好,我爱编程,我的主要研究语言方向是Java"]我们根据Java这个关键字来获取与之相似文本向量为“你好,我爱编程,我的主要研究语言方向是Java”。
RAG增强搜索
简单来说,RAG(检索增强生成)是一种从本地数据中查找相关信息,并在将提示发送给LLM之前注入到提示中的方法。这样依赖,LLM就能获得(希望是)相关的信息,并基于这些信息来进行回答,从而降低产生幻觉的概率。
通过引入外部知识来源来增强LLM的输出能力,传统的LLM通常基于其训练数据生成响应,但这些数据可能过时或不够全面。RAG允许模型在生成答案之前,从特定的知识库中检索相关信息,从而提供更准确的上下文相关回答。
RAG的流程
RAG整体上分为两个阶段:索引和检索。
索引
索引首先清理和提取各种格式的原始数据,如PDF、HTML、Wrod和Markdown,然后将其转化为统一的纯文本格式。为了适应语言模型上下文的限制,文本被分割成更小的、可消化的块(Chunk)。然后使用嵌入式模型将块编码成向量表示,并存储在向量数据库中。这一步在随后的检索阶段实现高效的相似性搜索至关重要。知识库分割成chunks,并将chunks向量化至向量库中。

检索
在收到用户查询后,RAG系统采用与索引阶段相同的编码模型将查询转换为向量表示,然后计算索引语料库中查询向量与块向量相似性得分。该系统优先级和检索最高K(Top-K)块,显示最大相似性查询。
RAG的实现
我们根据RAG流程来实现一个基于错误码给出运维信息的大模型,首先因为这个错误码是每个系统特有的,肯定不会被训练到大模型里面的去的。如果我们直接去问大模型,得到的结果肯定不是正确的,所以我们就需要利用RAG技术来实现,让大模型知道我们的编码信息。
1️⃣创建一份RAG知识库(classpath:ops.txt)
A00001 您的手机无信号
A00002 请关注您后续的短信通知
A00003 系统繁忙,请稍后再试
A00004 您的账户余额已不足,请重置后重试
A00005 您的账户出现异常,请关注系统信息提示
A00006 您的权益已经生效,请关注2️⃣创建一个自定义初始化器来完成数据的向量化
@Component
public class InitCommandLineRunner implements CommandLineRunner {
@Value("classpath:ops.txt")
private Resource resource;
@Autowired
private VectorStore vectorStore;
@Override
public void run(String... args) throws Exception {
// 读取文件的内容
TextReader textReader = new TextReader(resource);
textReader.setCharset(Charset.defaultCharset());
// 将文件拆分成合适的chunks
List<Document> transform = new TokenTextSplitter().transform(textReader.read());
// 拆分后的数据经过向量化后直接存储到的向量数据库中
vectorStore.add(transform);
}
}3️⃣在与大模型交互的时候实现RAG增强
@GetMapping("/template9")
public Flux<String> template9(@RequestParam("message")String message) {
String systemInfo = """
你是一个运维工程,按照给出的编码给出对应的故障解释,否则回复找不到信息
""";
RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder().vectorStore(vectorStore).build())
.build();
return chatClient.prompt().system(systemInfo).user(message).advisors(advisor).stream().content();
}4️⃣测试
此时我们访问对应的接口:
// http://localhost:8854/chat/template9?message=A00003
系统繁忙,请稍后再试
// http://localhost:8854/chat/template9?message=A00002
请关注您后续的短信通知
// http://localhost:8854/chat/template9?message=A00009
找不到信息