垂直领域 RAG 的第一块基石:LangExtract 信息抽取与可溯源结构化

在构建垂直领域 RAG 系统时,信息抽取是连接**"原始文档 → 知识图谱 / 向量库 → 智能问答"的关键一环。如果没有稳定、可控、可溯源**的抽取能力,后面的 RAG、Agent、溯源问答都只是空中楼阁。

本文系统讲解 Google 开源的 LangExtract 框架,重点围绕:

  • 核心使用场景:非结构化文本处理、医疗病历分析、法律文档解析、金融报告提取、长文档信息抽取
  • 五大功能亮点:Prompt-Driven 零代码定义任务、Few-Shot Learning、Source Grounding 溯源、Schema Enforcement、长文档 Multi-Pass 提取
  • 与传统方法 / 纯 Prompt 方案的对比:自动去重、结构化输出保证、精确的原文位置对齐(Source Grounding),从开发门槛、领域适配、表达能力、可维护性、可溯源性五大维度全面超越传统方案

一、非结构化文本的痛点与 LangExtract 的定位

1.1 非结构化文本:信息密度高,结构混乱复制

以医疗场景为例:

"患者张某,男,45岁,主诉胸痛3天。既往有高血压病史10年,目前服用缬沙坦80mg每日一次。体格检查:血压150/95mmHg..."

医院想要统计:所有患者的用药情况、剂量分布、共病模式,常见做法有:

  • 人工标注
    • 准确但依赖领域专家标注,成本高且难以规模化
  • 正则表达式 / 规则
    • 针对"缬沙坲80mg每日一次 / 80mg qd / 1 次/天"等各种写法,规则复杂度高且泛化能力差
  • 传统 NER / RE 模型
    • 需要大量标注数据,训练成本高,不同科室还要分别训练,跨领域迁移极差

传统信息提取方法对比

方法类型 优点 局限性 适用场景
正则表达式/规则 精准、可控 规则复杂、维护困难、泛化能力差 格式固定的简单文本
传统NER模型 自动学习模式 需要大量标注数据、跨领域迁移差 有训练数据的特定领域
通用NLP工具 开箱即用 准确率低、无法定制 通用场景的粗粒度提取
人工标注 最准确 成本高、速度慢、无法规模化 小规模高价值数据

总结:在医疗病历、法律文书、金融报告、长篇技术报告这些高价值文本上,传统方法要么贵,要么脆,要么不够智能。

1.2 LangExtract:让 LLM 变成"可控的信息抽取引擎"

为解决上述问题,Google 开源了 LangExtract。这是一个 Python 库,其核心使命可以用一句话概括:利用大型语言模型,将非结构化文本转换为结构化数据,并确保每个提取结果都精确对应回原文位置。

它不是一个具体的"大模型",而是一个围绕 LLM 抽取能力的 工程框架,提供以下五大核心能力:

能力一:零代码定义提取任务(Prompt-Driven)

在传统方案中,为了抽取药物信息,可能需要编写:

  • 大量正则(匹配剂量、时间、频率)
  • 自定义分词、语法分析

在 LangExtract 中,只需要一个 Prompt:

python 复制代码
# 示例:定义提取任务的 Prompt
extraction_prompt = """
从临床笔记中提取以下信息:
1. 药物名称(medication)
2. 剂量(dosage) 
3. 给药频率(frequency)
4. 持续时间(duration)

请确保提取的内容与原文完全一致。
"""

# 这就是全部!无需编写任何解析逻辑
能力二:少样本学习能力(Few-Shot Learning)

只需给模型 1~3 个高质量示例,就能显著提升抽取效果。

python 复制代码
import langextract as lx

# 定义一个示例:告诉模型"什么样的输入应该产生什么样的输出"
example = lx.data.ExampleData(
    text="患者目前服用缬沙坲80mg每日一次,已持续3个月。",
    extractions=[
        lx.data.Extraction(
            extraction_class="medication",
            extraction_text="缬沙坲"
        ),
        lx.data.Extraction(
            extraction_class="dosage",
            extraction_text="80mg"
        ),
        lx.data.Extraction(
            extraction_class="frequency",
            extraction_text="每日一次"
        ),
        lx.data.Extraction(
            extraction_class="duration",
            extraction_text="3个月"
        )
    ]
)

# 提供1-3个这样的示例,模型就能学会输出格式!

在医疗病历场景,一个这样的 ExampleData 就可以教会模型:

  • 什么算"药物名称"
  • 什么算"剂量 / 频率 / 持续时间"
