命名实体识别 NER:从标注到上线
经验驱动。实体识别是信息抽取的第一步,也是搜索、知识图谱、风控的底层能力。本文用本机真实跑通的
bert4ner-base-chinese讲清楚:模型怎么抽、真实输出长什么样、有哪些坑,以及一条能从”标注”走到”上线”的完整链路。
什么是 NER
命名实体识别(Named Entity Recognition)是从文本里找出实体并给它们分类,比如人名、机构名、地名、时间。它是序列标注任务:给每个 token 打标签。
最常用两套标注体系:
- BIO:B-实体(开头)、I-实体(中间/结尾)、O(非实体)。例如
李/B-PER 明/I-PER。 - BIOES:在 BIO 基础上加 E(结尾)、S(单字实体),边界更精确,评估时更不容易歧义。
中文 NER 比英文难在:没有空格分词,实体边界要靠模型自己学;还有大量未登录词(新公司名、英文名实体)。
真跑:用 bert4ner 抽实体
bert4ner-base-chinese 是基于 bert-base-chinese 的中文 NER 模型,标签体系是 B/I-PER、B/I-ORG、B/I-LOC、B/I-TIME、O。本机推理代码:
1 | from transformers import pipeline |
aggregation_strategy="simple" 会把同一个实体的子词自动合并成一个 span。
真实输出(本机,原样,含置信度)
1 | SENT: 李明在北京大学参观了腾讯公司的总部。 |
真实踩坑(这些才是面试能讲的东西)
1. “北京大学”被标成 ORG 而不是 LOC。
按常识北大是地点,但模型给的是 ORG(0.997)。原因:训练数据里”大学/学院/医院”这类常被标注为机构,模型学到了”机构优先”。上线的教训:实体类型定义要和你的业务一致,必要时在自有数据上继续微调,别直接信通用模型的类型划分。
2. TIME 置信度明显偏低(0.824)。
“2023年”被识别为 TIME 但置信度只有 0.824,远低于其他实体的 0.99。时间表达式变化多(”去年””下周三””2023年Q3”),模型泛化弱。上线的教训:时间类实体要单独补规则或词典(正则 + 候选日历)兜底,不能只靠模型。
3. “特斯拉”被漏召回。
第四句只抽出”上海市政府”,**”特斯拉”完全没识别,更别说”超级工厂”。这是未登录词 + 英文实体的典型失效。上线的教训:对产品名、英文名实体要做词典/别名词典增强,或接入一个实体链接(entity linking)环节。**
4. 输出带空格分词(”李 明”)。
BERT 中文是按字切的,聚合后字段里带空格,要后处理拼回原词、并和原文 offset 对齐,否则展示会错位。
从标注到上线的完整链路
- 定标注规范:选 BIO 还是 BIOES;定实体类型(PER/ORG/LOC/TIME/…),写标注指南,避免”北大算机构还是地点”这类歧义。
- 标数据:小样本用
doccano等工具标注;中文可用CLUENER、MSRA等公开语料冷启动。 - 训练:用
transformers的Trainer+AutoModelForTokenClassification,num_labels按标签数设,loss 用默认的 cross-entropy(序列标注通常不上 CRF 也能work,bge/bert4ner 都是直接 softmax)。 - 评估:必须用 entity-level(span 级)指标,不是 token-level。用
seqeval直接算实体级别的 P/R/F1,因为它要求类型和边界都对齐才算对。 - 服务化:用 FastAPI 包成
/ner接口,输入文本、输出实体列表;加后处理(拼接子词、过滤置信度 < 阈值、按类型分组)。 - 兜底增强:时间/数字用正则,产品名/英文名用语义词典,低置信实体走人工复核队列。
面试常考点
- BIO vs BIOES:BIOES 边界更清晰,评估更稳;BIO 标注成本低。
- 为什么评估用 entity-level:token-level 会让”标错一个字但整体对”被惩罚过重,且无法反映真实抽取质量;
seqeval是标准做法。 - 序列标注 vs span-based(如 SpanBERT):序列标注简单成熟;span-based 直接预测片段,长实体更友好但计算量大。
- CRF 还有没有必要:现代预训练模型 + softmax 往往够用,CRF 在标签强约束场景(如嵌套实体)仍有价值。
小结
NER 不是一个 pipeline 调用就结束的活。本机真跑让我看清了通用模型的三个真实短板(类型偏差、时间弱、未登录词漏召),这些恰恰是决定它能不能上线的关键。标注规范 + 实体级评估 + 兜底增强,才是从 demo 到生产的差距。


