LangChain 学习笔记 08:一个 PDF 问答系统,真正要检查哪些环节
PDF 问答大概是最常见的 RAG Demo:上传文件,输入问题,几秒后得到答案。演示效果很直观,但“能回答一两个问题”和“能稳定处理一批真实 PDF”之间,还有不小的距离。
第 9 章把前面的 Loader、切分器、Embedding、向量库、Retriever 和问答链串到一起。这个案例最适合用来练习的,不是复制代码,而是沿着整条证据链逐段排查。
系统其实有两条流程
文档处理和用户提问不应该混在一次请求里。
索引流程:PDF -> 文本抽取 -> 清洗切分 -> Embedding -> 写入索引
查询流程:问题 -> 检索证据 -> 组织上下文 -> 模型回答 -> 返回引用
索引流程可以异步执行,并记录文档状态;查询流程只读取已经准备好的索引。否则每次提问都重新解析 PDF,不仅慢,也很难处理更新和失败重试。
PDF 不是天然干净的文本
PDF 保存的是版面。双栏排版可能把左右两列交叉读取,页眉页脚会在每页重复,表格可能只剩下一串错位文字,扫描件还需要 OCR。
所以文件加载完成后,我不会立刻生成向量,而是先抽样检查:
- 标题与段落顺序是否正确;
- 表格、代码和列表有没有被打散;
- 页码能否回到原文;
- 扫描页是否识别成功;
- 是否混入大量页眉、页脚和水印。
这一关没有过,后面调 Prompt 基本是在错误数据上继续加工。
切分要服务于“用户会怎样问”
技术手册适合优先按章节、标题和段落切分,再用长度限制兜底。合同、制度或论文则可能需要保留条款号、表格标题和脚注关系。
每个块除了正文,最好带上文件 ID、页码、章节、块序号、文档版本和权限标签。这样检索结果既能展示来源,也能在文档更新时准确删除旧向量。
内容哈希也很有用:没有变化的块无需重复生成 Embedding,修改过的块则可以单独重建。
回答必须和证据一起返回
在线查询时,系统先检索相关片段,再把问题与资料明确分开交给模型。Prompt 至少应约束三件事:只依据给定资料;资料不足时直接说明;回答要附带可核对的来源。
我更希望接口返回结构化结果:
{
"answer": "退款申请需要在支付后 24 小时内提交。",
"citations": [
{"file": "售后手册.pdf", "page": 12, "chunk_id": "manual-12-03"}
],
"grounded": true
}
模型生成的引用仍要校验,不能允许它凭空编一个页码。最稳妥的做法,是让模型引用系统提供的文档 ID,再由程序映射到真实文件和页码。
五类问题比“随便问一句”更有价值
我会至少准备下面五类测试:
- 答案明确存在于一个块中;
- 答案需要组合多个页面;
- 用户使用同义词或简称;
- 文档里根本没有答案;
- 不同版本或页面给出冲突信息。
评估时先看正确证据有没有被召回,再看回答是否忠于证据。模型凭常识碰巧答对,不算 RAG 成功;检索命中了正确页面,模型却遗漏例外条件,也不算完成。
权限必须发生在检索阶段
多用户知识库不能先召回所有文档,再要求模型“不要泄露”。租户、部门、密级等过滤条件,应在检索前或检索过程中生效。
上传文件也属于不可信输入。除了限制类型、大小和解析资源,文档里的指令性文字只能被当作资料,不能改变系统规则。
这章给我的启发
PDF 问答看似是一个应用案例,实际上把 RAG 的每个薄弱点都暴露了出来:抽取、切分、索引、检索、生成、引用和权限。
系统质量不是由最后一次模型调用单独决定的。只有当答案能沿引用回到原页,错误能沿 Trace 找到具体步骤,这个 Demo 才开始接近一个可用产品。

浙公网安备 33010602011771号