能力三:精确的来源定位(Source Grounding)

LangExtract 的每一个抽取结果都自带 char_interval,记录其在原文的起止字符位置。

这在以下场景尤为关键:

  • 医疗审计:监管部门核查 AI 提取的诊断结论是否真的出现在病历中
  • 法律合规:合规审查时必须能追溯每条规定来自合同的哪一页哪一行
  • 企业知识管理:构建企业知识库时,需链接回原始文档以供查证
能力四:结构化输出保证(Schema Enforcement)

大模型的常见问题之一是:输出格式不稳定。同一个任务可能出现:

  • 一次返回 JSON
  • 一次返回 Markdown 表格
  • 一次返回自然语言解释 + JSON 混合

LangExtract 通过两种机制解决:

  • 基于 Few-Shot 的格式约束:示例中使用目标结构,模型会模仿
  • Schema Enforcement(受控生成):对支持 JSON Schema 的模型(如 Google Gemini),可以强制其输出符合预定义 Schema

在实际应用中,LangExtract 可以批量处理成千上万份文档,而不必担心某一份输出格式错误导致整个流水线崩溃。

能力五:长文档多轮提取(Multi-Pass Extraction)

对于 100 页的合同 / 法规合集 / 白皮书,常见问题是:

  • 单次上下文放不下
  • 一次扫描漏掉隐蔽信息

LangExtract 的长文档策略包括:

  1. 自动分块(Automatic Chunking)
    • 将长文档切分为适合模型处理的小块
    • 保留块之间的上下文重叠
    • 多块并行处理,提高速度
  2. 多轮提取(Multi-Pass)
    • 第 1 轮:全面扫描,提取显著信息
    • 第 2 轮:针对第一轮可能遗漏的内容再次扫描
    • 第 3 轮:面向特定信息类型进行深挖

这种策略在合规审查、法律分析等不允许遗漏任何细节的场景中至关重要。

与传统方法的对比分析
对比维度 正则 / 规则 NER / 传统模型 LangExtract
开发门槛 需要熟悉文本模式、规则设计 需要数据标注 + 训练 + 调参 Prompt + 少量示例即可启动
领域适配 改一条规则可能影响多个场景 跨领域要重新标注和训练 换领域只需换 Prompt + 示例
表达能力 适合模式固定的字段抽取 适合浅层实体识别 可同时抽实体、关系、事件、指标
可维护性 场景增多后规则庞大难维护 模型更新需重新训练 维护 Prompt & 示例集,迭代成本低
可溯源性 每条结果携带 char_interval

以上五大能力使得 LangExtract 非常适合作为 医疗 / 法律 / 金融 / 合规审查 / 企业知识库 等场景的抽取底座。


二、LangExtract 的典型使用场景

2.1 非结构化文本处理(通用场景)

  • 海量 FAQ、工单、客服对话日志
  • 企业内部技术文档、设计文档
  • 论坛 / 社区 / 评论文本

利用 LangExtract 可以低成本定义:

  • 关键实体(人 / 组织 / 产品 / 功能)
  • 事件(发布、故障、变更)
  • 指标(数值、时间、地点)

并将其批量转化为结构化数据,供搜索、分析和下游任务使用。

2.2 医疗病历分析

医疗场景中的典型需求:

从病历中抽取 药物名称、剂量、给药频率、持续时间 等字段,用于统计研究、风险预警、智能随访。

通过 LangExtract,可以用非常少的 Few-Shot 示例,快速搭建:

  • 用药模式分析(同一疾病下不同用药方案)
  • 不良反应监控(药物组合 + 病史)
  • 个体化治疗决策支持

2.3 法律文档解析

合同、判决书、法律条款 等场景中,LangExtract 可抽取:

  • 条款编号、条款标题
  • 权利义务主体
  • 违约责任、赔偿条款
  • 关键期限、金额

结合 Source Grounding,审查人员可以做到:

  • "这条风险提示来自合同第几条、第几款?"
  • "这个结论有没有对应的原文依据?"

2.4 金融报告与监管文本抽取

对上市公司年报、季报、监管报告等:

  • 抽取关键指标:营收、净利、现金流、负债率等
  • 抽取风险提示:重大诉讼、合规风险
  • 抽取相关主体:控股股东、实控人、主要客户 / 供应商

LangExtract 支持:

  • 直接从 PDF 经 OCR + Markdown 解析后进行结构化抽取
  • 通过长文档 Multi-Pass 确保指标不遗漏

