【SpringAIAlibaba新手村系列】(11)Embedding 向量化与向量数据库

简介: 本文围绕 Embedding 与向量数据库展开,讲解了文本向量化、相似度检索和 VectorStore 的基本用法,并结合 SimpleVectorStore 示例说明了 Spring 中自动装配与手动注册 Bean 的区别,为后续学习 RAG 打下基础。

第十一章 Embedding 向量化与向量数据库

版本标注

  • Spring AI: 1.1.2
  • Spring AI Alibaba: 1.1.2.0

章节定位

  • EmbeddingModelVectorStore 是 RAG 的核心基础设施。
  • 学习本章时,重点应放在统一抽象:EmbeddingModel 负责向量化,VectorStore 负责检索;至于底层是 Redis 还是其他向量库,属于实现选型问题。

s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > [ s11 ] s12 > s13 > s14 > s15 > s16 > s17 > s18

"Embedding 不负责回答问题, 它负责让机器看懂相似度" -- 向量化是检索、推荐和 RAG 的基础设施。


一、为什么需要 Embedding?

1.1 计算机 vs 人类

作为人类,我们天然理解文字的含义:

"猫" ──→ 毛茸茸的、会喵喵叫、养来抓老鼠...
"狗" ──→ 忠诚的、会看家、是人类的好朋友...

但对计算机来说,"猫"和"狗"只是两个字符串,它不知道它们有什么关系。

1.2 Embedding 的思想

Embedding(向量化) 的核心思想是:把文字转换成一串数字(向量)

           Embedding 思想
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

"猫" ──→ [0.12, -0.34, 0.56, 0.78, ...]  (1536维向量)
"狗" ──→ [0.15, -0.31, 0.53, 0.80, ...]  (1536维向量)
"汽车" ──→[0.89, 0.12, -0.34, 0.21, ...]  (1536维向量)

              ↓ 向量距离很近(相似)
              ↓ 向量距离很远(不相似)

如果两个向量的距离很近,说明对应的文本在语义上也相似。

1.3 Embedding 的应用场景

应用场景 说明
语义搜索 搜"手机"也能找到"智能手机"相关内容
相似推荐 找到和当前内容最相似的其他内容
分类聚类 把相似的内容自动归类
去重判断 判断两段文字是否重复

二、向量数据库

2.1 传统数据库的局限

传统数据库存储的是精确值:

SELECT * FROM products WHERE name = '手机';  -- 精确匹配

但如果你搜"手机",就搜不到"智能手机"。

2.2 向量数据库的优势

向量数据库可以存储向量,并支持相似度检索:

// 向量数据库查询
SearchRequest request = SearchRequest.builder()
    .query("手机")                    // 搜索关键词
    .topK(5)                          // 返回最相似的5个结果
    .build();

vectorStore.similaritySearch(request);  // 返回语义相似的结果

即使搜索词不完全一样,也能找到语义上相关的内容!

2.3 Redis Stack

本章示例使用的向量数据库是 Redis Stack

  • 本身就是内存数据库,性能很快
  • 支持向量存储和检索
  • 安装使用简单

三、项目代码详解

3.1 VectorStore 配置方式

这一章有一个很容易忽略、但实际运行时一定会踩到的点:VectorStore 只是一个接口,Spring 容器不会无条件帮你变出一个可注入的实现对象。

也就是说,如果你在控制器里直接写:

@Resource
private VectorStore vectorStore;

但项目里既没有自动装配出某个向量库实现,也没有自己手动声明 Bean,启动时就会报:

A component required a bean of type 'org.springframework.ai.vectorstore.VectorStore' that could not be found.

在学习阶段,最简单的做法之一,是先手动提供一个 SimpleVectorStore Bean:

package com.atguigu.study.config;

import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class VectorStoreConfig {
   

    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel) {
   
        return SimpleVectorStore.builder(embeddingModel).build();
    }
}

这段配置类的意思很简单:

  • 容器里已经有 EmbeddingModel
  • 现在我们基于它手动创建一个 SimpleVectorStore
  • 再把这个对象注册成 VectorStore Bean

这样后面的 Controller 才能顺利注入:

@Resource
private VectorStore vectorStore;

不过,这里还有一个很重要的补充:

如果你引入的是某个具体向量库的 Starter,并且配置也写全了,那么 VectorStore 也可能由自动配置直接提供,不需要你再手动写 @Bean

