news 2026/9/10 12:49:11

Haystack 文本提取器深度指南:LLMDocumentContentExtractor、LLMMetadataExtractor 与 RegexTextExtractor

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Haystack 文本提取器深度指南:LLMDocumentContentExtractor、LLMMetadataExtractor 与 RegexTextExtractor

Haystack 文本提取器深度指南:LLMDocumentContentExtractor、LLMMetadataExtractor 与 RegexTextExtractor

【免费下载链接】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 是开源、面向生产环境的 LLM 应用编排框架,其 extractors 组件族 专门负责从文档中抽取结构化信息。本文以 extractors_api.md 为骨架,结合 源码 与 测试用例,系统讲解LLMDocumentContentExtractor(图像文档内容抽取)、LLMMetadataExtractor(LLM 元数据抽取)与RegexTextExtractor(正则文本抽取)三大组件的设计原理、参数语义、运行流程与实战用法,读完即可在索引、RAG 与 Agent 流程中落地使用。

一、组件总览:三种抽取器各司其职

haystack/components/extractors包由三个模块组成,模块入口在 extractors/init.py,并通过 pydoc/extractors_api.yml 生成 API 文档:

组件模块路径输入输出能力
LLMDocumentContentExtractorimage/llm_document_content_extractor.py图像/PDF 文件路径(存于文档 meta)将图像内容抽取为文本(content),并可附带元数据
LLMMetadataExtractorllm_metadata_extractor.py文本 Documents为每个文档生成结构化元数据(如 NER 实体)
RegexTextExtractorregex_text_extractor.py字符串或ChatMessage列表用正则捕获组提取指定文本片段

从源码结构看,三者都通过@component装饰器注册为标准 Haystack 组件,均提供run/run_async(或其中一种)与to_dict/from_dict序列化能力,可以无缝嵌入 Pipeline。其中LLMDocumentContentExtractorLLMMetadataExtractor属于"LLM 驱动型"抽取器,RegexTextExtractor则是零依赖的"规则型"抽取器。

二、LLMDocumentContentExtractor:用视觉 LLM 抽取图像文档

2.1 核心思想与工作流

LLMDocumentContentExtractor面向图像型文档(扫描件、截图、PDF 页面渲染图),借助支持视觉输入的 ChatGenerator 完成内容抽取。其内部流程如下:

  1. 每个文档一次 prompt、一次 LLM 调用
  2. 通过DocumentToImageContent(见 converters/image/document_to_image.py)将文档转换为ImageContent——它支持直接图像文件,也支持从 PDF 按page_number渲染指定页;
  3. 将 prompt 与图像组装成多模态ChatMessageTextContent+ImageContent,见 llm_document_content_extractor.py)发给 ChatGenerator;
  4. 按约定的响应格式解析结果,回填文档的contentmeta

组件内建默认 prompt 模板(DEFAULT_PROMPT_TEMPLATE,源码 L33-L61),要求模型"精确抽取、按 markdown 排版、保持阅读顺序",对图表用[img-caption][/img-caption]添加说明、表格用[table-caption][/table-caption]加注,表单勾选以 markdown 还原,最终返回含document_content键的 JSON 对象。

2.2 响应处理规则(重点)

组件对 LLM 返回文本采用统一解析逻辑_process_response(源码 L256-L274):

  • 纯字符串(非 JSON 或非 JSON 对象):整个字符串直接写入文档content
  • 仅含document_content键的 JSON 对象:该键的值写入content
  • 含多个键的 JSON 对象document_content的值写入content,其余键值对合并进文档 meta(例如 author、date、title 等);
  • 合法 JSON 但不是对象(数组或原始值):报告错误,文档进入failed_documents

因此,为了让模型稳定输出结构化结果,推荐在generation_kwargs中配置response_format={"type": "json_object"}或更严格的json_schema

2.3 参数说明

__init__签名(源码 L136-L177):