2.5 长文档信息抽取

不论是:

  • 戏剧脚本(如《罗密欧与朱丽叶》)
  • 长篇技术白皮书
  • 成百页的法律合约合订本

LangExtract 都可以通过:

  • 文本分块(max_char_buffer)
  • 多轮抽取(extraction_passes)
  • 并行处理(max_workers)

实现 完整覆盖 + 较高精度 的长文档抽取,并为每条结果提供位置索引,便于可视化和溯源。


三、【实战】Prompt Engineering 对比 LangExtract

在实际项目中,一个常见的疑问是:"直接用提示词让大模型提取不就行了吗?为什么还要用 LangExtract?"

本节通过 真实的新闻信息提取场景,分别运行纯提示词方式和 LangExtract 方式,从重复实体、完整性、原文对齐能力三个维度进行深度对比。

安装依赖:

python 复制代码
%pip install langextract
python 复制代码
%pip install openai python-dotenv

3.1 环境准备

导入纯提示词所需的 OpenAI 客户端和 LangExtract 框架:

python 复制代码
# 导入所有需要的库
import os
import time
import json
from pathlib import Path
from collections import Counter

# 纯提示词方式所需
from openai import OpenAI

# LangExtract 方式所需
import langextract as lx
from langextract.providers.openai import OpenAILanguageModel
from langextract.prompt_validation import PromptValidationLevel

# 环境变量加载
from dotenv import load_dotenv

print("所有依赖库导入成功")

加载 DeepSeek API 配置,确保两种方案使用完全相同的模型和配置:

python 复制代码
# 加载环境变量
load_dotenv()

# 读取 API 配置
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")
DEFAULT_MODEL = os.getenv("DEFAULT_MODEL", "deepseek-chat")

# 创建输出目录
OUTPUT_DIR = Path("./outputs")
OUTPUT_DIR.mkdir(exist_ok=True)

print("环境变量加载完成")
print(f"  模型: {DEFAULT_MODEL}")
print(f"  API: {DEEPSEEK_BASE_URL}")

3.2 准备测试文本

测试文本采用真实新闻风格的复杂文本,包含多个时间、机构、人物、地点、事件和指标,用于压力测试两种方案:

python 复制代码
# 定义测试文本
input_text = """
2025年12月22日上午,国家统计局在北京国务院新闻办公室举行新闻发布会,公布2025年前11个月国民经济运行情况。
国家统计局新闻发言人付凌晖表示,规模以上工业增加值同比增长6.1%,社会消费品零售总额增长7.3%。

同日,国家发展改革委(以下简称"发改委")在例行发布会上介绍,将于2026年起对"人工智能+制造"试点城市给予专项资金支持,首批覆盖上海、深圳、成都等10个城市。
发改委副主任李春临称,资金将重点投向算力基础设施和工业软件,并与地方财政配套安排相衔接。

22日傍晚,中国人民银行(央行)公告,自12月23日起下调金融机构存款准备金率0.25个百分点。
央行副行长宣昌能在答记者问时称,此举旨在保持流动性合理充裕,并支持中小微企业融资。

对此,清华大学经济管理学院教授李稻葵认为,上述措施有助于稳定市场预期,但需警惕部分行业"低价竞争"风险。
他同时提到,地方政府隐性债务化解仍是明年宏观政策的重要约束。
""".strip()

print("✓ 测试文本已准备")
print(f"文本长度: {len(input_text)} 字符")
print(f"\n原文预览(前200字符):\n{input_text[:200]}...")

重点关注:文本中包含"2026年起"、"12月23日起"等时间表达,两种方案对此的处理方式有明显差异。

3.3 纯提示词方案

纯提示词方案直接调用 DeepSeek API,通过精心设计的 Prompt 提取信息。

定义 Few-shot 示例,引导大模型输出格式:

python 复制代码
# 定义 Few-shot 示例文本
example_text = (
    "2025年6月3日,工业和信息化部在北京发布《算力基础设施高质量发展行动计划》。"
    "工信部副部长张云明表示,到2027年全国算力总规模将达到300 EFLOPS。"
)

# 定义示例的标准输出格式
example_output = """{
  "extractions": [
    {"class": "时间", "text": "2025年6月3日"},
    {"class": "机构", "text": "工业和信息化部"},
    {"class": "地点", "text": "北京"},
    {"class": "人物", "text": "张云明"},
    {"class": "事件", "text": "发布《算力基础设施高质量发展行动计划》"},
    {"class": "指标", "text": "300 EFLOPS"}
  ]
}"""

