RAG学习笔记

一、核心框架

框架

从基础认知到项目集成形成完整闭环:①理解 RAG→②两条核心流水线→③知识库构建→④检索与生成→⑤关键参数调试→⑥可解释检索→⑦失败模式排错→⑧项目落地适配,另含参数调试与可解释检索的补充内容。

二、RAG 核心定义与价值

(一)本质定义

RAG(检索增强生成)并非单一函数,而是通过 "先检索知识库相关片段,再将片段与问题结合喂给大模型" 的技术方案,核心是解决大模型训练数据滞后、知识不可追溯的痛点,让生成结果既精准又有依据。

(二)核心优势

  • 知识更新灵活:无需重新训练大模型,仅需更新知识库即可覆盖新内容;
  • 结果可追溯:通过可解释检索功能,明确答案来源于知识库的具体片段,降低 "幻觉" 风险;

三、两条核心流水线实操解析

(一)离线流水线(Ingest):知识库构建

1. 核心流程
(1)文档初始化
复制代码
# 核心功能:创建并写入原始知识库文本
import os

# 定义知识库文件路径(飞书文档推荐目录结构)
KNOWLEDGE_PATH = "./knowledge.txt"

# 示例:高数知识库内容(可替换为自身项目内容)
knowledge_content = """
高等数学-函数极限
1. 极限的定义:设函数f(x)在点x0的某一去心邻域内有定义,如果存在常数A,对于任意给定的正数ε(无论它多么小),总存在正数δ,使得当x满足0<|x-x0|<δ时,对应的函数值f(x)都满足|f(x)-A|<ε,那么常数A就叫做函数f(x)当x→x0时的极限。
2. 极限的运算法则:
   - 两个函数的和的极限等于极限的和:lim[f(x)+g(x)] = limf(x) + limg(x)
   - 两个函数的积的极限等于极限的积:lim[f(x)·g(x)] = limf(x)·limg(x)
3. 常见极限公式:
   - lim(sinx/x) = 1 (x→0)
   - lim(1+1/x)^x = e (x→∞)
"""

# 写入知识库文件(指定UTF-8编码避免中文乱码,飞书文档重点提示)
def create_knowledge_base():
    if not os.path.exists(KNOWLEDGE_PATH):
        with open(KNOWLEDGE_PATH, "w", encoding="utf-8") as f:
            f.write(knowledge_content)
        print("知识库创建成功!")
    else:
        print("知识库已存在,无需重复创建")

if __name__ == "__main__":
    create_knowledge_base()
(2)文档切分
复制代码
# 核心功能:中文友好的文档切分(段落→句子→字符分层策略)
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 加载知识库文本
def load_knowledge():
    with open("./knowledge.txt", "r", encoding="utf-8") as f:
        return f.read()

# 初始化切分器(飞书文档推荐参数)
def split_text():
    text = load_knowledge()
    # 核心参数:chunk_size(单块长度)、chunk_overlap(重叠长度)
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,  # 初始值,可调整范围300-800
        chunk_overlap=50,  # 重叠长度,建议为chunk_size的10%-20%
        separators=["\n\n", "\n", "。", "!", "?", ";", ",", " "],  # 中文切分分隔符优先级
        length_function=len  # 按字符长度计算
    )
    # 执行切分
    chunks = text_splitter.split_text(text)
    print(f"切分完成,共生成 {len(chunks)} 个文本块")
    # 打印第一个块验证
    print("第一个文本块内容:", chunks[0])
    return chunks

if __name__ == "__main__":
    split_text()
(3)向量化与存储
复制代码
# 核心功能:文本向量化并存储到Chroma向量库
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma

# 加载切分后的文本块(承接上一步)
def load_split_chunks():
    from demo_02_ingest_split import split_text
    return split_text()

# 初始化embedding模型(飞书文档推荐硅基流动模型)
def init_embedding():
    return HuggingFaceEmbeddings(
        model_name="siliconflow/text-embedding-ada-002",  # 兼容OpenAI格式的中文embedding模型
        model_kwargs={"device": "cpu"},  # 无GPU则设为cpu
        encode_kwargs={"normalize_embeddings": True}  # 归一化向量,提升检索精度
    )

