大语言模型 (LLM) 虽然强大,但它们天生擅长生成非结构化的文本。当我们需要从文本中提取知识,并将其转化为结构化的数据,例如用于构建知识图谱时,就会遇到挑战。本文将深入探讨如何利用 Instructor 和 Pydantic 这两个强大的 Python 库,让 Hugging Face 上的 LLM 也能高效地输出结构化的数据,解决 LLM 输出 JSON 格式数据时常出现的格式错误、数据类型不匹配等问题,最终构建稳健的结构化信息提取流程。
结构化输出的需求与挑战
在使用 LLM 处理科研论文等非结构化文本时,我们往往需要提取特定的实体、关系或论断,并将其转化为可用于知识图谱、数据库或分析流程的结构化数据。 然而,Hugging Face 上的开源 LLM 并不原生支持 JSON 格式的输出,即使尝试生成 JSON,也经常出现格式错误,导致下游解析过程变得复杂且容易出错。
举例来说,如果想从一篇医学论文中提取药物与疾病之间的关系,理想情况下,我们希望得到一个包含 drug
(药物名称) 和 disease
(疾病名称) 字段的 JSON 对象。但如果 LLM 输出的 JSON 对象缺少逗号、包含错误的字段名或数据类型不匹配,就会导致程序无法正确解析,从而影响后续的数据分析和知识图谱构建。
Instructor:将 LLM 转化为结构化输出生成器
Instructor 库的核心功能是将任何 Hugging Face 文本生成模型转化为一个结构化输出生成器。 它通过以下步骤实现这一目标:
- 提示工程 (Prompt Engineering) 与模式注入 (Schema Injection): Instructor 接收一个 Pydantic 模型作为输入,并将其转化为一个 JSON 模式。然后,它将这个模式嵌入到提示词中,引导 LLM 生成符合该模式的结构化输出。
- 解析 (Parsing) 与验证 (Validation): 一旦 LLM 做出响应,Instructor 会将输出解析为 JSON 格式,并使用 Pydantic 验证每个记录是否符合预定义的模式。如果输出不符合模式,例如数据类型错误或字段缺失,Instructor 会引发错误。
- 自动重试 (Automatic Retries): 如果模型输出格式错误或验证失败,Instructor 会自动重新提示模型。它还可以选择性地添加错误提示 (如果使用
patch_instructor
),并重试多次,直到收到有效的响应或达到重试次数上限。
例如,在作者处理心理学论文的案例中, Instructor可以确保提取的“心理学概念/主题”、“测量方式”以及“论证”这三个要素符合预定义的格式,避免了人为解析和校验的繁琐工作。
Instructor 通过 output_type
参数指定输出类型,将通用的语言模型转化为类似 API 客户端的角色,专门用于生成结构化响应。这极大地简化了代码,提高了效率。
Pydantic:定义和验证结构化数据
Pydantic 是一个用于定义和验证结构化数据的 Python 库。 它可以被视为 Python 形式的 JSON Schema。 Pydantic 允许我们使用类型和约束来定义数据模型,从而确保数据的质量和一致性。
在心理学知识图谱构建的案例中,作者使用 Pydantic 定义了一个 PsychTriple
类,用于表示心理学概念、测量方法和论证之间的关系:
from pydantic import BaseModel
class PsychTriple(BaseModel):
topic_or_construct: str
measured_by: str
justification: str
这个类定义了三个字段:topic_or_construct
(心理学概念或主题), measured_by
(测量方法) 和 justification
(论证)。每个字段都指定了数据类型 (str
),并且可以添加额外的约束,例如字段不能为空或必须符合特定的正则表达式。
Pydantic 提供了类型验证、自动解析和清晰的错误消息,使得数据处理更加可靠和高效。 通过将 Pydantic 模型传递给 Instructor 的 output_type
参数,我们可以确保 LLM 生成的输出符合预定义的模式,无需进行额外的后处理。
Instructor + Pydantic 的魔力:构建类型化的 LLM 接口
Instructor 和 Pydantic 结合使用,可以让我们在开源 LLM 之上构建一个类型化的接口。 这种方法结合了 Hugging Face 模型的开放性和灵活性、Pydantic 的结构化约束以及 Instructor 的自动化和重试逻辑,从而实现了一个模块化、强大的非结构化文本结构化信息提取流程。
具体来说,这种组合带来的优势包括:
- 数据质量保证: Pydantic 模型定义了数据的结构和类型,确保 LLM 生成的输出符合预期,减少了数据错误的可能性。
- 开发效率提升: Instructor 自动处理提示工程、解析和验证等任务,简化了开发流程,提高了效率。
- 系统稳定性增强: Instructor 的自动重试机制可以处理模型输出中的错误,提高了系统的鲁棒性。
案例:从心理学论文中提取知识三元组
作者提供了一个完整的脚本,用于从 TEI 格式的心理学论文中提取结构化信息。 目标是构建一个轻量级的知识图谱,其中包含心理学概念与其测量工具之间的关系,以及来自论文的论证。
以下是该脚本的关键步骤:
- 定义 Schema: 使用 Pydantic 定义
PsychTriple
类,如上所示。 - 从 TEI XML 中提取文本: 使用 BeautifulSoup 库解析 TEI XML 文件,并提取文本内容。
- 构建提示词: 构建一个提示词,指导 LLM 从文本中提取心理学概念、测量方法和论证。该提示词包含领域特定的指令,例如提取有意义的短语而不是完整的句子,以及提供支持连接的简短论证。
- 使用 Instructor 处理每个文件: 对于每个文件,提取文本,构建提示词,并使用 Instructor 调用 LLM。 Instructor 会自动将提示词发送给 LLM,解析 LLM 的输出,并验证输出是否符合
PsychTriple
模式。 - 运行 Pipeline: 使用 Hugging Face 的
pipeline
函数加载 LLM 模型和 tokenizer,并将其传递给 Instructor。然后,遍历所有 XML 文件,并使用process_file
函数处理每个文件。
以下是一个具体的提示词示例:
你是一位心理学和计算知识表示方面的专家。你的任务是从心理学研究文章中提取关键的科学信息,以构建一个结构化的知识图谱。
知识图谱旨在表示心理学**主题或概念**与其相关的**测量工具或量表**之间的关系。具体来说,对于每篇文章,以三元组的形式提取信息,捕获:
1. 正在研究的心理学主题或概念
2. 用于评估它的测量工具或量表
3. 来自文章文本的支持此测量链接的简要论证(1-3句话)
指南:
- 为`topic_or_construct`和`measured_by`提取有意义的**短语**(而不是完整的句子或模糊的描述),适用于包含在知识图谱中。
- 为每次提取包含一个简短的论证,清楚地支持这种联系。
- 如果文章没有讨论心理学概念以及如何测量它们(例如,没有提及概念、工具或量表),则返回一个空列表`[]`。
输入论文:
"""{text}"""
输出:以以下格式提供您的响应作为JSON列表:
[
{
"topic_or_construct": "...",
"measured_by": "...",
"justification": "..."
},
...
]
通过运行这个 pipeline,作者可以获得每个文章的 JSON 输出,其中包含提取的心理学概念、测量方法和论证。 这些数据可以轻松地导入到知识图谱中,用于进一步的分析和推理。
Instructor 的幕后工作:Prompt 工程、解析、验证和重试
为了更好地理解 Instructor 的工作原理,让我们深入了解一下它在幕后做了什么:
- Prompt 工程与 Schema 注入: Instructor 接收 Pydantic 模型 (例如,
List[PsychTriple]
),将其转换为 JSON 模式,并将该模式自动嵌入到提示词中,从而引导 LLM 生成符合模式的结构化输出。 - 解析与验证: 一旦 LLM 做出响应,Instructor 会将输出解析为 JSON 格式,并使用 Pydantic 验证每个记录是否符合模式。 如果不匹配 (例如,类型错误,字段缺失),则会引发错误。
- 自动重试: 如果模型输出格式错误或未通过验证,Instructor 会自动重新提示模型。 还可以选择性地添加错误提示 (如果使用
patch_instructor
),并重试多次,直到收到有效的响应或达到重试次数上限。
通过自动处理这些任务,Instructor 极大地简化了结构化信息提取流程,并提高了系统的鲁棒性。
优势总结:结构化生成变得简单
通过运行上述 pipeline,我们可以获得以下结果:
- 每个文章的 JSON 输出,已经过清洗和验证。
- 一致的类型化数据,可以随时导入到知识图谱中。
- 完整的可追溯性 (每个输入文件都保存了提示词)。
- 零解析错误。
总之,Instructor + Pydantic + Hugging Face 提供了一个强大的解决方案,用于从非结构化文本中提取结构化信息。 这种方法结合了 LLM 的灵活性和 Pydantic 的结构化约束,使得结构化生成变得简单易用。
扩展与展望
作者还提出了一些进一步探索的方向:
- 添加单元测试: 使用
mockLLM
响应添加单元测试,以确保系统的正确性。 - 分析提取模式: 分析语料库中的提取模式,以了解 LLM 的行为。
- 构建 Streamlit 应用: 构建一个 Streamlit 应用,用于浏览结构化结果。
这些扩展方向可以帮助我们进一步提高系统的质量和可用性。
结论:LLM 可以流利地说结构化数据
LLM 不必说谜语。 借助合适的工具,它们可以流利地输出结构化数据。 Instructor 和 Pydantic 使这一切成为可能,并且完全开源。
未来,我们可以期待更多类似 Instructor 和 Pydantic 的工具出现,从而进一步简化结构化信息提取流程,并释放 LLM 的潜力。 如何利用 LLM 来处理非结构化文本,并将其转化为可用于各种应用的结构化数据,仍然是一个值得探索的领域。随着技术的不断发展,我们有理由相信,LLM 将在知识图谱构建、数据分析和信息检索等领域发挥越来越重要的作用。
在处理结构化数据时,你使用什么技巧? 你使用解析技巧、少样本提示、函数调用,还是其他方法? 欢迎分享你的工作流程、技巧或问题。
希望你的 JSON 是有效的,你的三元组是有意义的!