print("Few-shot 示例已准备")
print(f"示例文本: {example_text}")
print(f"\n示例输出:\n{example_output}")

示例包含所有实体类别(时间、地点、机构、人物、事件、指标),用于引导 LLM 的提取行为。

构建完整 Prompt,包含任务说明、输出格式要求、Few-shot 示例和待提取文本:

python 复制代码
# 构建完整 Prompt
prompt = f"""
请从下面的新闻文本中提取结构化信息。

【抽取类别】
- 时间
- 地点
- 机构
- 人物
- 事件
- 指标(数值/增速/比例/数量等)

【要求】
1. 所有 `text` 必须是原文中的精确子串,不要改写
2. 去重并按原文出现顺序输出

【输出格式】
请严格输出 JSON(不要添加任何解释、Markdown、代码块):
{{
  "extractions": [
    {{
      "class": "类别",
      "text": "原文精确文本"
    }}
  ]
}}

【Few-shot 示例】
示例文本:
{example_text}

示例输出:
{example_output}

---

现在请抽取这段新闻文本:
{input_text}
"""

print("Prompt 构建完成")
print(f"Prompt 总长度: {len(prompt)} 字符")

调用 DeepSeek API 进行提取

python 复制代码
# 创建 DeepSeek 客户端
client = OpenAI(
    api_key=DEEPSEEK_API_KEY,
    base_url=DEEPSEEK_BASE_URL
)

print("DeepSeek 客户端创建成功")

调用大模型提取信息:

python 复制代码
# 调用 DeepSeek API
print("正在调用 DeepSeek API...")
start_time = time.time()

response = client.chat.completions.create(
    model=DEFAULT_MODEL,
    messages=[
        {
            "role": "system",
            "content": "你是一个文本信息抽取助手,请严格按照用户指定的 JSON 格式输出,不要添加多余解释。"
        },
        {
            "role": "user",
            "content": prompt
        }
    ],
    temperature=0.3,
    max_tokens=2000,
    stream=False
)

result_prompt = response.choices[0].message.content
elapsed = time.time() - start_time

print(f"提取完成(耗时 {elapsed:.2f} 秒)")

查看纯提示词提取结果

python 复制代码
# 打印原始结果
print("纯提示词提取结果:")
print("=" * 80)
print(result_prompt)
print("=" * 80)

解析并统计纯提示词的结果:

python 复制代码
# 解析 JSON 并统计
prompt_result = json.loads(result_prompt)
prompt_extractions = prompt_result["extractions"]

# 基本统计
total_count_prompt = len(prompt_extractions)
type_counts_prompt = Counter(ext["class"] for ext in prompt_extractions)

print(f"纯提示词统计:")
print(f"  总实体数: {total_count_prompt}")
print(f"  按类型分布:")
for entity_type, count in sorted(type_counts_prompt.items()):
    print(f"    - {entity_type}: {count} 个")

纯提示词提取了大量实体,但数量多不代表质量高------需要检查重复问题:

python 复制代码
# 检查重复
text_counts = Counter(ext["text"] for ext in prompt_extractions)
duplicates = {text: count for text, count in text_counts.items() if count > 1}

if duplicates:
    print("发现重复实体:")
    for text, count in duplicates.items():
        print(f"  - '{text}' 重复了 {count} 次")
    
    total_duplicates = sum(count - 1 for count in duplicates.values())
    unique_count_prompt = total_count_prompt - total_duplicates
    
    print(f"\n去重后实际数量: {unique_count_prompt} 个(减少了 {total_duplicates} 个重复)")
else:
    print("✓ 未发现重复实体")
    unique_count_prompt = total_count_prompt

纯提示词存在明显的重复问题,这会导致:

  1. 数量虚高
  2. 需要人工去重

3.4 LangExtract 方案

LangExtract 框架会自动处理去重、原文对齐等细节。

定义 LangExtract 任务描述 ,比纯提示词简洁得多,因为它内置了很多最佳实践:

python 复制代码
# 定义 LangExtract 的任务描述
langextract_prompt = """
从新闻文本中提取以下信息:
- 时间
- 地点
- 机构
- 人物
- 事件
- 指标(数值/增速/比例/数量等)

要求:
1. 使用原文中的完整表述
2. 不要重复
3. 按出现顺序提取
"""

print("LangExtract 任务描述已定义")
print(f"Prompt 长度: {len(langextract_prompt)} 字符(比纯提示词简洁得多)")

