想象你是一名资深侦探。案发现场(文档)里躺着一份写满线索的报告(原文),上级给你丢来一个任务:“报告里,嫌疑人的作案时间到底是几点几分?”你的工作不是凭记忆编造,而是拿起一支荧光笔,在报告中精确地圈出那句话——“晚上十点三十分”。圈出来就行,不用改写,不能发挥。 这就是“抽取式机器阅读理解(MRC)”的本质。机器读完一篇文章,面对一个问题,不做想象、不做翻译,只做一件事:从原文中找出答案所在的连续片段,圈出它的起点和终点。就像侦探用荧光笔在报告上画一道线。传统方法像雇佣十个实习生去翻报告,费时费力;而现代做法是派出一个叫 BERT 的双向超级侦探,它目光如炬,一眼看遍全文,再精准圈出答案。 但进阶之路远不止“圈线”这么简单:怎么让侦探理解上下文?怎么决定线的起点和终点?如果现场根本没有这个线索,侦探该不该如实说“查无此证”?如果线索散落在多个现场,又该如何联合排查?这篇文章,我们就陪这位“BERT 侦探”完整走一遍进阶之旅。
对 AI 从业者而言,MRC 是问答系统、智能客服和知识抽取的基石技术。掌握答案边界预测、拒答机制与多文档处理,就等于掌握了构建高精度 NLP 系统的核心手艺。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
任务定义
接到报案后,侦探的第一件事是明确任务书:现场是哪份报告?要回答什么问题?答案是写在纸上的原话,还是要自己发挥写一篇作文?抽取式 MRC 的任务书只有三行——输入一篇文档 C 和一个问题 Q,输出答案在文档中的起点位置 i 和终点位置 j。这个片段必须是原文里的连续字符串,就像侦探圈出的那句“晚上十点三十分”,一个字都不能改。
与之相对的是生成式阅读理解:模型像一位作家,看着报告后自己组织语言写出答案摘要。抽取式更像是“复制粘贴”,生成式更像是“转述创作”。两者各有分工:需要引经据典、逐字考据的场景(合同条款、法律条文)用抽取式更可靠;需要总结概括的场景(新闻摘要)则生成式更合适。理解了这一层,你就明白为什么 MRC 圈子里常说“找答案”而不是“想答案”。
在实际系统中,问答任务被形式化为一个条件概率问题:给定问题 Q 与文档 C,求最可能的答案区间。这个区间用一对整数 (i, j) 表示,i 是起点 token 下标,j 是终点 token 下标,且满足 0 ≤ i ≤ j < len(C)。模型的全部任务就是预测这两个数的取值。
回到侦探的视角:任务定义就是“圈定现场范围”。明确了从哪份报告找、以什么形式提交答案,后面的所有高级技巧——BERT 编码、边界预测、拒答机制——都是为了让这一笔荧光笔落得更准。
- 条件概率含义P(i, j | H) 表示在给定文档编码向量 H 的条件下,答案起点为 i、终点为 j 的概率。
- 区间约束i ≤ j 保证了答案片段是连续的,不会出现“倒着读”的答案。
- H 的含义H 是文档经过编码器后每个 token 的向量表示,携带着上下文信息。
BERT编码
侦探拿到了任务书,但报告有三千字,问题提到了“嫌疑人”这个词。如果只盯着这个词看,很容易忽略它在后文中多次出现的指代。传统方法(如 BiDAF 等词向量模型)像拿着放大镜逐词打量,对一词多义和指代关系常常犯迷糊。而 BERT 这座“双向探照灯塔”同时照亮整个句子:每个词都能“看见”它左边和右边的所有邻居,从而在上下文中确定自己此刻的含义。
实际操作时,我们将问题和文档拼接成一段输入:[CLS] 问题 [SEP] 文档 [SEP]。CLS 像一个会议主持人,站在开头汇总全场信息;两个 [SEP] 像分隔符,把“提问区”和“现场报告区”清晰分开。BERT 内部的多层 Transformer 逐层传递信息,最终输出每个 token 的向量表示 h₁ 到 hₙ。这些向量不再是孤立的词,而是“戴着上下文眼镜”的语义编码。
这就是 BERT 编码的核心价值:它把原始文本变成了携带双向语义的向量序列。对 MRC 任务而言,这个向量序列就是后续起点终点打分的地基。实验中一个直观感受是:同一句话在问句中出现和在文档中出现时,BERT 会给它们织入不同的上下文含义——这正是“探照灯”双向照明的效果。
侦探的“探照灯塔”建好了——每一盏灯都照亮全场。接下来,他就要举起荧光笔,在这片被照亮的现场里扫描答案的起点了。
- 输入拼接问题和文档按顺序拼成一个序列,句首加 CLS 标记。
- 逐词编码每个位置 t 通过多层 Transformer 编码,得到 h_t。
- 语义融合h_t 聚合了左右两侧所有词的信息,不再孤立。
边界预测
灯塔照亮全场后,侦探举起荧光笔。他先问:“答案的第一个字最可能在哪?”然后逐个 token 打分:这个位置像不像起点?那个位置像不像起点?打分最高的 token 就是起点。紧接着,从起点出发向右看:“答案的最后一个字在哪?”同样逐个打分,选出终点。两个分数一组合,一条荧光笔线就画出来了。
技术实现上,我们为起点和终点各训练一个打分向量(权重矩阵 S 和 E)。对于每个 token,用它的编码向量 hᵢ 与打分向量做点积,得到一个原始分数。这些分数经过 softmax 归一化,变成概率分布。起点概率 P_start(i) 表示“第 i 个 token 是答案起点”的概率,终点同理。
联合解码时,我们通常要求 i ≤ j,然后在所有满足条件的 (i, j) 对中找起点概率与终点概率乘积最大的那一个。有时候还要加上区间长度惩罚(如 +λ·(j-i)),避免模型偏爱过长或过短的区间。这个“起点概率 × 终点概率”的联合打分,就是抽取式 MRC 最核心的解码逻辑。
侦探的荧光笔现在拥有了“双段式瞄准”:先确定起点,再锁定终点。两条线一夹,答案的边界就水落石出。
P_{\text{start}}(i) = \frac{\exp(S^{\top}\mathbf{h}_i)}{\sum_{k=1}^{n} \exp(S^{\top}\mathbf{h}_k)}, \quadP_{\text{end}}(j) = \frac{\exp(E^{\top}\mathbf{h}_j)}{\sum_{k=1}^{n} \exp(E^{\top}\mathbf{h}_k)}- 起点打分S 是一个可学习的向量,与每个 token 的 h_i 做点积,得到该位置作为起点的原始分数。
- softmax 归一化将一排原始分数映射成概率分布,总和为 1。
- 终点对称计算用另一个向量 E 对每个位置计算终点得分并归一化。
损失函数
荧光笔已经学会了瞄准,但“瞄准”这个动作本身需要一场严格的射击训练。训练时,数据集里每个样本都标好了标准答案的起点 g_s 和终点 g_e。模型要让真实的起终点概率尽可能大——也就是说,侦探射出的每一枪都应落在靶心附近。衡量偏离程度的尺子叫负对数似然损失。
直觉是这样理解的:如果模型给真实起点打出的概率是 0.9,说明它很有把握,损失就小(-log 0.9 ≈ 0.1);如果只打出 0.1,说明它犹豫不决,损失就大(-log 0.1 ≈ 2.3)。模型的训练目标就是把所有样本的损失压到最低。因为起点和终点都要预测,最终损失是两者之和,像两个科目都要及格一样。
反向传播时,梯度会告诉每个参数“往哪个方向调一点,能让损失降一点”。BERT 底层的参数同样参与更新,这被称为端到端联合微调。这也是 MRC 进阶的关键所在:不是只学起终点打分层,而是连同整个 BERT 一起调整,让“阅读理解”本身也变得更贴合任务。
训练场上的无数次瞄准,让侦探的荧光笔从“大概知道方向”进化到“枪枪命中靶心”。下一关的挑战则是:当现场根本没有线索时,侦探该不该交白卷?
- 起点损失项真实起点 g_s 的概率取负对数,概率越大损失越小。
- 终点损失项真实终点 g_e 的概率取负对数。
- 联合损失两项相加,简洁地表达“起点终点同时要准”的要求。
不可回答
新手侦探最容易犯的错,是面对“报告里根本没写”的问题也要强行圈一段答案。比如问“嫌疑人的鞋子是什么颜色”,而报告通篇只提了外套颜色。强行圈个答案,反而暴露了不专业。进阶的 MRC 必须学会一个优雅的退场:判定此题为不可回答,然后如实拒答。
技术上的做法是引入一个“无答案”特殊位置,用特殊的 CLS 标记输出来代表“空区间”的得分。推理时,模型先找出所有候选区间中得分最高者(称为 best span),再把它与“空区间”的得分做对比:如果最佳区间的得分减去空区间得分没有超过某个阈值 τ,就认为是不可回答问题,返回“无答案”;反之才返回找到的区间。
这就像侦探在现场兜了一圈,发现根本没有鞋子的线索,他拿起对讲机汇报:“现场查无此证,建议从其他方向侦查。”阈值 τ 是一个超参数,调大调小会影响模型“惜字如金”还是“强行作答”的倾向。SQuAD 2.0 这个著名数据集正是靠这种“可回答 + 不可回答”混合设计,逼着模型学会权衡。
“查无此证”不是能力不足,而是判断力的体现。一个成熟的 MRC 系统,要像老练的侦探一样懂得知进退。
- 最佳区间得分在所有 i ≤ j 的候选中找得分最高的区间。
- 空区间得分用 CLS 标记的向量算出一个“无答案”得分 S_null。
- 阈值判断两者差值小于 τ 则拒答,否则正常输出区间。
多文档处理
有些案件涉及多个现场:嫌疑人在 A 报告里出现了行踪,在 B 报告里出现了作案工具,在 C 报告里又提到时间点。MRC 的进阶难题之一就是多文档联合阅读:答案可能散落在多个文档中,每个文档单看都不完整。侦探需要把所有现场的报告都摊在桌上,交叉比对。
工程上最常用的策略是滑窗截断:BERT 有最大输入长度限制(通常是 512 token),如果文档太长,就按窗口切成多个片段,每个片段与问题拼接后单独预测答案区间,最后汇总所有片段的候选答案。汇总时,不同窗口可能给出同一个答案的不同截断版本,于是需要去重与重排——用答案的字符串精确匹配或 F1 相似度合并重复项,再按预测得分排序,取最可信者。
这个“切块 - 各自预测 - 合并排序”的流水线,像侦探团队分工:每个小分队负责一个现场,各自圈出可能的线索,回到指挥部再把所有圈出的线索拼成完整的证据链。另一种更新颖的思路是用“证据句子选取”先把不相关的文档过滤掉,再对精选段落做精细抽取,效率更高。
多现场联合排查,让侦探的视野从“一屋一室”扩展到“全城联动”。靠的不仅是更长的探照灯,更是聪明的分工与汇总策略。
- 窗口划分长文档按长度切分为若干不重叠(或部分重叠)的窗口。
- 窗口内打分每个窗口独立计算答案区间的联合概率。
- 全局取最大最终答案来自得分最高的那个窗口。
评估指标
侦探勤勉工作,总得有个衡量标准来判断他圈得准不准。在 MRC 领域,两把权威的“成绩尺”是 EM(Exact Match,完全匹配率) 和 F1(词级重合度)。
EM 是一把严苛的尺子:模型预测的答案字符串与标准答案必须逐字完全相同才算对,多一个字少一个字都算错。它像考试中的填空题,答案必须一字不差。F1 则温柔一些:它把预测答案和标准答案都拆成词的集合,看两者重叠多少,用“召回率(该圈对的圈对了多少)”和“精确率(圈出来的内容里有多少是对的)”求调和平均。F1 分数高说明“虽不完美,但大方向对了”。
实际项目里两者通常一起看:EM 反映系统的“硬准确率”,F1 反映系统的“软质量”。SQuAD 榜单上顶尖模型 EM≈87%、F1≈93%,意味着近九成问题能够原原本本圈对,剩下那些即便没圈得完美,也大多八九不离十。指标不是目的,但它们像侦探考勤表上的星星,时刻提醒我们:模型真正学到了多少?
成绩尺就位,侦探的每次出勤、每笔圈画都有了客观评价。从任务定义到评估指标,这位 BERT 侦探终于完成了进阶的全部修炼。
F_1 = \frac{2 \times P \times R}{P + R}, \quadP = \frac{|A_{\text{pred}} \cap A_{\text{gold}}|}{|A_{\text{pred}}|}, \quadR = \frac{|A_{\text{pred}} \cap A_{\text{gold}}|}{|A_{\text{gold}}|}- 精确率 P预测答案的词中有多少比例在标准答案中——“圈出的东西里,对的占多少”。
- 召回率 R标准答案的词有多少被预测覆盖了——“该圈的东西,圈到了多少”。
- 调和平均P 和 R 的调和平均,防止偏科,只有两者都高 F1 才高。
AI 应用场景
智能客服工单自动定位
阶段:在线问答与信息抽取
解决的问题:传统客服需要人工翻阅冗长的产品或协议文档,才能回答“我们产品的保修期是多久”这类问题。有了抽取式 MRC,系统直接定位到合同原文中的“保修期为十二个月”对应片段,答案有据可查。与生成式模型相比,抽取式杜绝了模型“编造条款”的风险,这在法律和售后场景极为关键。
具体案例:某电商平台接入 BERT-MRC 问答模块后,用户提问“退换货的运费谁承担”,系统从《售后服务政策》中抽取“非质量问题退货,运费由买家承担”这一原始句子作为答案,并附上原文截图,用户问题解决率提升 31%。
医疗文献证据检索
阶段:循证医学信息抽取
解决的问题:医生检索“二甲双胍对糖尿病患者的肾功能影响”时,传统关键词搜索返回整篇论文,阅读成本高。抽取式 MRC 直接给出论文中关于肾功能指标的原始描述段落,医生可快速核对数据与结论,避免生成式摘要造成的原文信息失真。
具体案例:某医学知识平台将 PubMed 摘要作为文档库,构建 MRC 问答接口。当医生提问“奥希替尼的常见不良反应”,系统从多篇文献中分别抽取相关句子并融合去重,按证据强度排序输出,附带每句话的来源文献链接,供医生判断参考。
Python 演示
import numpy as np class SimpleExtractiveMRC: """一个极简化的抽取式MRC Demo,模拟BERT输出logits后进行边界预测。""" def __init__(self, vocab): self.vocab = vocab # 词表 self.null_threshold = 0.5 # 拒答阈值 def encode(self, text): return text.split() def _score(self, tokens): """模拟BERT编码后的起终点打分(仅做Demo演示)。""" n = len(tokens) start_logits = np.array([0.5 + 0.1 * i for i in range(n)]) end_logits = np.array([0.5 + 0.1 * i for i in range(n)]) return start_logits, end_logits def _softmax(self, x): e = np.exp(x - x.max()) return e / e.sum() def predict_span(self, context, question): """预测答案区间,返回(start, end)索引;不可回答时返回None。""" tokens = self.encode(context) q_words = set(self.encode(question)) n = len(tokens) # 模拟:与问题词重叠的位置打分更高 start_logits, end_logits = self._score(tokens) for i, w in enumerate(tokens): if w in q_words: start_logits[i] += 1.0 end_logits[i] += 1.0 p_start = self._softmax(start_logits) p_end = self._softmax(end_logits) # 联合解码:找P_start(i) * P_end(j)最大的区间 best_score = -1.0 best_span = None for i in range(n): for j in range(i, n): score = p_start[i] * p_end[j] if score > best_score: best_score = score best_span = (i, j) # 不可回答判断:模拟空区间得分 s_null = 0.3 * p_start.mean() + 0.3 * p_end.mean() if best_score - s_null < self.null_threshold: return None return best_span if __name__ == "__main__": mrc = SimpleExtractiveMRC(vocab=["太阳", "从", "东方", "缓缓", "升起"]) context = "太阳从东方缓缓升起" question = "什么从东方升起" span = mrc.predict_span(context, question) if span is not None: i, j = span print("预测答案:", context.split()[i:j + 1]) else: print("拒答:未找到可靠答案")
start_logits, end_logits = self._score(tokens)模拟 BERT 的输出:每个 token 得到一个起点原始分和一个终点原始分。if w in q_words: start_logits[i] += 1.0与问题词重叠的 token 获得加分,模拟注意力聚焦。p_start = self._softmax(start_logits)将原始起点分数转为概率分布。for i in range(n): for j in range(i, n):遍历所有 i ≤ j 的候选区间,保证答案连续。score = p_start[i] * p_end[j]联合概率是起点概率与终点概率的乘积。if best_score - s_null < self.null_threshold: return None与空区间得分比较,决定是否拒答。
常见误区
误区我用了 BERT-MRC 模型,下载下来就能问什么答什么,做通用问答机器人。
正解抽取式 MRC 只能在给定文档范围内找答案。它像侦探只在案发现场找线索,现场没有的东西它既不能编也不能猜。问“1+1等于几”这种知识性问题,或问文档范围之外的事实,模型只能拒答或给出错误答案。要建通用问答系统,必须搭配知识库检索(如 RAG)才能补齐短板。
为何常见:很多人把“机器阅读”误解为“无所不知”,忽略了 MRC 的任务边界——它回答的是关于给定上下文的问题,不是百科全书。
误区只要把起点和终点的概率预测做准,EM 和 F1 分数就会很高,其他环节不重要。
正解工程实践中,BERT 输出概率只是第一公里。真实的问答流水线还包括文档检索(召回相关段落)、滑窗切分、候选答案去重、跨文档融合、拒答阈值调优。任何一个环节拉胯,都会让最终用户体验大打折扣。比如检索环节没召回正确文档,后面模型再厉害也白搭。
为何常见:学术界 SQuAD 评测给定了段落,让研究者专注于边界预测;而工业界要自己决定“给模型看哪段文字”,问题往往出在文档检索而不是边界预测上。
误区不可回答问题的判断很简单,把拒答阈值设成 0.5 之类的固定值,万事大吉。
正解阈值与模型的得分分布强相关。不同领域的文档、不同长度的段落,最优阈值差异很大。正确做法是在验证集上扫描不同阈值,绘制“可回答问题正确率 vs 不可回答问题正确率”曲线,选业务更看重的平衡点。比如客服场景宁可漏答也不愿乱答,阈值就该调高一些。
为何常见:因为阈值在代码里只是一个常数,看起来不起眼,但实际上它决定了模型“多疑”还是“自信”,是影响用户体验的隐形旋钮。
面试题
Q1. 抽取式MRC的核心输出是什么?
- A.一段重新组织生成的摘要
- B.文档中一个连续片段的起止位置← 正确答案
- C.对文档主题的概率分布
- D.多个候选关键词的排序
答案:B。抽取式 MRC 的特点就是在原文中圈出连续片段,输出表示答案边界的位置对 (i, j)。A 是生成式模型的行为,C 和 D 属于分类或排序任务,均不符合抽取式 MRC 的定义。
Q2. BERT-MRC 模型中,输入拼接格式通常是?
- A.[CLS]文档[SEP]问题[SEP]
- B.[SEP]问题[CLS]文档[SEP]
- C.[CLS]问题[SEP]文档[SEP]← 正确答案
- D.问题和文档各自独立输入
答案:C。BERT-MRC 通常将问题放在前面、文档放在后面,句首加 [CLS] 标记,中间和末尾用 [SEP] 分隔。CLS 位置最终会用来表示“空答案”的得分,因此必须位于句首。
Q3. 答案联合概率 P(i,j) 的计算方式通常是什么?
- A.P(i) 与 P(j) 的和
- B.P_start(i) 与 P_end(j) 的乘积← 正确答案
- C.P_start(i) 与 P_start(j) 的差
- D.P_end(i) 与 P_end(j) 的乘积
答案:B。答案区间要求起点在终点之前,联合概率由起点概率和终点概率相乘得到,并满足 0 ≤ i ≤ j。求和或求差没有概率意义,且 D 使用了两个终点概率,方向错误。
Q4. 处理“不可回答问题”时,通常采用什么策略?
- A.直接输出得分最高的区间
- B.引入 CLS 空区间得分并与最优区间比较← 正确答案
- C.随机选择一个答案
- D.将问题重新表述后再次询问
答案:B。标准做法是额外计算“空区间”得分,将最优区间的联合概率与空区间得分比较,差值小于阈值则拒答。这相当于侦探确认现场无证后如实汇报,而非乱圈一气。
Q5. F1 指标中,精确率 P 的含义是?
- A.标准答案中词被预测覆盖的比例
- B.预测答案中词属于标准答案的比例← 正确答案
- C.预测完全正确的比例
- D.预测区间长度与标准区间长度之比
答案:B。精确率 P = |预测∩标准| / |预测|,衡量预测答案中“圈对的占比”。A 描述的是召回率,C 是 EM 指标,D 是长度比例,均与 P 的定义不符。
Q6. 在多文档 MRC 中,对于超过 BERT 长度限制的文档,通常采用什么处理方式?
- A.直接截断前半部分
- B.用滑窗切分为多个片段分别预测← 正确答案
- C.丢弃过长文档
- D.将文档整体压缩成向量
答案:B。工业界普遍采用滑窗切分策略:长文档按窗口切成可处理的片段,每个窗口独立做 MRC 预测,最后通过去重、重排融合答案。直接截断会丢失答案所在的尾部信息,丢弃文档则更不可取。
Q7. EM(Exact Match)指标的特点是什么?
- A.允许一定程度的同义词替换
- B.要求预测答案与标准答案逐字完全一致← 正确答案
- C.只看关键词是否出现
- D.与 F1 的计算方式完全相同
答案:B。EM 是一把严苛的尺子,预测字符串与标准答案必须完全一致才算正确,不容许同义词替换或顺序调整。F1 则更宽松,不要求全对,只衡量词级重合度。
Q8. 关于抽取式 MRC 的损失函数,下列说法正确的是?
- A.通常使用负对数似然作为损失← 正确答案
- B.损失函数包含起点项和终点项← 正确答案
- C.训练时只需优化终点预测
- D.损失越小表示模型预测越准← 正确答案
答案:ABD。MRC 训练使用联合负对数似然 L = −log P_start(g_s) − log P_end(g_e),起点和终点都要优化(B 对、C 错)。负对数似然值越小,真实答案的概率越大,模型越准(D 对)。标准做法正是如此(A 对),因此答案是 0、1、3。
Q9. 关于不可回答问题的阈值 τ,下列说法正确的是?
- A.τ 越大,模型越倾向于拒答← 正确答案
- B.τ 越小,模型越容易强行作答← 正确答案
- C.τ 不需要在验证集上调整
- D.τ 衡量“最优区间比空区间好多少”← 正确答案
答案:ABD。阈值 τ 是比较两把尺子的刻度差:最优区间得分减去空区间得分必须大于 τ 才作答。τ 大 → 要求差距大 → 更难作答,更易拒答(A 对);τ 小 → 容易满足 → 更易强行作答(B 对)。τ 是需在验证集上扫描调优的超参数(C 错)。D 描述的正是阈值的语义,正确。
Q10. 评估 MRC 模型时常用的两个指标是?
- A.EM(完全匹配率)← 正确答案
- B.F1(词级重合度)← 正确答案
- C.BLEU(译文质量分)
- D.ROC 曲线下面积
答案:AB。SQuAD 与绝大多数 MRC 基准都同时报告 EM 和 F1:EM 要求逐字完全一致,F1 衡量词级重叠。BLEU 更常用于生成式翻译任务,ROC-AUC 用于二分类排序,二者不是 MRC 的标准评测指标。