# 构建向量库
def build_vectorstore():
    chunks = load_split_chunks()
    embeddings = init_embedding()
    # 存储到本地chroma_db目录
    vector_db = Chroma.from_texts(
        texts=chunks,
        embedding=embeddings,
        persist_directory="./chroma_db"  # 向量库存储目录
    )
    vector_db.persist()  # 持久化存储
    print("向量库构建完成,存储路径:./chroma_db")
    return vector_db

if __name__ == "__main__":
    build_vectorstore()
2. 关键参数与实操注意
  • chunk size:单块文本长度,常用区间 300-800,需根据知识库体量调整(如高数教材可设为 800-1000);
  • chunk overlap:块间重叠长度(相邻两个文本块之间重复的字符长度),建议 10%-20%,用于避免跨 chunk 关键信息断裂(如公式、长句拆分丢失逻辑);
  • 核心禁忌:入库参数(chunk sizeoverlap)与查询参数(TOPKsoccer sold)需分开调试,不可混改导致流程混乱。

(二)在线流水线(Query):检索与生成

1. 核心流程
(1)问题检索与过滤
复制代码
# 核心功能:问题向量化+相似检索+阈值过滤
from langchain.vectorstores import Chroma
from demo_03_build_vectorstore import init_embedding

# 加载向量库
def load_vectorstore():
    embeddings = init_embedding()
    return Chroma(
        persist_directory="./chroma_db",
        embedding_function=embeddings
    )

# 检索与过滤
def retrieve_and_filter(query):
    vector_db = load_vectorstore()
    # 核心参数:k(TOPK)、score_threshold(soccer sold)
    retriever = vector_db.as_retriever(
        search_kwargs={
            "k": 3,  # 召回3个最相关文本块(飞书文档推荐3-5)
            "score_threshold": 0.5  # 相似度阈值,0.3-0.6为合理区间
        }
    )
    # 执行检索
    relevant_docs = retriever.get_relevant_documents(query)
    print(f"检索到 {len(relevant_docs)} 个相关文本块")
    # 打印检索结果及相似度
    for i, doc in enumerate(relevant_docs):
        print(f"\n第{i+1}个相关块:")
        print("内容:", doc.page_content)
        print("相似度得分:", doc.metadata["score"] if "score" in doc.metadata else "未返回")
    return relevant_docs

if __name__ == "__main__":
    # 测试查询:高数极限的运算法则有哪些
    retrieve_and_filter("高数极限的运算法则有哪些")
(2)提示词组装与生成
复制代码
# 核心功能:组装上下文+提示词+调用大模型生成答案
from demo_04_query_retrieve_filter import retrieve_and_filter
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

# 初始化大模型(可替换为国产大模型)
def init_llm():
    return ChatOpenAI(
        model_name="gpt-3.5-turbo",
        temperature=0.1,  # 低温度保证答案精准
        api_key="your-api-key",  # 替换为自己的API Key
        base_url="your-base-url"  # 飞书文档中验证的base URL
    )

# 组装提示词并生成答案
def generate_answer(query):
    # 1. 检索相关文本块
    relevant_docs = retrieve_and_filter(query)
    if not relevant_docs:
        return "知识库中未找到相关内容,无法回答该问题"
    
    # 2. 组装上下文
    context = "\n\n".join([doc.page_content for doc in relevant_docs])
    
    # 3. 构建提示词(飞书文档强调:约束大模型仅基于上下文回答)
    prompt_template = """
    请仅基于以下上下文内容回答用户问题,禁止使用上下文外的任何信息。
    如果上下文没有相关内容,请直接回答"知识库中未找到相关内容"。
    
    上下文:
    {context}
    
    用户问题:
    {query}
    
    回答要求:
    1. 条理清晰,分点说明;
    2. 语言简洁,准确对应上下文内容;
    3. 仅回答问题本身,不额外扩展。
    """
    prompt = PromptTemplate(
        input_variables=["context", "query"],
        template=prompt_template
    )
    
    # 4. 调用大模型生成答案
    llm_chain = LLMChain(llm=init_llm(), prompt=prompt)
    answer = llm_chain.run(context=context, query=query)
    return answer