比如 Redis 向量存储场景中,如果你已经引入:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>

并且在 application.yml 中配置好了:

spring:
  ai:
    vectorstore:
      redis:
        initialize-schema: true
        index-name: custom-index
        prefix: custom-prefix

  data:
    redis:
      host: localhost
      port: 6379

那么在很多情况下,Spring Boot 就会自动帮你创建 Redis 对应的 VectorStore Bean,此时就不需要再写一个手动的 VectorStoreConfig

所以这一节真正要记住的是:

  • 如果你用的是 SimpleVectorStore 这种本地实现,通常自己写 @Bean 最直接
  • 如果你用的是 Redis 这类带 Starter 的向量库实现,往往可以依赖自动装配

3.2 向量化控制器

package com.atguigu.study.controller;

import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;

/**
 * 向量化控制器
 * 展示文本Embedding和向量检索的使用
 */
@RestController
@Slf4j
public class Embed2VectorController
{
   
    // 注入 Embedding 模型(用于文本→向量)
    @Resource
    private EmbeddingModel embeddingModel;

    // 注入向量存储器(用于存储和检索向量)
    @Resource
    private VectorStore vectorStore;

    /**
     * 文本转向量(Text to Embedding)
     * 
     * 接口:http://localhost:8011/text2embed?msg=射雕英雄传
     * 
     * @param msg 要转换的文本
     * @return EmbeddingResponse 包含向量结果
     */
    @GetMapping("/text2embed")
    public EmbeddingResponse text2Embed(String msg)
    {
   
        // 方法1:使用默认配置进行向量化
        // EmbeddingResponse response = embeddingModel.call(
        //     new EmbeddingRequest(List.of(msg), null));

        // 方法2:显式指定使用 text-embedding-v3 模型(推荐)
        // DashScopeEmbeddingOptions 包含阿里云特有的配置
        EmbeddingResponse embeddingResponse = embeddingModel.call(
            new EmbeddingRequest(
                List.of(msg),  // 要向量化的文本列表(可以一次批量处理多个)
                DashScopeEmbeddingOptions.builder()
                    .withModel("text-embedding-v3")  // 指定使用 embedding v3 模型
                    .build()
            )
        );

        // 打印向量结果(可以看到生成了1536维的向量数组)
        System.out.println(Arrays.toString(embeddingResponse.getResult().getOutput()));

        // 返回完整的 EmbeddingResponse(包含向量数据)
        return embeddingResponse;
    }

    /**
     * 向量入库:将文本转为向量并存储到向量数据库
     * 
     * 接口:http://localhost:8011/embed2vector/add
     * 
     * 这个方法将文本转换为向量,并存入 VectorStore
     */
    @GetMapping("/embed2vector/add")
    public void add()
    {
   
        // 1. 准备要存储的文档
        //    Document 是 Spring AI 定义的文档对象
        //    包含 content(内容)、id、metadata(额外信息)
        List<Document> documents = List.of(
            new Document("i study LLM"),           // 英语:我学习大语言模型
            new Document("i love java")            // 英语:我喜欢Java
        );

        // 2. 调用 VectorStore.add() 方法
        //    内部会自动:
        //    - 用 EmbeddingModel 把文本转为向量
        //    - 将向量和原始文本一起存入底层向量库
        vectorStore.add(documents);

        // 3. 简单测试:查看底层向量库中是否已经写入文档
    }

    /**
     * 向量检索:从向量数据库中查找相似内容
     * 
     * 接口:http://localhost:8011/embed2vector/get?msg=LLM
     * 
     * @param msg 搜索关键词
     * @return 和 msg 语义最相似的文档列表
     */
    @GetMapping("/embed2vector/get")
    public List<Document> getAll(@RequestParam(name = "msg") String msg)
    {
   
        // 1. 构建搜索请求
        //    SearchRequest 是 Spring AI 的搜索请求构建器
        SearchRequest searchRequest = SearchRequest.builder()
            .query(msg)              // 搜索词(会自动转为向量)
            .topK(2)                 // 返回最相似的2个结果
            .build();

        // 2. 执行相似度搜索
        //    传入搜索请求,返回匹配度最高的文档列表
        List<Document> list = vectorStore.similaritySearch(searchRequest);

        // 3. 打印结果
        System.out.println(list);

        // 4. 返回结果
        return list;
    }
}

四、核心原理详解

4.1 为什么有时要写配置类,有时又不用?

