作为编程学习者,你是否想亲手搭建能解决大模型幻觉、知识过时问题的实用RAG系统?Paddle-ERNIE-RAG这款开源的大模型知识库问答系统绝对值得你深入学习——它融合PP-StructureV3文档解析、Milvus混合检索、综合重排序及多模态问答技术,既能攻克LLM幻觉和知识时效性痛点,又支持企业级多文档高精度分析与问答,还提供完整开源代码和可视化交互界面,堪称新手入门RAG技术的绝佳实战项目。

项目地址:https://github.com/LiaoYFBH/Paddle-ERNIE-RAG

1、系统架构概览(新手友好版)

对于刚接触RAG的开发者来说,不用怕架构复杂!本项目核心模块拆解为4个易懂的层级,每一层都有明确的功能定位:

  1. 数据提取层:借助在线OCR API完成高精度文档布局分析,哪怕是复杂排版的文档也能精准解析,告别纯文本提取的杂乱。
  2. 存储层:用Milvus向量数据库存语义向量(Dense Embedding),同时维护倒排索引支撑关键词检索,兼顾语义和精准匹配。
  3. 检索与问答层:把向量检索和关键词检索通过RRF算法加权融合,再对接ERNIE大模型API生成靠谱回答,大幅降低幻觉概率。
  4. 应用层:基于Gradio快速搭建交互界面,不用懂复杂前端也能做出可视化操作页面。

🔗 新手必存项目资源

  • 🐙 GitHub代码仓库(可直接Fork学习):https://github.com/LiaoYFBH/Paddle-ERNIE-RAG
  • 🚀 星河社区在线应用(免部署直接体验):https://aistudio.baidu.com/application/detail/107183

2、关键技术实现(附新手易懂注释)


2.1 PP-StructureV3 文档解析:解决PDF解析痛点

新手用PyPDF2解析科研论文、企业文档时,是不是常遇到双栏排版乱序、表格崩坏、公式识别错误?这正是本项目引入PP-StructureV3的原因——在backend.py中封装的OnlinePDFParser类,直接调用其在线API做高精度布局分析,对新手超友好。

该方案的核心优势(新手也能秒懂):

  • 结构化输出:直接返回Markdown格式,自动识别标题层级、段落边界,不用自己手动整理格式。
  • 图表提取:解析文本时自动提取图片并保存,为后续多模态问答铺路,新手也能轻松实现图文问答。
  • 上下文保留:用滑动窗口切分文本,避免关键信息在切片边界丢失,比如一句话不会被硬生生切成两段。
2.1.1 核心解析逻辑(新手可直接复用)

核心思路是把PDF转Base64后调用API,再解析返回结果提取文本和图片,代码逻辑清晰,新手稍作修改就能适配自己的场景:

# backend.py (OnlinePDFParser 类核心逻辑摘要,新手友好注释)
def predict(self, file_path):
    # 1. 将PDF文件转为Base64格式(API要求的传输格式)
    with open(file_path, "rb") as file:
        file_data = base64.b64encode(file.read()).decode("ascii")
    # 2. 构造API请求参数,新手可根据需求调整fileType等参数
    payload = {
        "file": file_data,
        "fileType": 1, # 1代表PDF类型,固定值不用改
        "useChartRecognition": False, # 不需要识别图表时设为False,提速
        "useDocOrientationClassify": False
    }
    # 3. 发送请求获取布局分析结果
    response = requests.post(self.api_url, json=payload, headers=headers)
    res_json = response.json()
    # 4. 提取Markdown文本和图片资源(新手重点关注这部分)
    parsing_results = res_json.get("result", {}).get("layoutParsingResults", [])
    mock_outputs = []
    for item in parsing_results:
        md_text = item.get("markdown", {}).get("text", "") # 提取解析后的文本
        images = item.get("markdown", {}).get("images", {}) # 提取图片
        # 新手可在这里添加自己的文本清洗、图片保存逻辑
        mock_outputs.append(MockResult(md_text, images))
    return mock_outputs, "Success"
2.1.2 滑动窗口文本分块(新手必学的文本处理技巧)

拿到结构化Markdown文本后,新手容易犯的错是直接按固定长度切分,导致语义断裂。这个滑动窗口分块函数带重叠区(overlap),完美解决该问题:

# backend.py 滑动窗口分块函数(新手友好注释)
def split_text_into_chunks(text: str, chunk_size: int = 300, overlap: int = 120) -> list:
    """
    新手必学:带重叠区的文本分块,避免语义断裂
    :param text: 待切分的Markdown文本
    :param chunk_size: 每个切片的最大长度(新手可根据自己的模型调整)
    :param overlap: 重叠区长度,保证上下文连贯
    :return: 切分后的文本切片列表
    """
    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)
        # 累积长度超过阈值,生成一个切片
        if current_length > chunk_size:
            chunks.append("\n".join(current_chunk))
            # 保留重叠区文本,作为下一个切片的开头(核心技巧)
            overlap_text = current_chunk[-1][-overlap:] if current_chunk else ""
            current_chunk = [overlap_text] if overlap_text else []
            current_length = len(overlap_text)
    # 把最后剩余的文本加入切片列表
    if current_chunk:
        chunks.append("\n".join(current_chunk).strip())
    return chunks

2.2 Milvus 向量库与混合检索策略(新手也能搭的检索系统)

2.2.1 知识库命名的工程化处理(新手避坑点)

新手直接用中文命名Milvus集合会报错!项目里的编解码函数完美解决这个问题,新手可直接复制使用:

import binascii
import re
def encode_name(ui_name):
    """
    新手避坑:把中文名称转为Milvus合法的Hex字符串
    :param ui_name: 前端输入的中文知识库名(比如"Python教程")
    :return: Milvus可识别的集合名
    """
    if not ui_name: return ""
    # 纯英文/数字/下划线可直接用,不用编码
    if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', ui_name):
        return ui_name
    # 中文转Hex并加前缀kb_,避免命名冲突
    hex_str = binascii.hexlify(ui_name.encode('utf-8')).decode('utf-8')
    return f"kb_{hex_str}"

def decode_name(real_name):
    """
    把Milvus里的Hex字符串转回中文,前端展示更友好
    :param real_name: Milvus中的集合名
    :return: 原始中文名称
    """
    if real_name.startswith("kb_"):
        try:
            hex_str = real_name[3:]
            return binascii.unhexlify(hex_str).decode('utf-8')
        except:
            return real_name # 解码失败返回原名称,避免报错
    return real_name
2.2.2 向量化入库与元数据绑定(新手必学的向量库操作)

新手容易只存向量不存元数据,导致后续无法溯源答案来源。这个函数不仅批量向量化,还绑定了文件名、页码等关键信息,新手可直接复用:

# vector_store.py(新手友好注释)
def insert_documents(self, documents):
    """
    批量向量化并写入Milvus,新手重点关注元数据绑定
    :param documents: 包含文本、文件名、页码的字典列表
    """
    if not documents: return
    # 1. 提取文本列表,批量生成向量(减少API调用次数,提速)
    texts = [doc['content'] for doc in documents]
    embeddings = self.get_embeddings(texts)
    # 2. 数据清洗:过滤向量生成失败的坏数据(新手必加,避免入库报错)
    valid_docs, valid_vectors = [], []
    for i, emb in enumerate(embeddings):
        if emb and len(emb) == 384: # 确保向量维度正确(和Embedding模型匹配)
            valid_docs.append(documents[i])
            valid_vectors.append(emb)
    # 3. 组装数据:新手注意Milvus要求列式数据格式
    data = [
        [doc['filename'] for doc in valid_docs],  # 文件名(溯源用)
        [doc['page'] for doc in valid_docs],      # 页码(新手查错超有用)
        [doc['chunk_id'] for doc in valid_docs],  # 切片ID
        [doc['content'] for doc in valid_docs],   # 原始文本(关键词检索用)
        valid_vectors                             # 384维语义向量
    ]
    # 4. 执行插入并持久化(新手别忘flush,否则数据可能丢失)
    self.collection.insert(data)
    self.collection.flush()
2.2.3 混合检索策略(新手提升检索准确率的关键)

新手只用向量检索容易漏检专有名词,只用关键词检索又丢语义关联。项目的RRF融合策略完美结合两者优势,核心逻辑如下:

# vector_store.py 中的检索逻辑摘要(新手友好注释)
def search(self, query: str, top_k: int = 10, **kwargs):
   '''新手必学:向量+关键词双检索+RRF融合,提升准确率'''
   # 1. 向量检索:捕捉语义相似度(比如"苹果手机"和"iPhone")
   dense_results = []
   query_vector = self.embedding_client.get_embedding(query) 
   # 新手可补充:这里添加Milvus向量检索的具体代码
   
   # 2. 关键词检索:精准匹配专有名词/数字(比如公式变量、型号)
   # 通过jieba分词后构建模糊查询,新手可替换成自己的分词工具
   keyword_results = self._keyword_search(query, top_k=top_k * 5, expr=expr)
   
   # 3. RRF融合:把两种检索结果按排名加权合并(核心算法)
   rank_dict = {}
   def apply_rrf(results_list, k=60, weight=1.0):
       for rank, item in enumerate(results_list):
           doc_id = item.get('id') or item.get('chunk_id')
           if doc_id not in rank_dict:
               rank_dict[doc_id] = {"data": item, "score": 0.0}
           # RRF核心公式:排名越靠前,得分越高
           rank_dict[doc_id]["score"] += weight * (1.0 / (k + rank))
   
   # 新手可调整权重:向量检索权重设为4,关键词设为1,侧重语义
   apply_rrf(dense_results, weight=4.0)
   apply_rrf(keyword_results, weight=1.0) 
   
   # 4. 按得分排序输出,新手可调整返回数量
   sorted_docs = sorted(rank_dict.values(), key=lambda x: x['score'], reverse=True)
   return [item['data'] for item in sorted_docs[:top_k * 2]]

2.3 综合重排序算法(新手也能理解的打分逻辑)

检索回来的片段还需要二次筛选!这个综合打分算法结合了字面匹配、关键词覆盖、语义相似度等多个维度,新手可根据自己的场景调整权重:

# reranker_v2.py(新手友好注释)
def _calculate_composite_score(self, query: str, chunk: Dict[str, Any]) -> float:
    content = chunk.get('content', '')
    # 1. 字面重合度:用fuzzywuzzy计算,新手可理解为“文字相似度”
    fuzzy_score = fuzz.partial_ratio(query, content)
    # 2. 关键词覆盖率:查询的核心词在文本中出现的比例
    query_keywords = self._extract_keywords(query)
    content_keywords = self._extract_keywords(content)
    keyword_coverage = (len(query_keywords & content_keywords) / len(query_keywords)) * 100 if query_keywords else 0
    # 3. 向量语义分:归一化后更易理解(0-100分)
    milvus_distance = chunk.get('semantic_score', 0)
    milvus_similarity = 100 / (1 + milvus_distance * 0.1)
    # 4. 长度惩罚:偏好200-600字的段落(新手可调整区间)
    content_len = len(content)
    if 200 <= content_len <= 600:
        length_score = 100
    else:
        # 偏离最优长度越多,扣分越多,新手可调整惩罚力度
        length_score = 100 - min(50, abs(content_len - 400) / 20)
    # 5. 加权求和:新手可调整各维度权重,比如侧重语义就提高milvus_similarity的权重
    base_score = (
        fuzzy_score * 0.25 +
        keyword_coverage * 0.25 +
        milvus_similarity * 0.35 +
        length_score * 0.15
    )
   # 6. 位置奖励:排名靠前的片段额外加分
    position_bonus = 0
    if 'milvus_rank' in chunk:
        rank = chunk['milvus_rank']
        position_bonus = max(0, 20 - rank)
    # 7. 专有名词加分:匹配到专有名词(比如Milvus、ERNIE)额外加30分
    proper_noun_bonus = 30 if self._check_proper_nouns(query, content) else 0
    return base_score + proper_noun_bonus

2.4 API 速率限制与自适应保护(新手避坑:避免调用API被限流)

新手调用大模型API时,很容易因请求太频繁触发429限流!这个自适应降速机制能自动调整请求间隔,新手可直接加到自己的代码里:

# 遇到限流时的处理逻辑(新手友好注释)
if is_rate_limit:
    self._adaptive_slow_down() # 永久增加请求间隔,避免再次限流
    # 指数退避:重试次数越多,等待时间越长,新手可调整系数
    wait_time = (2 ** attempt) + random.uniform(1.0, 3.0) 
    time.sleep(wait_time)

def _adaptive_slow_down(self):
    """
    新手必加:触发限流时自动降速,避免被封IP
    最大间隔设为15秒,兼顾效率和稳定性
    """
    self.current_delay = min(self.current_delay * 2.0, 15.0)
    logger.warning(f"📉 触发速率限制(429),系统自动降速: 新间隔 {self.current_delay:.2f}s")

