1. 概述

在应用中集成人工智能通常需要处理文本数据。嵌入模型(Embedding Model)是这一领域的核心技术,它能将文本信息转换为应用可处理的嵌入向量。

本教程将探索 Spring AI 中的嵌入模型 API。这个强大的 API 提供了抽象层,让我们能轻松切换不同的嵌入模型,帮助应用理解文本语义。

2. 嵌入模型简介

要让 AI 模型学习文本和图像的语义含义,我们通常将这些数据转换为高维向量表示,即嵌入(Embeddings)

AI 模型通过计算嵌入之间的相似度理解它们的关系。当两个嵌入的相似度分数较高时,表示它们所代表的文本在语义上更接近。

3. 嵌入模型 API

Spring AI 提供了一套简化嵌入模型操作的 API。这些接口封装了所有实现细节,让我们专注于业务逻辑。

3.1. EmbeddingModel 接口

嵌入模型是训练好的机器学习模型,能将段落、图像等对象转换为高维向量空间。

不同提供商(如 BERT)提供多种模型。Spring AI 嵌入 API 通过 EmbeddingModel 接口封装了模型实现细节:

public interface EmbeddingModel extends Model<EmbeddingRequest, EmbeddingResponse> {
    EmbeddingResponse call(EmbeddingRequest request);

    // 构造函数和其他方法
}

call() 方法接收包含数据源的 EmbeddingRequest,将其发送给模型提供商,并返回包含 EmbeddingEmbeddingResponse

3.2. EmbeddingRequest 类

EmbeddingRequest 包含待转换文本列表的载荷。除了文本,我们还可以添加特定于 EmbeddingModel 的额外选项:

public class EmbeddingRequest implements ModelRequest<List<String>> {
    private final List<String> inputs;
    private final EmbeddingOptions options;

    // 构造函数和其他方法
}

3.3. EmbeddingResponse 类

EmbeddingResponse 封装了嵌入模型提供商的响应。它包含 Embedding 对象列表和元数据(如 token 使用情况):

public class EmbeddingResponse implements ModelResponse<Embedding> {
    private final List<Embedding> embeddings;
    private final EmbeddingResponseMetadata metadata;

    // 构造函数和其他方法
}

3.4. Embedding 类

Embedding 包含 float 数组形式的向量表示。其维度取决于所选模型,通常在几百到几千之间:

public class Embedding implements ModelResult<float[]> {
    private final float[] embedding;
    private final Integer index;
    private final EmbeddingResultMetadata metadata;

    // 构造函数和其他方法
}

4. 集成 OpenAI

Spring AI 支持 OpenAI 作为嵌入模型集成方案之一。 本节我们将采用 OpenAI,创建一个将文本转换为嵌入向量的 Spring 服务。

4.1. Maven 依赖

首先在 pom.xml 中添加 Spring AI OpenAI 依赖

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

4.2. OpenAI 配置

完成集成需要在 application.yml 中配置 OpenAI API 密钥:

spring:
  ai:
    openai:
      api-key: "sk-1234567890abcdef"  # 替换为你的实际密钥

4.3. EmbeddingModel 自动配置

Spring AI 能自动配置 EmbeddingModel。在 application.yml 中添加以下属性启用自动配置:

spring:
  ai:
    openai:
      embedding:
        options:
          model: "text-embedding-3-small"

model 属性指定使用的嵌入模型。OpenAI 目前提供三种不同模型

定义模型后,直接在 Spring Boot 服务中注入 EmbeddingModel 即可,无需关心 OpenAI 实现细节:

@Service
public class EmbeddingService {
    private final EmbeddingModel embeddingModel;

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

    public EmbeddingResponse getEmbeddings(String... texts) {
        EmbeddingRequest request = new EmbeddingRequest(Arrays.asList(texts), null);
        return embeddingModel.call(request);
    }
}

