RAG进阶实战:PaddleOCR+混合检索打造高精度知识库
type
status
date
slug
summary
tags
category
icon
password
网址

在大型语言模型(LLM)的应用落地中,RAG(检索增强生成)是解决模型幻觉和知识时效性的关键技术。
而在RAG的诸多场景中,基于多文档高精度智能分析与问答系统,也就是知识库又必然是我们最常遇到,且企业场景最刚需的一类。
那么如何做好知识库?
本文将以开源项目Paddle-ERNIE-RAG为例,对其关键技术进行说明介绍。
项目地址:https://github.com/LiaoYFBH/Paddle-ERNIE-RAG
该系统集成了在线 OCR 解析、Milvus 混合检索(向量+关键词)以及多维度的重排序(Reranker)策略,可以提升低资源环境下的检索准确率,以实现高精度多文档分析与问答。
01
系统架构概览
本项目的系统主要由四个核心模块组成:
1.数据提取层:使用在线 OCR API 进行高精度的文档布局分析(Layout Parsing)。
2.存储层:利用 Milvus 向量数据库存储 Dense Embedding,同时维护倒排索引以支持关键词检索。
3.检索与问答层:实现向量检索与关键词检索的加权融合(RRF),集成 ERNIE 大模型 API 接口生成回答。
4.应用层:基于 Gradio 构建交互界面。
🔗 项目资源
• 🐙 GitHub 代码仓库:https://github.com/LiaoYFBH/Paddle-ERNIE-RAG
• 🚀 星河社区在线应用:https://aistudio.baidu.com/application/detail/107183
02
关键技术实现
2.1 PP-StructureV3 文档解析
针对科研论文中常见的双栏排版、公式混排及图表嵌入问题,传统的 PyPDF2 等纯文本提取工具往往力不从心(容易导致段落乱序、表格崩坏)。
为此,本项目在 backend.py 中封装了 OnlinePDFParser 类,直接集成 PP-StructureV3 在线 API 进行高精度的文档布局分析(Layout Parsing)。
该方案具备三大核心优势:
• 结构化输出:直接返回 Markdown 格式(自动识别标题层级、段落边界)。
• 图表提取:在解析文本的同时,自动提取文档中的图片并转存,为后续的“多模态问答”提供素材。
• 上下文保留:基于滑动窗口进行切分,防止关键信息在切片边界丢失。
2.1.1 核心解析逻辑
在 backend.py 中,我们构建了 API 请求,将 PDF 文件流发送至服务端,并解析返回的 layoutParsingResults,提取出清洗后的 Markdown 文本和图片资源。
backend.py (OnlinePDFParser 类核心逻辑摘要)
def predict(self, file_path):
1. 文件转 Base64
with open(file_path, "rb") as file:
file_data = base64.b64encode(file.read()).decode("ascii")
2. 构造请求 Payload
payload = {
"file": file_data,
"fileType": 1, # PDF 类型
"useChartRecognition": False, # 根据需求配置
"useDocOrientationClassify": False
}
3. 发送请求获取 Layout Parsing 结果
response = requests.post(self.api_url, json=payload, headers=headers)
res_json = response.json()
4. 提取 Markdown 文本与图片
parsingresults = resjson.get("result", {}).get("layoutParsingResults", [])
mock_outputs = []
for item in parsing_results:
md_text = item.get("markdown", {}).get("text", "")
images = item.get("markdown", {}).get("images", {})
... (后续图片下载与文本清洗逻辑)
mockoutputs.append(MockResult(mdtext, images))
return mock_outputs, "Success"
2.1.2 滑动窗口文本分块
拿到结构化的 Markdown 文本后,为了避免语义被生硬切断(例如一句话跨了两个 chunk),我们实现了一个带有 overlap(重叠区)的滑动窗口分块策略。
backend.py
def splittextintochunks(text: str, chunksize: int = 300, overlap: int = 120) -> list:
"""基于滑动窗口的文本分块,保留 overlap 长度的重叠上下文"""
if not text: return []
lines = [line.strip() for line in text.split("\n") if line.strip()]
chunks = []
current_chunk = []
current_length = 0
for line in lines:
while len(line) > chunk_size:
处理超长单行
part = line[:chunk_size]
line = line[chunk_size:]
current_chunk.append(part)
... (切分逻辑) ...
current_chunk.append(line)
current_length += len(line)
当累积长度超过阈值,生成一个 chunk
if currentlength > chunksize:
chunks.append("\n".join(current_chunk))
回退:保留最后 overlap 长度的文本作为下一个 chunk 的开头
overlaptext = currentchunk[-1][-overlap:] if current_chunk else ""
currentchunk = [overlaptext] if overlap_text else []
currentlength = len(overlaptext)
if current_chunk:
chunks.append("\n".join(current_chunk).strip())
return chunks
2.2 Milvus 向量库与混合检索策略
2.2.1 知识库命名的工程化处理
在实际部署中,Milvus 等向量数据库对集合名称(Collection Name)通常有严格的命名限制。为了解决这一问题,我们在后端代码中实现了一套透明的编解码机制。
1.编码 (Encode):当用户创建如“物理论文”的库时,系统将其 UTF-8 字节转换为 Hex 字符串,并添加
kb_ 前缀。2.解码 (Decode):在前端展示时,自动将 Hex 字符串反解为原始中文。
import binascii
import re
def encodename(uiname):
"""把中文名称转为 Milvus 合法的 Hex 字符串"""
if not ui_name: return ""
如果是纯英文/数字/下划线,直接返回
if re.match(r'^[a-zA-Z][a-zA-Z0-9]*$', ui_name):
return ui_name
Hex 编码并加前缀 kb_
hexstr = binascii.hexlify(uiname.encode('utf-8')).decode('utf-8')
return f"kb{hexstr}"
def decodename(realname):
"""把 Hex 字符串转回中文"""
if realname.startswith("kb"):
Loading...
.png?table=collection&id=cbe6506e-1263-8358-a4d7-07ce62fcbb3f&t=cbe6506e-1263-8358-a4d7-07ce62fcbb3f)