乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • Spring AI 学习路径
  • 第1章 Spring AI 概述与核心理念

    • 章节导读
    • Spring AI 概述与可移植 API
    • 核心模块与依赖关系
  • 第2章 快速入门与第一个AI应用

    • 章节导读
    • 环境准备与配置
    • 第一个 AI 对话应用
  • 第3章 聊天模型与ChatClient

    • 章节导读
    • ChatClient 详解
    • ChatModel 底层抽象
    • 多轮对话与 ChatMemory
  • 第4章 提示词管理与模板

    • 章节导读
    • Prompt 与 Message 体系
    • 提示词模板与动态构建
  • 第5章 输出解析与结构化响应

    • 章节导读
    • 输出解析器与 BeanOutputConverter
  • 第6章 嵌入模型与向量存储

    • 章节导读
    • EmbeddingModel 与文本向量化
    • ETL 数据注入流水线
    • 向量存储抽象与配置
  • 第7章 检索增强生成(RAG)

    • 章节导读
    • RAG 核心机制与流程
    • QuestionAnswerAdvisor 详解
    • RAG 实战案例
  • 第8章 函数调用(Function Calling)

    • 章节导读
    • Tool 注解与函数声明
    • 函数调用实战
  • 第9章 多模态

    • 章节导读
    • 图像输入与视觉模型
    • 图像生成
  • 第10章 Advisor拦截器链

    • 章节导读
    • Advisor 链与内置拦截器
  • 第11章 MCP 协议与跨语言工具集成

    • 章节导读
    • MCP 协议深入
  • 第12章 可观测性测试与最佳实践

    • 章节导读
    • 可观测性与指标监控
    • 测试策略与 Mock 实践
    • 最佳实践与面试考点汇总

小崔盯着屏幕:"Embedding 不就是把一句话变成一个浮点数数组吗,为什么能表示语义?"白歌说:"你不需要懂 Transformer 数学,你只需要知道:两段语义相似的文本,它们的向量在空间中角度接近。"

EmbeddingModel 与文本向量化

定义与作用

EmbeddingModel 是 Spring AI 的文本向量化接口——将一段自然语言文本转换为固定维度的浮点数数组(float[])。这个数组就是"语义指纹"。

public interface EmbeddingModel {
    EmbeddingResponse call(EmbeddingRequest request);
    
    default Embedding embed(String text) {
        // 便捷方法:单文本向量化
    }
    
    List<Embedding> embed(List<String> texts);  // 批量
    float[] embed(String text, EmbeddingOptions options);  // 带参数
}

核心价值:向量化是 AI 理解私有文档的前提。没有 Embedding,就没有语义搜索、没有 RAG。

核心原理:文本到向量的转换流程

图释:文本经过 Embedding 模型(通常调用 OpenAI API)转换为 1536 维向量。每个维度没有"可读"的物理含义,但整体向量在空间中编码了文本的语义。

不同模型的向量维度对比

模型维度最大输入 Token适用场景
text-embedding-3-small15368191通用,性价比高
text-embedding-3-large30728191高精度语义搜索
text-embedding-ada-00215368191旧版本,兼容
Ollama nomic-embed-text7688192本地部署,免费

维度越高,语义表达能力越强,但存储成本也越高。对于大多数企业场景,1536 维已经足够。

完整示例一:课程描述向量化

场景说明

飞翔科技学生管理系统需要将课程描述向量化,为后续课程语义搜索做准备。

关键代码

@RestController
public class EmbeddingDemoController {

    private final EmbeddingModel embeddingModel;

    public EmbeddingDemoController(EmbeddingModel embeddingModel) {
        this.embeddingModel = embeddingModel;
    }

    @GetMapping("/embed")
    public Map<String, Object> embedText(@RequestParam String text) {
        // 单文本向量化
        Embedding embedding = embeddingModel.embed(text);
        
        Map<String, Object> result = new HashMap<>();
        result.put("input", text);
        result.put("dimensions", embedding.getOutput().length);
        result.put("first_5_values", Arrays.copyOf(embedding.getOutput(), 5));
        result.put("embedding_length", embedding.getOutput().length);
        return result;
    }

