在數據驅動的時代,大量有價值的信息隱藏在非結構化文本中—比如詳盡的臨床記錄、冗長的法律文件、大量客戶反饋與評價等。很多時候我們需要把其抽取成更結構化的內容。這是因為結構化信息:更易于被索引與查詢、更適合統計分析與挖掘,也更易于被軟件集成(RPA、API、工作流等)。 本篇為大家介紹LangExtract -- Google 新出品的一款開源Python 工具。它可以更完美的借助LLM,并根據用戶指令,將海量非結構化文本轉換為結構清晰、來源可追溯的結構化信息 。這也是近期看到最好的 “小而美” 工具之一:簡潔、高效、有用。 本文內容:
01 起源與動機 從低密度的自然語言文本中做結構化信息抽取一直是 AI 的難題。傳統方法要么依賴繁瑣的正則表達式,要么借助機器學習提取上下文特征,但很難應對語言多變、含義深刻的真實語料。 LLM給我們看到了解決問題的新方向,但是: 盡管當前的LLM已經具備了通識領域非常強大的自然語言理解能力,且具備結構化輸出能力(大部分LLM)。但直接讓 LLM “讀文本吐結構” 仍然存在諸多痛點:
LangExtract 正是為了解決上述這些問題而生 。它由 Google 開源,可以讓開發者通過自然語言指令和少量示例數據來定義并完成抽取任務 。 相較于普通 LLM 的直接輸出,LangExtract 在后臺采取了一系列策略來強化結果的可靠性和可控性。開發者無需深厚的機器學習專業知識,只需用幾行代碼結合提示和示例,就能高效地將自由文本轉換為結構化數據:它嘗試把 LLM 抽取變成了一套可控、可追溯的過程。 02 區別于直接LLM輸出的特點 與讓LLM直接嘗試生成 JSON 等結構化結果相比,LangExtract 提供了一整套機制來保證抽取結果的準確、穩定和易用。其主要特點包括:
以上這些特性使得 LangExtract 將大模型從一個不可控的“黑盒”變成了開發者手中可定制、可追蹤的工具。特別是對于追求嚴格數據質量和合規性的企業應用來說,這種嚴格的控制力正是我們非常需要的。 03 實例演示:LangExtract抽取醫學報告 LangExtract 的核心思想最早正是應用于醫學信息抽取研究:例如從臨床筆記中自動識別藥物名稱、劑量、頻率、適應癥狀等用藥信息,并構建信息間的關系 。 我們通過一個簡單示例演示 LangExtract 在該領域的應用。在該示例中,LangExtract從雜亂的病人記錄里提取出用藥清單,包括藥物名稱、用法用量,以及不同藥物之間的分組關系等,實現了對非結構化病歷到結構化用藥報告的自動化轉換。 使用LangExtrace進行結構化信息抽取的基本步驟如下: 【基礎抽取】 這里逐步完成一個基礎示例:
import textwrap
import langextract as lx
from langextract.factory import ModelConfig
# 提取指令
prompt_description = textwrap.dedent('''提取藥物信息,包括藥物名稱、劑量、給藥途徑、頻率和持續時間,按照它們在文本中出現的順序提取。
''')
input_text = '患者服用了400毫克口服布洛芬,每4小時一次,持續兩天。'
#配置模型 - 明確指定OpenAI提供者
model_config = ModelConfig(
model_id='qwen3-14b',
provider='OpenAILanguageModel', # 明確指定使用OpenAI提供者
provider_kwargs={
'temperature': 0.1,
'max_tokens': 2048,
'base_url': 'your-base-url',
'api_key': 'your-api-key'
}
)
result_ner = lx.extract(
text_or_documents=input_text,
prompt_description=prompt_description,
examples=examples_ner,
config=model_config, # 使用 ModelConfig
fence_output=True,
use_schema_constraints=False,
debug=False
)
LangExtract的解析結果為Extraction類型的對象列表,它代表了抽取信息的完整結構。它是一個數據結果的容器,包含有如下信息:
上面的簡單例子中簡單的打印了extraction_class與extraction_text信息: 此外,我們把結果可視化到了一個html文件。通過它你可以直觀的查看提取的實體列表及其在原文本的位置(追溯)。 遺憾的是,目前LangExtraction版本的可視化(visualization)功能對中文支持不完善。如果是英文環境,利用輸出的html文件,可看到類似如下的效果: 相信后續的版本將會對多語言環境支持的更好。 【關聯抽取】 實際應用中,可能需要把多個相關的抽取結果關聯在一起,比如在上例中,需要把一種藥物的名稱、用法、劑量等關聯到一起。這有兩種方法可以實現: 利用分組關聯多個實體 這種方法給每一個抽取實體賦予一個”分組“屬性,比如medication_group,這樣,具有共同分組屬性的實體就被自然的關聯起來,而你只需要修改提示詞和示例。 我們對上面的例子改造,引入更復雜的醫學文本(input_text): “患者上個月被開了利辛普利和二甲雙胍。他每天服用利辛普利10毫克治療高血壓,但經常漏服二甲雙胍500毫克劑量,應該每日兩次服用治療糖尿病。” 現在修改prompt和examples: prompt_description_re = textwrap.dedent('''提取藥物及其詳細信息,使用屬性將相關信息分組:
1. 按照實體在文本中出現的順序提取
2. 每個實體必須具有 'medication_group' 屬性,將其鏈接到相應的藥物
3. 一個藥物的所有詳細信息應該共享相同的 medication_group 值
''')
examples_re = [
lx.data.ExampleData(
text='患者服用阿司匹林100毫克每日一次用于心臟健康,以及辛伐他汀20毫克睡前服用。',
extractions=[
# 第一個藥物組
lx.data.Extraction(
extraction_class='medication',
extraction_text='阿司匹林',
attributes={'medication_group': '阿司匹林'}
),
lx.data.Extraction(
extraction_class='dosage',
extraction_text='100毫克',
attributes={'medication_group': '阿司匹林'}
),
lx.data.Extraction(
extraction_class='frequency',
extraction_text='每日一次',
attributes={'medication_group': '阿司匹林'}
),
lx.data.Extraction(
extraction_class='condition',
extraction_text='心臟健康',
attributes={'medication_group': '阿司匹林'}
),
# 第二個藥物組【省略】
]
)
] 這里通過medication_group把一個藥物相關的多個抽取實體關聯起來。現在,通過對抽取結果解析打印(代碼略),可以輕松查看每種藥物的關聯性質: 以實體為中心的屬性抽取 另外一種抽取方式是以藥物作為中心的抽取實體,而其他相關的性質則作為藥物實體的屬性抽取。提示與示例如下:
在調用lx.extract進行抽取與結果解析后,你應該得到與上面方式基本一致的結果。 04 實例演示:LangExtract超長文本抽取 如果你針對超長文本進行傳統的結構化信息提取(借助LLM),你可能會面臨模型理解能力下降(詳見大模型“大海撈針”測試結果)、性能低下、準確率不夠等問題。 LangExtract針對長文本的解析與抽取做了更多獨特的設計。 我們用一篇“漫威世界背景知識”的文本文件做測試,該文件共約23000個中文字符。文件中描述了大量漫威世界中的人物、關系、事件、組織等,很適合用來做復雜的結構化信息抽取與知識圖譜的測試。 首先仍然是設定prompt并提供examples: prompt_description = textwrap.dedent('''從給定的漫威宇宙文本中提取角色、能力、關系、組織和事件。
為每個實體提供有意義的屬性以增加上下文和深度。
重要提示:使用輸入文本中的確切文字作為 extraction_text,不要意譯。
按出現順序提取實體,不要重疊文本片段。注意:在漫威宇宙中,角色通常有多個身份、綽號、能力和隸屬組織。''')
example_data = [
ExampleData(
text='X教授是一位在漫威漫畫中的出版物《X戰警》中的虛構人物。X教授和至交好友萬磁王不同,他一心想讓變種人與人類能和平共處。',
extractions=[
Extraction(
extraction_class='角色',
extraction_text='X教授',
attributes={'身份': '變種人領袖', '能力': '心靈感應', '組織': 'X戰警', '目標': '人類變種人和平共處'}
),
Extraction(
extraction_class='角色',
extraction_text='萬磁王',
attributes={'身份': '變種人', '關系': 'X教授至交好友', '立場': '與X教授不同'}
),
Extraction(
extraction_class='組織',
extraction_text='X戰警',
attributes={'類型': '超級英雄團隊', '領袖': 'X教授', '成員': '變種人'}
),
Extraction(
extraction_class='關系',
extraction_text='至交好友',
attributes={'類型': '友誼', '人物1': 'X教授', '人物2': '萬磁王', '狀態': '理念不同'}
),
]
),
..... 接下來從文件中讀取內容進行解析,這里的解析參數有一些針對長文本的特殊設定:
這里省略后續的輸出打印部分,直接看最后的解析結果,一共提取1926個實體: ![]() 打印出提取的前十名角色及屬性: ![]() 前十名組織(這里看到一點瑕疵:X戰警這個組織出現了兩次): ![]() 重要事件的前十名: ![]() 最后總結下LangExtract在超長文檔解析上的一些設計策略:
05 總結與應用展望 LangExtract 為從非結構化文本中獲取洞察帶來了新的體驗和很多有效的改進——將 LLM 功能以一種更可控、可靠的方式應用于信息抽取,極大的解決了結果不可預期和不可溯源的問題,這對于企業場景中的應用具有重大的意義。 LangExtract可以在很多企業級場景中獲得應用:
LangExtract 已經發布在 PyPI 上,你可以輕松安裝并集成到自己的應用中,快去試試吧! |
|