想象你接手了一座塞满旧食谱的档案馆。里面既有印刷成册、纸张发黄的菜谱活页(PDF),也有用打字机敲出来的电子稿(Word)。你想把每道菜里的“用料清单”表格都抄进手机 App,做成可搜索的菜品数据库——可那些表格有的有框线、有的模糊不清、有的“调味料”三个字横跨三行。你要做的,就是系统地“抄表”:先看懂表格长什么样,再选对抄写工具,处理跨行跨列的怪格子,最后把抄好的内容整齐录入数据库。这套流程,正是 RAG 文档处理中的“表格提取”。本文将从识别到入库,带你完整走一遍这条抄表流水线。

岗位关联

掌握表格提取,你就能让 RAG 系统真正“读懂”文档里的表格信息,而不是跳过或乱序输出,问答质量会得到肉眼可见的提升。

目录
  1. 可视化演示
  2. 表格识别基础
  3. PDF提取工具
  4. Word提取方法
  5. 合并单元格
  6. 转结构化数据
  7. 质量评估
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示PDF/Word文档表格识别、工具对比与合并单元格处理的完整流程,支持模式切换与参数交互。

本节配有交互动效(进入视口后自动加载,约 3KB)。

表格识别与提取流程 规则法基于线条和坐标对齐检测 CV法利用形态学操作定位表格 Accuracy = TP / (TP + FN) 深度学习法如TableNet实现端到端检测

表格识别基础

走进档案馆的第一步,是学会辨认“什么是菜谱表格”。旧食谱里,用料清单总是被印刷成规规矩矩的格子:最上面一行写着“食材、用量、备注”,下面每一行对应一种食材。在文档处理领域,这种由行和列围成的二维网格就叫表格,围出每个小空间的格子叫单元格,最上面那行叫表头,表头之下每一行都是代表一种食材的数据记录。RAG 系统要检索表格,得先让程序知道“哪里是表格”。

有了定义还不够,真正的难点在识别。就像有的菜谱用明显线条画格子(有线表格),有的只用空格和缩进暗示结构(无线表格),还有的老菜谱是整页扫描的图片(图片型表格)。PDF 里文字还分“活字印刷”和“照片成像”两种底层形式,识别策略完全不同。所以动手提取前,先做分类:表格是否有边框、是否是扫描件、表头是否多级——这些信息直接决定用哪类工具。

为了量化“抄得完不完整”,可以用提取完整度来度量:把文档里真实存在的单元格总数当作分母,把工具成功提取出的单元格数当作分子。分数越接近 1,说明抄录得越齐全。

回到档案馆的场景:如果连哪些页有表格都分不清,后面的抄写工具再利索也白搭。表格识别基础,就是把“哪些是表格、什么类型、难点在哪”先摸清楚,这一步做对了,后面按图索骥就轻松得多。

C=NokNreal\displaystyle C=\frac{N_\text{ok}}{N_\text{real}}
完整度 C 表示成功提取的单元格占真实单元格的比例,是衡量表格提取“有没有抄漏”的第一把尺子。
  1. N_ok成功提取的单元格数:程序准确读出来的格子个数,相当于完整抄录到笔记本上的那些用料行。
    Nok=#{成功读出的格子}N_\text{ok}=\#\{\text{成功读出的格子}\}
  2. N_real真实总单元格数:原文档里实际存在的所有格子,包括没被读出来的部分。
    Nreal=Nok+NfailN_\text{real}=N_\text{ok}+N_\text{fail}
  3. C提取完整度:两者相除得到比例,C 越接近 1 说明抄录越完整,越接近 0 说明漏得越多。
    C=NokNok+NfailC=\frac{N_\text{ok}}{N_\text{ok}+N_\text{fail}}

PDF提取工具

印刷版的菜谱活页(PDF)是档案馆里最难抄的部分。PDF 天然只记录每个文字块的位置,不告诉你哪几条线围成了一个表格。好在有专门的“抄写工具”:PyMuPDF 像一把轻快的剪刀,擅长快速剪下文字及其坐标,适合表格线条清晰、结构简单的页面;pdfplumber 像一把细齿梳,会沿着文字行去推断哪些字符处于同一行同一列,对带边框的表格效果很好;Camelot 则像一位耐心的拓印工,先用计算机视觉算法找出页面上的直线,再根据虚拟线条重建出完整网格,复杂表格也拿得下,但安装依赖较重、速度偏慢。