✅ 自动配置提供了便利,同时隐藏了具体实现细节,让我们只需修改 application.yml 就能轻松切换不同实现。

4.4. EmbeddingModel 手动配置

虽然自动配置很方便,但某些场景下缺乏灵活性,比如需要同时使用多个嵌入模型或不同提供商时。

此时可在配置类中手动定义嵌入模型:

@Configuration
public class EmbeddingConfig {
    @Bean
    public OpenAiApi openAiApi(@Value("${spring.ai.openai.api-key}") String apiKey) {
        return OpenAiApi.builder()
          .apiKey(apiKey)
          .build();
    }

    @Bean
    public OpenAiEmbeddingModel openAiEmbeddingModel(OpenAiApi openAiApi) {
        OpenAiEmbeddingOptions options = OpenAiEmbeddingOptions.builder()
          .model("text-embedding-3-small")
          .build();
        return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, options);
    }
}

首先使用注入的 API 密钥创建 OpenAI 客户端 OpenAiApi,然后用该客户端创建 OpenAI 嵌入模型。

修改服务类注入 OpenAIEmbeddingModel 实现而非接口:

@Service
public class ManualEmbeddingService {
    private final OpenAiEmbeddingModel openAiEmbeddingModel;

    public ManualEmbeddingService(OpenAiEmbeddingModel openAiEmbeddingModel) {
        this.openAiEmbeddingModel = openAiEmbeddingModel;
    }

    public EmbeddingResponse getEmbeddings(String... texts) {
        EmbeddingRequest request = new EmbeddingRequest(Arrays.asList(texts), null);
        return openAiEmbeddingModel.call(request);
    }
}

5. 测试嵌入服务

基于前文的自动配置服务,我们暴露一个 REST 接口测试嵌入服务:

@RestController
public class EmbeddingController {
    private final EmbeddingService embeddingService;

    public EmbeddingController(EmbeddingService embeddingService) {
        this.embeddingService = embeddingService;
    }

    @PostMapping("/embeddings")
    public ResponseEntity<EmbeddingResponse> getEmbeddings(@RequestBody String text) {
        EmbeddingResponse response = embeddingService.getEmbeddings(text);
        return ResponseEntity.ok(response);
    }
}

使用 curl 向该接口发送请求:

$ curl -X POST http://localhost:8080/embeddings -H "Content-Type: text/plain" -d "Hello world"

响应如下(为简洁起见已截断):

{
    "metadata": {
        "model": "text-embedding-3-small",
        "usage": {
            "promptTokens": 2,
            "completionTokens": 0,
            "totalTokens": 2,
            "nativeUsage": {
                "prompt_tokens": 48,
                "total_tokens": 48
            }
        },
        "empty": true
    },
    "result": {
        "index": 0,
        "metadata": {
            "modalityType": "TEXT",
            "documentId": "",
            "mimeType": {
                "type": "text",
                "subtype": "plain",
                "parameters": {},
                "charset": null,
                "concrete": true,
                "wildcardSubtype": false,
                "subtypeSuffix": null,
                "wildcardType": false
            },
            "documentData": null
        },
        "output": [
            -0.0020785425,
            -0.049085874,
            ...
       ]
    }
}

⚠️ 注意这不是完整响应,实际数据非常长。我们截取后重点说明两个顶级节点:

  • metadata:提供模型信息和资源使用情况

    • model:使用的 OpenAI 模型
    • totalTokens:转换消耗的 token 数量
  • result:包含嵌入结果

    • output:由模型生成的 float 数组向量

6. 总结

Spring AI 的嵌入模型 API 提供了抽象层和对 OpenAI 等模型提供商的支持,使我们能轻松将其集成到 Java 应用中。

本文通过 OpenAI 演示了两种配置方式:✅ 自动配置适合简单场景,✅ 手动配置提供更高灵活性。嵌入 API 核心能力是将文本转换为嵌入向量。

完整代码示例请查看 GitHub 仓库