LangExtract 会自动处理输出格式、去重等细节。

定义 Few-shot 示例 ,与纯提示词使用完全相同的示例文本,确保对比公平性:

python 复制代码
# 定义 LangExtract 的 Few-shot 示例
examples = [
    lx.data.ExampleData(
        text=example_text,
        extractions=[
            lx.data.Extraction("时间", "2025年6月3日"),
            lx.data.Extraction("机构", "工业和信息化部"),
            lx.data.Extraction("地点", "北京"),
            lx.data.Extraction("人物", "张云明"),
            lx.data.Extraction("事件", "发布《算力基础设施高质量发展行动计划》"),
            lx.data.Extraction("指标", "300 EFLOPS"),
        ]
    )
]

print("LangExtract Few-shot 示例已定义")
print(f"示例数量: {len(examples)}")
print(f"示例实体数: {len(examples[0].extractions)}")

初始化 LangExtract 模型 ,使用相同的 DeepSeek API:

python 复制代码
# 创建 LangExtract 模型
model = OpenAILanguageModel(
    model_id=DEFAULT_MODEL,
    api_key=DEEPSEEK_API_KEY,
    base_url=DEEPSEEK_BASE_URL
)

print("LangExtract 模型创建成功")
print(f"使用模型: {DEFAULT_MODEL}(与纯提示词相同)")

执行 LangExtract 提取 ,自动完成:构建优化的 Prompt、调用 LLM、解析结果、对齐原文位置、自动去重:

python 复制代码
result = lx.extract(
    text_or_documents=input_text,
    prompt_description=prompt,
    examples=examples,
    model=model,
    fence_output=True,
    use_schema_constraints=False,
    prompt_validation_level=PromptValidationLevel.OFF,  

)

查看 LangExtract 提取结果 ,注意每个实体都有精确的位置信息:

python 复制代码
# 打印 LangExtract 结果
print("LangExtract 提取结果:")
print("=" * 80)
for ext in result.extractions:
    if ext.char_interval:
        pos_info = f"[{ext.char_interval.start_pos}-{ext.char_interval.end_pos}]"
    print(f"[{ext.extraction_class}] {ext.extraction_text} {pos_info}")
print("=" * 80)

LangExtract 的每个实体都有精确的位置信息,这意味着可以回到原文验证、可视化高亮展示。

统计 LangExtract 结果

python 复制代码
# 统计 LangExtract 结果
langextract_extractions = result.extractions
total_count_lang = len(langextract_extractions)
type_counts_lang = Counter(ext.extraction_class for ext in langextract_extractions)

# 统计有位置信息的实体数
with_position = sum(1 for ext in langextract_extractions if ext.char_interval is not None)

print(f"LangExtract 统计:")
print(f"  总实体数: {total_count_lang}")
print(f"  按类型分布:")
for entity_type, count in sorted(type_counts_lang.items()):
    print(f"    - {entity_type}: {count} 个")

四、【实战】LangExtract 长文本提取

本节通过实战深入理解 LangExtract 处理长文本的核心能力

以完整的《罗密欧与朱丽叶》中文版(约 54,000 字符)作为案例,演示如何从长文档中提取人物、情感和关系信息。

本章核心要点:

  • 长文本处理策略:分块 + 多轮 + 并行
  • 戏剧文本特点:角色对话、情感丰富、关系复杂
  • 数据分析与可视化:从 1,889 个实体中挖掘价值
  • 核心参数调优extraction_passesmax_workersmax_char_buffer

4.1 配置运行环境

导入必要的 Python 库:

  • osPath:文件和目录操作
  • textwrap:格式化多行字符串
  • Counterdefaultdict:统计和数据聚合
  • langextract:核心提取框架
  • OpenAILanguageModel:DeepSeek 兼容的模型接口
  • dotenv:加载环境变量
python 复制代码
import os
import textwrap
from pathlib import Path
from collections import Counter, defaultdict

from dotenv import load_dotenv
import langextract as lx
from langextract.providers.openai import OpenAILanguageModel
from langextract.prompt_validation import PromptValidationLevel

print("所有依赖库导入成功!")
python 复制代码
# 加载环境变量
load_dotenv()

print("环境变量加载成功!")

load_dotenv() 从项目根目录的 .env 文件中读取配置信息,主要是 API Key 和相关配置。

配置 API 参数:

python 复制代码
# 配置 DeepSeek API
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "")
DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")
DEFAULT_MODEL = os.getenv("DEFAULT_MODEL", "deepseek-chat")