__init__( *, chat_generator: ChatGenerator, prompt: str = DEFAULT_PROMPT_TEMPLATE, file_path_meta_field: str = "file_path", root_path: str | None = None, detail: Literal["auto", "high", "low"] | None = None, size: tuple[int, int] | None = None, raise_on_failure: bool = False, max_workers: int = 3 ) -> None
参数类型默认值说明
chat_generatorChatGenerator必填支持视觉输入的 ChatGenerator,可选配置 JSON 输出
promptstr内建模板抽取指令,严禁包含 Jinja 变量(构造时用沙箱环境解析并校验,见 L245-L254)
file_path_meta_fieldstr"file_path"文档 meta 中保存图像/PDF 路径的字段名
root_pathstr \| NoneNone文档文件所在根目录;设置后路径按相对根目录解析并强制限定在该目录内,用于防御路径穿越
detail"auto"\|"high"\|"low"None图像细节级别(仅 OpenAI 支持)
sizetuple[int,int]None等比缩放到 (宽, 高) 范围内,降低传输与处理开销
raise_on_failureboolFalseTrue 时 LLM 异常直接抛出;False 时失败文档进入failed_documents
max_workersint3并行 LLM 调用的最大线程数

安全提示(务必阅读):该组件会读取file_path_meta_field指向的宿主机文件。若文档 meta 可能受不可信输入影响,必须设置root_path为专用数据目录,使绝对路径或../等路径穿越载荷被拒绝而非读取。这一约束同样内置于DocumentToImageContent(document_to_image.py L81-L86)。

2.4 完整用法示例

以下示例取自 API 文档,使用OpenAIChatGenerator并配置json_schema强制输出document_content与可选元数据字段:

from haystack import Document from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.extractors.image import LLMDocumentContentExtractor prompt = """ Extract the content from the provided image. Format everything as markdown. Return only the extracted content as a JSON object with the key 'document_content'. No markdown, no code fence, only raw JSON. Extract metadata about the image like source of the image, date of creation, etc. if you can. Return this metadata as additional key-value pairs in the same JSON object. """ chat_generator = OpenAIChatGenerator( generation_kwargs={ "response_format": { "type": "json_schema", "json_schema": { "name": "entity_extraction", "schema": { "type": "object", "properties": { "document_content": {"type": "string"}, "author": {"type": "string"}, "date": {"type": "string"}, "document_type": {"type": "string"}, "title": {"type": "string"}, }, "additionalProperties": False, }, }, } } ) extractor = LLMDocumentContentExtractor( chat_generator=chat_generator, file_path_meta_field="file_path", raise_on_failure=False, ) documents = [ Document(content="", meta={"file_path": "test/test_files/images/image_metadata.png"}), Document(content="", meta={"file_path": "test/test_files/images/apple.jpg", "page_number": 1}), ] result = extractor.run(documents=documents) updated_documents = result["documents"]

注意page_number用于指示 PDF 文档要渲染的页码;若传入的是图片文件,则无需该字段。失败文档会进入result["failed_documents"],其 meta 中带有content_extraction_error键(测试见 test_llm_document_content_extractor.py 中test_run_with_llm_failure_raise_on_failure_false等用例)。

2.5 生命周期方法与异步支持

  • warm_up()/warm_up_async():预热底层 ChatGenerator(异步版本优先调用warm_up_async,否则回退同步warm_up);
  • close()/close_async():释放底层生成器资源;
  • run_async():异步版本,LLM 调用并发执行但受max_workers信号量约束;若生成器仅实现同步run,会在线程中执行以避免阻塞事件循环;图片文件读取与 PDF 渲染属于阻塞操作,会在线程中执行(源码 L407-L451)。测试test_run_async_falls_back_to_sync_runtest_run_async_converts_images_off_the_event_looptest_run_async_respects_max_workers对此均有覆盖。

三、LLMMetadataExtractor:LLM 驱动的结构化元数据抽取

3.1 设计原理

LLMMetadataExtractor(llm_metadata_extractor.py)接收 Documents 列表与一个 prompt,对每个文档分别运行一次 LLM,将抽取结果合并进文档 meta。典型场景是 NER 实体识别、文档标签、摘要字段等。

