LlamaIndex 集成 Azure AI Search:AzureAISearchVectorStore 向量存储完整实战指南
【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
本指南围绕 LlamaIndex 官方集成的 Azure AI Search 向量存储(AzureAISearchVectorStore,即旧称CognitiveSearchVectorStore)展开,讲解如何在 LlamaIndex 应用中把文档向量与元数据写入 Azure AI Search 索引、执行向量/混合/语义混合检索,以及通过索引管理、字段映射和 OData 元数据过滤实现工程化落地。读完本文,你将掌握从安装、索引自动创建、批量写入到多模式查询的完整实战方案,并理解其底层实现原理。
集成概览:为什么选择 Azure AI Search 作为向量存储
Azure AI Search(前身 Azure Cognitive Search)是微软 Azure 上托管的搜索服务,原生支持向量索引(HNSW、Exhaustive KNN)、全文检索、语义排序(Semantic Ranker)与 OData 元数据过滤。在 LlamaIndex 的向量存储能力对比表中,Azure AI Search 被列为云托管型(cloud)向量存储,支持异步、元数据过滤等能力(见 vector_stores.md)。
在官方社区集成列表中,Azure AI Search 是首屈一指的 Azure 系向量存储方案(见 vector_stores.md 集成清单)。本集成由独立的 Python 包llama-index-vector-stores-azureaisearch提供,包版本 0.5.1,依赖azure-search-documents>=11.5.1,<12与llama-index-core>=0.13.0,<0.15(见 pyproject.toml)。
注意:
CognitiveSearchVectorStore是AzureAISearchVectorStore的别名,两者指向同一个类(见 base.py 源码 与init.py)。文档 API 参考页 azureaisearch.md 同时收录了这两个类名。
安装与最小可用示例
安装依赖
pip install llama-index-vector-stores-azureaisearch该包会在安装时拉取azure-search-documents与llama-index-core。若缺少 SDK,构造向量存储时会抛出ImportError,提示先执行pip install azure-search-documents==11.4.0(见 base.py 导入检查)。
官方示例:完整初始化
以下代码取自类的 docstring 官方示例(见 base.py Examples),展示了从创建 Azure 客户端到初始化向量存储的完整链路:
from azure.core.credentials import AzureKeyCredential from azure.search.documents import SearchClient from azure.search.documents.indexes import SearchIndexClient from llama_index.vector_stores.azureaisearch import AzureAISearchVectorStore from llama_index.vector_stores.azureaisearch import IndexManagement, MetadataIndexFieldType # Azure AI Search setup search_service_api_key = "YOUR-AZURE-SEARCH-SERVICE-ADMIN-KEY" search_service_endpoint = "YOUR-AZURE-SEARCH-SERVICE-ENDPOINT" search_service_api_version = "2024-07-01" credential = AzureKeyCredential(search_service_api_key) # Index name to use index_name = "llamaindex-vector-demo" # Use index client to demonstrate creating an index index_client = SearchIndexClient( endpoint=search_service_endpoint, credential=credential, ) metadata_fields = { "author": "author", "theme": ("topic", MetadataIndexFieldType.STRING), "director": "director", } # Creating an Azure AI Search Vector Store vector_store = AzureAISearchVectorStore( search_or_index_client=index_client, filterable_metadata_field_keys=metadata_fields, hidden_field_keys=["embedding"], index_name=index_name, index_management=IndexManagement.CREATE_IF_NOT_EXISTS, id_field_key="id", chunk_field_key="chunk", embedding_field_key="embedding", embedding_dimensionality=1536, metadata_string_field_key="metadata", doc_id_field_key="doc_id", language_analyzer="en.lucene", vector_algorithm_type="exhaustiveKnn", semantic_configuration_name="mySemanticConfig", )社区集成文档还给出了更精简的启动方式:直接传入SearchIndexClient与index_name、embedding_dimensionality三个参数即可完成初始化(见 integrations 文档示例)。
客户端类型与校验规则
search_or_index_client是构造函数的必填参数,接受SearchClient、SearchIndexClient及其异步版本。构造函数内部遵循如下校验逻辑(见 base.pyinit):
- 传入
SearchIndexClient时,必须同时提供index_name,否则抛出ValueError;内部会通过get_search_client(index_name)派生出用于读写文档的SearchClient; - 传入
SearchClient时,不能再提供index_name,否则抛出ValueError; - 若
index_management == CREATE_IF_NOT_EXISTS且未传入索引客户端(Index 类客户端),会抛出ValueError; - 同步与异步客户端都未提供时抛出
ValueError。
此外,构造时会为 SDK 客户端注入llamaindex-python用户代理头(可通过user_agent参数追加自定义标识),测试用例 test_user_agent_configuration 验证了该行为。
构造函数核心参数全解
构造函数签名(见 base.pyinit)中的核心参数如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
search_or_index_client | SearchClient/SearchIndexClient/ 异步版本 | 无(必填) | 用于读写索引或管理索引的 Azure SDK 客户端 |
id_field_key | str | 无(必填) | 存储节点 ID 的索引字段名 |
chunk_field_key | str | 无(必填) | 存储节点文本(chunk)的索引字段名 |
embedding_field_key | str | 无(必填) | 存储向量(embedding)的索引字段名 |
metadata_string_field_key | str | 无(必填) | 以 JSON 字符串存储节点元数据的索引字段名 |
doc_id_field_key | str | 无(必填) | 存储 doc_id(源文档 ID)的索引字段名 |
async_search_or_index_client | 异步客户端 | None | 异步场景专用客户端,缺省时复用同步客户端类型 |
filterable_metadata_field_keys | List[str]/Dict[str, str]/Dict[str, Tuple[str, MetadataIndexFieldType]] | None | 需要作为独立可过滤字段落库的元数据键,见下文 |
hidden_field_keys | List[str] | None | 对客户端隐藏的字段(如["embedding"]),避免检索返回大向量 |
index_name | Optional[str] | None | 索引名(使用 Index 类客户端时必填) |
index_mapping | Callable | 默认映射 | 自定义「节点字段 → 索引字段」映射函数 |
index_management | IndexManagement | NO_VALIDATION | 索引管理策略:不校验 / 校验 / 不存在则创建 |
embedding_dimensionality | int | 1536 | 向量维度,需与嵌入模型输出维度一致 |
vector_algorithm_type | str | "exhaustiveKnn" | 向量索引算法,仅支持exhaustiveKnn或hnsw |
language_analyzer | str | "en.lucene" | 可搜索文本字段的语言分析器,多语言内容建议调整 |
compression_type | str | "none" | 向量压缩类型,支持"binary"、"scalar"、"none" |
semantic_configuration_name | Optional[str] | None | Azure 语义检索配置名,用于语义混合查询 |
user_agent | Optional[str] | None | 追加到 SDK 请求的自定义 User-Agent 标识 |
关键参数深入说明
字段映射(Field Mapping):五个必填字段键构成默认映射{"id", "chunk", "embedding", "metadata", "doc_id"}(见 base.py 字段映射)。index_mapping允许自定义(enriched_doc, metadata) -> index_doc函数,enriched_doc的键固定为["id", "chunk", "embedding", "metadata"]。
可过滤元数据字段:filterable_metadata_field_keys决定哪些节点元数据以独立字段形式写入索引(从而支持 OData 过滤)。支持三种写法(见 _normalise_metadata_to_index_fields):
List[str]:如["author"],索引字段名与元数据键同名,类型默认STRING;Dict[str, str]:如{"author": "author"},键为元数据键、值为索引字段名;Dict[str, Tuple[str, MetadataIndexFieldType]]:如{"theme": ("topic", MetadataIndexFieldType.STRING)},可同时指定索引字段名与类型;- 若值为
int/float/bool/list,会自动推断为INT32/DOUBLE/BOOLEAN/COLLECTION类型。
隐藏字段:hidden_field_keys中的字段不会在检索结果中返回,典型用法是把embedding字段隐藏以减小响应体(官方示例与测试 create_mock_vector_store 均如此配置)。
索引管理:自动建索引的三种策略
IndexManagement枚举定义三种策略(见 base.py):
| 枚举值 | 行为 |
|---|---|
NO_VALIDATION | 不做任何校验,索引需由用户在 Azure 侧预先创建 |
VALIDATE_INDEX | 初始化时校验索引是否存在,不存在则抛出ValueError |
CREATE_IF_NOT_EXISTS | 初始化时检查索引,不存在则自动创建 |
当选择CREATE_IF_NOT_EXISTS时,_create_index会生成一份默认索引 Schema(见 _create_index):
- 固定字段:
id(Edm.String,主键 key、可过滤)、chunk(Edm.String,可搜索,应用language_analyzer)、embedding(Collection(Edm.Single),向量维度为embedding_dimensionality,绑定向量检索 Profile)、metadata(Edm.String,JSON 字符串)、doc_id(Edm.String,可过滤); - 元数据字段:根据
filterable_metadata_field_keys生成对应的SimpleField,映射到Edm.String/Edm.Int32/Edm.Int64/Edm.Double/Edm.Boolean/Collection(Edm.String)(见 _create_metadata_index_fields); - 向量检索算法:同时配置
myHnsw(HNSW,参数m=4、ef_construction=400、ef_search=500,COSINE 度量)与myExhaustiveKnn(Exhaustive KNN,COSINE 度量)两套算法及对应 Profile;vector_algorithm_type决定向量字段绑定的 Profile; - 压缩:
compression_type为"binary"/"scalar"时分别附加BinaryQuantizationCompression/ScalarQuantizationCompression(见 _get_compressions)。注意 Exhaustive KNN Profile 暂不支持压缩; - 语义检索:默认创建名为
mySemanticConfig(或semantic_configuration_name指定值)的SemanticConfiguration,其 content 字段绑定 chunk 字段;若元数据中存在title、keyWords键,会自动将其配置为语义标题字段与关键词字段。
同步初始化时自动建索引(异步客户端传入时改为惰性创建,在首次async_add时触发)。
写入:节点批量写入与自动分批
add(nodes)与async_add(nodes)负责把带嵌入向量的节点写入索引(见 base.py add)。实现要点:
- 批量上传统一采用 merge/upload 语义:通过
IndexDocumentsBatch.add_upload_actions累积文档; - 自动分批:默认每批最多
DEFAULT_MAX_BATCH_SIZE = 700个文档,或累计字节数达到DEFAULT_MAX_MB_SIZE = 14MB时立即上传(见 base.py 常量),避免超大请求被服务端拒绝; - 索引文档构造:
_create_index_document把node.node_id写入 id 字段、node.get_content(MetadataMode.NONE)写入 chunk 字段、node.get_embedding()写入 embedding 字段、node.ref_doc_id写入 doc_id 字段,元数据经node_to_metadata_dict(..., remove_text=True, flat_metadata=self.flat_metadata)序列化为 JSON 字符串存入 metadata 字段(见 _create_index_document); - 测试用例 test_azureaisearch_add_two_batches 验证了多批次写入路径。
查询:向量 / 稀疏 / 混合 / 语义混合四种模式
query(query, **kwargs)根据VectorStoreQuery.mode分发到不同的检索实现(见 base.py query):
| 查询模式 | 实现类 | 行为说明 |
|---|---|---|
VectorStoreQueryMode.DEFAULT | AzureQueryResultSearchDefault | 纯向量检索:用query_embedding构造VectorizedQuery,k_nearest_neighbors取hybrid_top_k或similarity_top_k,返回@search.score |
VectorStoreQueryMode.SPARSE | AzureQueryResultSearchSparse | 纯文本检索:以query_str作为search_text执行关键词搜索 |
VectorStoreQueryMode.HYBRID | AzureQueryResultSearchHybrid | 向量 + 全文混合:同时提供向量查询与文本查询 |
VectorStoreQueryMode.SEMANTIC_HYBRID | AzureQueryResultSearchSemanticHybrid | 语义混合:额外指定query_type="semantic"与语义配置名,向量k固定为 50(对齐 Azure 语义重排模型的文档接受上限),相似度取@search.reranker_score(见 base.py L1716-L1792) |
所有模式都支持通过kwargs直接透传 Azure SDK 的搜索参数(如odata_filters/odata_filter、scoring_profile等)。查询结果统一封装为VectorStoreQueryResult:先尝试用metadata_dict_to_node还原节点,失败时走legacy_metadata_dict_to_node兼容旧格式(见 base.py L1574-L1590)。
节点读取:get_nodes/aget_nodes支持按node_ids或MetadataFilters分页拉取节点,每批 1000 条,命中limit后停止(见 base.py get_nodes),底层由 azureaisearch_utils.py 中的create_search_request、create_node_from_result、process_batch_results辅助完成。
元数据过滤:OData 过滤器的生成机制
Azure AI Search 使用 OData 语法过滤。本集成将 LlamaIndex 的MetadataFilters翻译为 OData 表达式(见 _create_odata_filter):
- 基本运算符映射:
EQ→eq、NE→ne、GT→gt、LT→lt、GTE→ge、LTE→le(见 BASIC_ODATA_FILTER_MAP); FilterOperator.IN:字符串集合生成{field}/any(t: t eq 'a' or t eq 'b')形式(COLLECTION 字段)或search.in(field, 'a,b', ',')(删除场景);- 字符串转义:单引号自动转义为
''防止 OData 注入; - 组合条件:支持
FilterCondition.AND/OR/NOT,嵌套MetadataFilters递归加括号; - 约束:过滤的元数据键必须出现在
filterable_metadata_field_keys中,否则抛出ValueError提示补充映射;不支持的运算符同样抛错。
删除操作:delete(ref_doc_id)通过doc_id eq '{ref_doc_id}'定位并分批(每批 1000)删除;delete_nodes支持按node_ids或MetadataFilters构造过滤条件删除(见 base.py delete)。
资源清理与异步注意事项
向量存储实现了close()、aclose()与析构函数__del__(见 base.py L838-L884):
- 只关闭由本类内部创建的搜索客户端(
_owns_search_client/_owns_async_search_client标记),用户传入的客户端不代为关闭; close()在存在运行中事件循环时以create_task方式调度异步客户端关闭,否则用asyncio.run临时关闭;- 文档建议对确定性清理优先显式调用
close()/aclose(),不要依赖垃圾回收。
异步使用注意:若只传入同步客户端而未传async_search_or_index_client,构造时会打印警告——同步或异步方法可能只有其一可用(见 base.py L687-L691)。
端到端实践建议
- 维度对齐:
embedding_dimensionality必须与所选嵌入模型输出维度一致(如 OpenAItext-embedding-3-small的 1536 维); - 元数据过滤前置规划:凡是查询阶段需要过滤的元数据键,写入前就必须在
filterable_metadata_field_keys中声明,因为 Azure AI Search 的过滤字段需预先定义在索引 Schema 中; - 隐藏 embedding 字段:将
embedding加入hidden_field_keys可显著减小查询响应体积,向量检索本身不受影响; - 大数据量写入:依赖内置的 700 文档/14MB 自动分批机制,无需手动切分;
- 语义检索:使用
SEMANTIC_HYBRID模式前,需确保 Azure 侧已配置语义搜索(可用semantic_configuration_name指定);索引创建时默认生成的mySemanticConfig可开箱即用; - 在 LlamaIndex 中的应用:
AzureAISearchVectorStore实现了BasePydanticVectorStore接口(stores_text=True、flat_metadata=False),可直接传给VectorStoreIndex或StorageContext,配合VectorIndexRetriever、QueryEngine构建 RAG 流水线。
更完整的 Notebook 演练可参考仓库中的 AzureAISearchIndexDemo.ipynb,测试套件位于 tests,可供深入理解各功能分支的行为。
【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考