2.5 多模态问答(新手也能实现的图文问答)

针对带图表的文档,新手也能轻松实现图文问答!核心是把图片和上下文文本一起发给模型,还加了降级策略,避免接口报错导致程序崩溃:

# backend.py - 多模态问答核心逻辑(新手友好注释)
# 1. 检索图片所在页面的文本作为背景(让模型理解图片上下文)
# 新手注意:从文件名解析页码(比如"p3_figure.jpg"解析出第3页)
page_num = int(img_path.split("_")[0].replace("p", "")) # 简单的页码解析逻辑
page_text_context = milvus_store.get_page_content(doc_name, page_num)[:800] # 截取前800字,避免过长

# 2. 拼装提示词:新手重点学习这种“上下文+问题”的提示词写法
final_prompt = f"""
【任务】结合图片和背景信息回答问题,不要凭空编造答案!
【图片元数据】来源:{doc_name} (第{page_num}页)
【背景文本】{page_text_context}
【用户问题】{user_question}
"""

# 3. 调用多模态接口,加try-except做降级(新手必学的异常处理)
try:
   answer = ernie_client.chat_with_image(query=final_prompt, image_path=img_path)
except Exception as e:
   print(f"⚠️ 多模态接口调用失败,自动切换到文本模式!错误原因:{e}")
   # 降级策略:用文本继续回答,保证程序不崩溃
   answer, metric = ask_question_logic(final_prompt, collection_name)

3、界面交互与效果(新手也能做出好看的UI)

3.1 深度CSS定制(新手快速美化Gradio界面)

新手用Gradio默认界面太单调?这段CSS能快速做出现代感的聊天界面,新手可直接复制到main.py里:

/* main.py - modern_css 片段(新手友好注释) */
/* 输入框美化:白底圆角+轻微阴影,模拟微信/钉钉聊天框 */
.custom-textbox textarea {
    background-color: #ffffff !important;
    border: 1px solid #e5e7eb !important;
    border-radius: 12px !important; /* 圆角更美观 */
    box-shadow: 0 4px 12px rgba(0,0,0,0.05) !important; /* 轻微阴影增加层次感 */
    padding: 14px !important; /* 内边距更舒适 */
}
/* 发送按钮美化:渐变色+悬浮阴影,新手可调整颜色 */
.send-btn {
    background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%) !important;
    color: white !important;
    box-shadow: 0 4px 10px rgba(99, 102, 241, 0.3) !important;
}
/* 新手可添加:按钮悬浮效果,提升交互体验 */
.send-btn:hover {
    box-shadow: 0 6px 15px rgba(99, 102, 241, 0.5) !important;
    transform: translateY(-1px); /* 轻微上移,更有动感 */
}

3.2 LaTeX 公式渲染(新手也能显示数学公式)

新手做科研文档问答时,公式显示乱码是常见问题!这段配置能让Gradio正确渲染LaTeX公式,新手直接用:

# main.py 配置LaTeX规则(新手友好注释)
latex_config = [
    {"left": "$$", "right": "$$", "display": True},   # 行间公式(单独一行)
    {"left": "$", "right": "$", "display": False},    # 行内公式(和文字在一起)
    {"left": "\\(", "right": "\\)", "display": False}, # 标准LaTeX行内格式
    {"left": "\\[", "right": "\\]", "display": True}   # 标准LaTeX行间格式
]

# 新手注意:在Chatbot和Markdown组件中启用LaTeX
# 1. 聊天框启用公式渲染
chatbot = gr.Chatbot(
    label="智能问答",
    latex_delimiters=latex_config  # 关键配置:启用公式渲染
)
# 2. 文档摘要区启用公式渲染
doc_summary = gr.Markdown(
    value="*暂无摘要*",
    latex_delimiters=latex_config
)

3.3 可解释性设计(新手也能看懂答案来源)

新手搭建RAG系统后,不知道答案怎么来的?这个可解释性设计能清晰展示答案的来源和置信度,新手可直接复用:

  • 相关性(微观指标):在参考来源里显示每个切片的综合得分,告诉用户“为什么选这段内容”:
# backend.py - 构建参考来源列表(新手友好注释)
sources = "\n\n📚 **参考来源(新手可直接看相关性得分):**\n"
for c in final:
    # 去重逻辑(新手可保留)
    key = f"{c.get('filename', '未知文件')} 第{c.get('page', 0)}页"
    if key not in seen:
        seen.add(key)
        # 显示相关性得分,新手可根据得分判断内容是否匹配
        sources += f"- {key} [相关性:{c.get('composite_score',0):.0f}%]\n"
  • 置信度(宏观指标):显示本次问答的整体可信度,低于60%时提醒用户注意幻觉:
# backend.py - 计算整体置信度(新手友好注释)
final = processed[:22]
# 取排名第一的切片得分作为整体置信度
top_score = final[0].get('composite_score', 0) if final else 0
# 归一化处理,封顶100%,新手可根据置信度判断答案可靠性
metric = f"{min(100, top_score):.1f}%"
# 新手可添加:置信度低于60%时给出提示
if float(metric.replace("%", "")) < 60:
    metric += " ⚠️ 置信度较低,答案可能存在幻觉,请核对参考来源!"

界面效果展示(新手可直观看到):


4、总结(新手学习指南)

4.1 新手能学到的核心亮点

  • 高精度问答:学会向量+关键词混合检索、RRF融合、综合重排序,从0到1搭建低幻觉的问答系统。
  • 工程化技巧:掌握API限流处理、文本分块、向量库元数据绑定等新手易踩坑的工程化细节。
  • 可视化交互:用Gradio快速做出带公式渲染、可解释性的美观界面,不用写复杂前端代码。
  • 实战功能:实现多知识库管理、召回率自测、大文件上传进度显示等企业级功能。

4.2 新手可尝试的优化方向

这个项目对新手非常友好,你可以基于它做这些优化(易上手):

  • 替换成本地Embedding模型,摆脱API依赖(比如用BGE-small)。
  • 把规则重排序换成轻量级的BGE-Reranker模型,提升准确率。
  • 扩展多模态能力,比如支持表格问答、公式问答。
  • 优化界面交互,比如添加知识库导入/导出功能。

总结

  1. Paddle-ERNIE-RAG是新手入门RAG技术的优质项目,核心解决大模型幻觉和知识时效性问题,且代码结构清晰、易复用;
  2. 项目的核心亮点是PP-StructureV3高精度解析、Milvus混合检索、综合重排序和多模态问答,新手可重点学习这些模块;
  3. 文中补充了大量新手友好的注释和避坑提示,复制代码即可快速上手,还能基于项目做轻量化优化,提升实战能力。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线科技企业深耕十二载,见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事,早已在效率与薪资上形成代际优势,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套 AI 大模型突围资料包

  • ✅ 从零到一的 AI 学习路径图
  • ✅ 大模型调优实战手册(附医疗/金融等大厂真实案例)
  • ✅ 百度/阿里专家闭门录播课
  • ✅ 大模型当下最新行业报告
  • ✅ 真实大厂面试真题
  • ✅ 2025 最新岗位需求图谱

所有资料 ⚡️ ,朋友们如果有需要 《AI大模型入门+进阶学习资源包》下方扫码获取~
在这里插入图片描述

① 全套AI大模型应用开发视频教程

(包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点)
在这里插入图片描述

② 大模型系统化学习路线

作为学习AI大模型技术的新手,方向至关重要。 正确的学习路线可以为你节省时间,少走弯路;方向不对,努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划,带你从零基础入门到精通!
在这里插入图片描述

③ 大模型学习书籍&文档

学习AI大模型离不开书籍文档,我精选了一系列大模型技术的书籍和学习文档(电子版),它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。
在这里插入图片描述

④ AI大模型最新行业报告

2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。
在这里插入图片描述

⑤ 大模型项目实战&配套源码

学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。
在这里插入图片描述

⑥ 大模型大厂面试真题

面试不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我精心整理了一份大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余

图片

以上资料如何领取?

在这里插入图片描述

为什么大家都在学大模型?

最近科技巨头英特尔宣布裁员2万人,传统岗位不断缩减,但AI相关技术岗疯狂扩招,有3-5年经验,大厂薪资就能给到50K*20薪!

图片

不出1年,“有AI项目经验”将成为投递简历的门槛。

风口之下,与其像“温水煮青蛙”一样坐等被行业淘汰,不如先人一步,掌握AI大模型原理+应用技术+项目实操经验,“顺风”翻盘!
在这里插入图片描述
在这里插入图片描述

这些资料真的有用吗?

这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。
在这里插入图片描述
在这里插入图片描述

以上全套大模型资料如何领取?

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