if __name__ == "__main__":
    # 测试查询
    query = "高数极限的运算法则有哪些"
    print("用户问题:", query)
    print("\n生成答案:", generate_answer(query))
2. 核心参数与效果影响
参数名 作用 文档推荐值 实操调整逻辑
TOPK 召回相关 chunk 数量 3-5 个 过多易稀释注意力,过少易遗漏关键信息
soccer sold 相似度过滤阈值 0.3-0.6 低于 0.3 引入无关信息,高于 0.6 可能漏检

四、关键参数调试技巧

(一)调试核心原则

  1. 单一变量原则:每次仅调整一个参数(如固定overlap=50,仅测试chunk size),避免多变量干扰结果;
  2. 先看后调原则:优先打印raw result(原始检索结果),明确是 "检索不到" 还是 "检索到用不好",再针对性调参;
  3. 二分法高效试错:以chunk size为例,在 100-2000 区间内逐步缩小范围(如 100→1000→500→750),快速找到最优值。

(二)参数调试对比代码

复制代码
# 核心功能:对比不同参数组合的检索效果
from demo_04_query_retrieve_filter import load_vectorstore

def tune_parameters(query):
    vector_db = load_vectorstore()
    # 定义待测试的参数组合(飞书文档推荐的对比思路)
    param_combinations = [
        {"k": 3, "score_threshold": 0.5, "chunk_size": 500},  # 基准参数
        {"k": 5, "score_threshold": 0.5, "chunk_size": 500},  # 仅调整TOPK
        {"k": 3, "score_threshold": 0.4, "chunk_size": 500},  # 仅调整阈值
        {"k": 3, "score_threshold": 0.5, "chunk_size": 800}   # 仅调整chunk_size
    ]
    
    # 逐一测试参数组合
    for i, params in enumerate(param_combinations):
        print(f"\n=== 测试参数组合 {i+1} ===")
        print(f"参数:TOPK={params['k']}, 阈值={params['score_threshold']}, chunk_size={params['chunk_size']}")
        retriever = vector_db.as_retriever(search_kwargs={"k": params["k"], "score_threshold": params["score_threshold"]})
        results = retriever.get_relevant_documents(query)
        print(f"检索结果数量:{len(results)}")
        if results:
            print("第一个结果相似度:", results[0].metadata.get("score", "N/A"))

if __name__ == "__main__":
    tune_parameters("高数极限的运算法则有哪些")

五、可解释检索与失败模式排错

(一)可解释检索代码

复制代码
# 核心功能:返回答案溯源信息(来源、位置、相似度)
from demo_04_query_retrieve_filter import load_vectorstore

def explainable_retrieve(query):
    vector_db = load_vectorstore()
    # 执行带分数的检索
    results = vector_db.similarity_search_with_score(query, k=3)
    
    # 组装可解释结果
    explain_results = []
    for i, (doc, score) in enumerate(results):
        explain_results.append({
            "序号": i+1,
            "内容片段": doc.page_content,
            "相似度得分": round(score, 4),
            "来源文件": "knowledge.txt",
            "建议可信度": "高" if score >= 0.5 else "中" if score >= 0.3 else "低"
        })
    
    # 打印可解释结果
    print("=== 检索结果溯源 ===")
    for res in explain_results:
        print(f"\n{res['序号']}. 可信度:{res['建议可信度']}(相似度:{res['相似度得分']})")
        print(f"内容:{res['内容片段']}")
        print(f"来源:{res['来源文件']}")
    
    return explain_results

if __name__ == "__main__":
    explainable_retrieve("lim(sinx/x)的结果是什么")

(二)常见失败模式与排错步骤

  1. 文档未入库 / 未持久化:检查chroma_db/目录是否存在;
  2. 查询过于口语化 / 过短:优化 query(如 "高数极限怎么求"→"高等数学中函数极限的求解方法");
  3. 模型 "幻觉"(瞎编内容):在提示词中明确 "禁止使用知识库外信息",并提高soccer sold至 0.5;
  4. 上下文过长导致截断:采用摘要式检索,先压缩 chunk 文本再喂给大模型。

六、项目集成与落地适配