这个问题表面上看是在问“为什么有时要写 @Configuration”,其实本质上是在问:

为什么 EmbeddingModel 往往可以直接注入,而 VectorStore 却经常需要我自己注册成 Bean?

  • EmbeddingModel 通常是 框架已经帮你自动装配好的 Bean
  • VectorStore 通常是 你还需要自己决定具体实现的 Bean

所以两者最大的区别不在于“是不是接口”,而在于:

这个对象到底是谁放进 Spring 容器里的。

1. 为什么 EmbeddingModel 经常可以直接注入?

当你引入了 Spring AI Alibaba 的 DashScope Starter,并且配置好了 API Key 之后,框架通常会自动帮你创建好一个 EmbeddingModel Bean。

所以在控制器里这样写:

@Resource
private EmbeddingModel embeddingModel;

往往就能直接成功。

这是因为:

  • Starter 已经知道你在使用 DashScope
  • 它也知道该创建哪种 Embedding 实现
  • 所以自动配置类会替你把这个对象注册进 Spring 容器

也就是说,这里的 EmbeddingModel 并不是“凭空出现的”,而是 框架提前帮你准备好的

2. 为什么 VectorStore 有时不能直接注入?

因为 VectorStore 虽然也是一个接口,但它背后的实现选择并不唯一。

比如你完全可以选择:

  • SimpleVectorStore
  • Redis VectorStore
  • Milvus
  • PGVector
  • Elasticsearch
  • 你自己写的实现

Spring 不知道你到底想用哪一个,所以在没有更具体条件时,它通常不会替你“猜一个”然后自动注册。

这时如果你直接写:

@Resource
private VectorStore vectorStore;

但项目里又没有任何一个 VectorStore Bean,Spring 启动时就会报:

A component required a bean of type 'org.springframework.ai.vectorstore.VectorStore' that could not be found.

3. 这时为什么要写配置类?

当你用的是 SimpleVectorStore 这种不依赖外部中间件、也没有专门 Starter 自动装配的实现时,你就需要明确告诉 Spring:

“这个项目里我决定使用 SimpleVectorStore 作为 VectorStore 的实现。”

最常见的写法就是:

@Configuration
public class VectorStoreConfig {
   

    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel) {
   
        return SimpleVectorStore.builder(embeddingModel).build();
    }
}

这段代码的意思是:

  • EmbeddingModel 已经由框架自动提供
  • 现在我们基于它手动创建一个 SimpleVectorStore
  • 再把这个对象注册成 VectorStore Bean

这样后面谁再写:

@Resource
private VectorStore vectorStore;

Spring 就能顺利注入了。

但这里要补一句非常关键的话:

并不是所有 VectorStore 都必须手动写配置类。

如果你已经引入了某个向量库的 Starter,例如 Redis 向量存储:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>

并且相关配置也写全了,那么 VectorStore 可能就会由自动配置直接提供。这时你只需要像下面这样注入即可:

@Resource
private VectorStore vectorStore;

不需要你再额外写:

@Bean
public VectorStore vectorStore(...) {
    ... }

4. 那什么时候可以不写配置类?

如果某个对象只是你在当前方法里临时用一下,其实完全可以自己创建:

VectorStore vectorStore = SimpleVectorStore.builder(embeddingModel).build();

这种写法没有错,只是它有一个前提:

  • 这个对象只在当前方法里用
  • 你不打算让它被别的 Controller / Service 复用
  • 你也不需要 Spring 去管理它

一旦这个对象要在整个项目里复用,或者要被注入到别的类里,通常还是应该把它写成 @Bean

5. 最终怎么判断该不该写配置类?

可以用一个非常实用的判断标准:

  • 框架已经自动装配好的对象:通常直接注入就行,例如 EmbeddingModel
  • 没有 Starter 自动装配、需要你自己决定实现的对象:通常要自己注册 Bean,例如 SimpleVectorStore
  • 已经有专门 Starter 且配置完整的对象:很多时候也可以直接注入,例如 Redis VectorStore

所以一句话总结就是:

不是“有的类能直接注入,有的类必须写配置类”,而是“谁已经被框架自动放进 Spring 容器里了,谁还需要你自己决定实现并注册进去”。

4.2 Embedding 的维度

