Haystack 文档分类器组件实战:DocumentLanguageClassifier 与 TransformersZeroShotDocumentClassifier 全解析
【免费下载链接】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 2.24 版本classifiers模块中的两个文档分类组件:基于langdetect的DocumentLanguageClassifier(按语言给文档打标)与基于 Hugging Face 零样本分类管线的TransformersZeroShotDocumentClassifier(按自定义标签给文档打标)。文章完整覆盖两个组件的 API 签名、全部初始化参数、run/warm_up/序列化方法的语义、独立使用与管道集成示例,并结合本仓库的组件使用文档与发布说明(releasenotes)补充版本演进信息,帮助你掌握在索引管道与检索管道中落地文档分类的完整方案。
模块概览:classifiers 能做什么
在 Haystack 2.24 中,分类器组件位于haystack.components.classifiers包内,专门负责在管道中对Document执行分类任务,并把分类结果写回文档的meta元数据中。其典型定位是数据处理阶段的分流开关:为后续的检索、嵌入、写入或路由决策提供依据。模块包含两个核心组件:
| 组件 | 分类依据 | 输出元数据字段 | 底层依赖 |
|---|---|---|---|
DocumentLanguageClassifier | 语言(ISO 语言代码) | meta.language | langdetect |
TransformersZeroShotDocumentClassifier | 用户自定义标签(zero-shot / NLI) | meta.classification | Hugging Facetransformers |
两个组件在管道中的最常见位置都是一个MetadataRouter之前:先完成分类,再用路由规则把不同类别的文档分发到不同的下游分支(例如不同语言的嵌入模型、不同索引或不同处理链路)。二者的 API 参考详见 classifiers_api.md。
版本提示:本仓库当前
VERSION.txt标识为 3.2.0-rc0,而本文依据的 API 文档属于 version-2.24。在 3.x 中这两个组件已从核心库迁移至langdetect-haystack与transformers-haystack集成包(详见文末"版本演进"小节),2.24 的用法与参数语义仍完全适用于理解其工作原理。
DocumentLanguageClassifier:按语言分类文档
功能与设计
DocumentLanguageClassifier对每个文档的文本内容进行语言检测,并将检测结果写入该文档的meta.language字段。初始化时需要传入一组期望的语言代码(ISO 格式);若文档文本无法匹配其中任何语言,则meta.language被置为"unmatched"。默认配置下仅针对英语(["en"])分类,其余文档一律归为"unmatched"。
该组件只负责打标,不负责路由。需要按语言将文档分发到不同管道分支时,请在组件之后紧跟MetadataRouter;若要对纯文本(而非 Document 对象)做同样的"分类 + 路由",则改用TextLanguageRouter组件。
初始化与运行 API
DocumentLanguageClassifier.__init__:
def __init__(languages: list[str] | None = None)languages:ISO 语言代码列表,例如["en", "de"]。支持的语言集合与langdetect库保持一致;不传时默认["en"]。
DocumentLanguageClassifier.run:
@component.output_types(documents=list[Document]) def run(documents: list[Document])- 输入
documents:待分类的文档列表。 - 异常:若输入不是
Document列表,抛出TypeError。 - 返回:字典,键为
documents,值为新增了language元数据字段的文档列表;未匹配任何指定语言的文档该字段值为"unmatched"。
独立使用示例
先安装依赖(该组件基于langdetect,需要单独安装):
pip install langdetect单独使用组件,对英、德两种语言的文档分类:
from haystack.components.classifiers import DocumentLanguageClassifier from haystack import Document documents = [ Document(content="Mein Name ist Jean und ich wohne in Paris."), Document(content="Mein Name ist Mark und ich wohne in Berlin."), Document(content="Mein Name ist Giorgio und ich wohne in Rome."), Document(content="My name is Pierre and I live in Paris"), Document(content="My name is Paul and I live in Berlin."), Document(content="My name is Alessia and I live in Rome."), ] document_classifier = DocumentLanguageClassifier(languages=["en", "de"]) document_classifier.run(documents=documents)运行后,每篇文档都会被写入language元数据;由于语言集合仅含en与de,上述意大利语风格的句子将被标记为"unmatched"。
在索引管道中结合 MetadataRouter 使用
下面是一个完整的索引管道示例(源自 documentlanguageclassifier.mdx):先用分类器打语言标签,再由MetadataRouter按语言分流,英文文档走英文嵌入模型、德文文档走德文嵌入模型,最终分别写入两个InMemoryDocumentStore索引:
from haystack import Pipeline from haystack import Document from haystack.document_stores.in_memory import InMemoryDocumentStore from haystack.components.classifiers import DocumentLanguageClassifier from haystack.components.embedders import SentenceTransformersDocumentEmbedder from haystack.components.writers import DocumentWriter from haystack.components.routers import MetadataRouter document_store_en = InMemoryDocumentStore() document_store_de = InMemoryDocumentStore() document_classifier = DocumentLanguageClassifier(languages=["en", "de"]) metadata_router = MetadataRouter( rules={"en": {"language": {"$eq": "en"}}, "de": {"language": {"$eq": "de"}}}, ) english_embedder = SentenceTransformersDocumentEmbedder() german_embedder = SentenceTransformersDocumentEmbedder( model="PM-AI/bi-encoder_msmarco_bert-base_german", ) en_writer = DocumentWriter(document_store=document_store_en) de_writer = DocumentWriter(document_store=document_store_de) indexing_pipeline = Pipeline() indexing_pipeline.add_component(document_classifier, name="document_classifier") indexing_pipeline.add_component(metadata_router, name="metadata_router") indexing_pipeline.add_component(english_embedder, name="english_embedder") indexing_pipeline.add_component(german_embedder, name="german_embedder") indexing_pipeline.add_component(en_writer, name="en_writer") indexing_pipeline.add_component(de_writer, name="de_writer") indexing_pipeline.connect("document_classifier.documents", "metadata_router.documents") indexing_pipeline.connect("metadata_router.en", "english_embedder.documents") indexing_pipeline.connect("metadata_router.de", "german_embedder.documents") indexing_pipeline.connect("english_embedder", "en_writer") indexing_pipeline.connect("german_embedder", "de_writer") indexing_pipeline.run( { "document_classifier": { "documents": [ Document(content="This is an English sentence."), Document(content="Dies ist ein deutscher Satz."), ], }, }, )要点说明:
MetadataRouter的rules键对应管道输出端口(router.en、router.de),值描述了元数据匹配条件。上面示例使用{"language": {"$eq": "en"}}语法;Haystack 也支持点路径写法(如{"field": "meta.language", "operator": "==", "value": "en"}),两种写法均可实现同样效果,详见 API 参考示例中的规则结构。MetadataRouter是 haystack 2.24 核心组件,实现位于 metadata_router.py。- 分流之后,每个分支可独立配置语言相关的嵌入模型、切分策略或文档存储,实现真正的"多语言索引隔离"。
TransformersZeroShotDocumentClassifier:按自定义标签零样本分类
功能与设计
TransformersZeroShotDocumentClassifier基于 Hugging Face 的 zero-shot classification pipeline(底层是 NLI/蕴涵推理模型),将每个文档归入你在初始化时给定的标签集合,并把预测结果写入文档的meta.classification字典。它特别适合"标签集合预先已知、无需针对标签微调模型"的场景,例如情感极性(positive/negative)、主题领域(animals/food)等粗粒度分类。
几个关键行为:
- 默认对文档的
content字段执行分类;若想改用其他字段,可通过classification_field指定某个元数据字段。 - 分类结果存于
meta["classification"]字典;当multi_label=True时,每个标签的得分会进一步存放在classification["details"]键下。 - 组件自身只是"分类器",若要按分类结果路由文档,同样建议在其后接
MetadataRouter。
初始化与运行 API
TransformersZeroShotDocumentClassifier.__init__:
def __init__(model: str, labels: list[str], multi_label: bool = False, classification_field: str | None = None, device: ComponentDevice | None = None, token: Secret | None = Secret.from_env_var( ["HF_API_TOKEN", "HF_TOKEN"], strict=False), huggingface_pipeline_kwargs: dict[str, Any] | None = None)各参数含义如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | str | 是 | Hugging Face 零样本分类(NLI)模型的名称或本地路径,例如cross-encoder/nli-deberta-v3-xsmall |
labels | list[str] | 是 | 候选类别标签列表,例如["positive", "negative"];标签语义依赖所选模型 |
multi_label | bool | 否(默认False) | 是否允许多个标签同时为真。False时对每个序列的标签似然做归一化(总和为 1);True时标签相互独立,对每个候选标签分别对蕴涵分与矛盾分做 softmax 归一化 |
classification_field | str \| None | 否(默认None) | 用于分类的文档元数据字段名;不设置时默认使用Document.content |
device | ComponentDevice \| None | 否(默认None) | 模型加载设备。为None时自动选择默认设备;若在huggingface_pipeline_kwargs中显式指定了 device/device_map,则以此为准(覆盖本参数) |
token | Secret \| None | 否 | 作为 HTTP bearer 鉴权的 Hugging Face Token;默认从环境变量HF_API_TOKEN/HF_TOKEN读取(strict=False,未设置时不报错) |
huggingface_pipeline_kwargs | dict[str, Any] \| None | 否 | 传递给 Hugging Face text-classification pipeline 初始化的关键字参数 |
run方法:
@component.output_types(documents=list[Document]) def run(documents: list[Document], batch_size: int = 1)documents:待分类的文档列表。batch_size:处理每篇文档内容时使用的批大小,默认1。- 返回:字典,键为
documents,值为新增了classification元数据字段的文档列表。
其他方法:
warm_up():预加载模型与 pipeline,完成组件初始化。首次run前调用可避免运行时加载延迟。to_dict() -> dict[str, Any]:将组件序列化为字典(含模型名、标签、设备、token 等配置)。from_dict(cls, data) -> "TransformersZeroShotDocumentClassifier":类方法,从字典反序列化重建组件。二者配合可实现组件/管道的 YAML 或 JSON 持久化。
可用模型参考
官方文档给出的零样本分类(NLI)模型示例:
valhalla/distilbart-mnli-12-3cross-encoder/nli-distilroberta-basecross-encoder/nli-deberta-v3-xsmall
更完整的模型清单可在 Hugging Face 模型库中按zero-shot-classification任务标签筛选(transformers会自动下载并缓存所选模型权重)。
独立使用示例
from haystack import Document from haystack.components.classifiers import TransformersZeroShotDocumentClassifier documents = [ Document(id="0", content="Cats don't get teeth cavities."), Document(id="1", content="Cucumbers can be grown in water."), ] document_classifier = TransformersZeroShotDocumentClassifier( model="cross-encoder/nli-deberta-v3-xsmall", labels=["animals", "food"], ) document_classifier.warm_up() document_classifier.run(documents=documents)运行后,每篇文档的meta["classification"]将包含预测的label(以及对应的得分信息)。
在检索管道中结合 BM25 使用
下面的管道示例(源自 transformerszeroshotdocumentclassifier.mdx)演示了"先检索、再分类"的常见组合:用InMemoryBM25Retriever从文档库中取回与查询最相关的文档,再由零样本分类器对命中文档打上情感标签:
from haystack import Document from haystack.components.retrievers.in_memory import InMemoryBM25Retriever from haystack.document_stores.in_memory import InMemoryDocumentStore from haystack.core.pipeline import Pipeline from haystack.components.classifiers import TransformersZeroShotDocumentClassifier documents = [ Document(id="0", content="Today was a nice day!"), Document(id="1", content="Yesterday was a bad day!"), ] document_store = InMemoryDocumentStore() retriever = InMemoryBM25Retriever(document_store=document_store) document_classifier = TransformersZeroShotDocumentClassifier( model="cross-encoder/nli-deberta-v3-xsmall", labels=["positive", "negative"], ) document_store.write_documents(documents) pipeline = Pipeline() pipeline.add_component(retriever, name="retriever") pipeline.add_component(document_classifier, name="document_classifier") pipeline.connect("retriever", "document_classifier") queries = ["How was your day today?", "How was your day yesterday?"] expected_predictions = ["positive", "negative"] for idx, query in enumerate(queries): result = pipeline.run({"retriever": {"query": query, "top_k": 1}}) classified_docs = result["document_classifier"]["documents"] assert classified_docs[0].id == str(idx) assert ( classified_docs[0].meta["classification"]["label"] == expected_predictions[idx] )该示例同时展示了从管道输出中读取分类结果的方式:result["document_classifier"]["documents"],随后通过doc.meta["classification"]["label"]获取预测标签。在 2.24 的 API 参考中也可用doc.to_dict()["classification"]["label"]读取同等信息,两者指向同一个元数据结构。
多标签(multi_label)模式的输出细节
当multi_label=True时,模型将每个候选标签视为独立事件,分别评估"文本蕴含该标签"与"文本矛盾该标签"的概率;此时每个文档的meta["classification"]中:
label仍给出综合预测结果;details键下会包含每个标签的得分明细,便于下游组件或业务逻辑读取细粒度置信度。
而在multi_label=False(默认)下,各标签似然会被归一化使得总和为 1,更接近"单选"语义,适合互斥类别(如 positive/negative)。
结合管道设计:分类器的两种落地位置
综合两个组件的定位,在实际 Haystack 2.24 管道中,文档分类器通常出现在两类位置:
- 索引阶段(写入前):
DocumentLanguageClassifier或零样本分类器位于文档转换、切分之后、嵌入与写入之前。典型链路为转换器 → 切分器 → 分类器 → MetadataRouter → (多路嵌入器) → DocumentWriter。此时分类结果决定文档进入哪个索引、使用哪种嵌入模型,是"数据治理"层面的分类。 - 检索阶段(读取后):零样本分类器位于检索器之后,对"查询命中的结果"做实时再分类。典型链路为
Retriever → TransformersZeroShotDocumentClassifier → (后续处理/输出)。此时分类结果是面向用户或下游生成任务的动态标注,例如情感、主题、风险等级。
两种场景都强调:分类器输出的是元数据,而非路由行为本身;真正的分支选择由后续的MetadataRouter(或自定义路由逻辑)基于meta.language/meta.classification完成。
版本演进:从核心包到集成包
结合本仓库 releasenotes/notes 下的发布说明,可以梳理出这两个组件在 Haystack 版本演进中的轨迹:
- 早期版本中,
TextLanguageClassifier与DocumentLanguageClassifier曾被整理迁移至classifiers包(见 move-classifiers-943d9d52b4bfc49f.yaml),这正是本文所述haystack.components.classifiers目录的由来。 - 后续版本中,
DocumentLanguageClassifier(连同TextLanguageRouter)被标记为弃用,并迁移到langdetect-haystack集成包(见 deprecate-langdetect-components-7ff32c5b6d139a39.yaml);TransformersZeroShotDocumentClassifier(连同TransformersTextRouter、TransformersZeroShotTextRouter等)被迁移到transformers-haystack集成包(见 deprecate-transformers-components-6efaf61d1eab0c22.yaml)。 - 在 Haystack 3.0 中,上述组件正式移出核心库,导入方式更新为集成包路径,例如
from haystack_integrations.components.classifiers.langdetect import DocumentLanguageClassifier(见 remove-langdetect-components-b18af414c497a70c.yaml)。
因此,若你的项目锁定 Haystack 2.24(本文 API 参考的版本),可直接按haystack.components.classifiers导入使用;若升级到 3.x,请改用对应集成包并保持参数语义不变。这一演进也印证了 Haystack 将"强第三方依赖的组件"下沉为集成包、保持核心库轻量化的设计思路。
小结
classifiers模块为 Haystack 管道提供了两种即插即用的文档分类能力:DocumentLanguageClassifier解决"文档是什么语言"的硬规则问题(依赖轻量、无模型下载,适合索引阶段多语言分流);TransformersZeroShotDocumentClassifier解决"文档属于哪个预定义类别"的语义问题(基于 NLI 模型、支持多标签,适合主题/情感等灵活分类)。两者都将结果沉淀为文档元数据,配合MetadataRouter即可构造出多分支、可解释的复杂管道。更多 API 细节可继续查阅 classifiers_api.md 与两个组件的独立使用文档(documentlanguageclassifier.mdx、transformerszeroshotdocumentclassifier.mdx)。
【免费下载链接】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),仅供参考