(一)功能开关实现代码

复制代码
# 核心功能:RAG功能开关控制,适配不同项目场景
from demo_05_assemble_generate import generate_answer
from langchain.chat_models import ChatOpenAI

# 全局开关:控制是否启用RAG
USE_RAG = True  # True启用,False禁用

# 直接调用大模型(禁用RAG时使用)
def direct_answer(query):
    llm = ChatOpenAI(
        model_name="gpt-3.5-turbo",
        temperature=0.3,
        api_key="your-api-key",
        base_url="your-base-url"
    )
    return llm.predict(f"请回答以下问题:{query}")

# 统一问答入口
def qa_entry(query):
    if USE_RAG:
        print("【启用RAG模式】")
        return generate_answer(query)
    else:
        print("【禁用RAG模式,直接调用大模型】")
        return direct_answer(query)

if __name__ == "__main__":
    # 测试不同场景
    print("=== 数学项目(启用RAG)===")
    USE_RAG = True
    print(qa_entry("lim(sinx/x)的结果是什么"))
    
    print("\n=== 情绪项目(禁用RAG)===")
    USE_RAG = False
    print(qa_entry("怎么安慰心情不好的人"))

(二)项目适配场景

1. 高度适配场景
  • 专业知识问答(如数学解题):将高数教材 / 公式库存入knowledge.txt,通过 RAG 精准答疑并溯源;
  • 小众信息检索(如小众景点、专业手册):补充大模型知识盲区,提高答案准确性;
  • 企业内部文档查询(如规章制度、技术手册):支持快速更新,员工检索高效且可追溯。
2. 不推荐场景
  • 情绪交互类产品:RAG 无法模仿人性化表达,建议用 "提示词约束 + 微调" 替代;
  • 大众信息查询(如热门景点、通用常识):大模型原生知识足够,RAG 会增加召回耗时,降低响应速度。

七、总结

(一)核心

  1. RAG 的核心是 "两条流水线协同":离线构建高质量知识库(切分 + 向量化),在线精准检索 + 约束生成,二者缺一不可;
  2. 参数调试是落地关键:通过单一变量法 + 二分法试错,无固定最优值,需结合知识库体量和业务场景调整;
  3. 场景适配决定效果:RAG 并非 "万能",仅在 "高精度、需追溯" 场景中优势明显,需通过功能开关灵活适配。

(二)总结

  1. RAG 核心是 "离线构建知识库 + 在线检索生成" 两条流水线,代码层面需重点关注文档切分、向量存储、参数过滤三大核心环节;
  2. 关键参数(chunk_size、TOPK、score_threshold)需通过单一变量法调试;
  3. 项目落地时需通过功能开关适配不同场景,高精度 / 可追溯场景启用 RAG,通用交互场景直接调用大模型更高效。
相关推荐
一秒推GEO2 小时前
一秒推GEO优化方案是什么?主要具备哪几项核心功能?
人工智能·百度·媒体·geo·ai优化
说私域2 小时前
共生与赋能:产品与运营的一体化逻辑——以AI智能名片链动2+1模式S2B2C商城系统为例
大数据·人工智能·产品运营·流量运营·私域运营
ZPC82102 小时前
通过神经网络识别图像位置
人工智能·算法·机器人
马猴烧酒.2 小时前
智能协图云图库学习笔记day6-主流图片优化技术
笔记·学习
梵高的代码色盘2 小时前
Spring AI 整合大模型:Prompt 提示词的标准化设计与最佳实践
人工智能·spring·prompt
翱翔的苍鹰2 小时前
完整的“RNN + jieba 中文情感分析”项目之一:添加 API 接口(FastAPI) 和 支持 批量分析
人工智能·rnn·fastapi
安畅检测齐鲁物联网测试中心2 小时前
企业数字化转型
人工智能
驭白.2 小时前
当硬件成为载体:制造端如何支撑持续的OTA与功能进化?
大数据·人工智能·ai·制造·数字化转型·制造业·新能源汽车
北京耐用通信2 小时前
耐达讯自动化Profibus光纤中继模块实现冶金车间长距离抗干扰通信
人工智能·物联网·网络协议·自动化·信息与通信