其 prompt 约束是关键设计

  • prompt 中必须有且仅有一个变量document,指向列表中的单个文档,例如{{ document.content }}
  • 组件在__init__中通过SandboxedEnvironment().parse(prompt)解析模板变量,若变量集合不等于["document"]会直接抛出ValueError(源码 L187-L194);
  • 组件内部用PromptBuilder(prompt, required_variables=variables)渲染 prompt,再包装为ChatMessage.from_user(...)调用生成器(源码 L285-L312)。

3.2 参数说明

__init__( prompt: str, chat_generator: ChatGenerator, expected_keys: list[str] | None = None, page_range: list[str | int] | None = None, raise_on_failure: bool = False, max_workers: int = 3, ) -> None
参数类型默认值说明
promptstr必填模板 prompt,必须恰好含一个变量document
chat_generatorChatGenerator必填LLM 实例,建议配置generation_kwargs={"response_format": {"type": "json_object"}}强制 JSON 输出
expected_keyslist[str]None期望 LLM JSON 输出中包含的键;解析时校验缺失键(见_extract_metadata,L271-L283)
page_rangelist[str\|int]None按页抽取范围,可被run方法覆盖
raise_on_failureboolFalseLLM 执行或 JSON 校验失败时是否抛出异常
max_workersint3线程池最大并发数,run_async中用作并发上限

3.3 page_range:按页抽取

page_range支持单页与可打印范围字符串,由expand_page_range展开(haystack/utils/misc.py):

  • ['1', '3']→ 抽取第 1、3 页;
  • ['1-3', '5', '8', '10-12']→ 展开为 1,2,3,5,8,10,11,12;
  • 传入整数时若含-会被拒绝(要求范围必须是'start-end'字符串);空结果会抛出ValueError

实现上,组件内部创建DocumentSplitter(split_by="page", split_length=1)(源码 L198),在_prepare_prompts中按展开后的页码拼接目标页文本,再填充进 prompt;不传page_range时对整篇文档抽取。runrun_async均支持运行期覆盖page_range

3.4 失败处理与重跑机制

这是该组件最具实战价值的设计:

  • 失败文档进入failed_documents,meta 中写入metadata_extraction_error(错误信息)与metadata_extraction_response(LLM 原始回复,供后续重试参考);
  • 成功重跑后,组件会清除之前遗留的metadata_extraction_error/metadata_extraction_response键(源码 L378-L382);
  • 可将metadata_extraction_responsemetadata_extraction_error重新注入 prompt,用另一个抽取器对失败文档二次抽取。

3.5 NER 实战示例

以下为 API 文档的完整 NER 示例(使用OpenAIChatGenerator+json_schema强制输出entities数组):

from haystack import Document from haystack.components.extractors.llm_metadata_extractor import LLMMetadataExtractor from haystack.components.generators.chat import OpenAIChatGenerator NER_PROMPT = ''' -Goal- Given text and a list of entity types, identify all entities of those types from the text. -Steps- 1. Identify all entities. For each identified entity, extract the following information: - entity: Name of the entity - entity_type: One of the following types: [organization, product, service, industry] Format each entity as a JSON like: {"entity": <entity_name>, "entity_type": <entity_type>} 2. Return output in a single list with all the entities identified in steps 1. -Examples- ###################### Example 1: entity_types: [organization, person, partnership, financial metric, product, service, industry, investment strategy, market trend] text: Another area of strength is our co-brand issuance. Visa is the primary network partner for eight of the top 10 co-brand partnerships in the US today and we are pleased that Visa has finalized a multi-year extension of our successful credit co-branded partnership with Alaska Airlines, a portfolio that benefits from a loyal customer base and high cross-border usage. ... output: {"entities": [{"entity": "Visa", "entity_type": "company"}, {"entity": "Alaska Airlines", "entity_type": "company"}, ...]} ############################# -Real Data- ###################### entity_types: [company, organization, person, country, product, service] text: {{ document.content }} ###################### output: ''' docs = [ Document(content="deepset was founded in 2018 in Berlin, and is known for its Haystack framework"), Document(content="Hugging Face is a company that was founded in New York, USA and is known for its Transformers library") ] chat_generator = OpenAIChatGenerator( generation_kwargs={ "max_completion_tokens": 500, "temperature": 0.0, "seed": 0, "response_format": { "type": "json_schema", "json_schema": { "name": "entity_extraction", "schema": { "type": "object", "properties": { "entities": { "type": "array", "items": { "type": "object", "properties": { "entity": {"type": "string"}, "entity_type": {"type": "string"} }, "required": ["entity", "entity_type"], "additionalProperties": False } } }, "required": ["entities"], "additionalProperties": False } } }, }, max_retries=1, timeout=60.0, ) extractor = LLMMetadataExtractor( prompt=NER_PROMPT, chat_generator=chat_generator, expected_keys=["entities"], raise_on_failure=False, ) result = extractor.run(documents=docs)

