主题
Azure AI 服务
本节引导你设置 AzureVectorStore,以使用 Azure AI 搜索服务存储文档嵌入并执行相似度搜索。
Azure AI 搜索 是一个多功能的、云托管的信息检索系统,属于微软更大 AI 平台的一部分。除其他特性外,它允许用户使用基于向量的存储与检索来查询信息。
前置条件
- Azure 订阅:使用任何 Azure 服务,你都需要一个 Azure 订阅。
- Azure AI 搜索服务:创建一个 AI 搜索服务。服务创建后,从
Settings下的Keys部分获取管理员 apiKey,并从Overview部分的Url字段获取端点。 1.(可选)Azure OpenAI 服务:创建一个 Azure OpenAI 服务。注意: 你可能需要填写一份单独的表单才能访问 Azure OpenAI 服务。服务创建后,从Resource Management下的Keys and Endpoint部分获取端点和 apiKey。
配置
在启动时,如果你在构造器中把相关的 initialize-schema boolean 属性设为 true,或(使用 Spring Boot 时)在 application.properties 文件中设置 ...initialize-schema=true,那么 AzureVectorStore 便可尝试在你的 AI 搜索服务实例中创建一个新索引。
NOTE
这是一处破坏性变更!在较早的 Spring AI 版本中,此模式初始化默认进行。
或者,你可以手动创建该索引。
要设置一个 AzureVectorStore,你需要上面前置步骤中获取的设置项,连同你的索引名:
- Azure AI 搜索端点
- Azure AI 搜索密钥 -(可选)Azure OpenAI API 端点 -(可选)Azure OpenAI API 密钥
你可以把这些值作为操作系统环境变量提供。
bash
export AZURE_AI_SEARCH_API_KEY=<My AI Search API Key>
export AZURE_AI_SEARCH_ENDPOINT=<My AI Search Index>
export OPENAI_API_KEY=<My Azure AI API Key> (Optional)NOTE
你可以用任何支持 Embeddings 接口的合法 OpenAI 实现来替换 Azure OpenAI 实现。例如,你可以用 Spring AI 的 OpenAI 或 TransformersEmbedding 实现来代替 Azure 实现做嵌入。
依赖
NOTE
Spring AI 的自动配置、starter 模块的制品名称发生了重大变更。 更多信息请参阅 升级说明。
把这些依赖添加到你的项目:
1. 选择一个 Embeddings 接口实现。你可以在以下之间选择:
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>2. Azure(AI 搜索)向量库
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-store</artifactId>
</dependency>TIP
参见 依赖管理 一节,把 Spring AI BOM 添加到你的构建文件。
配置属性
你可以在 Spring Boot 配置中使用以下属性来定制 Azure 向量库。
| 属性 |
|---|
| 默认值 |
spring.ai.vectorstore.azure.url |
spring.ai.vectorstore.azure.api-key |
spring.ai.vectorstore.azure.use-keyless-auth |
| false |
spring.ai.vectorstore.azure.initialize-schema |
| false |
spring.ai.vectorstore.azure.index-name |
| springaiazurevectorstore |
spring.ai.vectorstore.azure.default-top-k |
| 4 |
示例代码
要在你的应用中配置一个 Azure SearchIndexClient,可以使用以下代码:
java
@Bean
public SearchIndexClient searchIndexClient() {
return new SearchIndexClientBuilder().endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
.credential(new AzureKeyCredential(System.getenv("AZURE_AI_SEARCH_API_KEY")))
.buildClient();
}要创建一个向量库,你可以使用以下代码:注入上面示例中创建的 SearchIndexClient bean,连同 Spring AI 库提供的、实现了所需 Embeddings 接口的一个 EmbeddingModel。
java
@Bean
public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) {
return AzureVectorStore.builder(searchIndexClient, embeddingModel)
.initializeSchema(true)
// Define the metadata fields to be used
// in the similarity search filters.
.filterMetadataFields(List.of(MetadataField.text("country"), MetadataField.int64("year"),
MetadataField.date("activationDate")))
.defaultTopK(5)
.defaultSimilarityThreshold(0.7)
.indexName("spring-ai-document-index")
.build();
}NOTE
对于在过滤表达式中使用的任何元数据键,你必须显式列出所有的元数据字段名和类型。上面的列表注册了可过滤的元数据字段:类型为 TEXT 的 country、类型为 INT64 的 year,以及类型为 BOOLEAN 的 active。
如果可过滤的元数据字段新增了条目,你必须用这些元数据(重新)上传/更新文档。
在你的主代码中,创建一些文档:
java
List<Document> documents = List.of(
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("country", "BG", "year", 2020)),
new Document("The World is Big and Salvation Lurks Around the Corner"),
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "year", 2023)));把文档添加到你的向量库:
java
vectorStore.add(documents);最后,检索与某个查询相似的文档:
java
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query("Spring")
.topK(5).build());如果一切顺利,你应能检索到包含文本 "Spring AI rocks!!" 的文档。
元数据过滤
你也可以在 AzureVectorStore 上利用通用、可移植的元数据过滤器。
例如,你可以使用文本表达式语言:
java
vectorStore.similaritySearch(
SearchRequest.builder()
.query("The World")
.topK(TOP_K)
.similarityThreshold(SIMILARITY_THRESHOLD)
.filterExpression("country in ['UK', 'NL'] && year >= 2020").build());或以编程方式使用表达式 DSL:
java
FilterExpressionBuilder b = new FilterExpressionBuilder();
vectorStore.similaritySearch(
SearchRequest.builder()
.query("The World")
.topK(TOP_K)
.similarityThreshold(SIMILARITY_THRESHOLD)
.filterExpression(b.and(
b.in("country", "UK", "NL"),
b.gte("year", 2020)).build()).build());这些可移植的过滤表达式会被自动转换为 Azure 搜索专有的 OData 过滤器。例如,下面这个可移植的过滤表达式:
sql
country in ['UK', 'NL'] && year >= 2020会被转换为如下的 Azure OData 过滤表达式:
graphql
$filter search.in(meta_country, 'UK,NL', ',') and meta_year ge 2020自定义字段名
默认情况下,Azure 向量库在 Azure AI 搜索索引中使用以下字段名:
content- 用于文档文本embedding- 用于向量嵌入metadata- 用于文档元数据
然而,在使用采用不同字段名的既有 Azure AI 搜索索引时,你可以配置自定义字段名以匹配你的索引模式。这让你能把 Spring AI 集成到既有索引上而无需修改它们。
用例
自定义字段名在以下情形尤其有用:
- 与既有索引集成:你的组织已有采用既定字段命名约定的 Azure AI 搜索索引(例如
chunk_text、vector、meta_data)。 - 遵循命名标准:你的团队遵循与默认值不同的特定命名约定。
- 从其他系统迁移:你正从另一个向量数据库或搜索系统迁移,并希望保持一致的字段名。
通过属性配置
你可以使用 Spring Boot 应用属性来配置自定义字段名:
properties
spring.ai.vectorstore.azure.url=${AZURE_AI_SEARCH_ENDPOINT}
spring.ai.vectorstore.azure.api-key=${AZURE_AI_SEARCH_API_KEY}
spring.ai.vectorstore.azure.index-name=my-existing-index
spring.ai.vectorstore.azure.initialize-schema=false
# Custom field names to match existing index schema
spring.ai.vectorstore.azure.content-field-name=chunk_text
spring.ai.vectorstore.azure.embedding-field-name=vector
spring.ai.vectorstore.azure.metadata-field-name=meta_dataWARNING
在使用带自定义字段名的既有索引时,请设置 initialize-schema=false,以防 Spring AI 尝试用默认模式创建一个新索引。
通过 Builder API 配置
或者,你可以使用构建器 API 以编程方式配置自定义字段名:
java
@Bean
public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) {
return AzureVectorStore.builder(searchIndexClient, embeddingModel)
.indexName("my-existing-index")
.initializeSchema(false) // Don't create schema - use existing index
// Configure custom field names to match existing index
.contentFieldName("chunk_text")
.embeddingFieldName("vector")
.metadataFieldName("meta_data")
.filterMetadataFields(List.of(
MetadataField.text("category"),
MetadataField.text("source")))
.build();
}完整示例:处理既有索引
下面是一个完整示例,展示如何把 Spring AI 用于一个带自定义字段名的既有 Azure AI 搜索索引:
java
@Configuration
public class VectorStoreConfig {
@Bean
public SearchIndexClient searchIndexClient() {
return new SearchIndexClientBuilder()
.endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
.credential(new AzureKeyCredential(System.getenv("AZURE_AI_SEARCH_API_KEY")))
.buildClient();
}
@Bean
public VectorStore vectorStore(SearchIndexClient searchIndexClient,
EmbeddingModel embeddingModel) {
return AzureVectorStore.builder(searchIndexClient, embeddingModel)
.indexName("production-documents-index")
.initializeSchema(false) // Use existing index
// Map to existing index field names
.contentFieldName("document_text")
.embeddingFieldName("text_vector")
.metadataFieldName("document_metadata")
// Define filterable metadata fields from existing schema
.filterMetadataFields(List.of(
MetadataField.text("department"),
MetadataField.int64("year"),
MetadataField.date("created_date")))
.defaultTopK(10)
.defaultSimilarityThreshold(0.75)
.build();
}
}然后你可以照常使用该向量库:
java
// Search using the existing index with custom field names
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query("artificial intelligence")
.topK(5)
.filterExpression("department == 'Engineering' && year >= 2023")
.build());
// The results contain documents with text from the 'document_text' field
results.forEach(doc -> System.out.println(doc.getText()));用自定义字段名创建新索引
你也可以通过设置 initializeSchema=true 创建一个带自定义字段名的新索引:
java
@Bean
public VectorStore vectorStore(SearchIndexClient searchIndexClient,
EmbeddingModel embeddingModel) {
return AzureVectorStore.builder(searchIndexClient, embeddingModel)
.indexName("new-custom-index")
.initializeSchema(true) // Create new index with custom field names
.contentFieldName("text_content")
.embeddingFieldName("content_vector")
.metadataFieldName("doc_metadata")
.filterMetadataFields(List.of(
MetadataField.text("category"),
MetadataField.text("author")))
.build();
}这会用一个新 Azure AI 搜索索引并按你的自定义字段名创建它,让你从一开始就确立自己的命名约定。
访问原生客户端
Azure 向量库实现通过 getNativeClient() 方法提供对底层原生 Azure 搜索客户端(SearchClient)的访问:
java
AzureVectorStore vectorStore = context.getBean(AzureVectorStore.class);
Optional<SearchClient> nativeClient = vectorStore.getNativeClient();
if (nativeClient.isPresent()) {
SearchClient client = nativeClient.get();
// Use the native client for Azure Search-specific operations
}原生客户端让你得以访问那些可能未通过 VectorStore 接口暴露的 Azure 搜索特定功能与操作。