RAG 实战指南:让大模型拥有最新知识 什么是 RAG RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识检索与大语言模型(LLM)生成能力结合的技术架构。它的核心思想很简单:让 AI 在回答问题前,先去知识库中查找相关信息,再基于检索到的内容生成答案 。
为什么需要 RAG 大语言模型虽然强大,但存在几个固有限制:
问题
说明
知识过时
模型的训练数据有截止日期,无法获取最新信息
幻觉问题
模型可能生成看似合理但实际错误的内容
私有知识
模型无法访问你的内部文档、业务数据
成本高昂
微调模型成本高,且需要重新训练
RAG 通过检索 + 生成 的方式,有效缓解了这些问题。
RAG 工作原理 RAG 的流程可以分为以下几个步骤:
1 用户问题 → 检索 → 增强 → 生成 → 回答
1. 文档处理(Ingection) 将原始文档切分成小块(Chunk),然后通过 Embedding 模型转换为向量,存入向量数据库。
1 2 3 4 5 6 7 8 text = "长文档内容..." chunks = text_splitter.split_text(text) for chunk in chunks: vector = embedding_model.encode(chunk) vector_db.add(vector, chunk)
2. 检索阶段(Retrieval) 当用户提问时,将问题本身也转换为向量,在向量数据库中进行相似度搜索,找到最相关的文档块。
1 2 3 4 5 6 7 8 query = "公司的年假政策是什么?" query_vector = embedding_model.encode(query) results = vector_db.search(query_vector, top_k=5 )
3. 增强阶段(Augmentation) 将检索到的相关文档块与用户问题组合,形成一个「上下文 + 问题」的提示词。
1 2 3 4 5 6 7 8 prompt = f""" 根据以下上下文回答问题。如果上下文中没有相关信息,请如实说明。 上下文: {retrieved_docs} 问题:{user_query} """
4. 生成阶段(Generation) 将增强后的提示词发送给 LLM,由模型生成最终回答。
1 response = llm.chat(prompt)
RAG 关键技术点 1. 文档切分(Chunking) 切分策略直接影响检索效果:
固定大小切分 :简单但可能切断语义
句子级别切分 :保持完整性但块太小
递归切分 :按段落/句子逐层切,更灵活
语义切分 :用模型判断语义边界,效果最好
1 2 3 4 5 6 7 8 9 from langchain.text_splitter import CharacterTextSplittersplitter = CharacterTextSplitter( chunk_size=500 , chunk_overlap=50 , separator="\n" ) chunks = splitter.split_text(document)
Chunk 大小选择建议:
通用问答:300-500 tokens
摘要任务:1000-2000 tokens
代码检索:200-1000 tokens
2. 向量嵌入(Embedding) 选择合适的 Embedding 模型:
模型
特点
适用场景
OpenAI text-embedding-ada-002
效果好,收费
生产环境
BGE
开源效果好
私有部署
M3E
中文优化,免费
中文场景
Cohere
多语言支持好
多语言场景
1 2 3 4 from sentence_transformers import SentenceTransformermodel = SentenceTransformer('moka-ai/m3e-base' ) vector = model.encode("要嵌入的文本" )
3. 向量数据库 主流向量数据库对比:
数据库
特点
适用规模
Milvus
功能完善,支持混合检索
中大规模
Chroma
轻量级,易上手
小规模/实验
Qdrant
性能好,支持过滤
生产环境
Pinecone
云原生,无需运维
大规模
Weaviate
支持多模态
多模态场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import chromadbclient = chromadb.Client() collection = client.create_collection("docs" ) collection.add( embeddings=[vector], documents=["文档内容" ], ids=["doc1" ] ) results = collection.query( query_embeddings=[query_vector], n_results=5 )
4. 检索策略 基本相似度检索:
1 results = vector_db.similarity_search(query, k=5 )
带分数阈值的检索:
1 2 3 results = vector_db.similarity_search_with_score(query, k=5 ) filtered = [r for r, score in results if score > 0.8 ]
混合检索(关键词 + 向量):
1 2 3 4 5 6 hybrid_results = vector_db.hybrid_search( query, vector_weight=0.7 , keyword_weight=0.3 )
5. 重排序(Reranking) 初步检索后,用重排序模型进一步优化结果顺序:
1 2 3 4 5 6 7 8 from sentence_transformers import CrossEncoderreranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2' ) reranked = reranker.predict([ (query, doc) for doc in initial_results ])
RAG 实战框架 LangChain 最流行的 RAG 开发框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from langchain.document_loaders import PDFLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.embeddings import OpenAIEmbeddingsfrom langchain.vectorstores import Chromafrom langchain.chat_models import ChatOpenAIfrom langchain.chains import RetrievalQAloader = PDFLoader("document.pdf" ) documents = loader.load() splitter = RecursiveCharacterTextSplitter( chunk_size=500 , chunk_overlap=50 ) chunks = splitter.split_documents(documents) vectorstore = Chroma.from_documents( documents=chunks, embedding=OpenAIEmbeddings() ) qa_chain = RetrievalQA.from_chain_type( llm=ChatOpenAI(model="gpt-4" ), retriever=vectorstore.as_retriever() ) result = qa_chain({"query" : "文档的主要内容是什么?" })
LlamaIndex 更专注于索引和检索的框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from llama_index import VectorStoreIndex, SimpleDirectoryReaderfrom llama_index.query_engine import RetrieverQueryEnginefrom llama_index.retrievers import VectorIndexRetrieverdocuments = SimpleDirectoryReader("./data" ).load_data() index = VectorStoreIndex.from_documents(documents) retriever = VectorIndexRetriever( index=index, similarity_top_k=5 ) query_engine = RetrieverQueryEngine(retriever=retriever) response = query_engine.query("你的问题" )
RAG 优化技巧 1. 提升检索质量 使用更好的 Embedding 模型:
1 2 3 4 embedding = HuggingFaceBgeEmbeddings( model_name="BAAI/bge-small-zh-v1.5" )
添加元数据过滤:
1 2 3 4 5 vector_db.search( query_vector, filter ={"category" : "技术文档" , "date" : "2024" } )
2. 优化生成质量 Few-shot 提示:
1 2 3 4 5 6 7 8 9 10 11 12 13 prompt = """ 你是一个技术文档助手。请根据上下文回答问题。 示例: 问:如何重置密码? 答:进入设置页面,点击「账户安全」,选择「重置密码」。 上下文: {context} 问:{question} 答: """
链式思考(Chain of Thought):
1 2 3 4 5 6 7 8 9 10 prompt = """ 请分步骤分析以下问题: 1. 首先理解问题的关键点 2. 从上下文中找到相关信息 3. 基于信息给出回答 上下文:{context} 问题:{question} """
3. 处理长上下文 上下文压缩:
1 2 3 4 5 6 7 8 from langchain.retrievers import ContextualCompressionRetrieverfrom langchain.retrievers.document_compressors import LLMChainExtractorcompressor = LLMChainExtractor.from_llm(llm) compressor_retriever = ContextualCompressionRetriever( base_retriever=base_retriever, document_compressor=compressor )
4. 多跳推理 处理需要组合多个知识点的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sub_questions = [ "A公司的CEO是谁?" , "A公司CEO的年薪是多少?" ] answers = [retriever.search(q) for q in sub_questions] final_prompt = f""" 基于以下信息回答:{answers} 原始问题:{original_question} """
RAG 的局限性 RAG 不是银弹,仍然存在一些局限:
检索质量依赖文档质量 :脏乱差的数据无法带来好结果
复杂推理仍有局限 :多跳推理、逻辑推演仍是难题
实时性 vs 成本的权衡 :频繁更新索引有成本
上下文长度限制 :无法一次性处理超长文档
RAG vs 微调
维度
RAG
微调
知识更新
实时,更新索引即可
需要重新训练
成本
低,无需训练
高,GPU + 训练时间
可解释性
高,可查看检索来源
低,隐含在模型中
定制程度
中等
高
幻觉问题
较少
可能继承模型问题
适用场景
知识库问答
风格/领域适配
建议:
知识库问答 → RAG
领域特定风格 → 微调
两者结合 → 最佳效果
总结 RAG 是当前构建知识库问答系统的主流方案,它通过「检索 + 生成」的范式,让大模型能够访问最新、最准确的外部知识。
掌握 RAG 的核心组件(文档处理、嵌入、向量数据库、提示工程),理解常见的优化技巧(混合检索、重排序、上下文压缩),就能构建出效果不错的知识库问答系统。
在实际项目中,建议从简单方案开始迭代,根据效果逐步引入更复杂的技术。
有问题或想法,欢迎留言交流!