输出示意(来自 API 文档):

{'documents': [ Document(id=.., content: 'deepset was founded in 2018 in Berlin, ...', meta: {'entities': [{'entity': 'deepset', 'entity_type': 'company'}, {'entity': 'Berlin', 'entity_type': 'city'}, {'entity': 'Haystack', 'entity_type': 'product'}]}), Document(id=.., content: 'Hugging Face is a company ...', meta: {'entities': [{'entity': 'Hugging Face', 'entity_type': 'company'}, {'entity': 'New York', 'entity_type': 'city'}, {'entity': 'USA', 'entity_type': 'country'}, {'entity': 'Transformers', 'entity_type': 'product'}]}) ], 'failed_documents': []}

要点提示:

  • expected_keys=["entities"]会在_extract_metadata中校验输出 JSON 是否含该键;
  • 推荐temperature=0.0seed=0提升确定性;json_schemajson_object约束更严格,能显著降低解析失败率;
  • 若 LLM 输出非合法 JSON 或缺失键,且raise_on_failure=False,文档会进入failed_documents,可通过metadata_extraction_response人工检查或重试。

四、RegexTextExtractor:零依赖的正则文本抽取

4.1 功能与用法

RegexTextExtractor(regex_text_extractor.py)是三者中最轻量的组件:给定一个含捕获组的正则,从字符串或ChatMessage列表中提取匹配文本。适用于从 LLM 输出或结构化文本中提取 URL、ID、命令等确定模式,无需调用任何模型。

from haystack.components.extractors import RegexTextExtractor from haystack.dataclasses import ChatMessage # 传入字符串 parser = RegexTextExtractor(regex_pattern='<issue url="(.+)">') result = parser.run(text_or_messages='<issue url="github.com/hahahaha">hahahah</issue>') # result: {"captured_text": "github.com/hahahaha"} # 传入 ChatMessages(仅处理最后一条消息) messages = [ChatMessage.from_user('<issue url="github.com/hahahaha">hahahah</issue>')] result = parser.run(text_or_messages=messages) # result: {"captured_text": "github.com/hahahaha"}

4.2 行为细节(从源码与测试印证)

  • __init__(regex_pattern: str):构造时用re.compile(...).groups检查捕获组数量,若无捕获组会打印警告"整个匹配将被返回"(源码 L52-L59),此时返回match.group(0)即完整匹配;
  • run(text_or_messages: str | list[ChatMessage]) -> dict[str, str]
    • 输入为字符串:直接re.search提取;
    • 输入为ChatMessage列表:仅处理最后一条消息_process_last_message),若末元素不是ChatMessage实例抛出TypeError;空列表返回{"captured_text": ""}
    • 有捕获组时返回第 1 个捕获组match.group(1);无匹配返回{"captured_text": ""}
  • 序列化:to_dict/from_dict仅保留regex_patternfrom_dict会兼容清理旧版本遗留的return_empty_on_no_match参数(源码 L80-L84),保证老 Pipeline 反序列化不中断。

4.3 与 LLM 抽取器的分工

维度RegexTextExtractorLLMMetadataExtractorLLMDocumentContentExtractor
依赖需 LLM(ChatGenerator)需视觉 LLM(ChatGenerator)
适用输入字符串 / ChatMessage文本 Documents图像 / PDF Documents
输出captured_text合并进meta写入content+meta
失败处理返回空字符串failed_documents+ 重跑机制failed_documents+content_extraction_error
异步仅同步runrun/run_asyncrun/run_async

