LangExtract 日语信息抽取实战:UnicodeTokenizer、lx.extract 全流程与字符位置对齐 LangExtract 日语信息抽取实战UnicodeTokenizer、lx.extract 全流程与字符位置对齐【免费下载链接】langextractA Python library for extracting structured information from unstructured text using LLMs with precise source grounding and interactive visualization.项目地址: https://gitcode.com/GitHub_Trending/la/langextract本篇技术指南基于 LangExtract 仓库中的日语抽取示例文档docs/examples/japanese_extraction.md讲解如何从日语这类无空格分隔的语言文本中抽取结构化实体。读完本文你将掌握为什么日语必须使用UnicodeTokenizer而非默认分词器、lx.extract()完整流水线的各参数含义、UnicodeTokenizer的源码级分词机制grapheme 聚类、CJK 强制碎片化以及抽取结果如何携带精确的字符位置区间char_interval完成来源定位。问题背景日语为什么需要专用分词器LangExtract 的核心能力之一是将 LLM 返回的抽取文本精确对齐回源文档的字符位置source grounding从而实现可验证、可可视化的抽取结果。对齐过程依赖分词tokenization把文本切分为带位置信息的 token再在其中定位抽取文本。默认的RegexTokenizer定义见 langextract/core/tokenizer.py基于正则模式[^\W\d_]英文字母序列、\d数字和符号组来切分。对英文这类以空格分词的语言非常高效但日语文本如「東京出身の田中さんはGoogleで働いています。」中汉字、假名之间没有空格。从源码结构看若使用默认分词器CJK 字符序列会按[^\W\d_]被整段合并成少数大 token如「東京出身の田中さん」可能成为一个 token导致田中这样的实体无法在 token 层面精确框定对齐质量会显著下降。因此文档给出了明确提示对日语这类无空格语言应使用UnicodeTokenizer以保证基于字符的正确分词与对齐For non-spaced languages like Japanese, useUnicodeTokenizerto ensure correct character-based segmentation and alignment.。完整流程示例从日语文本中抽取人名、地名、组织下面是原示例文档中的完整可运行示例。输入是「Mr. Tanaka from Tokyo works at Google.」的日语翻译抽取目标为 Person人名、Location地名、Organization组织三类命名实体import langextract as lx from langextract.core import tokenizer # Japanese text with entities (Person, Location, Organization) # Mr. Tanaka from Tokyo works at Google. input_text 東京出身の田中さんはGoogleで働いています。 # Define extraction prompt prompt_description Extract named entities including Person, Location, and Organization. # Define example data (few-shot examples help the model understand the task) examples [ lx.data.ExampleData( text大阪の山田さんはソニーに入社しました。, # Mr. Yamada from Osaka joined Sony. extractions[ lx.data.Extraction(extraction_classLocation, extraction_text大阪), lx.data.Extraction(extraction_classPerson, extraction_text山田), lx.data.Extraction(extraction_classOrganization, extraction_textソニー), ] ) ] # 1. Initialize the UnicodeTokenizer # Essential for Japanese to ensure correct grapheme segmentation. unicode_tokenizer tokenizer.UnicodeTokenizer() # 2. Run Extraction with the Custom Tokenizer result lx.extract( text_or_documentsinput_text, prompt_descriptionprompt_description, examplesexamples, model_idgemini-3.5-flash, tokenizerunicode_tokenizer, # --- Pass the tokenizer here api_keyyour-api-key-here # Optional if env var is set ) # 3. Display Results print(fInput: {input_text}\n) print(Extracted Entities:) for entity in result.extractions: position_info if entity.char_interval: start, end entity.char_interval.start_pos, entity.char_interval.end_pos position_info f (pos: {start}-{end}) print(f• {entity.extraction_class}: {entity.extraction_text}{position_info}) # Expected Output: # Input: 東京出身の田中さんはGoogleで働いています。 # # Extracted Entities: # • Location: 東京 (pos: 0-2) # • Person: 田中 (pos: 5-7) # • Organization: Google (pos: 10-16)示例的关键点逐一说明lx.data.ExampleData/lx.data.Extractionlangextract.data是一个向后兼容模块langextract/data.py 实际是兼容性 shim把全部符号从 langextract/core/data.py 重新导出。Extraction的核心字段是extraction_class实体类别、extraction_text实体文本以及用于结果对齐的char_interval见后文。few-shot 示例用于让模型理解任务格式并参与生成输出 schema 约束。model_idgemini-3.5-flashmodel_id会被 provider 路由解析为具体的模型提供者。API key 除了显式传入api_key参数外也可走环境变量从 langextract/factory.py 的实现看Gemini 类模型会依次尝试GEMINI_API_KEY和LANGEXTRACT_API_KEYGPT 类模型尝试OPENAI_API_KEY和LANGEXTRACT_API_KEY若同时检测到多个 key 会发出警告并取第一个。tokenizerunicode_tokenizer这是本示例的核心改动将自定义分词器注入抽取管线机制见下一节。期望输出中的pos区间0-2即字符text[0:2] 「東京」5-7对应「田中」10-16对应「Google」。这是左闭右开的字符索引约定。源码解析UnicodeTokenizer 如何切分日语UnicodeTokenizer定义于 langextract/core/tokenizer.py其类 docstring 明确了三个设计要点基于 Unicode 标准的 grapheme 聚类分词循环使用regex库的\X模式regex.finditer(r\X, text)见 tokenizer.py#L352。\X对应 Unicode 标准附录 #29 定义的扩展词群extended grapheme cluster能正确把 Emoji、韩文音节等组合字符当作整体处理而不是按码点机械拆分。不做 NFC 归一化与某些 Unicode 分词器不同UnicodeTokenizer不会把文本归一化为 NFC 形式。TokenizedText的 docstring 特别注明 For UnicodeTokenizer, this is NOT normalized to NFC (to preserve indices)。这一设计保证了 token 上的字符索引与原始输入字符串严格一致——这正是char_interval位置信息可靠的前提。性能取舍由于逐 grapheme 聚类UnicodeTokenizer比RegexTokenizer慢文档注释也指出RegexTokenizer对英文更快因为跳过了复杂的 Unicode 处理。因此只在处理日/韩/泰等无空格语言时才切换分词器。CJK 强制碎片化是该分词器对日语最关键的行为。源码中定义了两个模式tokenizer.py#L249-L254_CJK_PATTERN regex.compile( r\p{Is_Han}|\p{Is_Hiragana}|\p{Is_Katakana}|\p{Is_Hangul} ) _NON_SPACED_PATTERN regex.compile( r\p{Is_Thai}|\p{Is_Lao}|\p{Is_Khmer}|\p{Is_Myanmar} )在合并逻辑中tokenizer.py#L370-L395当当前 token 类型为 WORD 时若当前或下一个字符命中_CJK_PATTERN/_NON_SPACED_PATTERNshould_merge强制为False即每个 CJK 字符汉字、平假名、片假名、韩文以及泰文、老挝文、高棉文、缅文字符都单独成为一个 token绝不互相合并。对示例句「東京出身の田中さんは…」「東京」会被切成「東」「京」两个 token各自携带精确的字符区间。这样田中第 5-7 字符就对应连续 token 区间resolver 可以精确重建出CharInterval(5, 7)。而 Google 这类拉丁字母序列仍按同脚本合并为单个 token脚本判定有 ASCII 快速路径和按脚本分组逻辑见_get_script_fasttokenizer.py#L273-L279。此外token 类型由unicodedata.category判定L 开头为 WORDN 开头为 NUMBER其余为 PUNCTUATION见 _classify_grapheme所以句读「。」会作为 PUNCTUATION token 独立切出而不是黏附在相邻词上。句界识别也覆盖日语标点_END_OF_SENTENCE_PATTERN为[.?!。\u0964]tokenizer.py#L152即日文句号「。」和感叹/疑问号「」都是句子终止符。find_sentence_range()tokenizer.py#L580-L647利用这些标点 token 和换行 首字母大写规则切分句子为小上下文场景确定句子边界。测试用例test_unicode_sentence_boundaries验证了这一点输入「こんにちは。」被切为 6 个 token——注释明确写道 こんにちは (5 tokens due to CJK fragmentation) 。 (1 token) 6 tokenstests/tokenizer_test.py#L969-L975恰好印证了 CJK 逐字碎片化行为。tokenizer 参数在 extract() 管线中的位置extract()的签名中tokenizer是一个显式参数langextract/extraction.py#L74docstring 说明其用途Optional Tokenizer instance to use for chunking and alignment. If None, defaults to RegexTokenizer.用于切块chunking与对齐alignment缺省为RegexTokenizer见 extraction.py#L91-L92。从源码结构看分词结果在管线中承担两个职责与 tokenizer.py 模块 docstring 一致对齐alignmentlangextract/resolver.py 负责把 LLM 的原始文本输出解析为结构化Extraction对象并把每个抽取文本对齐回源文档。对齐算法在 token 序列上运行精确匹配默认使用 DP 动态规划模糊匹配使用 LCS见 resolver.py#L57-L85 中的_FUZZY_ALGORITHM_LCS、_EXACT_ALGORITHM_DP等常量。分词越贴合目标语言的书写特征token 级匹配就越准char_interval也就越精确。句子/上下文切分find_sentence_range()基于 token 序列确定句子边界用于构建较小的上下文片段。Tokenizer是抽象基类tokenizer.py#L165-L177只需实现tokenize(text) - TokenizedText因此你也可以继承它来自定义分词策略而lx.extract()会接受任何该基类的实例。lx.tokenizer顶层惰性模块也直接指向langextract.tokenizerlangextract/init.py#L64-L84所以示例中使用from langextract.core import tokenizer与lx.tokenizer是等价路径。结果结构Extraction 与 char_interval 的来源定位抽取结果中每个实体都是一个Extraction对象定义于 langextract/core/data.py。示例中打印entity.char_interval.start_pos / end_pos的字段语义如下char_intervalCharInterval源文本中的字符区间start_pos含边界、end_pos不含左闭右开。当抽取文本无法在源文档中定位时该字段为None示例代码中if entity.char_interval:的判空正是为此设计。alignment_statusAlignmentStatus标记对齐方式取值为MATCH_EXACT精确匹配、MATCH_GREATER/MATCH_LESSER模型输出与源文本长度不等或MATCH_FUZZY模糊匹配命中。除示例用到的两个字段外Extraction还支持description、attributescore/data.py#L80-L92等字段可用于带属性的抽取任务。对日语示例而言位置 0-2 / 5-7 / 10-16这类区间意味着下游可以做原文高亮、可视化核对lx.visualize或基于位置的聚合统计而不是只拿到一段模型声称的文本。运行前提与适用限制模型与密钥示例使用model_idgemini-3.5-flash需要可用密钥如上文所述api_key参数可省略的前提是对应环境变量GEMINI_API_KEY/LANGEXTRACT_API_KEY已设置。何时必须切换分词器处理日语、韩语以及泰语、老挝语、高棉语、缅甸语等无空格语言时建议使用UnicodeTokenizer纯英文场景保留默认RegexTokenizer即可更快。性能注意UnicodeTokenizer的逐 grapheme 聚类开销高于正则分词类注释中明确 Grapheme clustering makes this tokenizer slower than RegexTokenizer大批量文本时这一点会影响本地预处理耗时不影响 LLM 计费。验证方式仓库中 tests/tokenizer_test.py 覆盖了 CJK 字符扩展范围检测、CJK 不合并、Unicode 句界日文句号等用例可作为修改分词策略后的回归参照。综上该日语抽取示例展示了 LangExtract 处理无空格语言的完整路径用UnicodeTokenizer的逐字符碎片化分词换取 token 级对齐精度由extract()管线中的 resolver 将 LLM 输出对齐回char_interval最终得到带可验证字符位置的实体结果。【免费下载链接】langextractA Python library for extracting structured information from unstructured text using LLMs with precise source grounding and interactive visualization.项目地址: https://gitcode.com/GitHub_Trending/la/langextract创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考