工具一多就面临选型。实践里的经验法则是:先看页面有没有明显的直线边框。有框线的优先试 pdfplumber,它轻量且对文字型 PDF 友好;无框线或框线残缺的,用 Camelot 靠线条重建网格往往更稳;如果只是想快速拿到文本块坐标自己拼表,则选 PyMuPDF。选错了工具,就像用剪刀去拓印,事倍功半。

选型之后如何判断工具抄得好不好?可以把工具输出与人工标注的标准答案做字符相似度比较。两段文本共同字符数的两倍,除以两段文本长度之和,得到 0 到 1 的相似度分数。

就像抄完菜谱后拿原稿抽查几个字,相似度帮助我们判断这个“抄写工具”到底准不准。把 pdfplumber、Camelot 分别在测试页上跑一遍相似度对比,选分数最高的那只笔,再正式开工抄全部表格。

Sim(A,B)=2×∣A∩B∣∣A∣+∣B∣\displaystyle \text{Sim}(A,B)=\frac{2\times|A\cap B|}{|A|+|B|}
这是杰卡德思想的变体,用于评估“提取出的文字与标准答案有多像”,分数越高说明工具的抄写质量越好。
  1. A 与 B两份待比较文本:一份是工具提取出的单元格文字,另一份是人工对照原文档录入的标准文字。
    A=工具输出,B=标准答案A=\text{工具输出},\quad B=\text{标准答案}
  2. |A∩B|共同字符数:两段文字中相同字符的个数,字符重叠越多则相似度越高。
    ∣A∩B∣=#{两边都出现的字符}|A\cap B|=\#\{\text{两边都出现的字符}\}
  3. |A|+|B|字符总数:两段文字长度之和,作为归一化的分母,避免文本越长分数越虚高。
    ∣A∣+∣B∣=∣A∣+∣B∣|A|+|B|=|A|+|B|
  4. ×2 后整体相除因为共同字符被两边重复计算了两遍,所以乘 2 把分数校正到 0~1 区间。
    Sim=2×∣A∩B∣∣A∣+∣B∣\text{Sim}=\frac{2\times|A\cap B|}{|A|+|B|}

Word提取方法

比起印刷的 PDF,档案馆里的 Word 电子稿就“乖”多了。Word 文档本身就是电子数据,表格结构被完整保存在内部文档模型里,不需要用视觉去猜,直接伸手到文件里就能把表格原样掏出来。在 Python 里,python-docx 就是那只手——它把 Word 文档解析成内存对象,其中 doc.tables 保存了文档中所有表格。

拿到表格对象后,遍历便是顺理成章的事:先遍历 doc.tables 得到每个表格,再遍历 table.rows 得到每一行,最后遍历 row.cells 取出每个单元格的文本。这就像把电子稿里的“用料清单”逐行复制粘贴到新文档里,不需要 OCR,也不需要图像识别,准确率天然就高。

Word 表格还保留着丰富的样式信息:单元格的合并状态、行高列宽、底纹颜色、字体加粗,都能被读取。这些信息在“还原表格”时非常有用——比如渲染回 Markdown 或 HTML 时,可以把表头单元格设为加粗、把合并结构保留下来。抄写电子稿菜谱,连排版风格都可以一并带走。不过在读取时也要注意:合并单元格会让 row.cells 返回重复的对象,需要结合合并信息去重。

在档案馆的电子稿区域,抄表几乎不受“印刷模糊”的困扰。遇到跨行跨列的怪格子时,只要记住“把起点值广播到覆盖区域”这条规则,Word 表格就能被整整齐齐地搬进结构化清单里。

