Notebooks
H
Hugging Face
Information Extraction Haystack Nuextract

Information Extraction Haystack Nuextract

zh-CNhf-cookbooknotebooks

使用 Haystack 和 NuExtract 进行信息提取

作者:Stefano Fiorucci

在本 Notebook 中,我们将展示如何使用语言模型自动化从文本数据中提取信息。

🎯 目标:创建一个应用程序,从给定的文本或 URL 中提取特定信息,遵循用户定义的结构。

🧰 技术栈

  • Haystack 🏗️:一个可定制的编排框架,用于构建 LLM 应用程序。我们将使用 Haystack 来构建信息提取管道。

  • NuExtract:一个小型语言模型,专门针对结构化数据提取进行了微调。

安装依赖

[ ]

组件

Haystack 有两个主要概念:组件和管道

🧩 组件 是执行单一任务的构建块:文件转换、文本生成、嵌入创建等。

管道 允许你通过将组件组合成有向(或循环)图,来定义数据在 LLM 应用程序中的流动。

接下来,我们将介绍我们信息提取应用程序的各个组件。之后,我们将把它们集成到一个管道中。

LinkContentFetcherHTMLToDocument:从网页提取文本

在我们的实验中,我们将从网络上的初创公司融资公告中提取数据。

为了下载网页并提取文本,我们使用两个组件:

[ ]
{'documents': [Document(id=65bb1ce4b6db2f154d3acfa145fa03363ef93f751fb8599dcec3aaf75aa325b9, content: 'This domain is for use in illustrative examples in documents. You may use this domain in literature ...', meta: {'content_type': 'text/html', 'url': 'https://example.com/'})]}

HuggingFaceLocalGenerator:加载并尝试模型

我们使用 HuggingFaceLocalGenerator,这是一个文本生成组件,允许使用 Transformers 库加载托管在 Hugging Face 上的模型。

Haystack 还支持许多其他的 生成器,包括 HuggingFaceAPIGenerator(与 Hugging Face APIs 和 TGI 兼容)。

我们加载 NuExtract,这是一个基于 microsoft/Phi-3-mini-4k-instruct 进行微调的模型,用于从文本中执行结构化数据提取。该模型的大小为 3.8B 参数。还有其他变体可用:NuExtract-tiny(0.5B)和 NuExtract-large(7B)。

该模型以 bfloat16 精度加载,以适应 Colab 环境,并且与 FP32 相比,性能几乎没有损失,正如模型卡片中所建议的那样。

关于 Flash Attention 的说明

在推理时,你可能会看到一个警告:“You are not running the flash-attention implementation”。

像 Colab 或 Kaggle 这样的免费环境中提供的 GPU 不支持 Flash Attention,因此我们决定在本笔记本中不使用它。

如果你的 GPU 架构支持 Flash Attention(详情),你可以安装它并获得加速,方法如下:

pip install flash-attn --no-build-isolation

然后,将 "attn_implementation": "flash_attention_2" 添加到 model_kwargs 中。

[ ]

该模型支持特定的提示结构,可以从模型卡片中推断出来。

我们将手动创建一个提示来尝试该模型。稍后,我们将看到如何根据不同的输入动态生成提示。

[ ]
You are not running the flash-attention implementation, expect numerical differences.
{'replies': ['{\n    "Car": {\n        "Name": "Fiat Panda",\n        "Manufacturer": "Fiat",\n        "Designers": [\n            "Giorgetto Giugiaro",\n            "Aldo Mantovani",\n            "Giuliano Biasio",\n            "Roberto Giolito"\n        ],\n        "Number of units produced": "over 7.8 million"\n    }\n}\n']}

漂亮 ✅

PromptBuilder:动态生成提示

PromptBuilder 是通过 Jinja2 提示模板初始化的,并通过填充传递的关键字参数来渲染该模板。

我们的提示模板复现了 模型卡片 中显示的结构。

在实验过程中,我们发现缩进模式对于确保良好的结果非常重要。这可能与模型的训练方式有关。

[ ]
[ ]
<|input|>
### Template:
{
    "Car": {
        "Designers": [],
        "Manufacturer": "",
        "Name": "",
        "Number of units produced": ""
    }
}

### Text
The Fiat Panda is a city car...
<|output|>

运行良好 ✅

OutputAdapter

你可能已经注意到,提取结果是 replies 列表中的第一个元素,并且是一个 JSON 字符串。

我们希望能够为每个源文档获得一个字典。

