面向 FAQ、流程文档、规则文档的 RAG 处理方案
一文了解LangChain4j RAG的概念、阶段、流程、Query压缩、Query路由、RAG+Tool等实战 介绍了LangChain4j的RAG的使用,尚未深入处理具体的业务文档,本文对具体业务类型文档RAG。
概览
如果知识库里的内容同时来自 Markdown、Word、PDF ,而且还包含 表格、图片、超链接、公式 等复杂元素,直接切分和向量化,通常会遇到两个问题:
- Chunk 不完整:同一段规则、同一张表格、同一条流程被拆散,检索命中后信息不全。
- 语义被污染:尤其是图片 URL、无意义路径、格式噪声,会降低向量检索质量。
这类文档特别适合先做一次 统一语义结构转换,再进入 RAG(Retrieval-Augmented Generation,检索增强生成)流程。
读完本文,你可以获得 4 个核心结论:
- 为什么异构文档不能直接切分向量化
- 如何设计一套统一的文档语义结构
- 如何处理 Word/PDF 中的图片,避免 URL 带来语义噪声
- 检索命中后,如何再把占位图片恢复成真实可访问 URL
一、这类文档为什么要单独处理
FAQ、流程型文档、规则型文档有一个共同特点:结构比自然语言更重要。
例如:
- FAQ 依赖"问题-答案"的配对关系
- 流程文档依赖"步骤顺序"和"条件分支"
- 规则文档依赖"章节层级""编号""表格约束"
如果直接把 Word、PDF 文本抽出来再粗暴切分,常见问题包括:
- 标题和正文被拆开
- 表格被打散成无序文本
- 列表项失去编号关系
- 图片只剩下链接,丢失图意
- 公式、链接、批注等信息在抽取中丢失
因此,更稳妥的做法是:
先把不同格式文档转换成统一的"语义树",再生成适合 LLM 和向量检索的标准化 Markdown。
二、整体处理流程
整个方案可以分成两个阶段。
1. 索引阶段
text
异构文档
→ 统一语义结构
→ 输出标准 Markdown
→ 生成适合 LLM 的 Markdown
→ 文档切分与向量化
2. 检索阶段
text
查询检索
→ 命中 Chunk
→ 恢复图片真实 URL
→ 组装上下文
→ 交给 LLM 生成回答
这套流程的核心目标只有一个:
让进入向量库的内容尽可能"语义完整、噪声更低、结构可恢复"。
三、统一语义结构:先把文档变成"可理解的树"
为了兼容 Word、PDF、Markdown,建议先抽象出一层中间结构。
1. 基础结构
java
@Data
public class DocumentNode {
private NodeType type;
private String content;
private Map<String, Object> attrs;
// 记录文档结构信息,例如:
// "level": 3, "numbering": "1.1", "style": "Heading3", "page": 4
private List<DocumentNode> children;
}
java
public enum NodeType {
HEADING,
PARAGRAPH,
LIST,
TABLE,
IMAGE,
CODE,
LINK
}
2. 这层结构有什么意义
这不是简单的文本抽取,而是把文档还原为"有层次的内容单元"。
例如:
HEADING:表示标题,能保留层级关系PARAGRAPH:表示普通段落LIST:表示列表,便于保留步骤顺序TABLE:表示表格,避免列与列之间被打乱IMAGE:表示图片,后续可绑定图片语义和元数据LINK:表示超链接,必要时保留锚文本与目标地址
这样做的好处是:
- 后续切分时可以按节点边界切,而不是按字符硬切
- 检索时更容易保留上下文完整性
- 回答时能更接近原始文档结构
3. 建议补充的节点类型
如果你的文档里公式较多,建议在 NodeType 中增加:
FORMULA:公式节点QUOTE:引用节点NOTE:备注或提示框SECTION:大章节容器节点
尤其是规则型文档,公式和注释往往会直接影响答案准确性。
四、索引阶段的关键设计
1. 第一步:异构文档解析
针对不同来源文档,先做基础解析:
- Markdown:读取标题、列表、表格、图片、代码块
- Word:读取段落样式、编号、表格、内嵌图片、超链接
- PDF:按版面结构提取段落、表格、页码、图片区域
这里的重点不是"把字读出来",而是尽量保留:
- 标题层级
- 段落关系
- 编号关系
- 表格结构
- 图片位置
- 页码信息
其中 attrs 很关键,它能保存结构线索,例如:
json
{
"level": 2,
"numbering": "3.1",
"style": "Heading2",
"page": 12
}
这些信息在后续切分、检索排序、结果展示时都很有价值。
2. 第二步:转换为统一语义结构
当 Word、PDF、Markdown 都被转换为 DocumentNode 树之后,后续流程就统一了。
此时你可以做几件重要的标准化操作:
标题归一化
把 Word 的 Heading1/Heading2、PDF 的字号层级、Markdown 的 # / ## / ###,统一成标准层级。
列表归一化
将:
1.(1)a.-
统一识别为列表项,并保留原始编号。
表格归一化
表格不要直接压扁成连续文本,建议保留:
- 表头
- 行列关系
- 单元格内容
- 跨行跨列信息(如果可提取)
图片归一化
每张图片至少保留:
- 图片 ID
- 图片说明文字(caption)
- 原始位置
- 页码
- 宽高、类型等元数据
3. 第三步:输出标准 Markdown
统一语义结构生成 Markdown 的目的,不只是为了"好看",而是为了形成一个:
既适合人工检查,也适合机器处理的中间产物。
例如:
- 标题转为
# / ## / ### - 列表转为标准 Markdown 列表
- 表格转为 Markdown 表格,或必要时转为结构化文本
- 图片转为 Markdown 图片语法
- 链接保留锚文本
这一层输出后,通常可以作为"归档版 Markdown"。
4. 第四步:生成适合 LLM 的 Markdown
标准 Markdown 不一定最适合向量化和大模型理解,因此建议再做一层"LLM 友好化"处理。
例如:
补足上下文
把孤立的小标题和正文合并,避免只向量化一个短标题。
表格语义展开
对于重要表格,可以额外转为自然语言描述,例如:
费用审批规则表:A 类金额上限 5000 元,审批人为部门负责人;B 类金额上限 20000 元,审批人为总监。
保留图片语义,不保留噪声 URL
图片不要直接保留真实 CDN 链接,而应保留语义占位符。
加入结构提示
在必要时补充轻量标签,例如:
text
[章节] 请假审批规则
[步骤] 2
[页面] 4
这类提示有助于提升召回和回答稳定性。
5. 第五步:按语义边界切分并向量化
这里的关键不是"切多大",而是"按什么切"。
推荐切分原则
优先按以下边界切分:
- 标题块
- 列表步骤块
- 表格块
- 图片说明块
- 规则条款块
为什么不能只按字数切
因为 FAQ、流程、规则类文档的核心信息,常常依赖完整结构:
- 一个问题必须和它的答案放在一起
- 一个流程步骤必须和前后步骤关联
- 一条规则必须保留编号、条件、例外说明
因此,建议采用:
结构切分优先,长度限制兜底。
术语说明
- Chunk:切分后的文本片段
- Embedding:把文本映射为向量,用于语义检索
- 向量化:生成 Embedding 的过程
五、Word / PDF 图片处理:真正容易出问题的环节
在这类文档中,图片经常很重要,比如:
- 审批流程图
- 系统操作截图
- 架构图
- 规则示意图
但图片处理不当,会直接影响检索效果。
1. 问题:真实图片 URL 会带来语义噪声
例如在 Markdown 中写成:
markdown