M[i][j]←M[i0][j],i0≤i<i0+span\displaystyle M[i][j]\gets M[i_0][j],\quad i_0 \le i < i_0+\text{span}
这条规则表示:当 Word 表格里有纵向合并的单元格时,程序会把合并起始行的值复制到被合并覆盖的所有行位置,保证后续读取到的每个位置都有值。
  1. M[i][j]单元格矩阵:把表格看作一个二维矩阵,i 是行号,j 是列号,M[i][j] 就是该格的值。
    M[i][j]=第 i 行第 j 列的文字M[i][j]=\text{第 }i\text{ 行第 }j\text{ 列的文字}
  2. i0合并起始行:纵向合并是从第 i0 行开始的,该行存有真正的文字值。
    i0=合并区域的起点行号i_0=\text{合并区域的起点行号}
  3. span合并跨度:合并总共占了几行,被覆盖的行号范围是 i0 到 i0+span-1。
    span=纵向合并的行数\text{span}=\text{纵向合并的行数}
  4. 赋值箭头把起点行的值复制到合并覆盖的所有行,于是这些行在矩阵中都有同样的值。
    M[i][j]←M[i0][j]M[i][j]\gets M[i_0][j]

合并单元格

旧菜谱里常出现这样的排版:一栏“调味料”的竖排文字,横跨了三行食材——酱油、糖、醋下面共用这一个分类名。这种跨行跨列的格子在文档术语里叫合并单元格,是表格提取中最容易翻车的地方。如果不处理,三行数据中只会有第一行有“调味料”,另外两行全空,下游检索时就会丢掉两条记录。

第一步是合并识别。在 Word 的底层 XML 里,合并单元格会有 rowspan 或 colspan 属性;而在 PDF 里没有这么明确的标识,只能看“某个格子是否同时与多个格子共享一条边框”来推断。识别出合并区域后,第二步做行列映射:记录合并区域的起始行列和跨度,把“哪些行、哪些列共享同一个值”建模清楚。最后一步是数据填充:把起始格的值复制到合并覆盖的所有逻辑位置,让每个格子都有值可读。

一个合并区域本质上是一个矩形:从起点 (r0, c0) 横向延伸到 c0+colspan-1、纵向延伸到 r0+rowspan-1,覆盖范围内的所有格子在逻辑上都等于起点格的值。

处理合并单元格就像给旧食谱的跨行分类补上重复标注:虽然印刷原稿只写了一次,但你在抄录本上每行都要写一遍,这样检索时每行食材都能对应到正确的分类,不会因为缺值而被漏掉。

T[i][j]=T[r0][c0],(i,j)∈region(r0,c0)\displaystyle T[i][j]=T[r_0][c_0],\quad (i,j)\in \text{region}(r_0,c_0)
这条公式表达合并单元格的核心处理逻辑:被合并覆盖的每个位置,最终都填上合并区域起点格的值,保证数据不缺项。
  1. T[i][j]逻辑表格位置:i 和 j 表示展开后的行列坐标,每个位置最终都要有值。
    T[i][j]=展开后第 i 行第 j 列的取值T[i][j]=\text{展开后第 }i\text{ 行第 }j\text{ 列的取值}
  2. T[r0][c0]合并起点值:合并区域左上角那个真正有文字的格子,是数据的唯一来源。
    T[r0][c0]=合并区域左上角的值T[r_0][c_0]=\text{合并区域左上角的值}
  3. region(r0,c0)覆盖矩形:以起点为中心、按跨度扩展开的连续行列范围。
    region(r0,c0)=[r0,r0+rowspan)×[c0,c0+colspan)\text{region}(r_0,c_0)=[r_0,r_0+\text{rowspan})\times[c_0,c_0+\text{colspan})
  4. 等号连接覆盖范围内的每个位置都引用起点值,相当于把调味料的名字复制到每一行。
    T[i][j]=T[r0][c0]T[i][j]=T[r_0][c_0]

转结构化数据

表格抄完,最后一步是把抄录清单录入手机 App 的菜品数据库。从通用表格到可供 RAG 检索的数据,中间要过三道关。第一关是表头提取:默认表格第一行是字段名,把“食材、用量、备注”这些列名逐一摘出来,必要时还要处理多级表头。第二关是行转记录:每一行数据都对应菜谱里的一种食材,变成一个独立的记录对象。第三关是字段映射:把第一行的表头当作键,把当前行的单元格当作值,凑成一个“字段名:内容”的配对集合。