// 阿里云的 text-embedding-v3 模型生成的向量维度是 1536
// 每个文本都会被转换成 1536 个数字的数组
// 
// 就好像把文字映射到一个1536维的空间中的一点
// 语义相似的文字,在这个空间中的距离也会比较近

4.3 相似度计算

向量数据库通常使用以下几种相似度算法:

算法 说明 适用范围
余弦相似度 (Cosine) 夹角越小越相似 方向敏感场景
欧氏距离 (L2) 直线距离 数值敏感场景
内积 (IP) 点积运算 排序优化

很多向量库默认采用余弦相似度或相近策略,具体行为取决于底层实现和索引配置。


五、本章小结

5.1 核心概念

概念 说明
Embedding 把文本转为向量的技术
VectorStore 向量数据库存储接口
维度/Vector Dimension 向量的长度(如1536)
相似度检索 根据向量距离找相似内容
text-embedding-v3 阿里云的向量化模型

5.2 使用流程

文本 → EmbeddingModel → 向量 → VectorStore.add() → 存入数据库
                               ↑
搜索词 → 自动转向量 → similaritySearch() → 返回相似结果

5.3 拓展:RAG 的基础

Embedding + VectorStore = RAG(检索增强生成) 的核心技术!

后面章节我们会学习完整的 RAG 流程。

本章重点

  1. 理解 Embedding 的核心思想(文字→数字)
  2. 掌握文本向量化的方法
  3. 学会使用向量数据库进行相似度检索

下章剧透(s12):

掌握了向量化技术,下一章我们将学习 RAG(检索增强生成)——让 AI 能够"查阅"知识库来回答专业问题!


💡 TIP:不要把 VectorStore 只理解成 Redis

本章示例使用 Redis 只是因为它简单、容易上手。但在实际项目里,VectorStore 更重要的价值在于统一抽象:

抽象 作用
EmbeddingModel 把文本转成向量
VectorStore 存储向量并做相似度检索
SearchRequest 描述一次检索请求

这样你后续切换底层实现时,业务代码改动会小很多。


📝 编辑者:Flittly
📅 更新时间:2026年4月

目录
相关文章
|
13天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
11452 124
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
2天前
|
人工智能 JSON 监控
Claude Code 源码泄露:一份价值亿元的 AI 工程公开课
我以为顶级 AI 产品的护城河是模型。读完这 51.2 万行泄露的源码,我发现自己错了。
3459 8
|
1天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
1327 2
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
12天前
|
人工智能 IDE API
2026年国内 Codex 安装教程和使用教程:GPT-5.4 完整指南
Codex已进化为AI编程智能体,不仅能补全代码,更能理解项目、自动重构、执行任务。本文详解国内安装、GPT-5.4接入、cc-switch中转配置及实战开发流程,助你从零掌握“描述需求→AI实现”的新一代工程范式。(239字)
7462 139
|
2天前
|
云安全 供应链 安全
Axios投毒事件:阿里云安全复盘分析与关键防护建议
阿里云云安全中心和云防火墙第一时间响应
1144 0
|
3天前
|
人工智能 自然语言处理 数据挖掘
零基础30分钟搞定 Claude Code,这一步90%的人直接跳过了
本文直击Claude Code使用痛点,提供零基础30分钟上手指南:强调必须配置“工作上下文”(about-me.md+anti-ai-style.md)、采用Cowork/Code模式、建立标准文件结构、用提问式提示词驱动AI理解→规划→执行。附可复制模板与真实项目启动法,助你将Claude从聊天工具升级为高效执行系统。
|
2天前
|
人工智能 定位技术
Claude Code源码泄露:8大隐藏功能曝光
2026年3月,Anthropic因配置失误致Claude Code超51万行源码泄露,意外促成“被动开源”。代码中藏有8大未发布功能,揭示其向“超级智能体”演进的完整蓝图,引发AI编程领域震动。(239字)
2150 9
|
11天前
|
人工智能 并行计算 Linux
本地私有化AI助手搭建指南:Ollama+Qwen3.5-27B+OpenClaw阿里云/本地部署流程
本文提供的全流程方案,从Ollama安装、Qwen3.5-27B部署,到OpenClaw全平台安装与模型对接,再到RTX 4090专属优化,覆盖了搭建过程的每一个关键环节,所有代码命令可直接复制执行。使用过程中,建议优先使用本地模型保障隐私,按需切换云端模型补充功能,同时注重显卡温度与显存占用监控,确保系统稳定运行。
2550 9

热门文章

最新文章