文档解析与知识抽取
很多知识库项目一开始最容易犯的错是:
- 先想着向量化
- 先想着怎么问答
但如果文档根本没被解析对,后面检索和生成都会一起歪。
所以这节最重要的不是先讲向量 库,而是先建立一个判断:
文档要先被解析成“可理解、可切块、可追溯”的知识对象。
学习目标
- 理解为什么 PDF / Word / PPT 不能只抽纯文本
- 理解扫描版 PDF 和图片页为什么会把 OCR 拉进链路
- 学会把文档解析成“正文 + 层级 + 元数据 + 例题”这类结构
- 看懂一个最小的文档解析与知识抽取流程
先建立一张地图
文档解析更适合按“文件 -> 结构 -> 知识块”来理解:
所以这节真正想解决的是:
- 为什么知识库项目不是“把文件内容抠出来就结束”
- 为什么标题层级、页码、章节和例题都会影响后面检索质量
一、为什么文档解析经常比想象中更难?
因为不同文档格式的问题完全不一样:
PDF可能只是“视觉排版结果”,段落顺序并不天然稳定DOCX结构通常更清楚,但样式、标题层级不一定统一PPTX常常是碎片化要点,不像连续文章- 扫描版 PDF 则连正文文字都不一定能直接拿到
这意味着真正可用的知识库通常要先回答:
- 文本抽出来了吗?
- 顺序对了吗?
- 标题、页码、章节还在吗?
- 哪些内容是例题、定义、正文、备注?
二、一个更适合新人的总类比
你可以把文档解析理解成:
- 先把一大箱资料整理成可翻阅的卡片盒
如果你只是把所有纸随便倒出来,
后面当然也能翻,但会很乱。
更稳的做法是先把它们整理成:
- 主题
- 章节
- 标题
- 例题
- 来源
这样后面系统问“我要找哪个主题的例题”时,才有可能真的找得准。
三、不同文件类型最常见的问题
| 文件类型 | 最常见的问题 |
|---|---|
| 顺序错、页眉页脚混进正文、两栏排版打乱 | |
| Word | 标题层级不统一、表格和正文混在一起 |
| PPT | 一页信息少但碎,常需要保留“页”这个概念 |
| 扫描版 PDF / 图片页 | 需要 OCR,且容易识别错字和顺序 |
这张表特别适合新人,因为它会提醒你:
- 文档处理不是“一个解析器走天下”
四、一个最小文档解析工作流示例
下面这个例子不依赖真实第三方库,
但会把“不同文档类型走不同解析路线”这件事先讲清楚。
from pathlib import Path
def route_parser(filename):
suffix = Path(filename).suffix.lower()
if suffix == ".pdf":
return "pdf_text_or_ocr"
if suffix == ".docx":
return "word_parser"
if suffix == ".pptx":
return "ppt_parser"
return "unsupported"
files = [
"lesson_1.pdf",
"chapter_2.docx",
"course_outline.pptx",
]
for file in files:
print(file, "->", route_parser(file))
这个示例最重要的价值是:
- 先让你脑子里有“路由”这件事
也就是说,文件一进系统,不是直接统一塞进一个函数,
而是先判断:
- 这是什么文件
- 该走哪条解析链
五、一个更像真实系统的知识块长什么样?
真正送进知识库的,不应该只是:
- 一段裸文本
而更应该像下面这样:
chunks = [
{
"doc_id": "word_001",
"source_type": "docx",
"section_title": "应用题:折扣计算",
"page_or_slide": 3,
"content": "商店对 100 元商品打 8 折,问现价是多少?",
"content_type": "example",
},
{
"doc_id": "ppt_002",
"source_type": "pptx",
"section_title": "知识点总结",
"page_or_slide": 8,
"content": "折扣 = 原价 × 折扣率。",
"content_type": "concept",
},
]
for chunk in chunks:
print(chunk)
这个例子特别适合初学者,因为它会帮助你先看到:
- 真正有价值的不是“只拿到字”
- 而是把字放回来源、章节、页码和内容类型里
六、一个更像真实项目的解析结果 schema
第一次做这类系统时,最容易少掉的是:
- 文档级元数据
- 章节级结构
- 知识块级内容
更稳的做法通常是把解析结果分成三层:
| 层次 | 你最少要保留什么 |
|---|---|
| 文档层 | doc_id / 文件名 / 来源类型 / 创建时间 / 学科 |
| 章节层 | section_id / 标题 / 章节路径 / 页码范围 |
| 知识块层 | chunk_id / 文本 / 内容类型 / 来源页 / 是否例题 |
你可以先把它想成:
- 文档层像一本书的封面卡
- 章节层像目录
- 知识块层像真正拿去检索和生成的卡片
下面这个最小结构很适合新人先抄着做:
parsed_doc = {
"doc_id": "math_pdf_001",
"source_type": "pdf",
"title": "折扣应用题专项训练",
"subject": "数学",
"sections": [
{
"section_id": "s1",
"section_title": "折扣基础概念",
"page_range": [1, 2],
"chunks": [
{
"chunk_id": "c1",
"content_type": "concept",
"page_or_slide": 1,
"text": "折扣 = 原价 × 折扣率",
},
{
"chunk_id": "c2",
"content_type": "example",
"page_or_slide": 2,
"text": "商品原价 100 元,打 8 折后是多少元?",
},
],
}
],
}
print(parsed_doc["sections"][0]["chunks"][1]["text"])
这个 schema 的意义不是“设计得特别漂亮”,而是:
- 后面检 索时有东西可筛
- 后面生成课件时知道哪里是概念、哪里是例题
- 后面做引用回溯时知道内容从哪一页来
七、为什么“内容类型”特别重要?
因为你的项目不是普通问答,
而是要做:
- 按主题找资料
- 找相关例题
- 再按固定格式生成 Word 课件
这时系统如果能分清:
conceptexampleexercisedefinition
后面生成课件时就会稳很多。
八、一个最小“例题抽取”示例
对你的项目来说,只知道一段话属于哪一页还不够,
还要尽量分清:
- 这是不是例题
- 这是不是练习题
- 这是不是定义或公式
第一次做时不用一上来就上复杂模型,
可以先用最小规则版建立闭环。
def guess_content_type(text):
if "例" in text or "解:" in text:
return "example"
if "练习" in text or "思考题" in text:
return "exercise"
if "定义" in text or "公式" in text:
return "concept"
return "paragraph"
samples = [
"例1:商品原价 100 元,打 8 折后是多少元?",
"练习:一件衣服原价 80 元,打 7 折后是多少元?",
"公式:折扣 = 原价 × 折扣率",
]
for sample in samples:
print(guess_content_type(sample), "->", sample)
这个最小规则版虽然不完美,
但特别适合新人理解:
- “例题抽取”不是魔法
- 它本质上是在做文档内容分类
九、扫描件为什么会把 OCR 拉进来?
因为扫描版 PDF 或图片页本质上不是文字文件,而是:
- 文字长得像图片
所以你需要先做:
- OCR 识字
再继续做:
- 结构恢复
- 标题层级识别
- 例题抽取
如果你后面要处理很多扫描教案、截图或拍照资料,这一步会非常关键。
对应课程可以回看:
十、第一次做这个模块时,最稳的范围控制
第一次开发时,最容易失败的原因不是技术太难,
而是支持范围一下子开太大。
更稳的最小版本通常是:
- 先只支持文本型
DOCX - 再支持文本型
PDF - 再支持
PPTX - 最后再补扫描件 OCR
这个顺序的好处是:
- 你可以先把结构和 schema 跑顺
- 不会一开始就被 OCR 识别问题拖住
十一、一个新人可直接照抄的解析检查表
第一次做知识库文档解析时,最稳的检查表通常是:
- 文字有没有被完整抽出来?
- 标题和正文顺序对不对?
- 章节层级有没有保住?
- 页码 / 幻灯片页号有没有保留?
- 能不能区分正文和例题?
- 扫描件有没有 OCR 错字?
这 6 项比“先上向量库”更优先。
十二、如果把它做成项目,最值得展示什么?
最值得展示的通常不是:
- “我们支持 PDF / Word / PPT”
而是:
- 原始文档长什么样
- 解析后的结构化知识块长什么样
- 例题是怎么被识别出来的
- OCR 或结构恢复在哪些地方容易出错
这样别人会更容易看出:
- 你理解的是知识入库链路
- 不只是会“读文件”
小结
- 文档解析真正要解决的是“把文件变成结构化知识对象”
- schema 设计决定了后面的检索、引用和课件生成能不能稳
- 第一次做时,先把
DOCX / 文本 PDF / 例题抽取规则版跑顺,比一上来全支持更现实
这节最该带走什么
- 文档解析不是把字抠出来就结束,而是要恢复结构和来源
- 真正有价值的知识块,应该带标题、页码、内容类型等元数据
- 如果你的知识库来自大量 PDF / Word / PPT / 扫描件,这一步就是整条链最关键的入口之一