完成这三关后,所有记录组合起来就是一个 JSON 数组。JSON 是 RAG 系统非常喜欢的输入格式——它既是纯文本,又保持了结构,放进向量检索或关键词检索都清晰可解析。相比把整页表格塞成一段话,结构化之后的每一“行”都能单独成为一条可检索的知识单元,召回质量会有质的提升。

把这三关理清,可以用公式表达“每一行变一条记录”:

进入 App 的不仅是“菜名和正文”,更是每条整齐的记录。RAG 系统拿到 JSON 数组后,可以灵活地对任意字段做检索,就像在手机里按“食材”或“用量”筛选菜品一样自如。

Ri={ hj:vij∣j=1,2,…,n }\displaystyle R_i=\{\,h_j : v_{ij}\mid j=1,2,\dots,n\,\}
这条公式刻画行转记录的本质:第 i 行数据与表头逐列配对,生成 n 个键值对,组成一条结构化的 JSON 记录。
  1. R_i第 i 条记录:表头之下第 i 行数据转化而成的一条结构化记录,对应菜谱中的一种食材。
    Ri=第 i 行对应的记录R_i=\text{第 }i\text{ 行对应的记录}
  2. h_j第 j 个表头名:从表头行提取出的字段名,如“食材”“用量”。
    hj=表头第 j 列名称h_j=\text{表头第 }j\text{ 列名称}
  3. v_ij第 i 行第 j 列的值:当前行中与表头对应列的单元格内容,如“盐”“5克”。
    vij=第 i 行第 j 列单元格值v_{ij}=\text{第 }i\text{ 行第 }j\text{ 列单元格值}
  4. h_jv_ij 配对:冒号表示键值对,所有配对汇成一条 JSON 对象。
    Ri={h1:vi1, h2:vi2, …, hn:vin}R_i=\{h_1:v_{i1},\, h_2:v_{i2},\,\dots,\,h_n:v_{in}\}

质量评估

抄完一整个档案馆的菜谱,不能直接交差,得随机抽查几页,对照原稿看看有没有抄漏、抄错。这就是表格提取的质量评估环节,也是 RAG 数据上线前的最后一道闸门。完整性检查负责统计:提取出的单元格数对比真实单元格数,差距过大说明有表格被整体跳过,或某些行列被漏读。准确性校验负责内容层面:抽样几十条记录,人工或规则化地比对原文,看看文字是否有串位、错位。

召回率评估则从检索视角回答“有没有漏掉表格本身”。假设文档里实际有 10 个表格,程序只提取到 8 个,那么表格级别的召回率就是 80%。在 RAG 场景里,漏掉一个表格往往意味着对应问题永远得不到正确答案,所以召回率比精确率更值得优先关注。

质量评估就像档案馆的终检员,拿着放大镜抽查几页菜谱,确认没有漏行漏列才允许入库。在 RAG 系统中,只有通过完整性、准确性和召回率三重检查的表格数据,才值得写进知识库,否则检索到的“结构化表格”里可能处处是坑。

Recall=TPTP+FN\displaystyle \text{Recall}=\frac{TP}{TP+FN}
召回率衡量“该提取的表格/单元格有多少被成功提取”,值越高说明漏得越少,适合作为表格提取的上线门槛。
  1. TP正确提取数:被成功提取且内容正确的表格或单元格,像抄写本上与原稿一致的那些行。
    TP=#{提取正确且有效}TP=\#\{\text{提取正确且有效}\}
  2. FN漏提数:原稿中存在但程序没有提取出来的表格或单元格,像被翻页略过的菜谱。
    FN=#{存在于原文却漏掉}FN=\#\{\text{存在于原文却漏掉}\}
  3. TP+FN真实总数:两部分相加等于文档中实际应有的总量。
    TP+FN=NrealTP+FN=N_\text{real}
  4. Recall召回率:正确提取数与真实总数之比,1 表示一个不漏,0.9 表示漏了一成。
    Recall=TPTP+FN\text{Recall}=\frac{TP}{TP+FN}

