Spring AI 从入门到精通-Embedding 做好软件测试你要学习这些
·

7. Embedding:AI 的"理解"从数字开始
7.1 一个比喻:气味地图
想象你走进一家咖啡店,你闻到咖啡的香气、烤面包的焦味、还有一点点奶香。你的大脑不需要看到"咖啡豆"三个字,就能判断这是咖啡店。
Embedding(嵌入)就是这个过程的数字版。 它把一段文字转换成一串浮点数(向量),这串数字"代表"了文字的含义。语义相近的文字,向量在空间中距离也近。
7.2 EmbeddingModel 接口
Spring AI 的 EmbeddingModel 接口极其简洁:
public interface EmbeddingModel extends Model<EmbeddingRequest, EmbeddingResponse> {
// 嵌入一段文本
float[] embed(String text);
// 嵌入一个 Document 对象
float[] embed(Document document);
// 批量嵌入
List<float[]> embed(List<String> texts);
// 嵌入并返回完整响应(含元数据)
EmbeddingResponse embedForResponse(List<String> texts);
// 获取向量维度
int dimensions();
}
7.3 第一个 Embedding 示例
@Autowired
private EmbeddingModel embeddingModel;
public void demo() {
// 嵌入一段文本
float[] vector = embeddingModel.embed("Spring AI 是一个强大的 AI 框架");
System.out.println("向量维度: " + vector.length); // 比如 1536(OpenAI)或 768(Ollama)
System.out.println("前 5 个值: " + Arrays.toString(Arrays.copyOf(vector, 5)));
// 输出示例: [0.0123, -0.0456, 0.0789, 0.0234, -0.0567]
// 批量嵌入
List<float[]> vectors = embeddingModel.embed(List.of(
"Java 编程语言",
"Python 编程语言",
"今天天气很好"
));
// 计算余弦相似度
double similarity = cosineSimilarity(vectors.get(0), vectors.get(1));
System.out.println("Java 和 Python 的相似度: " + similarity); // 应该很高,比如 0.85
double similarity2 = cosineSimilarity(vectors.get(0), vectors.get(2));
System.out.println("Java 和天气的相似度: " + similarity2); // 应该很低,比如 0.12
}
// 余弦相似度计算:衡量两个向量在方向上的相似程度
// 值越接近 1 表示语义越相似,越接近 0 表示越不相关
private double cosineSimilarity(float[] a, float[] b) {
double dot = 0, normA = 0, normB = 0;
for (int i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
7.4 支持的 Embedding 模型
| 提供商 | 依赖 | 维度 | 特点 |
|---|---|---|---|
| OpenAI | spring-ai-starter-model-openai |
1536/3072 | 最常用 |
| Azure OpenAI | spring-ai-starter-model-azure-openai |
1536 | 企业合规 |
| Ollama | spring-ai-starter-model-ollama |
768/4096 | 免费本地 |
| Transformers (ONNX) | spring-ai-starter-model-transformers |
384/768 | 纯本地,无网络 |
| Vertex AI | spring-ai-starter-model-vertex-ai |
768 | Google 生态 |
| Bedrock | spring-ai-starter-model-bedrock |
1024/1536 | AWS 生态 |
| Mistral AI | spring-ai-starter-model-mistral-ai |
1024 | 欧洲厂商 |
7.5 配置 Embedding 模型
# OpenAI Embedding
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.embedding.options.model=text-embedding-3-small
# Ollama Embedding(免费本地)
spring.ai.ollama.embedding.options.model=nomic-embed-text
7.6 Document 对象:带元数据的文本
在 RAG 场景中,我们不只嵌入"纯文本",而是嵌入带元数据的 Document 对象:
Document doc = new Document(
"Spring AI 是 Spring 生态的 AI 框架,支持多种模型和向量数据库。",
Map.of(
"source", "官方文档",
"page", 1,
"author", "Spring 团队",
"category", "AI"
)
);
float[] embedding = embeddingModel.embed(doc);
// 元数据可用于后续过滤
7.7 一个完整的相似度搜索 Demo
@Service
public class SemanticSearchService {
private final EmbeddingModel embeddingModel;
public SemanticSearchService(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
/**
* 在候选文档中搜索与查询最相似的文档
*/
public List<ScoredDocument> search(String query, List<Document> candidates, int topK) {
// 1. 嵌入查询
float[] queryEmbedding = embeddingModel.embed(query);
// 2. 嵌入所有候选文档(批量)
List<float[]> candidateEmbeddings = embeddingModel.embed(
candidates.stream().map(Document::getText).toList()
);
// 3. 计算相似度并排序
return IntStream.range(0, candidates.size())
.mapToObj(i -> new ScoredDocument(
candidates.get(i),
cosineSimilarity(queryEmbedding, candidateEmbeddings.get(i))
))
.sorted((a, b) -> Double.compare(b.score, a.score))
.limit(topK)
.toList();
}
}
record ScoredDocument(Document document, double score) {}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)