# 配置输出目录
OUTPUT_DIR = Path("./outputs")
OUTPUT_DIR.mkdir(exist_ok=True)

print(f"配置完成!")
print(f"  模型: {DEFAULT_MODEL}")
print(f"  API 端点: {DEEPSEEK_BASE_URL}")
print(f"  输出目录: {OUTPUT_DIR}")

这里完成了三件事:

  1. 读取 API 配置:从环境变量中获取 DeepSeek API Key 和端点
  2. 设置默认模型 :使用 deepseek-chat 模型
  3. 创建输出目录OUTPUT_DIR.mkdir(exist_ok=True) 创建 outputs 目录,已存在则不报错

4.2 读取长文本数据

从本地文件读取《罗密欧与朱丽叶》的完整中文文本(约 54,000 字符),是典型的长文档场景。

由于中文文本可能有不同的编码格式,需要尝试多种编码读取:

python 复制代码
# 读取《罗密欧与朱丽叶》中文文本
romeo_file = Path("罗密欧与朱丽叶.txt")

if romeo_file.exists():
    # 尝试多种编码
    for encoding in ['gbk', 'gb2312', 'utf-8', 'utf-16']:
        try:
            with open(romeo_file, 'r', encoding=encoding) as f:
                input_text = f.read()
            print(f"✓ 成功使用 {encoding} 编码读取文件")
            break
        except:
            continue
else:
    print("错误: 未找到 罗密欧与朱丽叶.txt 文件")
    print("请确保文件存在于当前目录")

print(f"✓ 成功读取 {len(input_text):,} 字符")
print(f"\n文本预览(前 200 字符):")
print("-" * 60)
print(input_text[:200])
print("...")

这里有几个关键点:

  1. 多编码尝试 :依次尝试 gbkgb2312utf-8utf-16,确保正确读取中文文本
  2. 字符数统计:约 54,000 字符,典型的长文档场景
  3. 文本预览 :通过 input_text[:200] 查看前 200 字符,确认文本格式正确

4.3 定义提取任务 Prompt

Prompt 是告诉模型"要提取什么"的核心指令。对于戏剧文本,关注三类信息:

  • 人物:剧中角色
  • 情感:情感表达和心理活动
  • 关系:人物之间的关系描述

同时明确告诉模型戏剧脚本的特点:角色名称后跟冒号:

python 复制代码
# 定义提取任务的 Prompt 描述
prompt = textwrap.dedent("""\
    从中文戏剧文本中提取人物、情感和关系信息。
    
    为每个实体添加有意义的属性以增加上下文。
    
    重要: extraction_text 必须是原文的精确子串,不要改写。
    按出现顺序提取实体,不要重叠。
    
    注意: 在戏剧脚本中,角色名称后跟冒号。""")

print("Prompt 定义完成!")
print("\n" + "=" * 60)
print("Prompt 内容:")
print("=" * 60)
print(prompt)

Prompt 包含几个关键要求:

  1. 提取目标:人物、情感、关系
  2. 属性要求:为每个实体添加属性,增加上下文信息
  3. 精确对齐extraction_text 必须是原文精确子串
  4. 戏剧格式:角色名称后跟冒号,是戏剧脚本的特殊格式

4.4 定义 Few-shot 示例

Few-shot 示例是 LangExtract 的核心。通过提供高质量的示例,引导模型理解"什么是好的提取"。使用一段经典的罗密欧与朱丽叶对话作为示例:

python 复制代码
# 定义 Few-shot 示例
examples = [
    lx.data.ExampleData(
        text=textwrap.dedent("""\
            罗密欧: 轻声!那边窗子里亮起来的是什么光?
            那就是东方,朱丽叶就是太阳。
            朱丽叶: 啊!罗密欧,罗密欧!为什么你偏偏是罗密欧呢?"""),
        extractions=[
            lx.data.Extraction(
                extraction_class="人物",
                extraction_text="罗密欧",
                attributes={"情感状态": "惊叹"}
            ),
            lx.data.Extraction(
                extraction_class="情感",
                extraction_text="轻声!",
                attributes={"情感": "温柔敬畏", "人物": "罗密欧"}
            ),
            lx.data.Extraction(
                extraction_class="关系",
                extraction_text="朱丽叶就是太阳",
                attributes={"类型": "比喻", "人物1": "罗密欧", "人物2": "朱丽叶"}
            ),
            lx.data.Extraction(
                extraction_class="人物",
                extraction_text="朱丽叶",
                attributes={"情感状态": "渴望"}
            ),
            lx.data.Extraction(
                extraction_class="情感",
                extraction_text="为什么你偏偏是罗密欧呢?",
                attributes={"情感": "渴望的疑问", "人物": "朱丽叶"}
            ),
        ]
    )
]