AI 应用场景

金融研报财务表格抽取

阶段:数据准备与清洗

解决的问题:基金经理要把几十份 PDF 研报里的财务预测表(营收、利润、毛利率)整理成可比数据,传统做法是人工复制粘贴,一份报告要花半小时;AI 用 pdfplumber 解析加规则清理后,几分钟就能生成统一的 JSON 表,再进 RAG 向量库供投研问答检索。

具体案例:某金融科技的投研助手每天处理 200 份研报,提取出“2024 年营收预测”等表格后转换为 JSON 字段,分析师提问“哪些公司预期毛利率超过 30%”,系统直接检索结构化字段秒级给出答案。

合同条款信息结构化

阶段:文档解析与知识抽取

解决的问题:合同中的付款计划表、交付里程碑表,是法务高频查询的对象。AI 先用合并单元格处理补全横跨多行的“付款条件”,再用表头映射成“付款阶段/金额/截止日期”的记录,最终落入合同知识库。

具体案例:某企业法务系统接入表格提取管道后,上传 500 份 Word 合同时自动抽出所有付款计划表,法务提问“Q3 有哪些合同待付款”时,RAG 能准确定位到对应表格行并输出金额与日期。

Python 演示

python72 行
"""从 PDF 与 Word 中提取表格并转为结构化 JSON 的演示"""import jsonfrom typing import List  def extract_pdf_tables(pdf_path: str) -> List[List[List[str]]]:    """使用 pdfplumber 从 PDF 页面中提取表格"""    import pdfplumber    tables = []    with pdfplumber.open(pdf_path) as pdf:        for page in pdf.pages:            for table in page.extract_tables():                tables.append(table)    return tables  def extract_word_tables(docx_path: str) -> List[List[List[str]]]:    """使用 python-docx 从 Word 中提取表格"""    from docx import Document    doc = Document(docx_path)    tables = []    for table in doc.tables:        rows = []        for row in table.rows:            cells = [cell.text.strip() for cell in row.cells]            rows.append(cells)        tables.append(rows)    return tables  def fill_merged_cells(table: List[List[str]]) -> List[List[str]]:    """把合并单元格的值广播到覆盖位置,避免缺值"""    filled: List[List[str]] = []    for r, row in enumerate(table):        new_row = []        for c, cell in enumerate(row):            if cell:                new_row.append(cell)            elif r > 0:                new_row.append(filled[r - 1][c])            else:                new_row.append("")        filled.append(new_row)    return filled  def tables_to_records(tables: List[List[List[str]]]) -> List[dict]:    """表头映射为键,每一行转为一条 JSON 记录"""    records = []    for raw in tables:        table = fill_merged_cells(raw)        if not table:            continue        header = [h.strip() for h in table[0]]        for row in table[1:]:            record = {}            for i, cell in enumerate(row):                key = header[i] if i < len(header) else f"col_{i}"                record[key] = cell            records.append(record)    return records  def main() -> None:    pdf_tables = extract_pdf_tables("report.pdf")    docx_tables = extract_word_tables("notes.docx")    records = tables_to_records(pdf_tables + docx_tables)    print(json.dumps(records[:5], ensure_ascii=False, indent=2))  if __name__ == "__main__":    main()
目的:把 PDF 和 Word 中的表格统一提取为 JSON 记录,并演示了合并单元格补全与表头映射两个关键环节。
  1. page.extract_tables()用 pdfplumber 把一页 PDF 里所有表格以“行×列”的二维列表返回,是 PDF 表格提取的核心入口。
  2. doc.tablespython-docx 把 Word 文档中所有表格暴露成一个可遍历集合,直接拿到表格对象。
  3. cell.text.strip()取出单元格文字并去掉首尾空白,避免换行符和空格污染后续 JSON 字段。
  4. new_row.append(filled[r - 1][c])当前格为空时向上取上一行同列的值,完成纵向合并的复制填充。
  5. header[i] if i < len(header)把表头第 i 列当作键名,行单元格当作值,实现“表头→字段名”的映射。
  6. json.dumps(records[:5], ensure_ascii=False, indent=2)打印前 5 条记录,ensure_ascii=False 让中文正常显示。

