SiameseUIE完整教程:test.py中extract_pure_entities函数调用详解
1. 为什么你需要读懂这个函数
你刚登录云实例,执行完python test.py,屏幕上刷出几行漂亮的实体结果——人物、地点清清楚楚,没有“杜甫在成”这种奇怪的碎片。但当你想把模型用到自己的业务里,比如从客服对话中精准抓取客户提到的城市,或者从历史文档里批量提取人物籍贯时,光靠运行脚本远远不够。
真正决定抽取质量的,不是模型权重文件,也不是config.json,而是test.py里那个不起眼却极其关键的函数:extract_pure_entities。它像一道精密的闸门,控制着原始文本如何被解析、如何与预定义实体对齐、如何过滤掉所有干扰项,最终输出干净、可直接入库的结果。
本教程不讲模型原理,不跑训练流程,也不堆砌环境配置。我们只聚焦一件事:手把手带你拆解extract_pure_entities的每一个参数、每一种调用方式、每一种结果形态,让你在5分钟内就能修改、复用、甚至迁移到自己的项目中。
你不需要懂Siamese结构,不需要重装PyTorch,甚至不需要打开IDE——所有操作都在终端里完成,所有代码都来自镜像内置的test.py。
2. 函数位置与调用上下文
2.1 它在哪?怎么被调用?
打开镜像中的test.py文件(路径:nlp_structbert_siamese-uie_chinese-base/test.py),向下滚动到约第120行附近,你会看到类似这样的调用块:
for i, example in enumerate(test_examples, 1): print(f"========== {i}. {example['name']} ==========") print(f"文本:{example['text']}") extract_results = extract_pure_entities( text=example["text"], schema=example["schema"], custom_entities=example.get("custom_entities") )这就是整个测试流程的核心引擎。每次循环,它接收一个测试样例的三要素:原始文本、抽取模式定义、以及最关键的——你要找哪些实体。
注意:
extract_pure_entities并非 PyTorch 或 transformers 库的原生函数,而是该镜像为适配受限环境专门封装的轻量级抽取接口。它不依赖任何外部NLP pipeline,全部逻辑内嵌在test.py中,这也是它能在系统盘≤50G、PyTorch不可改的环境下稳定运行的根本原因。
3. 参数详解:每个字段都决定结果质量
3.1text: str—— 你的输入就是它的全部世界
这是唯一强制参数,类型为字符串,代表你要分析的原始中文文本。
- 支持任意长度:从单句“张三住在杭州市”到百字段落“苏轼于元丰三年被贬黄州,在东坡筑屋耕种……”均可处理;
- 兼容标点与空格:中英文标点、全角半角、换行符均自动归一化;
- 不支持HTML/Markdown标签:若文本含
<p>北京</p>,函数会把<p>当作普通字符处理,可能干扰分词——请提前清洗。
实操建议:
如果你的数据来自网页爬虫或数据库导出,建议在传入前做一次基础清洗:
import re clean_text = re.sub(r'<[^>]+>', '', raw_text) # 去HTML标签 clean_text = re.sub(r'\s+', ' ', clean_text).strip() # 合并空白符3.2schema: dict—— 你告诉它“要抽什么”,它才不会乱猜
schema 是一个固定格式的字典,定义了本次抽取的任务类型和实体类别。镜像默认只支持两类:"人物"和"地点",格式必须严格如下:
{"人物": None, "地点": None}- 键名
"人物"和"地点"不可更改,大小写、中英文、增减空格均会导致报错; - 值必须为
None(Python空值),不能写成""、[]或False; - 可以只保留一个键,例如
{"人物": None}表示只抽人物,忽略所有地点。
为什么设计成这样?
因为 SiameseUIE 的魔改版本在推理层做了硬编码约束:它只识别这两个schema下的实体边界。这不是限制,而是保障——避免模型在“时间”“机构”等未训练类别上胡乱输出“伪实体”。
常见错误示例:
# 错误:键名拼错 {"renwu": None} # 报错:schema key not supported # 错误:值类型不对 {"人物": []} # 报错:schema value must be None # 正确:精简但合法 {"地点": None}3.3custom_entities: Optional[dict]—— 精准抽取的开关(最核心参数)
这是决定结果是否“无冗余”的关键开关。它有两种取值方式,对应两种完全不同的抽取逻辑:
方式一:传入字典 → 启用自定义实体匹配模式(默认且推荐)
格式必须为:
{ "人物": ["李白", "杜甫", "王维"], "地点": ["碎叶城", "成都", "终南山"] }- 严格子串匹配:函数会在
text中查找这些字符串的完整、连续出现,不切分、不模糊、不联想; - 零冗余保障:只返回列表中明确存在的实体,绝不会输出“杜甫在成”“终南”这类截断结果;
- 大小写敏感:
"李白"能匹配“李白”,但不匹配“李白(盛唐诗人)”中的括号内容——括号本身不参与匹配,仅作为上下文存在。
底层逻辑简述:
函数内部实际执行的是if entity in text:的暴力遍历(因实体列表通常<100项,效率远高于正则),再结合字符位置做去重合并(如“成都”和“成都市”同时存在时,优先保留更长的“成都市”)。
方式二:传入None→ 启用通用规则匹配模式(备用方案)
extract_pure_entities( text="周杰伦去了台北市,林俊杰在杭州市开演唱会", schema={"人物": None, "地点": None}, custom_entities=None # ← 关键:设为None )此时函数将启用内置正则规则:
- 人物:匹配连续2~4个汉字,且不在停用词表中(如“的”“了”“在”被排除);
- 地点:匹配含“市”“省”“县”“区”“城”“镇”“岛”“湾”等后缀的2~5字字符串;
重要提醒:此模式无法保证无冗余。例如文本“杜甫草堂在成都”,可能抽到“杜甫草堂”(误判为人名)、“成都”(正确)、“杜甫”(正确)、“草堂”(误判为地名)。它适合快速探查,但绝不适用于生产环境。
4. 返回结果结构:如何解析与使用
extract_pure_entities的返回值是一个标准 Python 字典,结构清晰,无需额外解析:
{ "人物": ["李白", "杜甫", "王维"], "地点": ["碎叶城", "成都", "终南山"] }- 键名与
schema完全一致,顺序无关; - 值为去重后的字符串列表,已按原文首次出现顺序排列;
- 若某类实体未匹配到,对应键值为空列表
[],不会缺失该键; - 所有字符串均为原文中原始字形,不做繁简转换、不补全(如“北京市”不会变成“北京”)。
实用处理技巧:
# 场景:只取第一个地点用于地址归一化 result = extract_pure_entities(text, schema, custom_entities) first_location = result["地点"][0] if result["地点"] else "未知地点" # 场景:合并所有人名,用顿号连接 names_joined = "、".join(result["人物"]) if result["人物"] else "无人物"5. 实战:3种典型修改场景与代码示例
5.1 场景一:添加你自己的测试文本(5秒完成)
打开test.py,找到test_examples列表(通常在文件顶部附近),在末尾追加一个字典:
test_examples = [ # ... 原有5个例子 { "name": "自定义例子:电商客服对话", "text": "用户说他在深圳市福田区华强北买了iPhone,发货地是郑州市。", "schema": {"人物": None, "地点": None}, "custom_entities": { "人物": [], # 此处留空,表示不抽人物 "地点": ["深圳市", "福田区", "华强北", "郑州市"] # 明确指定要抽的地点 } } ]效果:下次运行python test.py,第6个例子将只返回["深圳市", "福田区", "华强北", "郑州市"],其他无关地点(如“iPhone”里的“i”)被彻底过滤。
5.2 场景二:切换为通用模式,快速验证新文本
假设你有一批未标注的新闻摘要,想先看看模型大概能抽到什么,再决定是否构建 custom_entities:
# 修改原调用(在 test.py 中找到对应行) # 原来是: # extract_results = extract_pure_entities(text=..., schema=..., custom_entities=...) # 改为: extract_results = extract_pure_entities( text="马斯克宣布特斯拉将在上海市建第二工厂,预计2025年投产。", schema={"人物": None, "地点": None}, custom_entities=None # ← 关键改动 )输出示例:
- 人物:马斯克 - 地点:上海市、2025年 # 注意:“2025年”被误判为地点(含“年”字),需人工校验提示:通用模式结果需人工复核。建议仅用于初期数据探查,确认高频实体后,再回填到
custom_entities中。
5.3 场景三:扩展为单类别抽取(专注地点,屏蔽人物)
你的业务只要城市名,人物信息全是噪声。只需两步:
- 修改 schema:只保留
"地点"键; - custom_entities 中人物列表置空:
extract_results = extract_pure_entities( text="张三和李四昨天去了北京和上海。", schema={"地点": None}, # ← 删除"人物"键 custom_entities={ "地点": ["北京", "上海", "广州市", "深圳市"] # 仅维护地点列表 } )输出:
- 地点:北京,上海为什么比删代码更安全?
直接注释掉人物相关逻辑可能导致模型加载失败(镜像依赖完整schema初始化)。而通过 schema 控制,既安全又符合设计契约。
6. 避坑指南:90%的报错都源于这4个细节
| 问题现象 | 根本原因 | 一行解决命令 |
|---|---|---|
KeyError: '人物' | schema字典里漏写了"人物"键,或拼写错误 | 检查schema = {"人物": None, "地点": None}是否完整 |
TypeError: expected str, bytes or os.PathLike object | text参数传入了None或数字(如123) | 确保text=str(your_variable)强制转字符串 |
抽取结果为空列表[] | custom_entities中的实体在text中完全未出现(注意全角/半角、空格、标点) | 用print(repr(text))查看真实字符,确认实体是否原样存在 |
| 运行卡住无输出 | 模型首次加载需从/tmp解压权重,实例磁盘满或/tmp权限异常 | 执行df -h /tmp查磁盘;若满,清理/tmp/*后重试 |
7. 总结:你已经掌握了SiameseUIE最实用的能力
读完本教程,你不再只是“运行脚本看结果”的使用者,而是能精准控制抽取行为的实践者:
- 你知道
extract_pure_entities的三个参数各司何职,尤其是custom_entities如何成为无冗余的保险栓; - 你能5秒内新增测试用例,也能10秒切换通用/自定义模式;
- 你理解返回字典的结构,能直接对接数据库或前端展示;
- 你掌握了4个高频报错的定位方法,遇到问题不再盲目重启。
最重要的是:这一切都不需要你动一行模型代码,不依赖额外GPU,不修改PyTorch版本——它就安静地躺在test.py里,等待你用最朴素的方式调用。
下一步,把你业务中最常处理的10条文本,填进custom_entities,跑一遍python test.py。当第一行干净的“- 地点:杭州市”出现在终端时,你就完成了从教程到落地的第一公里。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。