print("Few-shot 示例定义完成!")
print(f"\n示例数量: {len(examples)}")
print(f"示例文本长度: {len(examples[0].text)} 字符")
print(f"示例提取数量: {len(examples[0].extractions)} 个")
print("\n" + "=" * 60)
print("示例文本:")
print("=" * 60)
print(examples[0].text)

Few-shot 示例展示了高质量提取的标准:

  1. 人物提取:提取"罗密欧"和"朱丽叶",并添加"情感状态"属性
  2. 情感提取:提取"轻声!"和"为什么你偏偏是罗密欧呢?",标注情感类型和归属人物
  3. 关系提取:提取"朱丽叶就是太阳"这个比喻,标注类型和涉及的人物

注意每个 extraction_text 都是原文的精确子串,这是 LangExtract 的核心要求。

4.5 创建 LangExtract 模型

使用 OpenAILanguageModel 对接 DeepSeek API,LangExtract 的设计可以轻松使用任何 OpenAI 兼容的 API:

python 复制代码
# 创建 DeepSeek 模型实例
model = OpenAILanguageModel(
    model_id=DEFAULT_MODEL,
    api_key=DEEPSEEK_API_KEY,
    base_url=DEEPSEEK_BASE_URL
)

print("模型创建成功!")
print(f"  模型 ID: {DEFAULT_MODEL}")
print(f"  API 端点: {DEEPSEEK_BASE_URL}")

传入三个参数:

  • model_id:模型名称,这里是 deepseek-chat
  • api_key:API 密钥,从环境变量读取
  • base_url:API 端点,DeepSeek 的 API 端点

4.6 运行长文本提取(核心)

本节的核心部分。使用 lx.extract() 函数,配合长文本处理的三大核心参数:

长文本处理核心参数

参数名 作用
extraction_passes 3 多轮提取,提高召回率
max_workers 20 并行处理,加快速度
max_char_buffer 1000 分块大小,保持准确性

这三个参数是 LangExtract 处理长文本的核心策略:分块 + 多轮 + 并行

注意 :运行这个 Cell 会调用 DeepSeek API,处理 54,000 字符的文本,大约需要 1-2 分钟

python 复制代码
# 运行长文本提取
print("开始运行长文本提取...")
print(f"   输入文本: {len(input_text):,} 字符")
print(f"   提取轮数: 3 轮")
print(f"   并行数: 20 workers")
print(f"   分块大小: 1000 字符")
print("\n正在处理,请稍候...\n")

result = lx.extract(
    text_or_documents=input_text,
    prompt_description=prompt,
    examples=examples,
    model=model,
    extraction_passes=3,      # 多轮提取提高召回率
    max_workers=20,           # 并行处理加速
    max_char_buffer=1000      # 较小的上下文提高准确性
)

print("\n" + "=" * 60)
print("提取完成!")
print("=" * 60)
print(f"文本长度: {len(result.text):,} 字符")
print(f"提取实体总数: {len(result.extractions)} 个")

从 54,000 字符的文本中,提取了约 1,889 个实体

LangExtract 的长文本处理策略:

  1. 分块处理max_char_buffer=1000 将文本分成多个 ~1000 字符的块
  2. 并行执行max_workers=20 同时处理 20 个块,大幅提速
  3. 多轮提取extraction_passes=3 执行 3 轮独立提取,将不重叠的结果合并

4.7 保存提取结果

LangExtract 使用 JSONL 格式保存结果。JSONL 是一种人类可读的格式,每行是一个独立的 JSON 对象,便于解析和分享:

python 复制代码
# 保存提取结果为 JSONL 格式
lx.io.save_annotated_documents(
    [result], 
    output_name="罗密欧与朱丽叶_extractions.jsonl", 
    output_dir=str(OUTPUT_DIR)
)

output_jsonl_path = OUTPUT_DIR / "罗密欧与朱丽叶_extractions.jsonl"
print(f"结果已保存: {output_jsonl_path}")

