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

    • 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 实践
    • 最佳实践与面试考点汇总

李眉在服务器上装好 PGVector 后吐槽:"Spring AI 把向量存储也抽象成接口了,连 Redis 和 Pinecone 都能用同一套 API——这就是我喜欢的 SpringStyle。"

向量存储抽象与配置

定义与作用

VectorStore 是 Spring AI 的向量数据库抽象接口,屏蔽了 PGVector、Redis、Pinecone、Milvus 等不同后端的差异。

public interface VectorStore {
    void add(List<Document> documents);              // 存储文档
    List<Document> similaritySearch(SearchRequest request);  // 相似搜索
    void delete(List<String> ids);                   // 删除文档
}

核心价值:换向量数据库只需改 YAML + 换 Starter,代码 0 改动。

核心原理:文档写入与查询的完整流程

图释:VectorStore 在内部自动调用 EmbeddingModel 做文本向量化,应用代码不需要手动处理向量。

SearchRequest 参数详解

SearchRequest request = SearchRequest.builder()
    .query("人工智能选修课有哪些")          // 查询文本
    .topK(5)                               // 返回前 5 个最相似结果
    .similarityThreshold(0.7)               // 只返回相似度 > 0.7 的结果
    .filterExpression("category == 'CS'")   // 元数据过滤:只查 CS 类课程
    .build();

List<Document> results = vectorStore.similaritySearch(request);
参数说明典型值
query查询文本用户问题
topK返回数量3-5(太少丢失信息,太多引入噪声)
similarityThreshold相似度阈值0.7-0.8(低于此值的结果被过滤)
filterExpression元数据过滤按分类/部门/时间过滤

相似度距离类型对比

距离类型取值范围特点推荐场景
COSINE_DISTANCE[0, 2]只关注方向,忽略向量长度语义搜索(推荐)
EUCLIDEAN_DISTANCE[0, +∞)真实的欧几里得距离需要绝对距离的场景
DOT_PRODUCT(-∞, +∞)向量内积适用于归一化向量

完整示例:飞翔科技文档库的查询

PGVector 完整配置

# application.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/feixiang_vector
    username: postgres
    password: ${DB_PASSWORD}
  ai:
    vectorstore:
      pgvector:
        index-type: HNSW
        distance-type: COSINE_DISTANCE
        dimensions: 1536
        initialize-schema: true

依赖引入

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

关键代码

@Service
public class DocumentSearchService {

    private final VectorStore vectorStore;

    public DocumentSearchService(VectorStore vectorStore) {
        this.vectorStore = vectorStore;
    }

    /**
     * 查询飞翔科技产品手册
     */
    public String searchProductManual(String question) {
        SearchRequest request = SearchRequest.builder()
                .query(question)
                .topK(3)
                .similarityThreshold(0.7)
                .build();

        List<Document> results = vectorStore.similaritySearch(request);

        if (results.isEmpty()) {
            return "未在文档库中找到相关信息";
        }

        // 拼接搜索结果
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < results.size(); i++) {
            Document doc = results.get(i);
            sb.append(String.format("【匹配 %d】相似度: %.2f\n", 
                    i + 1, doc.getScore()));
            sb.append(doc.getContent()).append("\n\n");
        }
        return sb.toString();
    }
}

易错场景与面试考点

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

# ❌ 错误:PGVector 配置的 dimensions 与 Embedding 模型不一致
spring:
  ai:
    vectorstore:
      pgvector:
        dimensions: 768   # 错误:OpenAI text-embedding-3-small 是 1536 维

问题分析

PGVector 在创建表时会强制执行向量维度约束。维度不匹配会导致 INSERT 时抛异常:

ERROR: expected 1536 dimensions, not 768

解决:确认 Embedding 模型的实际维度后再配置。OpenAI 的 text-embedding-3-small 为 1536 维,Ollama 的 nomic-embed-text 为 768 维。

易错场景二:similarityThreshold 过高导致空结果

// ❌ 错误:阈值设为 0.95,几乎所有结果都被过滤
SearchRequest.builder()
    .similarityThreshold(0.95)   // 太高了
    .build();
// 结果:empty list

问题分析

0.7-0.8 是一个合理的取值范围。超过 0.9 会过滤掉大部分相关结果;不设置阈值会返回语义无关的结果。

面试高频题

Q1:VectorStore.add() 方法是同步的还是异步的?内部发生了什么?

同步调用。内部流程:①调用 EmbeddingModel.embed() 将 Document.content 转为向量;②将 content + metadata + embedding 写入底层数据库(如 PGVector)。这个过程通常 100ms-1s,取决于 Embedding API 的响应速度。

Q2:为什么推荐 COSINE_DISTANCE 而不是 EUCLIDEAN_DISTANCE?

余弦距离只衡量向量方向(语义方向),忽略向量长度(文本长度)。两段语义相同但长度不同的文本(如"你好"和"你好你好你好")在余弦距离下高度相似,但在欧氏距离下距离很大。语义搜索场景下余弦距离更合理。

本章小结

  • VectorStore.add() 写入时自动调用 EmbeddingModel 向量化
  • similaritySearch() 的核心参数是 topK、similarityThreshold、filterExpression
  • 推荐使用 COSINE_DISTANCE 做语义搜索
  • PGVector 配置的 dimensions 必须与 Embedding 模型输出维度一致
上一页
ETL 数据注入流水线