常见误区

误区我用了 pdfplumber 提取所有 PDF 的表格,遇到扫描件就提不出来,肯定是这个库不行,换个更强的库就好了。

正解扫描件里的表格本质是图片,任何基于文字定位的库都无效,必须先 OCR 把图片变成文字,再用有框线或无框线的解析策略。工具选型的本质是“按表格类型匹配工具”,而不是“找一个万能工具”。就像抄菜谱,活字印刷页用细齿梳,照片页得先拓印再抄写。

为何常见:初学者通常只接触过文字型 PDF,容易把工具能力绝对化,忽略输入格式对结果的决定性影响。

误区提取出的表格,合并单元格那几行是空的,直接转 JSON 存库里,反正检索时凑合能用。

正解空的合并区域会让记录缺字段,RAG 检索时该行无法被完整召回。正确做法是先识别 rowspan/colspan,做行列映射后把起点值复制到覆盖位置,保证每条记录字段齐全。这就像把“调味料”抄到每一行食材旁边,而不是只写一次。

为何常见:因为表格在视觉上“看起来”值只出现一次,新手误以为缺值是正常的,没有意识到这会让下游数据结构不完整。

误区表格提取脚本跑完没报错,输出 JSON 也生成了一堆数据,直接喂给 RAG 就好。

正解不报错不等于提取正确。必须做完整性检查(单元格数对比)、准确性校验(抽样比对原文)和召回率评估(漏表率),尤其要确认“文档里实际存在的表格”是否全部被提出来。终检员都没请,抄漏的菜谱自然悄悄进了数据库。

为何常见:报错导向的开发习惯让人只关注异常,忽略了静默错误——提取结果结构完整但内容错位,是表格提取最常见的失败模式。

误区每张表格都用第一行当表头做字段映射,结果有的表头是“名称/数量”,有的是“品名/规格/数量”,字段名对不上就报错。

正解真实文档里不同表格的表头往往不一致,需要做归一化:统一别名映射(“名称”→“品名”)、识别二级表头、无法匹配的列降级为 col_i 兜底名。表头是字段映射的钥匙,钥匙不对,门自然打不开。

为何常见:因为样例数据往往只有一张整齐的表格,容易忽略真实语料中表头多变的事实。

面试题

Q1. 在 RAG 文档处理中,为什么要对 PDF 和 Word 中的表格做专门提取?

单选题 · easy

  • A.因为表格比普通文字更能提升页面美观度
  • B.因为表格结构需要转为结构化数据才能高效检索← 正确答案
  • C.因为表格里的文字都是加密格式无法直接读取
  • D.因为 PDF 和 Word 本身不支持存储表格

答案:B。表格以行列结构承载信息,若整页转成文字会丢失结构,检索时无法按字段匹配。转为结构化数据后,RAG 才能对“行/列/字段”做精准召回。A 说的是视觉目标,C、D 与事实不符,选 B。

Q2. 下列哪个库可以从 Word 文档中直接读取表格对象?

单选题 · easy

  • A.pdfplumber
  • B.Camelot
  • C.python-docx← 正确答案
  • D.PyMuPDF

答案:C。python-docx 用于解析 Word 文档,doc.tables 直接暴露表格对象。pdfplumber、Camelot、PyMuPDF 都是处理 PDF 的工具,方向不同,故选 C。

Q3. 提取 PDF 表格时,发现页面完全没有可见边框线,最合理的做法是?

单选题 · mid

  • A.放弃提取,改为人工录入
  • B.用 PyMuPDF 按文本坐标自行拼行列← 正确答案
  • C.使用 pdfplumber 只提取文字段落
  • D.直接按整页文本送入向量检索

答案:B。无框线表格没有现成网格可循,适合用 PyMuPDF 拿到文字块坐标后按对齐关系自行拼表,或借助 Camelot 重建网格。A、C 放弃或退化为纯文本,D 丢失表格结构,故选 B。