JSONL 文件保存到 outputs 目录,包含:

  • 原始文本
  • 所有提取的实体
  • 每个实体的位置信息(start_posend_pos
  • 每个实体的属性

LangExtract 提供强大的可视化功能。通过 lx.visualize() 函数,生成交互式 HTML 页面,用于查看和分析提取结果:

python 复制代码
# 生成交互式可视化
html_content = lx.visualize(str(output_jsonl_path))

html_file = OUTPUT_DIR / "罗密欧与朱丽叶_visualization.html"
with open(html_file, "w", encoding="utf-8") as f:
    if hasattr(html_content, 'data'):
        f.write(html_content.data)
    else:
        f.write(html_content)

print(f"交互式可视化已生成: {html_file}")
print("\n提示: 在浏览器中打开 HTML 文件可以:")
print("   - 查看高亮显示的所有提取结果")
print("   - 按类别筛选实体")
print("   - 查看每个实体的详细属性")

可视化 HTML 文件提供:

  • 原文高亮显示
  • 按类别筛选
  • 点击实体查看详细信息
  • 可搜索、可导航

加入赋范空间,获取更多技术资源

如果你对本文内容感兴趣,欢迎加入 赋范空间 技术社区!

包括本文配套完整的 LangExtract 信息抽取技术实战

我们提供系统的课程体系,帮助你从零开始掌握:

  • AI Agent 开发:基于 LangChain 1.0、Google ADK 等主流框架,深入理解 Agent 架构与实战,打造智能体
  • RAG 技术:构建高性能的企业级知识库问答系统,涵盖混合检索、智能路由、以图搜图、视频检索等
  • MCP 协议:掌握下一代 AI 连接标准,连接万物
  • 大模型微调:掌握 Fine-tuning、RL 等技术,打造专属垂直领域模型
  • 企业项目实战:15+ 项目实战(多模态 RAG、实时语音助手、文档审核、智能客服系统等),将理论知识应用到实际项目中,解决真实业务问题

LangExtract 提供强大的可视化功能。通过 lx.visualize() 函数,生成交互式 HTML 页面,用于查看和分析提取结果:

python 复制代码
# 生成交互式可视化
html_content = lx.visualize(str(output_jsonl_path))

html_file = OUTPUT_DIR / "罗密欧与朱丽叶_visualization.html"
with open(html_file, "w", encoding="utf-8") as f:
    if hasattr(html_content, 'data'):
        f.write(html_content.data)
    else:
        f.write(html_content)

print(f"交互式可视化已生成: {html_file}")
print("\n提示: 在浏览器中打开 HTML 文件可以:")
print("   - 查看高亮显示的所有提取结果")
print("   - 按类别筛选实体")
print("   - 查看每个实体的详细属性")

可视化 HTML 文件提供:

  • 原文高亮显示
  • 按类别筛选
  • 点击实体查看详细信息
  • 可搜索、可导航

加入赋范空间,获取更多技术资源

如果你对本文内容感兴趣,欢迎加入 赋范空间 技术社区!

包括本文配套完整的 LangExtract 信息抽取技术实战

我们提供系统的课程体系,帮助你从零开始掌握:

  • AI Agent 开发:基于 LangChain 1.0、Google ADK 等主流框架,深入理解 Agent 架构与实战,打造智能体
  • RAG 技术:构建高性能的企业级知识库问答系统,涵盖混合检索、智能路由、以图搜图、视频检索等
  • MCP 协议:掌握下一代 AI 连接标准,连接万物
  • 大模型微调:掌握 Fine-tuning、RL 等技术,打造专属垂直领域模型
  • 企业项目实战:15+ 项目实战(多模态 RAG、实时语音助手、文档审核、智能客服系统等),将理论知识应用到实际项目中,解决真实业务问题
相关推荐
风43811 小时前
互联网大厂Java求职面试实战:Spring Boot+微服务+AI技术栈深度解析
spring boot·微服务·向量数据库·java面试·rag·ai技术·电商场景
m0_726965981 天前
RAG源代码笔记JAVA-高级RAG
笔记·ai·agent·rag
mubei-1231 天前
Self-RAG:通过自我反思学习检索、生成和批判
人工智能·llm·rag·检索增强生成
玄同7651 天前
Python 正则表达式:LLM 噪声语料的精准清洗
人工智能·python·自然语言处理·正则表达式·nlp·知识图谱·rag
夏日白云1 天前
《PDF解析工程实录》第 11 章|图像路线的工程现实:DPI、分辨率和内存炸裂
pdf·llm·大语言模型·rag·文档解析
mubei-1231 天前
万字RAG综述:大语言模型的检索增强生成
人工智能·llm·rag·检索增强生成