導讀:本文介紹科技大廠 Google 2025年 7 月最新開源的 Python 庫:
LangExtract
,用于從非結構文本提取結構化數據,以及非官方的Javascript
、Rust
語言實現版本。
文章目錄
- 一、關于 LangExtract
- 1.1 需求痛點
- 1.2 LangExtract
- 1.3 參考文章
- 二、小試牛刀
- 2.1 安裝依賴
- 2.2 簡單的人物信息抽取
- 2.3 提取公共資源交易信息
- 2.3.1 準備示例
- 2.3.2 運行結果
- 三、JavaScript 版本
- 四、Rust 版本
- 4.1 程序跑不起來😔
- 4.2 成功運行🎉
- 4.3 未來展望 🚀
- Java 版本
一、關于 LangExtract
1.1 需求痛點
很多時候,我們需要在一堆非標準的文本里面提取特定的字段(比如提取人名
、電話
、地址
等),形成結構化的數據,如保存到 Excel 。數據量不大的情況下,人工就能勝任。如果量很大,就得借助程序(使用規則匹配)來清洗,這種方式比人工高效,但出錯率也高。因為程序是非常死板
的,只認設定好的規則
(不會變通),而人工可以在各種未預見的情況下,依然能找到正確的數據,程序則由于不理解自然語言與答案失之交臂😂。
1.2 LangExtract
LangExtract : A Python library for extracting structured information from unstructured text using LLMs with precise source grounding and interactive visualization.
一個 Python 庫,用于使用具有精確源基礎和交互式可視化的 LLM 從非結構化文本中提取結構化信息。
這個庫是 Google 在 2025 年 7 月底發布,目前最新版本是 1.0.8(截至2025-08-22),具有以下特點:
- 精確的源頭定位:能將每次提取的內容映射到源文本中的確切位置,可通過可視化突出顯示進行追溯和驗證。
- 可靠的結構化輸出:基于少量示例強制執行一致的輸出模式,利用Gemini等支持模型中的受控生成來保證強大的結構化結果,輸出可直接接入數據庫等下游流程。
- 針對長文檔優化:通過優化文本分塊、并行處理和多次傳遞的策略,克服大型文檔提取中的困難,提高召回率,能處理完整的小說級別的文檔。
- 交互式可視化:可即時生成一個獨立的交互式HTML文件,以可視化和審查數千個提取的實體及其原始上下文,方便審核和錯誤分析。
- 靈活的LLM支持:支持用戶偏好的模型,從Google Gemini系列等基于云的LLM到通過內置Ollama接口的本地開源模型都可使用。
- 適應任何領域:只需幾個示例,即可為任何領域定義提取任務,無需進行模型微調就能適應用戶需求。
LangExtract 在醫療、金融、法律、科研等領域都有廣泛的應用前景,例如從臨床記錄中提取藥物名稱、劑量,從合同中提取責任條款、風險項等。
1.3 參考文章
- 谷歌出品!詳解“小而美” 的LangExtract:輕量卻強大的結構化信息提取神器。
- 谷歌開源LangExtract:三行代碼把“文本礦山”變結構化黃金,AI信息抽取從未如此簡單!
二、小試牛刀
本文我們將使用豆包大模型進行實踐😄。
2.1 安裝依賴
mkdir langextract
# 創建虛擬環境
python -m venv .env
source .env/bin/activate # On Windows: .env\Scripts\activate
# 安裝依賴
pip install langextract openai
2.2 簡單的人物信息抽取
import langextract as lx# 定義示例
examples = [lx.data.ExampleData(text = "梁思成(1901年4月20日-1972年1月9日),籍貫廣東新會,生于日本東京。畢生致力于中國古代建筑的研究和保護,是建筑歷史學家、建筑教育家和建筑師,被譽為中國近代建筑之父。",extractions=[lx.data.Extraction(extraction_class="姓名", extraction_text="梁思成"),lx.data.Extraction(extraction_class="出生日期", extraction_text="1901年4月20日"),lx.data.Extraction(extraction_class="逝世日期", extraction_text="1972年1月9日"),lx.data.Extraction(extraction_class="出生地", extraction_text="日本東京"),lx.data.Extraction(extraction_class="職業", extraction_text="建筑歷史學家、建筑教育家、建筑師"),lx.data.Extraction("榮譽", "中國近代建筑之父")]),lx.data.ExampleData(text = "林徽因(1904年6月10日-1955年4月1日),原名“徽音”,漢族,祖籍福建閩侯(今福建福州),出生于浙江杭州。為中國近現代建筑學家、文學家,清華大學建筑系教授。",extractions=[lx.data.Extraction(extraction_class="姓名", extraction_text="林徽因"),lx.data.Extraction(extraction_class="出生日期", extraction_text="1904年6月10日"),lx.data.Extraction(extraction_class="逝世日期", extraction_text="1955年4月1日"),lx.data.Extraction(extraction_class="出生地", extraction_text="浙江杭州"),lx.data.Extraction(extraction_class="職業", extraction_text="建筑學家、文學家"),lx.data.Extraction("榮譽", "")])
]# 配置模型并調用解析程序
result = lx.extract(text_or_documents="古龍(1938年6月7日一1985年9月21日),原名熊耀華,籍貫江西南昌,漢族。1938年6月7日出生于香港。武俠小說家,新派武俠小說泰斗,與金庸、梁羽生、溫瑞安并稱為中國武俠小說四大宗師。",prompt_description="從人物簡要介紹中提取姓名、出生日期、逝世日期(如有)、出生地、職業、榮耀/成就",examples = examples,config= lx.factory.ModelConfig(model_id="doubao-seed-1-6-flash-250615",provider="OpenAILanguageModel",provider_kwargs={"temperature" : 0.1,"max_tokens" : 2048,"base_url" : "https://ark.cn-beijing.volces.com/api/v3","api_key" : ""})
)for entity in result.extractions:position_info = ""if entity.char_interval:start, end = entity.char_interval.start_pos, entity.char_interval.end_posposition_info = f" (位置: {start}-{end})"print(f"? {entity.extraction_class.capitalize()}: {entity.extraction_text}{position_info}")
我們執行python index.py
,大概 5 秒就能看到結果。
2.3 提取公共資源交易信息
我之前寫過一篇Chrome插件 | 公共資源交易平臺中標公示數據采集工具(僅作技術交流學習)的文章,里面就涉及結構化信息提取,當時用的是專家規則+正則表達式
從文本中匹配結果,現在讓我們試下 langextract 是否能做的更好😄。
2.3.1 準備示例
2.3.2 運行結果
從上面的結果來看,提取的數據是準確的(耗時大概10秒),不過還多了一個結果(數據基本是空白),可以在程序中控制只要第一個結果即可😄。
借助 AI 理解自然語言,從中提取出想要的信息,是一條比專家規則更合適的路,雖然目前在時效上會久些,不過不是什么嚴重問題。
三、JavaScript 版本
在 github 上有一個 typescript 版本的實現:kmbro/langextract-typescript。
A TypeScript translation of the original Python LangExtract library by Google LLC. This library provides structured information extraction from text using Large Language Models (LLMs) with full TypeScript support, comprehensive visualization tools, and a powerful CLI interface.
import { extract } from "langextract"/**@type {Array<import("langextract").ExampleData>} */
const examples = [{text:"梁思成(1901年4月20日-1972年1月9日),籍貫廣東新會,生于日本東京。畢生致力于中國古代建筑的研究和保護,是建筑歷史學家、建筑教育家和建筑師,被譽為中國近代建筑之父。",extractions:[{ extractionClass:"姓名", extractionText:"梁思成"},{ extractionClass:"出生日期", extractionText:"1901年4月20日"},{ extractionClass:"逝世日期", extractionText:"1972年1月9日"},{ extractionClass:"出生地", extractionText:"日本東京"},{ extractionClass:"職業", extractionText:"建筑歷史學家、建筑教育家、建筑師"},{ extractionClass:"榮譽", extractionText:"中國近代建筑之父"}]},{text:"林徽因(1904年6月10日-1955年4月1日),原名“徽音”,漢族,祖籍福建閩侯(今福建福州),出生于浙江杭州。為中國近現代建筑學家、文學家,清華大學建筑系教授。",extractions:[{ extractionClass:"姓名", extractionText:"林徽因" },{ extractionClass:"出生日期", extractionText:"1904年6月10日"},{ extractionClass:"逝世日期", extractionText:"1955年4月1日"},{ extractionClass:"出生地", extractionText:"浙江杭州"},{ extractionClass:"職業", extractionText:"建筑學家、文學家"},{ extractionClass:"榮譽", extractionText:""}]}
]extract("古龍(1938年6月7日一1985年9月21日),原名熊耀華,籍貫江西南昌,漢族。1938年6月7日出生于香港。武俠小說家,新派武俠小說泰斗,與金庸、梁羽生、溫瑞安并稱為中國武俠小說四大宗師。",{promptDescription :"從人物簡要介紹中提取姓名、出生日期、逝世日期(如有)、出生地、職業、榮耀/成就",examples,modelType : 'openai',modelId : 'doubao-seed-1-6-flash-250615',baseURL : 'https://ark.cn-beijing.volces.com/api/v3',apiKey : '',temperature : 0.1,debug : true}
)
.then(result=>{console.debug(`documentId=${result.documentId}`)console.debug(result.extractions)
})
.catch(e=>console.debug(e))
很遺憾,這個代碼執行后沒有任何結果😔,感覺是對大模型的兼容性還不夠高。
四、Rust 版本
目前我在 github 找到兩個 Rust 的實現:modularflow/langextract-rust、daleione/langextract。
從文檔的質量及 crates.io 下載量來看,langextract-rust
更勝一籌,所以我選擇了它😎。
另外提一句,daleione/langextract 提交到 crates.io 的庫應該是搞錯了,依賴下載后是貨不對板的一個示例函數(間下圖),估計是作者沒上傳最新的版本。
4.1 程序跑不起來😔
按照文檔寫了一段代碼,還是上面一樣的人物信息識別,不出意外報錯了。 報的是ConfigurationError("Custom provider inference not yet implemented")
,我在 github 上提了 issue,希望能夠得到解決。
4.2 成功運行🎉
經過排查,發現上述的錯誤是因為代碼本身并沒有實現Custom provider inference
,
那要怎么樣才能使用豆包大模型呢?
一番努力后,終于被我找到了破解之法。
use langextract_rust::{extract, ExtractConfig,data::{ExampleData, Extraction},providers::ProviderConfig,
};#[tokio::main]
async fn main()-> Result<(), Box<dyn std::error::Error>> {// 獲取環境變量,不存在會返回 Errlet api_key = std::env::var("API_KEY").expect("請設置 API_KEY 環境變量");// 提取示例let examples = vec![ExampleData::new("梁思成(1901年4月20日-1972年1月9日),籍貫廣東新會,生于日本東京。畢生致力于中國古代建筑的研究和保護,是建筑歷史學家、建筑教育家和建筑師,被譽為中國近代建筑之父。".to_string(),vec![Extraction::new("姓名".to_string(), "梁思成".to_string()),Extraction::new("出生日期".to_string(), "1901年4月20日".to_string()),Extraction::new("逝世日期".to_string(), "1972年1月9日".to_string()),Extraction::new("出生地".to_string(), "日本東京".to_string()),Extraction::new("職業".to_string(), "建筑歷史學家、建筑教育家、建筑師".to_string()),Extraction::new("榮譽".to_string(), "中國近代建筑之父".to_string())]),ExampleData::new("林徽因(1904年6月10日-1955年4月1日),原名“徽音”,漢族,祖籍福建閩侯(今福建福州),出生于浙江杭州。為中國近現代建筑學家、文學家,清華大學建筑系教授。".to_string(),vec![Extraction::new("姓名".to_string(), "林徽因".to_string()),Extraction::new("出生日期".to_string(), "1904年6月10日".to_string()),Extraction::new("逝世日期".to_string(), "1955年4月1日".to_string()),Extraction::new("出生地".to_string(), "浙江杭州".to_string()),Extraction::new("職業".to_string(), "建筑學家、文學家".to_string()),Extraction::new("榮譽".to_string(), "".to_string())])];// 配置大模型let custom_config = ProviderConfig::openai_compatible("https://ark.cn-beijing.volces.com/api/v3","doubao-seed-1-6-flash-250615",Some(api_key.clone()));let extract_config = ExtractConfig {language_model_params:{let mut params = std::collections::HashMap::new();params.insert("provider_config".to_string(), serde_json::to_value(&custom_config)?);params},debug: false,..Default::default()};let result = extract("古龍(1938年6月7日一1985年9月21日),原名熊耀華,籍貫江西南昌,漢族。1938年6月7日出生于香港。武俠小說家,新派武俠小說泰斗,與金庸、梁羽生、溫瑞安并稱為中國武俠小說四大宗師。",Some("從人物簡要介紹中提取姓名、出生日期、逝世日期(如有)、出生地、職業、榮耀/成就"),&examples,extract_config).await?;println!("? Extracted {} items", result.extraction_count());// Show extractions with character positionsif let Some(extractions) = &result.extractions {for extraction in extractions {println!("? [{}] '{}' at {:?}",extraction.extraction_class,extraction.extraction_text,extraction.char_interval);}}Ok(())
}
運行代碼,得到以下的結果?。個人覺得我設置了 debug=false
,應該不顯示運行時日志才對,就跟 python 版本一樣默默返回結果。
4.3 未來展望 🚀
我計劃做一個帶 GUI 的結構化信息提取程序,基于 Tauri,所以有一個能用的 rust 版本 langextract 尤為重要😄。
Java 版本
目前我還沒有找到 Java 實現的版本,是不是一個機會😄?