Q4. 关于合并单元格,下列哪项描述正确?

单选题 · mid

  • A.合并单元格在 PDF 和 Word 中都有明确属性标识
  • B.提取时可以忽略合并单元格直接拼接文本
  • C.合并单元格需要识别跨度并填充覆盖位置← 正确答案
  • D.合并区域只影响显示样式不影响数据结构

答案:C。Word 有 rowspan/colspan 属性,PDF 通常要靠边框推断,A 错;忽略合并会导致缺值,B 错;合并既影响显示也影响数据结构,D 错。C 是标准处理流程的准确描述。

Q5. 表格转结构化数据时需要完成哪些环节?

多选题 · mid

  • A.从首行提取表头字段名← 正确答案
  • B.将每一行数据映射为一条记录← 正确答案
  • C.使用 OCR 识别所有图片内容
  • D.把表头作为键与单元格值配对← 正确答案

答案:ABD。结构化转换的核心是先提取表头、再行转记录、最后表头与值配对成键值对,三步缺一不可。OCR 只在扫描件场景才需要,不是通用必要环节,故选 ABD。

Q6. 在质量评估中,召回率主要回答什么问题?

单选题 · mid

  • A.提取出的内容有多少是准确无误的
  • B.文档中应提取的表格有多少被成功提取← 正确答案
  • C.提取过程是否使用了正确的工具库
  • D.结构化 JSON 的字段顺序是否合理

答案:B。召回率 = TP/(TP+FN),关注的是“该提取的有没有漏”。A 更接近准确率/精确率,C、D 与召回率无关,故选 B。

Q7. 一段工具输出文本 A 与标准答案 B 计算相似度,A=“盐糖醋”,B=“盐和糖醋”,共同字符为盐、糖、醋,则相似度约为多少?

单选题 · hard

  • A.0.50
  • B.0.67
  • C.0.86← 正确答案
  • D.1.00

答案:C。|A∩B|=3(盐、糖、醋),|A|=3,|B|=4,Sim=2×3/(3+4)=6/7≈0.86。A 是去掉乘 2 的结果,B 是分母取 6 的错误算法,D 要求完全相等。故选 C。

Q8. 关于 Camelot 与 pdfplumber 的差异,下列说法正确的是?

单选题 · hard

  • A.Camelot 速度更快且依赖更少
  • B.pdfplumber 擅长重建无框线表格
  • C.Camelot 通过视觉线条重建表格网格← 正确答案
  • D.pdfplumber 完全不支持表格提取

答案:C。Camelot 基于 OpenCV 找直线并重建网格,适合复杂表格但依赖重、速度慢,A 错;pdfplumber 对有线表格友好但对无框线表能力有限,B 错;pdfplumber 的核心能力之一就是表格提取,D 错。故选 C。

Q9. RAG 系统中表格提取的完整质量评估应包含哪些维度?

多选题 · hard

  • A.完整性检查:对比真实单元格数与提取数← 正确答案
  • B.准确性校验:抽样比对单元格文字是否一致← 正确答案
  • C.召回率评估:统计漏掉的表格数量← 正确答案
  • D.代码复杂度评估:统计解析脚本的行数

答案:ABC。完整性、准确性、召回率是表格提取质量评估的三个核心维度,分别回答“有没有漏格、有没有抄错、有没有漏表”。D 是工程维护指标,与提取质量无直接关系,故选 ABC。

Q10. 关于表格识别基础,以下说法正确的有哪些?

多选题 · easy

  • A.表格是由行列构成的二维网格结构← 正确答案
  • B.表格类型的差异会影响工具选型← 正确答案
  • C.扫描件属于图片型表格需要特殊处理← 正确答案
  • D.所有 PDF 表格结构都可以直接读取

答案:ABC。表格是行列网格,表头、行、列、单元格是其基本结构;有线/无线/图片型分类直接影响选型;扫描件本质是图片,需 OCR 预处理。D 与事实不符,文字型 PDF 可以直接读取,扫描型不能。故选 ABC。