1. 概述

传统数据库通常依赖精确关键词或基础模式匹配实现搜索功能。这种方案在简单应用中尚可,但无法真正理解自然语言查询背后的语义和上下文。

向量数据库通过将数据存储为捕获其语义的数值向量来解决这一局限。语义相近的词在向量空间中会彼此靠近,从而实现语义搜索——即使结果不包含查询中的精确关键词,也能返回相关内容。

本教程将探讨如何将开源向量数据库 ChromaDB 与 Spring AI 集成

要将文本数据转换为 ChromaDB 可存储和搜索的向量,我们需要一个嵌入模型。我们将使用 Ollama 在本地运行嵌入模型。

2. 依赖配置

首先在项目的 pom.xml 中添加必要依赖:

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

✅ ChromaDB 启动依赖用于建立与向量数据库的连接
✅ Ollama 启动依赖用于运行本地嵌入模型

由于当前版本 1.0.0-M6 是里程碑版本,还需在 pom.xml 添加 Spring Milestones 仓库:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

⚠️ 里程碑版本发布在此仓库而非标准 Maven 中央仓库

为避免版本冲突,添加 Spring AI BOM(物料清单):

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0-M6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

添加后可移除启动依赖中的 version 标签,BOM 会自动管理版本兼容性。

3. 使用 Testcontainers 搭建本地测试环境

为简化本地开发和测试,我们将使用 Testcontainers 启动 ChromaDB 和 Ollama 服务

前提:需要运行中的 Docker 实例。

3.1 测试依赖

pom.xml 添加测试依赖:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-spring-boot-testcontainers</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>chromadb</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>ollama</artifactId>
    <scope>test</scope>
</dependency>

这些依赖提供启动外部服务临时 Docker 实例所需类。

3.2 定义 Testcontainers Bean

创建 @TestConfiguration 类定义容器 Bean:

@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {

    @Bean
    @ServiceConnection
    public ChromaDBContainer chromaDB() {
        return new ChromaDBContainer("chromadb/chroma:0.5.20");
    }

    @Bean
    @ServiceConnection
    public OllamaContainer ollama() {
        return new OllamaContainer("ollama/ollama:0.4.5");
    }
}

使用 @ServiceConnection 注解动态注册连接所需属性。
⚠️ 即使不用 Testcontainers,Spring AI 也会自动连接本地默认端口(ChromaDB 8000,Ollama 11434)

生产环境可通过以下配置覆盖连接信息:

spring:
  ai:
    vectorstore:
      chroma:
        client:
          host: ${CHROMADB_HOST}
          port: ${CHROMADB_PORT}
    ollama:
      base-url: ${OLLAMA_BASE_URL}

配置正确后,Spring AI 会自动创建 VectorStoreEmbeddingModel Bean。

还需在 application.yml 添加额外配置:

spring:
  ai:
    vectorstore:
      chroma:
        initialize-schema: true
    ollama:
      embedding:
        options:
          model: nomic-embed-text
      init:
        chat:
          include: false
        pull-model-strategy: WHEN_MISSING

✅ 启用 ChromaDB 模式初始化
✅ 指定 nomic-embed-text 为嵌入模型
✅ 配置 Ollama 在缺失模型时自动拉取

3.3 开发阶段使用 Testcontainers

Testcontainers 主要用于集成测试,但也可用于本地开发。在 src/test/java 创建独立启动类:

class TestApplication {

    public static void main(String[] args) {
        SpringApplication.from(Application::main)
          .with(TestcontainersConfiguration.class)
          .run(args);
    }
}

此配置可便捷启动外部服务,Spring Boot 应用将自动连接到 Testcontainers 管理的服务实例

4. 应用启动时填充 ChromaDB

现在我们将在应用启动时向 ChromaDB 填充示例数据。

4.1 从 PoetryDB 获取诗歌数据

我们将使用 PoetryDB API 获取诗歌数据。创建工具类:

class PoetryFetcher {

    private static final String BASE_URL = "https://poetrydb.org/author/";
    private static final String DEFAULT_AUTHOR_NAME = "Shakespeare";

    public static List<Poem> fetch() {
        return fetch(DEFAULT_AUTHOR_NAME);
    }

    public static List<Poem> fetch(String authorName) {
        return RestClient
          .create()
          .get()
          .uri(URI.create(BASE_URL + authorName))
          .retrieve()
          .body(new ParameterizedTypeReference<>() {});
    }

}

record Poem(String title, List<String> lines) {}

使用 RestClient 调用 PoetryDB API,通过 ParameterizedTypeReference 自动推断泛型类型。
默认获取莎士比亚作品(后续将使用此方法)。

4.2 存储文档到向量数据库

创建 VectorStoreInitializer 在启动时填充数据:

@Component
class VectorStoreInitializer implements ApplicationRunner {

    private final VectorStore vectorStore;

    // 标准构造器

    @Override
    public void run(ApplicationArguments args) {
        List<Document> documents = PoetryFetcher
          .fetch()
          .stream()
          .map(poem -> {
              Map<String, Object> metadata = Map.of("title", poem.title());
              String content = String.join("\n", poem.lines());
              return new Document(content, metadata);
          })
          .toList();
        vectorStore.add(documents);
    }

}

核心处理逻辑:

  1. 获取诗歌列表
  2. 转换为 Document 对象(诗句作为内容,标题作为元数据)
  3. 调用 vectorStore.add() 存储

调用 add() 时,Spring AI 会自动将文本内容转换为向量表示,无需手动使用 EmbeddingModel

默认集合名为 SpringAiCollection,可通过 spring.ai.vectorstore.chroma.collection-name 覆盖。

5. 测试语义搜索

验证语义搜索功能:

private static final int MAX_RESULTS = 3;

@ParameterizedTest
@ValueSource(strings = {"Love and Romance", "Time and Mortality", "Jealousy and Betrayal"})
void whenSearchingShakespeareTheme_thenRelevantPoemsReturned(String theme) {
    SearchRequest searchRequest = SearchRequest
      .builder()
      .query(theme)
      .topK(MAX_RESULTS)
      .build();
    List<Document> documents = vectorStore.similaritySearch(searchRequest);

    assertThat(documents)
      .hasSizeLessThanOrEqualTo(MAX_RESULTS)
      .allSatisfy(document -> {
          String title = String.valueOf(document.getMetadata().get("title"));
          assertThat(title)
            .isNotBlank();
        });
}

测试要点:

  • 使用 @ValueSource 注入常见莎士比亚主题
  • 构建 SearchRequest 指定查询词和最大结果数
  • 调用 similaritySearch() 执行搜索
  • 验证返回结果数量及标题非空

返回结果将包含语义相关的诗歌,即使不含精确关键词

6. 总结

本文探讨了 Spring AI 集成 ChromaDB 向量数据库的完整流程:

  1. 使用 Testcontainers 启动 ChromaDB 和 Ollama 服务
  2. 通过 PoetryDB API 获取诗歌数据并存储到向量数据库
  3. 基于诗歌主题验证语义搜索功能

这种方案特别适合需要理解自然语言语义的搜索场景,相比传统关键词匹配能提供更智能的检索体验。


原始标题:Spring AI With ChromaDB Vector Store | Baeldung