对 Embedding 模型和 LLM 来说,下面这些内容几乎没有语义价值:
httpscdn- 哈希串
- 文件路径
- 文件名编号
这些字符会占据文本空间,却不能帮助模型理解内容,反而会降低有效语义密度。
简单说就是:
模型需要的是"这是一张什么图",而不是"图放在哪个 URL"。
2. 解决方案:语义占位 + 延迟注水
这是处理图片最实用的一种方式。
向量化前,不写真实 URL,而写语义占位符
例如:
plain

或者写得更明确一些:
plain
[IMAGE_REF:img_102]
caption: 员工请假审批流程图
这里的 image://img_102 是一种内部引用,不是真实访问地址。
这个方案的好处
1)Embedding 仍能感知图片语义
模型能看到"员工请假审批流程图"这几个字,这是真正有用的语义信息。
2)不会引入 URL 噪声
避免把一长串无意义路径送进向量模型。
3)回答阶段还能恢复真实图片
当检索命中这段内容后,再把 image://img_102 解析成真实 URL 即可。
这就是"延迟注水"的含义:
先保留语义,等真正展示或回答时,再把可访问资源补回来。
六、图片处理的推荐实现流程
1. 在文档解析阶段
从 Word 或 PDF 中读取图片时,先提取图片二进制内容。
如果技术链路方便,可以临时转成 Base64 进行传递,但要注意:
Base64 只适合作为中间传输格式,不应该进入向量化文本。
因为 Base64 同样会制造大量噪声。
2. 在生成 Markdown 阶段
把图片上传到云端或对象存储后,得到真实 URL,例如:
markdown

这一版 Markdown 适合作为"展示版"或"存档版"。
3. 在向量化前做一次替换
在送入向量模型前,把真实 URL 替换为占位符:
markdown

