Haystack Embedder 组件 API 实战指南:OpenAI、Azure OpenAI 与 Mock 向量化组件详解
【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack
本篇指南围绕 Haystack 开源框架中haystack.components.embedders模块的六个核心 Embedder 组件展开:OpenAITextEmbedder、OpenAIDocumentEmbedder、AzureOpenAITextEmbedder、AzureOpenAIDocumentEmbedder、MockTextEmbedder与MockDocumentEmbedder。你将掌握它们的全部初始化参数、run/run_async调用契约、warm_up/close生命周期与to_dict/from_dict序列化机制,并学会在索引管线与查询/RAG 管线中组合使用它们,把文本和文档转化为可供 Embedding Retriever 检索的向量。
Embedder 在 Haystack 中的定位:把文本变成可检索的向量
在 Haystack 中,Embedder 是负责"向量化"的一类组件:它们把一段字符串或一组Document对象转换为稠密向量(Embedding),从而支持基于向量相似度的语义检索。官方 API 参考对 Embedder 的定位是:Transforms queries into vectors to look for similar or relevant Documents(将查询转换为向量,用于寻找相似或相关的文档)。
按输入类型,六个组件可划分为两条职责线:
| 组件 | 输入 | 输出 | 适用场景 |
|---|---|---|---|
OpenAITextEmbedder | 单个字符串(如用户查询) | embedding+meta | 查询/RAG 管线中、Embedding Retriever 之前 |
OpenAIDocumentEmbedder | list[Document] | 带 embedding 的documents+meta | 索引管线中批量给文档补向量 |
AzureOpenAITextEmbedder | 单个字符串 | embedding+meta | 通过 Azure 部署的 OpenAI 模型做查询向量化 |
AzureOpenAIDocumentEmbedder | list[Document] | 带 embedding 的documents+meta | 通过 Azure 部署的 OpenAI 模型批量向量化文档 |
MockTextEmbedder | 单个字符串 | embedding+meta | 测试、冒烟测试与快速原型(不调用任何外部 API) |
MockDocumentEmbedder | list[Document] | 带 embedding 的documents+meta | 测试、冒烟测试与快速原型(不调用任何外部 API) |
从源码结构看,OpenAITextEmbedder与OpenAIDocumentEmbedder是两个独立的基类实现(见 openai_text_embedder.py 与 openai_document_embedder.py),而AzureOpenAITextEmbedder继承OpenAITextEmbedder、AzureOpenAIDocumentEmbedder继承OpenAIDocumentEmbedder(见 azure_text_embedder.py 与 azure_document_embedder.py),复用父类的批处理与文本组装逻辑。所有组件均通过@component装饰器注册为 Haystack 标准组件,并在 embedders/init.py 中统一导出,因此可以直接使用from haystack.components.embedders import ...导入。
OpenAITextEmbedder:把单个查询字符串向量化
OpenAITextEmbedder使用 OpenAI 的 Embedding 模型把单个字符串(典型场景是用户查询)转换为向量,再把向量送入 Embedding Retriever 做相似度检索。
最小用法示例
from haystack.components.embedders import OpenAITextEmbedder text_to_embed = "I love pizza!" text_embedder = OpenAITextEmbedder() print(text_embedder.run(text_to_embed)) # {'embedding': [0.017020374536514282, -0.023255806416273117, ...], # 'meta': {'model': 'text-embedding-ada-002-v2', # 'usage': {'prompt_tokens': 4, 'total_tokens': 4}}}默认情况下组件从环境变量OPENAI_API_KEY读取 API Key;也可以在初始化时显式传入(from haystack.utils import Secret):
from haystack.utils import Secret from haystack.components.embedders import OpenAITextEmbedder embedder = OpenAITextEmbedder(api_key=Secret.from_token("<your-api-key>"))完整初始化签名与参数说明
__init__( api_key: Secret = Secret.from_env_var("OPENAI_API_KEY"), model: str = "text-embedding-ada-002", dimensions: int | None = None, api_base_url: str | None = None, organization: str | None = None, prefix: str = "", suffix: str = "", timeout: float | None = None, max_retries: int | None = None, http_client_kwargs: dict[str, Any] | None = None, ) -> None| 参数 | 类型 | 说明 |
|---|---|---|
api_key | Secret | OpenAI API Key,可通过环境变量OPENAI_API_KEY或初始化参数传入 |
model | str | 用于计算 Embedding 的模型名,默认text-embedding-ada-002 |
dimensions | int \| None | 输出向量的维度数,仅text-embedding-3及之后的新模型支持 |
api_base_url | str \| None | 覆盖所有 HTTP 请求的默认 Base URL |
organization | str \| None | OpenAI 组织 ID |
prefix | str | 追加到待嵌入文本开头的前缀字符串 |
suffix | str | 追加到待嵌入文本末尾的后缀字符串 |
timeout | float \| None | OpenAI 客户端调用的超时时间(秒),未设置时回退到环境变量OPENAI_TIMEOUT,再回退到 30 秒 |
max_retries | int \| None | 内部错误后的最大重试次数,未设置时回退到环境变量OPENAI_MAX_RETRIES,再回退到 5 次 |
http_client_kwargs | dict \| None | 用于配置自定义httpx.Client/httpx.AsyncClient的关键字参数字典 |
环境变量约定
官方文档明确:在初始化组件之前,可以设置OPENAI_TIMEOUT与OPENAI_MAX_RETRIES两个环境变量来覆盖 OpenAI 客户端中的timeout和max_retries。源码中_client_kwargs()的实现印证了这一回退链(openai_text_embedder.py):
timeout = self.timeout if self.timeout is not None else float(os.environ.get("OPENAI_TIMEOUT", "30.0")) max_retries = ( self.max_retries if self.max_retries is not None else int(os.environ.get("OPENAI_MAX_RETRIES", "5")) )run 与 run_async 的调用契约
run(text: str) -> dict[str, Any]:同步嵌入单个字符串。返回字典含两个键:embedding:输入文本的向量(list[float]);meta:模型使用信息,包含model与usage(如prompt_tokens、total_tokens)。
run_async(text: str) -> dict[str, Any]:run的异步版本,参数与返回值完全一致,可在async代码中配合await使用。
源码中_prepare_input会先做类型校验(非字符串直接抛出TypeError),然后按prefix + text + suffix组装待嵌入文本,并仅在设置了dimensions时追加dimensions参数;_prepare_output则把响应中的首个向量与model、usage元数据打包返回。
OpenAIDocumentEmbedder:批量给文档补向量
OpenAIDocumentEmbedder针对的是"一批文档":它对list[Document]计算向量,并通过dataclasses.replace生成内容相同、但embedding字段被填充的新Document对象返回。
最小用法示例
from haystack import Document from haystack.components.embedders import OpenAIDocumentEmbedder doc = Document(content="I love pizza!") document_embedder = OpenAIDocumentEmbedder() result = document_embedder.run([doc]) print(result['documents'][0].embedding) # [0.017020374536514282, -0.023255806416273117, ...]完整初始化签名与参数说明
__init__( api_key: Secret = Secret.from_env_var("OPENAI_API_KEY"), model: str = "text-embedding-ada-002", dimensions: int | None = None, api_base_url: str | None = None, organization: str | None = None, prefix: str = "", suffix: str = "", batch_size: int = 32, progress_bar: bool = True, meta_fields_to_embed: list[str] | None = None, embedding_separator: str = "\n", timeout: float | None = None, max_retries: int | None = None, http_client_kwargs: dict[str, Any] | None = None, *, raise_on_failure: bool = False ) -> None除与OpenAITextEmbedder相同的api_key、model、dimensions、api_base_url、organization、prefix、suffix、timeout、max_retries、http_client_kwargs之外,文档版本还额外支持:
| 参数 | 类型 | 说明 |
|---|---|---|
batch_size | int | 每批同时嵌入的文档数量,默认 32 |
progress_bar | bool | 为True时在运行过程中显示进度条 |
meta_fields_to_embed | list[str] \| None | 需要随文档文本一起参与嵌入的元数据字段名列表 |
embedding_separator | str | 拼接元数据字段与文档文本时使用的分隔符,默认"\n" |
raise_on_failure | bool | 嵌入请求失败时是否抛异常;为False时记录错误并继续处理剩余文档,为True时立即抛出异常 |
元数据参与嵌入的原理
meta_fields_to_embed是文档 Embedder 的核心增强能力。从源码_prepare_texts_to_embed可以看出,每个文档最终送入模型的文本按以下规则组装:
texts_to_embed[doc.id] = ( self.prefix + self.embedding_separator.join(meta_values_to_embed + [doc.content or ""]) + self.suffix )其中meta_values_to_embed只收集meta_fields_to_embed中存在于doc.meta且值不为None的字段(转为字符串)。这意味着你可以把如title、author等元数据拼进文本一起编码,让"语义"同时包含元数据信息。
批处理与 usage 统计
_embed_batch使用more_itertools.batched把文档按batch_size分批,并通过tqdm渲染进度条(progress_bar=False时关闭)。每个批次调用self.client.embeddings.create(...),encoding_format固定为"float";若设置了dimensions则一并传入。多个批次的usage会跨批次累加:prompt_tokens与total_tokens逐批相加,model取首个响应值。失败行为由raise_on_failure控制——为False时该批次被跳过,对应文档保持无向量状态返回。
run 与 run_async 的调用契约
run(documents: list[Document]) -> dict[str, Any]:返回字典含两个键:documents:嵌入后的文档列表(embedding字段被填充);meta:模型使用信息。
run_async(documents: list[Document]) -> dict[str, Any]:异步版本,参数与返回值一致。
两个方法都会先做输入类型校验:输入不是list[Document]时抛出TypeError,提示"如果想嵌入字符串,请使用OpenAITextEmbedder"。
Azure OpenAI 系列:在 Azure 上部署的模型向量化
AzureOpenAITextEmbedder与AzureOpenAIDocumentEmbedder分别继承OpenAITextEmbedder与OpenAIDocumentEmbedder,用于调用部署在 Azure OpenAI 服务上的模型。两者共享同一套 Azure 专属参数,区别仅在于前者嵌入单个字符串、后者嵌入文档列表。
完整初始化签名
# AzureOpenAITextEmbedder __init__( azure_endpoint: str | None = None, api_version: str | None = "2023-05-15", azure_deployment: str = "text-embedding-ada-002", dimensions: int | None = None, api_key: Secret | None = Secret.from_env_var("AZURE_OPENAI_API_KEY", strict=False), azure_ad_token: Secret | None = Secret.from_env_var("AZURE_OPENAI_AD_TOKEN", strict=False), organization: str | None = None, timeout: float | None = None, max_retries: int | None = None, prefix: str = "", suffix: str = "", *, default_headers: dict[str, str] | None = None, azure_ad_token_provider: AzureADTokenProvider | None = None, http_client_kwargs: dict[str, Any] | None = None, ) -> None # AzureOpenAIDocumentEmbedder(在 Text 版本基础上增加) # batch_size: int = 32 # progress_bar: bool = True # meta_fields_to_embed: list[str] | None = None # embedding_separator: str = "\n" # raise_on_failure: bool = FalseAzure 专属参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
azure_endpoint | str \| None | 部署在 Azure 上的模型端点。未显式传入时从环境变量AZURE_OPENAI_ENDPOINT读取;两者皆缺则抛出ValueError |
api_version | str \| None | 使用的 API 版本,默认"2023-05-15" |
azure_deployment | str | 部署在 Azure 上的模型名,默认text-embedding-ada-002;该值同时作为meta中上报的model名 |
api_key | Secret \| None | Azure OpenAI API Key,可通过环境变量AZURE_OPENAI_API_KEY或初始化参数传入 |
azure_ad_token | Secret \| None | Microsoft Entra ID(原 Azure Active Directory)令牌,可通过环境变量AZURE_OPENAI_AD_TOKEN或初始化参数传入 |
default_headers | dict[str, str] \| None | 发送给 AzureOpenAI 客户端的默认请求头 |
azure_ad_token_provider | AzureADTokenProvider \| None | 一个返回 Entra ID 令牌的函数,会在每次请求时被调用 |
认证方式与端点校验
源码中体现了两条硬性约束(见 azure_document_embedder.py 与 azure_text_embedder.py):
azure_endpoint参数或AZURE_OPENAI_ENDPOINT环境变量必须提供其一,否则抛出ValueError;api_key与azure_ad_token必须至少提供一个,否则抛出ValueError("Please provide an API key or an Azure Active Directory token")。
在_client_kwargs()中,api_key与azure_ad_token会通过Secret.resolve_value()解析为真实值后传给AzureOpenAI/AsyncAzureOpenAI客户端;timeout与max_retries同样遵循OPENAI_TIMEOUT(默认 30 秒)与OPENAI_MAX_RETRIES(默认 5 次)的回退链。
序列化对 Token Provider 的特殊处理
由于azure_ad_token_provider是运行时回调函数,to_dict()在序列化时会通过serialize_callable将其转换为可序列化的名称,from_dict()再通过deserialize_callable还原为可调用对象,随后才交给default_from_dict完成组件重建。这与 Haystack 对可调用对象的标准序列化机制一致。
Mock 系列:零成本、确定性的向量化替身
MockTextEmbedder与MockDocumentEmbedder是真实 Embedder 的"替身":它们实现完全相同的接口(run、run_async、to_dict/from_dict、warm_up),但从不调用任何外部服务,因此完全确定、免费且可离线运行,适合测试、冒烟测试与快速原型——例如在 CI 中验证检索管线逻辑,或在开发阶段先跑通完整 Pipeline。
三种嵌入模式
根据配置方式,Mock 组件有三种取向量策略:
- 确定性模式(默认):不传
embedding与embedding_fn时,向量的种子来自(预处理后的)文本哈希。同一文本永远得到同一向量,不同文本得到不同向量,跨进程可复现,可以直接用于检索管线。 - 固定向量模式:传入
embedding向量后,所有输入(文档)都返回这同一个向量。 - 动态模式:传入
embedding_fn可调用对象,它接收(预处理后的)文本并返回向量,适用于需要自定义"向量随输入变化"逻辑的场景。
文档版 Mock 与真实文档 Embedder 行为一致:meta_fields_to_embed中列出的元数据字段会先与文档内容拼接,再参与确定性向量计算,因此嵌入结果会反映被嵌入的元数据。
用法示例
from haystack import Document from haystack.components.embedders import MockDocumentEmbedder, MockTextEmbedder # 文档版:给每个 Document 生成 8 维确定性向量 doc_embedder = MockDocumentEmbedder(dimension=8) result = doc_embedder.run([Document(content="I love pizza!")]) print(result["documents"][0].embedding) # 确定性的 8 个浮点数 # 文本版:给单个字符串生成 8 维确定性向量 text_embedder = MockTextEmbedder(dimension=8) result = text_embedder.run("I love pizza!") print(result["embedding"]) # 确定性的 8 个浮点数完整初始化签名
# MockTextEmbedder __init__( embedding: list[float] | None = None, *, embedding_fn: EmbeddingFn | None = None, dimension: int = 768, model: str = "mock-model", meta: dict[str, Any] | None = None, prefix: str = "", suffix: str = "" ) -> None # MockDocumentEmbedder(增加三个参数) # meta_fields_to_embed: list[str] | None = None # embedding_separator: str = "\n" # progress_bar: bool = False # 仅为接口兼容而接受,实际被忽略| 参数 | 类型 | 说明 |
|---|---|---|
embedding | list[float] \| None | 可选的固定向量,分配给每个文档/输入;与embedding_fn互斥 |
embedding_fn | EmbeddingFn \| None | 可选的回调函数,接收预处理文本并返回浮点列表;与embedding互斥。为保证可序列化,请传具名函数(lambda 与嵌套函数无法序列化) |
dimension | int | 确定性向量的维度数,默认 768;当提供embedding或embedding_fn时被忽略(维度由值或回调决定) |
model | str | 在元数据中上报的模型名,纯装饰性,不加载任何模型 |
meta | dict \| None | 额外的元数据,会合并进输出meta |
prefix/suffix | str | 嵌入前追加到文本开头/末尾的字符串 |
异常约束:同时传embedding与embedding_fn、dimension非正整数、或embedding为空列表时抛出ValueError;embedding不是数字序列时抛出TypeError。
确定性向量的底层实现
mock_utils.py中的_deterministic_embedding揭示了"确定性"的实现细节:先对文本做 SHA-256 哈希,取摘要前 8 字节作为随机种子(注意不是 Python 内置的进程加盐hash(),从而保证跨进程稳定),再用该种子驱动random.Random生成dimension个[-1.0, 1.0]均匀分布的随机数,最后做 L2 归一化——因此 Mock 向量与真实模型输出一样是单位向量,可无缝用于余弦相似度检索。_estimate_usage则按空白分词粗略估算prompt_tokens/total_tokens,让下游代码拿到"看起来真实"的用量元数据(这是近似值,并非真正的分词器)。
run 与 run_async
MockTextEmbedder.run(text: str):返回{"embedding": ..., "meta": {"model": ..., "usage": ..., 以及额外 meta}};非字符串输入抛TypeError。MockDocumentEmbedder.run(documents: list[Document]):返回{"documents": [带向量的文档...], "meta": {...}};非list[Document]输入抛TypeError。- 两者的
run_async均直接委托给同步run实现(见源码 mock_text_embedder.py 与 mock_document_embedder.py),因为不涉及任何 I/O,异步调用天然安全。
组件生命周期:warm_up、close 与序列化
所有六个组件都遵循 Haystack 组件标准的生命周期方法,且同步/异步版本成对出现:
| 方法 | 作用 |
|---|---|
warm_up() | 初始化同步客户端(OpenAI/Azure 系列创建OpenAI/AzureOpenAI客户端;Mock 系列为空操作,仅置_is_warmed_up标志) |
warm_up_async() | 在服务事件循环上初始化异步客户端(AsyncOpenAI/AsyncAzureOpenAI;Mock 系列为空操作) |
close() | 释放同步客户端资源(客户端被关闭并置为None) |
close_async() | 释放异步客户端资源(await client.close()) |
to_dict() -> dict[str, Any] | 将组件序列化为字典,供Pipeline.dumps、YAML 配置等场景使用 |
from_dict(data) -> 组件实例 | 从字典反序列化重建组件实例 |
真实组件的warm_up内部通过init_http_client(self.http_client_kwargs, async_client=...)构建自定义 HTTP 客户端,再把_client_kwargs()展开传入 OpenAI/Azure 客户端构造器,因此http_client_kwargs支持代理、超时、TLS 等高级 HTTP 配置。to_dict使用default_to_dict序列化全部初始化参数(API Key 等Secret会以安全形式序列化),Azure 组件额外处理azure_ad_token_provider可调用对象的序列化/反序列化。Mock 组件同样实现了完整的to_dict/from_dict,embedding_fn通过serialize_callable/deserialize_callable处理(具名函数可往返,lambda 不行)。
端到端实战:文档索引 + 查询检索 Pipeline
把文本版与文档版 Embedder 组合进同一个索引/查询流程,是 Embedding 检索最典型的落地方式。以下示例参考 OpenAITextEmbedder 使用文档:先用OpenAIDocumentEmbedder给文档补向量并写入InMemoryDocumentStore,再构建查询管线——OpenAITextEmbedder负责把查询向量化,InMemoryEmbeddingRetriever负责按余弦相似度召回最相似的文档。
from haystack import Document, Pipeline from haystack.document_stores.in_memory import InMemoryDocumentStore from haystack.components.embedders import OpenAITextEmbedder, OpenAIDocumentEmbedder from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever # 1. 索引:文档向量化并写入文档存储 document_store = InMemoryDocumentStore(embedding_similarity_function="cosine") documents = [ Document(content="My name is Wolfgang and I live in Berlin"), Document(content="I saw a black horse running"), Document(content="Germany has many big cities"), ] document_embedder = OpenAIDocumentEmbedder() documents_with_embeddings = document_embedder.run(documents)["documents"] document_store.write_documents(documents_with_embeddings) # 2. 查询:查询向量化 -> 向量检索 query_pipeline = Pipeline() query_pipeline.add_component("text_embedder", OpenAITextEmbedder()) query_pipeline.add_component( "retriever", InMemoryEmbeddingRetriever(document_store=document_store), ) query_pipeline.connect("text_embedder.embedding", "retriever.query_embedding") query = "Who lives in Berlin?" result = query_pipeline.run({"text_embedder": {"text": query}}) print(result["retriever"]["documents"][0]) # Document(id=..., content: 'My name is Wolfgang and I live in Berlin', score: ...)在真实项目中,你可以做几处升级:给文档版 Embedder 传meta_fields_to_embed=["title"]让标题参与语义编码;通过batch_size控制单次请求的文档数量;用raise_on_failure=True让索引任务在失败时快速失败以便及早发现数据问题;在 CI 或本地开发阶段,则可以把两处 Embedder 直接替换为MockTextEmbedder/MockDocumentEmbedder(MockDocumentEmbedder的progress_bar参数为接口兼容而保留、默认关闭),在零成本、确定性输出的前提下验证整条管线逻辑。完整组件清单与各 Embedder 的横向对比见 Embedders 总览,每个组件的更详细用法说明可查阅 OpenAIDocumentEmbedder、AzureOpenAITextEmbedder、AzureOpenAIDocumentEmbedder、MockTextEmbedder 等页面。
小结
六个组件按"文本 vs 文档"和"真实服务 vs Mock"两条轴覆盖了 Haystack 向量化的主流需求:OpenAITextEmbedder/OpenAIDocumentEmbedder面向 OpenAI 官方 API,AzureOpenAITextEmbedder/AzureOpenAIDocumentEmbedder面向 Azure 部署(支持 API Key 与 Entra ID 双认证、default_headers、azure_ad_token_provider),MockTextEmbedder/MockDocumentEmbedder则以完全确定、零成本的方式复刻了前者的接口契约。无论选择哪一组,warm_up/close生命周期、run/run_async双调用入口、to_dict/from_dict序列化能力都是一致的,这让它们可以在索引管线与查询管线中即插即用、随时替换。
【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考