实际 Pipeline 中常见组合:先用RegexTextExtractor做确定性的轻量抽取(如抓取工具调用返回中的 URL),再对需要语义理解的部分交给LLMMetadataExtractorLLMDocumentContentExtractor;两类组件共享ChatGenerator接口,便于替换后端模型。

五、序列化与 Pipeline 集成

三个组件都实现了标准的to_dict/from_dict

  • LLMDocumentContentExtractor.to_dict会序列化chat_generator(通过component_to_dict)、prompt、file_path_meta_fieldroot_pathdetailsizeraise_on_failuremax_workersfrom_dict通过deserialize_chatgenerator_inplace原地还原生成器(源码 L230-L243);
  • LLMMetadataExtractor额外序列化expected_keys与展开后的page_range(源码 L239-L255);
  • RegexTextExtractor仅序列化regex_pattern

这意味着三者都可以:

  1. 直接嵌入 Haystack Pipeline 用 YAML 声明(type: haystack.components.extractors.llm_metadata_extractor.LLMMetadataExtractor等);
  2. 与 DocumentSplitter 组合做按页/按块批量抽取;
  3. 配合DocumentWriter将更新后的文档(含新 meta)写入 DocumentStore。

六、总结

本文以 extractors_api.md 为主线,完整覆盖了 Haystack 三大文本抽取组件的设计、参数、运行流程与实战用法:

  • LLMDocumentContentExtractor:视觉 LLM +DocumentToImageContent完成图像/PDF 文档内容抽取,支持内容回填与元数据合并,务必关注root_path路径安全;
  • LLMMetadataExtractor:单变量 prompt 约束 + JSON 校验 +page_range按页抽取 + 失败重跑机制,是 RAG 元数据增强与 NER 的通用方案;
  • RegexTextExtractor:轻量确定性抽取,与 LLM 抽取器形成互补。

三者共享 Haystack 的组件协议(生命周期、序列化、同步/异步),可无缝组合进生产级 Pipeline。深入阅读可继续查看源码实现 haystack/components/extractors 与测试用例 test/components/extractors。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 12:48:52

Qt/C++ TCP多线程客户端:收发分离与粘包状态机实现

简介&#xff1a;这是一份面向C与Qt开发者的高并发TCP通信实战资源&#xff0c;聚焦多线程客户端设计&#xff0c;解决网络编程中收发阻塞、TCP粘包拆包、数据包自动成型等核心难点&#xff0c;适用于物联网终端、实时通信中间件及工业控制客户端开发等场景。资源共121个文件&a…

作者头像 李华
网站建设 2026/9/10 12:47:25

YOLOv8船舶救生衣检测系统:端到端部署与港口安防落地实践

简介&#xff1a;本资源是一套面向计算机、人工智能及相关专业在校学生与初学者的毕业设计级项目&#xff0c;聚焦港口船舶场景下救生衣穿戴状态的智能识别问题&#xff0c;基于YOLOv8目标检测框架实现端到端的检测与可视化分析。资源共8个文件&#xff0c;含3个核心Python脚本…

作者头像 李华
网站建设 2026/9/10 12:46:38

2026版ASNT无损检测认证全解析与备考指南

1. 无损检测认证的价值与行业定位 在石油化工、电力能源、航空航天等工业领域&#xff0c;设备安全是生命线。2019年某炼油厂管道破裂事故的直接原因&#xff0c;就是焊缝缺陷未被有效检出。这类案例让行业意识到&#xff1a;无损检测人员的专业水平直接关系到重大设施的安全运…

作者头像 李华
网站建设 2026/9/10 12:46:16

3 条命令,把 SillyTavern 变成双击启动的桌面版

3 条命令&#xff0c;把 SillyTavern 变成双击启动的桌面版 【免费下载链接】SillyTavern LLM Frontend for Power Users. 项目地址: https://gitcode.com/GitHub_Trending/si/SillyTavern 上周&#xff0c;我把一份 SillyTavern 桌面版产物拷到一台没装过 Node 的同事电…

作者头像 李华