为了在管道中执行这个转换,我们可以使用 OutputAdapter

[ ]
{'output': {'Car': {'Name': 'Fiat Panda', 'Manufacturer': 'Fiat', 'Designers': ['Giorgetto Giugiaro', 'Aldo Mantovani', 'Giuliano Biasio', 'Roberto Giolito'], 'Number of units produced': 'over 7.8 million'}}}

信息提取管道

构建管道

现在我们可以通过添加和连接各个组件来创建我们的管道

[ ]
<haystack.core.pipeline.pipeline.Pipeline object at 0x795de4121630>
,🚅 Components
,  - fetcher: LinkContentFetcher
,  - converter: HTMLToDocument
,  - prompt_builder: PromptBuilder
,  - generator: HuggingFaceLocalGenerator
,  - adapter: OutputAdapter
,🛤️ Connections
,  - fetcher.streams -> converter.sources (List[ByteStream])
,  - converter.documents -> prompt_builder.documents (List[Document])
,  - prompt_builder.prompt -> generator.prompt (str)
,  - generator.replies -> adapter.replies (List[str])
[ ]

让我们回顾一下我们的管道设置:

[ ]
Output

定义源和提取模式

我们选择了一些与最近初创公司融资公告相关的URL列表。

此外,我们定义了一个用于提取结构化信息的模式。

[ ]

运行管道!

我们将所需的数据传递给每个组件。

请注意,大多数组件从先前执行的组件中接收数据。

[ ]
 75%|███████▌  | 9/12 [01:53<00:41, 13.80s/it]You seem to be using the pipelines sequentially on GPU. In order to maximize efficiency please use a dataset
100%|██████████| 12/12 [02:32<00:00, 12.70s/it]

让我们检查一些提取的数据。

[ ]
[{'Company': {'Activity': 'vector database',
,   'Country': '',
,   'Name': 'Pinecone',
,   'Total funding': '$138 million',
,   'Total valuation': '$750 million'},
,  'Funding': {'Investors': ['Andreessen Horowitz',
,    'ICONIQ Growth',
,    'Menlo Ventures',
,    'Wing Venture Capital'],
,   'New funding': '$100 million'}},
, {'Company': {'Activity': 'developing a code-generating AI-powered tool',
,   'Country': 'San Francisco',
,   'Name': 'Replit',
,   'Total funding': 'over $200 million',
,   'Total valuation': '$1.16 billion'},
,  'Funding': {'Investors': ['Andreessen Horowitz',
,    'Khosla Ventures',
,    'Coatue',
,    'SV Angel',
,    'Y Combinator',
,    'Bloomberg Beta',
,    'Naval Ravikant',
,    'ARK Ventures',
,    'Hamilton Helmer'],
,   'New funding': '$97.4 million'}}]

数据探索与可视化

让我们探索提取的数据,以评估其正确性并获得一些洞察。

数据框(Dataframe)

我们首先创建一个 Pandas DataFrame。为了简化,我们将提取的数据展平。

[ ]
[ ]

dataframe

除了“公司 - 国家”部分的一些错误外,提取的数据看起来是正确的。

构建简单图表

为了理解公司与投资者之间的关系,我们构建一个图表并进行可视化。

首先,我们使用 NetworkX 构建图表。

NetworkX 是一个 Python 包,允许我们以简单的方式创建和操作网络/图表。

我们的简单图表将以公司和投资者作为节点。如果投资者和公司出现在同一文档中,我们将连接这些节点。

[ ]

接下来,我们使用 Pyvis 来可视化图表。

Pyvis 是一个用于网络/图表交互式可视化的 Python 包。它与 NetworkX 无缝集成,非常适合用于图形的可视化。

[ ]

graph visualization

看起来 Andreessen Horowitz 在选定的融资公告中出现得非常频繁 😊

结论与思考

在本 Notebook 中,我们演示了如何使用小型语言模型(NuExtract)和 Haystack(一个可定制的 LLM 应用编排框架)来设置信息提取系统。

我们可以如何利用提取的数据?

一些思路:

  • 提取的数据可以添加到存储在 Document Store 中的原始文档中。这允许通过 元数据过滤 实现更强大的搜索功能。
  • 在前一个思路的基础上,你可以进行 RAG(检索增强提取),通过从查询中提取元数据,如 这篇博客文章 中所述。
  • 将文档和提取的数据存储在知识图谱中,并执行图形 RAG(Neo4j-Haystack 集成)。