    @GetMapping("/embed/batch")
    public Map<String, Object> embedBatch() {
        // 批量向量化——一次 API 调用处理多条文本
        List<String> courses = List.of(
            "高等数学:微积分、线性代数和概率论基础",
            "数据结构:链表、树、图等数据组织方式",
            "操作系统:进程管理、内存管理和文件系统"
        );
        
        List<Embedding> embeddings = embeddingModel.embed(courses);
        
        // 计算结果数量
        Map<String, Object> result = new HashMap<>();
        result.put("count", embeddings.size());
        result.put("dimensions_per_vector", embeddings.get(0).getOutput().length);
        return result;
    }
}

运行结果

GET /embed?text=人工智能导论:机器学习与深度学习基础

{
  "input": "人工智能导论:机器学习与深度学习基础",
  "dimensions": 1536,
  "first_5_values": [-0.023, 0.145, -0.089, 0.056, 0.002],
  "embedding_length": 1536
}

完整示例二:相似课程检测

场景说明

孙鹤提了个 "课程去重" 需求——同一门课可能被不同老师以不同标题提交,需要用向量相似度检测。

关键代码

@Service
public class CourseSimilarityService {

    private final EmbeddingModel embeddingModel;

    public CourseSimilarityService(EmbeddingModel embeddingModel) {
        this.embeddingModel = embeddingModel;
    }

    /**
     * 计算两段课程描述之间的余弦相似度
     * 返回值范围 [-1, 1],接近 1 表示语义高度相似
     */
    public double cosineSimilarity(String text1, String text2) {
        float[] v1 = embeddingModel.embed(text1).getOutput();
        float[] v2 = embeddingModel.embed(text2).getOutput();
        return dotProduct(v1, v2) / (norm(v1) * norm(v2));
    }

    private double dotProduct(float[] a, float[] b) {
        double sum = 0;
        for (int i = 0; i < a.length; i++) {
            sum += a[i] * b[i];
        }
        return sum;
    }

    private double norm(float[] v) {
        double sum = 0;
        for (float x : v) sum += x * x;
        return Math.sqrt(sum);
    }
}

运行结果

// 测试1:同一门课的不同描述
similarity = courseSimilarityService.cosineSimilarity(
    "人工智能导论:涵盖机器学习、深度学习和强化学习",
    "AI基础:神经网络的原理与实践"
);
// 结果:0.92  ← 高度相似(尽管措辞完全不同)

// 测试2:不同方向的课程
similarity = courseSimilarityService.cosineSimilarity(
    "人工智能导论:机器学习基础",
    "中国现代文学:鲁迅与五四新文化运动"
);
// 结果:0.12  ← 语义不相关

易错场景与面试考点

易错场景一:向量维度不匹配

// ❌ 错误:用 text-embedding-3-small (1536维) 生成的向量
// 存入配置为 dimensions=768 的向量库
// 结果:PostgreSQL 插入时报错 "expected 768 dimensions, got 1536"

问题分析

Embedding 模型的输出维度必须与 VectorStore 配置的维度一致。

# ✅ 正确:确保维度匹配
spring:
  ai:
    openai:
      embedding:
        model: text-embedding-3-small   # 1536 维
    vectorstore:
      pgvector:
        dimensions: 1536                 # 与模型维度一致

面试高频题

Q1:Embedding 向量为什么能表示语义?

嵌入模型在训练时,通过让相似上下文的文本在向量空间中靠近、不相似的远离来优化参数。最终的结果是:语义相近的文本(如"北京天气"和"首都气温")在向量空间中的夹角很小(余弦相似度接近 1),而语义无关的文本夹角接近 90 度。

Q2:为什么不用 TF-IDF 而要用 Embedding?

TF-IDF 基于词频统计,无法处理同义词("汽车"和"轿车"被视为完全不同的词)。Embedding 模型能理解语义等价,精度显著更高。

本章小结

  • EmbeddingModel.embed(text) 将文本转为 float[] 向量
  • 不同模型的向量维度不同(1536 / 3072 / 768),需与 VectorStore 配置一致
  • 余弦相似度是判断语义相似度的标准度量
  • 批量向量化可减少 API 调用次数,降低成本
上一页
章节导读
下一页
ETL 数据注入流水线