本文介绍如何在 Spring Boot 项目中使用 Spring AI Alibaba 接入阿里云百炼 DashScope 的通义千问文本向量模型,实现文本向量化、查询向量生成以及简单的相似度计算。示例使用
text-embedding-v4。如果你的账号或依赖版本仍使用text-embedding-v3、text-embedding-v2,只需要替换模型名称和对应支持的维度即可。
一、什么是 Embedding
Embedding 模型可以把一段文本转换成一个浮点数数组,例如:
"Spring AI 是什么?"
↓
[0.0123, -0.0841, 0.2231, ...]
这个浮点数组称为文本向量。语义相近的文本,生成的向量通常也更接近,因此向量可以用于:
-
语义搜索;
-
RAG 知识库检索;
-
文本聚类;
-
文本分类;
-
推荐和相似内容匹配;
-
重复内容检测。
本文只演示如何生成向量。要实现完整的 RAG,还需要将向量保存到 Milvus、PGVector、Elasticsearch、Redis 等向量数据库中。
二、准备工作
开始之前,需要准备:
-
JDK 17 或更高版本;
-
Maven 3.9+;
-
Spring Boot 项目;
-
阿里云百炼 API Key;
-
已在百炼控制台开通对应的 Embedding 模型权限。
可以在 阿里云百炼控制台 创建 API Key。
不要把 API Key 直接写入 Git 仓库。 本文使用环境变量 AI_DASHSCOPE_API_KEY 注入密钥。
三、Maven 依赖配置
Spring AI Alibaba 为 DashScope 提供了 Spring Boot Starter,Starter 同时支持 DashScope 的 ChatModel 和 EmbeddingModel 自动配置。
下面是一个完整的 pom.xml 示例。版本应保持 Spring Boot、Spring AI Alibaba 和 Spring AI 核心依赖相互兼容。本文示例使用 Maven Central 中的 spring-ai-alibaba-starter-dashscope:2.0.0-M1.1。
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-ai-qwen-embedding-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai-qwen-embedding-demo</name>
<properties>
<java.version>17</java.version>
<spring-ai-alibaba.version>2.0.0-M1.1</spring-ai-alibaba.version>
</properties>
<dependencies>
<!-- Web 接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI Alibaba DashScope Starter ,包含 Embedding 自动配置 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
版本选择说明
Spring AI Alibaba 的版本会随着 Spring AI 和 Spring Boot 的大版本变化。实际项目中建议:
-
先查看 Spring AI Alibaba 官方仓库的兼容说明;
-
从 Maven Central确认可用版本;
-
保证 Starter 的传递依赖没有和项目中手工指定的 Spring AI 版本冲突。
如果项目已经使用 Spring AI Alibaba 1.x,请把依赖版本替换为与你的 Spring Boot 版本匹配的 1.x 稳定版本,不要直接混用 1.x 和 2.x 的依赖。
四、配置 application.yml
在 src/main/resources/application.yml 中配置 DashScope:
yaml
server:
port: 8080
spring:
application:
name: spring-ai-qwen-embedding-demo
ai:
dashscope:
# 从环境变量中读取百炼 API Key
api-key: ${AI_DASHSCOPE_API_KEY}
# DashScope 公共云基础地址
base-url: https://dashscope.aliyuncs.com
embedding:
# 启用 DashScope Embedding 自动配置
# 不同版本可能默认已启用 ,显式配置更清晰
options:
# 推荐使用当前可用的通用文本向量模型
model: text-embedding-v4
# 文档入库使用 document,用户查询使用 query
text-type: document
# v4 支持 2048、1536、1024、768、512、256、128、64
dimensions: 1024
# 新版 Spring AI Alibaba 文档使用该顶层属性选择 Embedding 模型
model:
embedding: dashscope
retry:
# 网络临时异常可以重试,4xx 参数错误默认不重试
max-attempts: 3
backoff:
initial-interval: 1s
multiplier: 2
max-interval: 10s
on-client-errors: false
设置环境变量:
Linux/macOS
bash
export AI_DASHSCOPE_API_KEY="你的百炼 API Key"
Windows PowerShell
$env:AI_DASHSCOPE_API_KEY = "你的百炼 API Key"
也可以在启动时临时传入:
bash
AI_DASHSCOPE_API_KEY="你的百炼 API Key" mvn spring-boot:run
五、通义千问向量模型选择
DashScope 常见文本向量模型如下:
| 模型 | 说明 | 常见维度 |
|---|---|---|
text-embedding-v4 |
新版通用多语言文本向量模型,适合新建知识库 | 2048、1536、1024、768、512、256、128、64 |
text-embedding-v3 |
多语言文本向量模型 | 1024、768、512、256、128、64 |
text-embedding-v2 |
较早版本通用文本向量模型 | 1536 |
text-embedding-v1 |
基础文本向量模型 | 以平台实际支持为准 |
本文使用 text-embedding-v4 和 1024 维。维度越高并不一定代表业务效果一定越好,需要结合检索质量、存储空间、查询延迟和向量数据库索引能力选择。
重要原则:索引和查询维度必须一致
例如文档入库使用:
yaml
model: text-embedding-v4
dimensions: 1024
那么用户问题也必须使用同一个模型和同一个维度:
text-embedding-v4 + 1024 维
如果文档向量是 1024 维,而查询向量是 768 维,向量数据库通常会直接报维度不匹配错误。
六、编写 Spring Boot 启动类
java
package com.example.embedding;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class QwenEmbeddingApplication {
public static void main(String[] args) {
SpringApplication.run(QwenEmbeddingApplication.class, args);
}
}
添加 DashScope Starter 后,Spring Boot 会自动创建 EmbeddingModel Bean,业务代码可以直接注入它。
七、生成单条文本向量
下面编写一个 Controller,通过 HTTP 参数接收文本并生成向量:
java
package com.example.embedding.controller;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingResponse;
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.HashMap;
import java.util.Map;
@RestController
public class EmbeddingController {
private final EmbeddingModel embeddingModel;
public EmbeddingController(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
@GetMapping("/ai/embedding")
public Map<String, Object> embedding(
@RequestParam(value = "text", defaultValue = "Spring AI 可以接入通义千问向量模型")
String text) {
EmbeddingResponse response = embeddingModel.embedForResponse(
java.util.List.of(text)
);
float[] vector = response.getResults().get(0).getOutput();
Map<String, Object> result = new HashMap<>();
result.put("text", text);
result.put("dimensions", vector.length);
// 示例只返回前 5 个元素,避免接口响应过大
result.put("preview", Arrays.copyOf(vector, Math.min(5, vector.length)));
result.put("model", response.getMetadata().getModel());
return result;
}
}
启动项目:
bash
mvn spring-boot:run
调用接口:
bash
curl --get 'http://localhost:8080/ai/embedding' \
--data-urlencode 'text=Spring AI 如何实现语义搜索?'
返回结果类似:
json
{
"text": "Spring AI 如何实现语义搜索?",
"dimensions": 1024,
"preview": [0.0123, -0.0831, 0.2214, 0.0172, -0.1045],
"model": "text-embedding-v4"
}
实际向量包含 1024 个浮点数 ,示例中只返回前 5 个元素。
不建议在生产接口中直接返回完整向量。完整向量体积较大,也可能暴露不必要的内部数据。通常应该在服务端直接写入向量数据库。
八、批量生成文本向量
Spring AI 的 EmbeddingModel 支持一次传入多条文本:
java
package com.example.embedding.service;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmbeddingService {
private final EmbeddingModel embeddingModel;
public EmbeddingService(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
public List<float[]> embedDocuments(List<String> documents) {
return embeddingModel.embed(documents);
}
}
调用示例:
java
List<String> documents = List.of(
"Spring AI 是面向 Java 的人工智能应用框架。",
"Embedding 可以将文本转换为向量。",
"向量数据库适合保存和检索文本向量。"
);
List<float[]> vectors = embeddingService.embedDocuments(documents);
for (int i = 0; i < vectors.size(); i++) {
System.out.println("第 " + i + " 条向量维度:" + vectors.get(i).length);
}
批量大小需要遵守当前模型的限制。以 text-embedding-v4 为例,官方接口文档显示单次请求最多支持 10 条输入,每条输入还有 Token 长度限制。业务代码中建议自行分批,不要一次提交几百或几千条文本。
九、区分 document 和 query 文本
在语义检索中,通常存在两种文本:
-
document:知识库中被检索的文档;
-
query:用户输入的查询问题。
为了让模型更好地适配非对称检索任务,建议:
-
文档入库时使用
text-type: document; -
用户查询时使用
text-type: query。
默认配置可以用于文档入库:
yaml
spring:
ai:
dashscope:
embedding:
options:
model: text-embedding-v4
text-type: document
dimensions: 1024
如果需要在同一个应用中针对不同请求切换 document 和 query,可以使用运行时 Embedding 选项。不同 Spring AI Alibaba 版本的 options builder 方法可能略有不同,常见写法如下:
java
import com.alibaba.cloud.ai.dashscope.api.DashScopeModel;
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import java.util.List;
public EmbeddingResponse embedQuery(EmbeddingModel embeddingModel, String query) {
DashScopeEmbeddingOptions options = DashScopeEmbeddingOptions.builder()
.model("text-embedding-v4")
.textType(DashScopeModel.EmbeddingTextType.QUERY.getValue())
.dimensions(1024)
.build();
return embeddingModel.call(new EmbeddingRequest(List.of(query), options));
}
如果 IDE 提示 DashScopeEmbeddingOptions 的包路径或 builder 方法不存在,说明当前项目使用的 Spring AI Alibaba 版本 API 有差异,应以该版本源码或 JavaDoc 为准。最稳妥的方式是先使用 application.yml 配置默认参数,确认基础调用成功后,再增加运行时选项。
十、计算两个文本的余弦相似度
向量生成后,可以使用余弦相似度判断两个文本的语义接近程度:
java
package com.example.embedding.util;
public final class VectorSimilarity {
private VectorSimilarity() {
}
public static double cosineSimilarity(float[] a, float[] b) {
if (a == null || b == null || a.length != b.length) {
throw new IllegalArgumentException("两个向量不能为空且维度必须一致");
}
double dot = 0.0;
double normA = 0.0;
double normB = 0.0;
for (int i = 0; i < a.length; i++) {
dot += (double) a[i] * b[i];
normA += (double) a[i] * a[i];
normB += (double) b[i] * b[i];
}
if (normA == 0.0 || normB == 0.0) {
return 0.0;
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
}
使用:
java
List<float[]> vectors = embeddingModel.embed(List.of(
"Java 是一种编程语言",
"Spring Boot 是 Java 生态中的开发框架"
));
double score = VectorSimilarity.cosineSimilarity(
vectors.get(0),
vectors.get(1)
);
System.out.println("相似度:" + score);
实际生产环境通常不在应用内遍历全部向量,而是将向量写入向量数据库,再使用数据库的 ANN 索引完成近似最近邻检索。
十一、封装成文档入库服务
下面给出一个简单的 Service 示例,用于将文档转换成向量对象。真实项目中可以在 save 方法中写入 PGVector、Milvus 或 Elasticsearch:
java
package com.example.embedding.service;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class KnowledgeDocumentService {
private final EmbeddingModel embeddingModel;
public KnowledgeDocumentService(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
public void saveDocument(String documentId, String content) {
float[] vector = embeddingModel.embed(content);
// TODO: 将 documentId、content、vector 写入向量数据库
// 例如:vectorStore.add(List.of(new Document(content, metadata)))
System.out.printf(
"documentId=%s, contentLength=%d, vectorDimensions=%d%n",
documentId,
content.length(),
vector.length
);
}
public List<float[]> embedBatch(List<String> contents) {
return embeddingModel.embed(contents);
}
}
十二、常见问题排查
1. 启动时报 API Key 为空
检查启动进程是否读取到了环境变量:
bash
echo "$AI_DASHSCOPE_API_KEY"
如果使用 IDE 启动,需要在 IDE 的 Run Configuration 中配置环境变量,而不仅仅是在另一个 Shell 窗口中执行 export。
也可以临时使用命令行启动:
bash
AI_DASHSCOPE_API_KEY="你的 API Key" mvn spring-boot:run
2. 返回 401 或 403
常见原因:
-
API Key 错误或已失效;
-
百炼账号没有开通对应模型;
-
使用了错误的地域或 Workspace;
-
环境变量中包含多余空格;
-
项目实际读取的不是你以为的那个配置文件。
3. 返回模型不存在
确认配置项:
yaml
spring:
ai:
dashscope:
embedding:
options:
model: text-embedding-v4
模型名称不能写成聊天模型名称,例如 qwen-plus、qwen-turbo 等不是文本向量模型。
4. 向量维度不匹配
检查三处是否一致:
-
application.yml的dimensions; -
向量数据库 collection/index 的维度;
-
查询向量生成时使用的维度。
例如全部使用 1024 维:
yaml
dimensions: 1024
5. EmbeddingModel 无法注入
检查:
-
是否加入了
spring-ai-alibaba-starter-dashscope; -
Starter 版本和 Spring Boot 版本是否兼容;
-
是否存在多个 EmbeddingModel Bean 导致注入歧义;
-
是否将
spring.ai.model.embedding错误设置成了none; -
是否把 ChatScope 的 Chat 依赖误当成 Embedding 依赖。
6. 是否必须使用 OpenAI 兼容接口
不必须。Spring AI Alibaba 的 DashScope Starter 直接封装了 DashScope API,适合使用 DashScope 特有的 text_type、dimension、稀疏向量等能力。
阿里云也提供 OpenAI 兼容的 Embedding 接口。如果项目已经统一使用 OpenAI SDK,可以选择兼容接口;但本文使用的是 Spring AI Alibaba 原生 DashScope 集成。
十三、项目目录结构
spring-ai-qwen-embedding-demo
├── pom.xml
└── src
└── main
├── java
│ └── com/example/embedding
│ ├── QwenEmbeddingApplication.java
│ ├── controller
│ │ └── EmbeddingController.java
│ ├── service
│ │ ├── EmbeddingService.java
│ │ └── KnowledgeDocumentService.java
│ └── util
│ └── VectorSimilarity.java
└── resources
└── application.yml
十四、总结
Spring AI 接入通义千问向量模型的核心步骤如下:
-
引入
spring-ai-alibaba-starter-dashscope; -
配置
spring.ai.dashscope.api-key; -
将 Embedding 模型配置为
text-embedding-v4; -
注入
EmbeddingModel; -
调用
embed或embedForResponse生成向量; -
将文档向量保存到向量数据库,用于后续相似度检索。
最简单的调用代码如下:
java
float[] vector = embeddingModel.embed("Spring AI 接入通义千问向量模型");
在生产环境中,还需要继续完善:
-
文档切分策略;
-
批量向量化和限流;
-
向量数据库索引;
-
查询和文档的
text_type区分; -
API Key 安全管理;
-
超时、重试和熔断;
-
Token 用量与成本统计;
-
文档更新和向量删除机制。