邮局分拣员老张每天清晨都会收到成百上千封信,收件人一栏写着“海明威”“苹果”“李娜”这样的名字。可全市叫海明威的人有好几个,“苹果”可能是水果店的、也可能是科技公司的。老张的秘诀是:先翻开档案册,把所有同名的收件人筛出来(候选生成);再看信封上的邮编号、街道名和寄信人备注(上下文表示);综合判断这封信该投进哪扇门(消歧决策);偶尔拿不准的信件他会直接退回(阈值拒识)。实体链接要做的,正是让机器像老张一样“把名字指回正确的实体”——把文本中每一个实体指代,映射到知识库中唯一确定的那个实体条目上。这是知识图谱构建、智能问答、文档检索等场景最底层的“分拣能力”。
掌握实体链接与消歧,你就能让机器在“同名不同人”的歧义中做出准确判断,为知识图谱、问答系统和搜索服务打牢地基——这是 NLP 工程岗高频考察的核心技能。
目录
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
链接基本概念:一封没有地址的信
老张在邮局工作三十年,最头疼收件人只写一个“李明”的信。实体链接干的事,可以照着他的日常来理解:一封来信上写着“海明威”,必须弄清楚这“海明威”指的是谁——是写《老人与海》的作家,还是隔壁街的演员?所谓实体链接(Entity Linking),就是把文本中出现的实体指代(Entity Mention)——比如“海明威”“苹果”“李娜”——映射到知识库(Knowledge Base)中唯一对应的实体条目上。
实体(Entity)是知识库中一个确定的对象:“欧内斯特·海明威(作家)”是一个实体,“苹果公司”也是一个实体;指代(Mention)则是文本中称呼它的那段文字。知识库相当于全市居民的户籍档案,是所有候选实体的大本营。实体链接的完整流程分两步:候选生成——先从档案里筛出所有可能有关系的同名者;实体消歧——再根据上下文排除干扰,锁定唯一目标。
形式化地看,实体链接就是给定一个指代和它所在的上下文,求知识库中最可能的那个实体:
1. 输入指代与上下文:$m$ 是文本中出现的实体指代,比如“海明威”;$c$ 是包含它的句子或窗口,为判断提供线索。
2. 遍历知识库候选:$e \in \mathcal{KB}$ 表示在知识库 $\mathcal{KB}$ 中逐个枚举候选实体,相当于老张翻档案册把所有“海明威”找出来。
3. 计算后验概率:$P(e \mid m, c)$ 表示看到指代 $m$ 和上下文 $c$ 之后,候选实体 $e$ 是正确答案的概率,同时融合名字匹配与上下文线索。
4. 取概率最大者:$\arg\max$ 在所有候选中挑出概率最高的那一个,作为最终的链接结果。
老张最后把信投进挂着“作家”铭牌的信箱,任务完成。对他来说是直觉,对机器来说,就是上面这个“遍历候选、求最大概率”的判断过程。
候选生成方法:先翻档案,别大海捞针
老张不会把全市几百万居民挨个问一遍,而是先翻开档案册,把名字能对上的几个“海明威”筛出来。这就是候选生成(Candidate Generation)——在知识库中快速召回一小批“有可能”的实体,供后续的消歧环节精排。候选集是不是越大越好?不是。候选太大既拖慢速度又引入噪声,太小又会漏掉正确答案,所以候选生成的核心目标是高召回——把正确答案尽量捞进来,哪怕混入一些干扰项。
候选生成有三类经典手段。第一,词典匹配:预先构建“指代→实体”的映射词典,做精确或部分匹配;第二,拼写变体:处理大小写、全半角、错别字等写法差异,比如"Apple""apple““苹果”应该指向同一实体;第三,缩写扩写:把”NBA“扩成”美国职业篮球联赛“,把”中科院“扩成”中国科学院"再去匹配。此外还能借助搜索引擎或倒排索引做检索召回,把实体名、别名、描述全部建进索引。
评估两个名字是否可能指向同一个实体,常用编辑距离相似度:
1. 计算编辑距离:$\text{edit\_dist}(m, e)$ 表示把指代字符串 $m$ 改成实体名 $e$ 所需的最少字符增、删、改次数。
2. 按长度归一化:除以 $\max(|m|, |e|)$ 中较长的那个长度,把绝对次数转化成相对差异度,避免长字符串天然吃亏。
3. 翻转为相似度:用 $1$ 减去差异度,得到 $0$ 到 $1$ 之间的相似度,越接近 $1$ 越可能是同一个实体。
档案册翻完,老张手里攥着三张“海明威”的资料卡:作家、演员、城市。接下来要做的,是看信上写了什么,才能在三个人中选出唯一的收件人——这正是下一节的上下文表示。
上下文表示:信件内容透露的真实身份
老张翻出信纸,看到信里提到“《老人与海》”“诺贝尔奖”,他立刻倾向作家海明威。对机器而言,“读信纸”就是把指代周围的上下文转换成一个可计算的向量表示,再与候选实体的描述做相似度比较,这就是上下文表示(Context Representation)。
最简单的上下文表示是窗口词向量平均:取指代左右各若干个词,把每个词的词嵌入(Word Embedding)相加取平均,得到上下文向量。更精细的做法是 TF-IDF 加权:给“老人与海”“诺贝尔”这类有区分度的词更高权重,给“我们”“今天”这类高频无义词更低权重。进阶方案还有知识图谱嵌入(如 TransE),把候选实体的关系邻居也编成向量,让“作家海明威”与“诺贝尔奖得主”天然相近。
记指代左右窗口内的词为 $w_1, \dots, w_n$,上下文向量为:
1. 取窗口词序列:$w_1, \dots, w_n$ 是包含指代在内的句子中(如左右各 $5$ 个词)按顺序排列的词。
2. 映射为词向量:$\text{Emb}(w_i)$ 通过预训练词向量模型把每个词变成 $d$ 维稠密向量,语义相近的词在向量空间里距离也近。
3. 取平均得到上下文向量:$\frac{1}{n}\sum_{i=1}^{n}$ 对所有词向量逐维求平均,得到一个代表整个上下文的向量 $v_c$。
把“作家海明威”的描述向量与上下文向量 $v_c$ 做余弦相似度,得分最高者即为消歧结果。老张读完信,心里已有了答案——但他还会看看本批其他信上写了什么,以免两封信投进同一个信箱。
消歧决策机制:不只逐封看,还要全局权衡
老张渐渐发现,逐封信单独判断有时会出错:一次收到两封信,一封提“海明威”的小说,一封提“海明威”的球队,单独看都说得通,但结合寄件人彼此认识、且都属文艺圈,答案立刻明朗。这就是局部消歧(Local Disambiguation)与全局消歧(Global Disambiguation)的区别。
局部消歧只看当前指代自己的上下文,独立决策,实现简单、速度快,但忽略了实体间的语义一致性;全局消歧把同一文档内所有指代放在一起求解,要求链接出的实体彼此兼容——“海明威”指向作家时,同文档出现的“福克纳”“巴黎”也应指向与之相关的实体。常用的协同消歧思路是:先给每个实体打主题标签(如“文学”“体育”),再约束同一文档实体主题尽量一致,用图模型或贪心迭代求解。
形式化地,设文档中有 $k$ 个指代,全局消歧要找一组实体使得整体得分最高:
1. 列出全局方案:$e_1, \dots, e_k$ 是同一文档中 $k$ 个指代待分配的链接结果,构成一个整体组合方案。
2. 保留局部得分:$\prod_{i=1}^{k} P(e_i \mid m_i, c_i)$ 沿用之前的局部后验概率,方案中每个指代单独得分连乘。
3. 加入实体相容性:$\phi(e_i, e_j)$ 衡量两个实体共同出现在同一文档是否合理,同主题实体 $\phi$ 接近 $1$,互不相干则接近 $0$。
4. 全局求最大化:$\arg\max$ 遍历(或近似搜索)所有组合,选择整体乘积最大的那组方案。
此外,若最佳候选的得分仍低于阈值,系统应当“拒识”——把指代标记为不可链接或建议新建实体,而不是硬猜一个错误答案。这就像老张拿不准时把信退回发件人,而不是随手塞进某个信箱。
评估方法:月末考核,看投递准不准
邮局每月对老张考核:送出的信里,有几封送对了?该送的九十八封信里,有几封真正送达?这正好对应实体链接的两大核心指标——精确率(Precision)与召回率(Recall)。精确率衡量“链接结果里有多少是真正正确的”,召回率衡量“应当被链接的指代里有多少成功链接对了”。二者常常互相牵制:严格阈值提升精确率但漏掉不少指代,宽松阈值提升召回率却混入更多错误。
工程师会把两类错误记下来做误差分析:假阳性(FP)是把错误候选链接给了指代,假阴性(FN)是该链接却没链接对。为了用单值比较模型优劣,业界常用二者的调和平均 F1:
1. 精确率 P:$P = \frac{TP}{TP + FP}$ 即系统输出的链接结果中,真正正确(TP)占全部输出(正确加误报 FP)的比例。
2. 召回率 R:$R = \frac{TP}{TP + FN}$ 即所有本应正确链接的指代中,系统成功且正确(TP)所占的比例。
3. 调和平均 F1:$\frac{2PR}{P + R}$ 在两者间取平衡,任何一方过低都会显著拉低 F1。
评估必须在公开基准数据集(如 AIDA-CoNLL、TAC-KBP)上与其他系统对齐比较,否则自造数据无法说明问题。老张看着考核表上 82.8 的 F1 分数,心里盘算着:那些送错的信,到底是信封识别错了,还是判断地址时看漏了线索?这正是误差分析的意义。
与NER融合:让分拣员多一双“自动读地址”的眼
过去的老张,得人工把信封上的地址拆出来再分拣;现在的邮件中心先让扫描仪自动把“收件人、街道、城市”从信封上识别出来,老张只负责对着识别结果投递。这正是命名实体识别(NER)与实体链接(EL)的分工:NER 负责从文本中圈出实体指代并标注类型(人名、地名、组织名),实体链接负责把圈出来的指代映射到知识库。二者配合,才能完成从“一段话”到“结构化知识”的完整转化。
最朴素的结合方式是流水线串联(Pipeline):先独立跑 NER,把输出传给实体链接。优点是模块解耦、各自调优方便;缺点是 NER 的错误会一路传播给实体链接,且无法互相纠正。进阶做法是联合模型(Joint Model):两个任务共享一套编码层特征,输出阶段同时预测实体边界与链接目标,让 NER 因为“这个指代能链接到某实体”而更有信心,实体链接也因为结构边界更准确而受益。
联合训练的损失函数把两个任务绑在一起:
1. NER 损失:$\mathcal{L}_{\text{NER}}$ 衡量实体边界与类型预测的错误,通常用交叉熵计算。
2. EL 损失:$\mathcal{L}_{\text{EL}}$ 衡量指代链接到知识库实体的错误,同样用交叉熵。
3. 加权求和:$\lambda$ 是平衡系数,控制两个任务在联合训练中的相对重要程度。
标注方案上,联合模型常把实体类型与“是否可链接”同时标出,例如 B-PER、I-PER 与“可链接/不可链接”二元标签并行。老张看到扫描仪偶尔把“街道”和“小区名”圈错了,如今可以反向提醒扫描仪“这个地址段我投不过去,你再看看”——这就是联合训练互相纠正的精髓。
工程部署优化:熟记常路,才能应对高峰邮件潮
双十一邮件量暴涨时,老张不可能每封信都翻一遍档案册。他早把常寄地址背得滚瓜烂熟,只有没见过的新地址才查档案。实体链接系统上线也面临同样的工程问题:响应延迟、吞吐量、内存占用。部署优化最直接的手段是缓存(Cache):高频出现的指代(如新闻里反复出现的“苹果公司”)首次消歧后,把指代名与上下文特征哈希存入缓存,后续命中直接返回结果;只有缓存未命中才走完整的“候选生成 + 上下文消歧”全流程。
再往下是索引构建:把所有实体名、别名、描述分词后建倒排索引,候选生成从全库扫描变成一次索引查询,耗时从毫秒级降到亚毫秒级。批量处理(Batch)则把一批文档合并成矩阵运算,用 GPU 并行计算上下文向量,吞吐量往往比逐条跑高一到两个数量级。上线后还需持续监控在线服务的延迟分位数(P95/P99)与告警,防止慢查询拖垮整体链路。
缓存系统的平均响应时间可以建模为:
1. 命中概率:$p_{\text{hit}}$ 是请求命中缓存的比例,取决于指代分布的集中程度与缓存容量。
2. 命中耗时:$t_{\text{cache}}$ 是缓存读取耗时,通常在微秒级,远小于完整流程耗时 $t_{\text{full}}$。
3. 期望总延迟:$E[T]$ 按命中与否加权平均得到,$p_{\text{hit}}$ 越高,整体响应越快。
老张把常走的街区装进脑海,把陌生路线留给档案册——缓存、索引、批处理、监控,正是让实体链接在真实流量下依然快而稳的“职业素养”。
AI 应用场景
知识图谱构建:从雪崩文档中抽出一张干净的关系网
阶段:知识获取与融合
解决的问题:从海量新闻、百科、研报抽取实体关系时,同一名字可能指向多个实体。传统正则替换会把所有“海明威”合并到同一个节点,导致图谱节点混淆、关系错挂。实体链接先为每个指代确定唯一的知识库 ID,再抽取关系,图谱质量才有保障。
具体案例:某企业知识图谱项目,从 500 万条文档中抽取实体关系,用实体链接把“苹果”区分成“苹果公司”与“苹果(水果)”两个节点,实体重复率从 12% 降到 1.5%,下游问答的检索准确率随之提升。
智能问答系统:先弄清“哪个苹果”,再回答“谁创建的”
阶段:语义理解与检索
解决的问题:用户问“苹果的创始人是谁”,传统关键词检索同时命中水果和公司两种网页,答非所问。实体链接在问答前先消歧,把“苹果”链接到知识库中的“苹果公司”实体,再查它的属性得到正确答案。
具体案例:客服机器人收到“海明威是哪国人”时,先链接“海明威”到作家实体,再读取该实体属性“国籍:美国”,回答准确率提升约 30%,且 answer 能带上知识库来源供核验。
舆情监测与文档检索:同名实体各走各的数据流
阶段:文本分析与检索
解决的问题:金融舆情系统搜索“苹果”时,科技公司与水果期货行情混在一起,分析师无法按实体过滤。实体链接把每篇文章的“苹果”指代拆分为“苹果公司”与“苹果期货”两路数据,再分别聚合。
具体案例:某券商舆情平台对每日 20 万条新闻做实体链接,按实体 ID 聚合情绪分数。当“苹果公司”负面指数升高而“苹果期货”平稳时,系统自动推送科技板块预警,误报率大幅下降。
Python 演示
# -*- coding: utf-8 -*-"""简易实体链接系统演示:候选生成 + 上下文消歧 + 阈值拒识""" class SimpleLinker: """基于词典候选与上下文重叠度的简易实体链接器""" def __init__(self, kb): self.kb = kb # 知识库: 实体名 -> 描述关键词列表 self.index = {} # 索引: 指代前两字 -> 候选实体名列表 for name in kb: self.index.setdefault(name[:2], []).append(name) def get_candidates(self, mention): """候选生成: 用前两字索引粗筛, 再按首字一致性过滤""" pool = [] for key, names in self.index.items(): if key == mention[:2] or mention[:2] in key: pool.extend(names) seen = set() candidates = [] for name in pool: if name not in seen and name[0] == mention[0]: seen.add(name) candidates.append(name) return candidates @staticmethod def context_overlap(sentence, keywords): """上下文表示: 计算句子字符集合与实体关键词的重叠比例""" chars = set(sentence) hits = 0 for kw in keywords: if any(ch in chars for ch in kw): hits += 1 return hits / max(len(keywords), 1) def disambiguate(self, mention, sentence): """消歧决策: 选重叠度最高的候选, 低于阈值则拒识""" candidates = self.get_candidates(mention) if not candidates: return None, 0.0 best_entity = None best_score = 0.0 for entity in candidates: score = self.context_overlap(sentence, self.kb[entity]) if score > best_score: best_entity, best_score = entity, score if best_score < 0.25: return None, best_score return best_entity, best_score def main(): kb = { "海明威_作家": ["作家", "老人与海", "诺贝尔", "美国"], "苹果_水果": ["水果", "超市", "每斤价格", "甜"], "苹果_公司": ["手机", "科技公司", "乔布斯", "智能设备"], "李娜_网球": ["网球", "大满贯", "法网", "运动员"], } linker = SimpleLinker(kb) cases = [ ("海明威", "海明威凭借《老人与海》获得诺贝尔文学奖。"), ("苹果", "苹果公司今日发布了新款智能手机。"), ("苹果", "今天超市的苹果每斤只要三元钱。"), ("李娜", "李娜夺下法网冠军, 创造了亚洲网球历史。"), ("小明", "小明今天在公园里放风筝。"), ] for mention, sentence in cases: entity, score = linker.disambiguate(mention, sentence) status = entity if entity else "[拒识]" print("指代=%-4s 链接到=%-8s 置信度=%.2f 句子=%s" % (mention, status, score, sentence)) if __name__ == "__main__": main()
self.index.setdefault(name[:2], []).append(name)为知识库实体建立“前两字 → 实体名列表”的索引,相当于老张的档案册目录。if key == mention[:2] or mention[:2] in key:候选生成粗筛:只在上层目录里翻找,避免全库扫描。if any(ch in chars for ch in kw):上下文表示:判断句子字符集合与实体关键词是否有重叠,模拟语义相似度。return hits / max(len(keywords), 1)除以关键词数量做归一化,得到 0~1 的相似度得分。if best_score < 0.25:阈值拒识:得分不足时返回 None,不硬猜实体。status = entity if entity else "[拒识]"主流程对拒识结果做统一输出,方便观察。
常见误区
误区我以为把文本里的“苹果”跟知识库里名为“苹果”的实体对上号就行,名字一样就是同一个实体,完全不需要额外处理。
正解字符串匹配只是候选生成的起点。同名实体在真实知识库中极其普遍(海明威、苹果、李娜都是典型),必须结合上下文特征才能判断。就像邮局分拣不能只看名字,还要看地址和邮编号。候选生成负责“找得到人”,消歧负责“选得对人”。
为何常见:初学者从词典匹配入手,往往把最直观的第一步当成完整任务,忽略了同名歧义才是实体链接真正要解决的难点。
误区我觉得一个名字在一个句子里就是确定的意思,分别判断每个名字就行,不需要看文档里其他名字链接到哪。
正解局部消歧忽略了实体间的语义一致性。同一篇文档中,“海明威”大概率与“福克纳”“巴黎”同属文学话题,利用这种全局一致性可显著提升准确率。就像老张发现两封信互相印证寄件人身份,比单看一封信更可靠。论文和工业系统中,全局消歧常比纯局部方法高出几个百分点。
为何常见:局部消歧实现简单、先入为主,而全局方法的联合求解复杂度高,容易让人望而却步、直接放弃。
误区只要 NER 把“苹果”识别成组织名,我就直接把它当成苹果公司,不需要再做实体链接了。
正解NER 只解决“哪里是实体、什么类型”。同样被标为“组织”的“苹果”,既可能是“苹果公司”,也可能是某个叫“苹果”的合作社;同一个词在不同文档中类型还会漂移。NER 输出的是文本片段,实体链接输出的是知识库 ID,两者是不同层级、不同困难度的任务。
为何常见:NER 与实体链接在流水线里挨得很近,初学者容易混淆“边界识别”与“语义映射”这两件完全不同的事。
误区消歧模型总会给出一个得分最高的候选实体,所以直接把最高的那个输出去准没错,不用设什么阈值。
正解知识库往往不完整,有些指代根本没有正确答案。硬链接会把噪声注入知识图谱,造成错误的事实关联,并且这类错误极难被后续环节发现。阈值拒识让系统在置信度不足时选择“不链接”或“建议新建实体”,对知识库质量至关重要——就像老张拿不准时退回信件,而不是乱投。
为何常见:离线评测只统计链接正确的比例,忽略了“不链接”的价值;但真实产品中错误链接的代价远高于不链接。
面试题
Q1. 实体链接的核心任务是什么?
- A.识别文本中实体并标出类别
- B.把实体指代映射到知识库实体← 正确答案
- C.抽取文本中实体间的语义关系
- D.将文本自动翻译成另一种语言
答案:B。实体链接的输入是文本中的实体指代,输出是知识库中唯一对应的实体 ID。A 是 NER 的任务,C 是关系抽取,D 是机器翻译。就像邮局分拣:A 是读信封,B 才是把信投进正确的信箱。
Q2. 候选生成的主要目标是什么?
- A.精确率优先,只保留最有把握的实体
- B.召回率优先,尽量捞回正确的候选← 正确答案
- C.让候选数量最小化从而提升速度
- D.删除文本中的所有冗余停用词
答案:B。候选生成追求高召回,宁可多混入干扰项也不能漏掉正确答案,因为漏掉的实体在后续消歧阶段永远无法找回。C 会牺牲召回,D 与实体链接无关。老张翻档案时宁可多抽几张卡,也不愿漏掉真正的收件人。
Q3. 关于局部消歧与全局消歧,下列说法正确的是?
- A.全局消歧对每个指代独立求解互不影响
- B.局部消歧会考虑实体间的语义一致性
- C.全局消歧将指代联合求解并要求实体兼容← 正确答案
- D.局部消歧的效果总是比全局消歧差
答案:C。全局消歧把同一文档内所有指代放在一起,追求整体最优并约束实体间主题一致。A 描述的是局部消歧;B 方向反了;D 过于绝对,局部消歧在简单场景或低资源下也可能够用。
Q4. 编辑距离相似度中做长度归一化的主要目的是什么?
- A.加快字符串之间的匹配处理速度
- B.消除字符串长度差异对相似度的影响← 正确答案
- C.提高编辑距离计算本身的准确率
- D.让相似度结果变成标准化概率
答案:B。两个字的短串与二十个字的长串,绝对编辑距离不可直接比较,除以较长长度得到相对差异度。编辑距离的计算复杂度与归一化无关,A、C、D 均不正确。
Q5. 下列哪些是上下文表示的常用方法?
- A.窗口内词向量求平均池化← 正确答案
- B.TF-IDF 加权后求和取均值← 正确答案
- C.实体知识图谱嵌入表示法← 正确答案
- D.对字符串做精确的词典匹配
答案:ABC。上下文表示的目标是把指代周围的语义转成向量。词向量平均、TF-IDF 加权、知识图谱嵌入都是常见手段。D 是候选生成阶段的匹配方式,不属于上下文表示。
Q6. 实体链接中“阈值拒识”的主要作用是什么?
- A.拒绝回答所有含歧义的提问
- B.对低置信度指代不强行链接以免污染知识库← 正确答案
- C.拒绝使用效果不佳的预训练模型
- D.拒绝对实体做词典匹配处理
答案:B。知识库往往不完整,有些指代没有正确答案,硬链接会向图谱注入噪声。设置阈值后,置信度不足的指代被标记为不可链接或建议新建实体。老张拿不准时退信,正是为了不让错误蔓延。
Q7. 下列哪些属于全局消歧的实现策略?
- A.构建主题一致性约束图模型← 正确答案
- B.使用贪心迭代修正实体分配← 正确答案
- C.让每个指代独立取最大概率
- D.基于实体相容性的联合推断← 正确答案
答案:ABD。全局消歧需要建模实体间关系,图模型、贪心迭代、联合推断都是常用手段。C 是局部消歧的做法,逐个独立取最大值无法保证文档整体的语义一致性。
Q8. NER 与实体链接的关系是什么?
- A.NER 与实体链接是完全相同的任务
- B.NER 识别边界与类型,实体链接做知识库映射← 正确答案
- C.实体链接的效果完全不依赖 NER 结果
- D.NER 直接输出知识库实体的 ID
答案:B。NER 输出文本片段及其类型(人名/组织等),实体链接把片段映射为知识库 ID。流水线中实体链接依赖 NER 输出,C 错;D 恰好把两者职责颠倒。二者是“圈地址”与“投信箱”的关系。
Q9. 提升实体链接在线服务性能的常用手段有哪些?
- A.构建倒排索引加速候选生成← 正确答案
- B.对高频指代链接结果加缓存← 正确答案
- C.批量矩阵化提升整体吞吐← 正确答案
- D.无限扩大候选集提升召回率
答案:ABC。倒排索引把全库扫描变成索引查询,缓存复用高频结果,批处理利用矩阵并行加速,都是工程实践标准做法。D 无限扩大候选集只会拖慢速度并引入噪声,不能解决性能问题。
Q10. 某实体链接系统 F1 为 0.6,下列说法正确的是?
- A.该系统精确率与召回率必然都为 0.6
- B.精确率与召回率的调和平均为 0.6← 正确答案
- C.系统的精确率一定高于召回率
- D.系统的召回率一定高于精确率
答案:B。F1 是精确率与召回率的调和平均,同一 F1 值可由无数对 P/R 组合得到,例如 P=0.5、R=0.75 的调和平均也是 0.6。A、C、D 都做了过度假设,唯有 B 是 F1 的定义本身。