同时在元数据(metadata)中保存图片真实信息:
json
{
"imageUrl_img_102": "https://example.com/img102.png",
"mime": "image/png",
"width": 1200,
"height": 800
}
这样做之后:
- 文本里保留的是语义
- 元数据里保留的是资源定位信息
二者分工明确。
七、检索阶段:命中后再恢复真实图片 URL
当用户提问后,系统会先检索出相关 Chunk。
如果 Chunk 中存在:
markdown

那么在把内容交给前端展示或交给 LLM 之前,可以通过内容注入器恢复:
markdown

1. 实现思路
可以自定义 ContentInjector,继承默认实现,在格式化内容时完成替换逻辑。
伪代码思路如下:
java
content = content.replace("image://img_102", "https://example.com/img_102.png");
更通用的方式是:
java
imageResolver.resolve("img_102")
由解析器从 metadata 中查出真实 URL,再注入内容。
2. 为什么要在检索后恢复,而不是索引前恢复
因为两个阶段目标不同:
索引阶段
目标是提高检索质量,所以要尽量减少噪声。
检索/展示阶段
目标是让回答更完整、结果更可读,所以要恢复真实资源。
这也是整个方案的关键思想:
索引时追求语义纯度,展示时追求内容完整。
八、一个更完整的流程示意
1. 索引阶段
text
Word/PDF/Markdown
→ 解析结构化内容
→ 转为 DocumentNode 语义树
→ 生成标准 Markdown
→ 图片上传对象存储
→ 将真实图片 URL 替换为 image:// 占位符
→ 保存图片 metadata
→ 按语义边界切分 Chunk
→ 向量化并写入向量库
2. 检索阶段
text
用户提问
→ 向量检索召回 Chunk
→ 发现 image://img_102
→ 从 metadata 解析真实 URL
→ 还原 Markdown 图片链接
→ 组装上下文
→ 交给 LLM 生成答案
九、这套方案能带来什么收益
采用统一语义结构后,FAQ、流程、规则类知识库通常会得到几个明显收益:
1. Chunk 完整性更高
标题、步骤、表格、规则条款不容易被错误拆散。
2. 检索召回更稳定
模型能更好理解"这段内容讲的是什么",而不是被格式噪声干扰。
3. 回答准确率更高
LLM 拿到的是结构化、上下文完整的内容,幻觉会更少。
4. 图片可检索、可展示
不仅能通过图片说明文字参与召回,还能在结果中恢复真实图片。
5. 技术链路更可维护
统一语义结构相当于建立了一层"文档中台",后续接入更多格式也更容易扩展。
十、实践建议
如果你准备落地这套方案,建议优先做好以下几点:
1. 把"文档解析"和"向量化"解耦
不要从原始 Word/PDF 直接一步到向量库,中间最好有统一语义层。
2. 图片、表格、标题优先保结构
这三类内容最容易影响召回质量。
3. 不要把 Base64、真实 URL 直接送入 Embedding
这类内容通常只会制造噪声。
4. Chunk 切分要基于语义节点
不是简单按字符数切块。
5. metadata 要足够完整
至少建议保存:
- 文档 ID
- 页码
- 标题路径
- 图片映射
- 表格标识
- 原始章节编号
十一、财务流程RAG实战效果
问:如何录入发票信息?
结果:
bash
[httpclient-dispatch-1] INFO tech.pplus.cases.ai.advanced.rag.FaqRagMain - text:如何录入发票信息?->aiMessage:
根据提供的参考资料,录入发票信息的具体操作如下:
1. **基本原则**:对外支付遵循"先开发票后付款"的规定。申请人在填写对公支付申请时,必须依据**已收到**的发票录入相关信息。
2. **关键选项设置**:
* 在"发票是否归档"处,必须选择"**是**"。
* 在"发票选择"处,需从系统中选择已录入的对应发票信息。
3. **关联规则**:
* **单行限制**:每行只能选择一张发票。
* **拆分关联**:如果同一张发票涉及多个部门或不同业务类型的费用支出,可以在同一个流程中多次关联该张发票。此时需将金额分开填写,但所有关联金额的总和必须等于发票总金额。

注意:有些大模型在使用RAG提供资料回答时,不会返回markdown格式图片,需要在SystemPrompt中要求返回图片。
总结
对于 FAQ、流程型、规则型文档,RAG 的难点不在"能不能抽出文本",而在:
能不能保住结构,减少噪声,并在回答时恢复完整信息。
一套更稳妥的处理方式是:
- 先把 Markdown、Word、PDF 转成统一语义结构
- 再生成标准化 Markdown
- 向量化前,把图片真实 URL 替换为语义占位符
- 检索命中后,再恢复真实图片 URL
- 最终把结构完整、语义干净的内容交给 LLM
这样做,既能提高检索质量,也能明显改善最终回答的准确性与可读性。