RAG(检索增强生成)技术指南


目录


什么是 RAG?

RAG(Retrieval-Augmented Generation,检索增强生成)是一种将信息检索与语言生成相结合的 AI 技术。它通过在生成回答之前先从外部知识库检索相关信息,显著提升了大语言模型的回答质量和准确性。

核心理念

RAG = 检索(Retrieval) + 生成(Generation)
  • 检索:从知识库中查找相关信息

  • 生成:基于检索到的信息生成回答

为什么需要 RAG?

传统 LLM 的局限性

  1. 知识截止 - 训练数据有时间限制

  2. 幻觉问题 - 可能生成虚假信息

  3. 缺乏专业性 - 通用知识多,专业知识少

  4. 无法更新 - 训练后知识固定

  5. 缺乏上下文 - 不了解特定业务场景

RAG 的优势

  1. ✅ 实时获取最新信息

  2. ✅ 基于事实生成,减少幻觉

  3. ✅ 融入专业知识

  4. ✅ 知识可动态更新

  5. ✅ 提供引用来源


核心原理

基本思路

用户提问
    ↓
[检索模块] → 从知识库查找相关信息
    ↓
[增强提示词] → 问题 + 检索结果
    ↓
[生成模块] → LLM 生成回答
    ↓
返回答案(附引用)

技术特点

  1. 知识外置

    • 知识存储在向量数据库

    • 不需要重新训练模型

    • 可随时更新知识

  2. 语义检索

    • 使用向量相似度搜索

    • 理解语义而非关键词匹配

    • 支持模糊查询

  3. 上下文增强

    • 检索结果作为上下文

    • 提供生成依据

    • 减少模型幻觉


技术架构

三层架构

┌─────────────────────────────────────┐
│         应用层(Application)         │
│  - 用户界面                          │
│  - API 接口                          │
│  - 业务逻辑                          │
└─────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────┐
│         RAG 引擎层(Engine)          │
│  - 查询处理                          │
│  - 检索模块                          │
│  - 提示词构建                        │
│  - 生成模块                          │
└─────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────┐
│         数据层(Data Layer)          │
│  - 向量数据库                        │
│  - 文档存储                          │
│  - 嵌入模型                          │
└─────────────────────────────────────┘

组件说明

1. 应用层
  • 用户交互界面

  • API 服务

  • 业务逻辑处理

2. RAG 引擎层
  • 查询处理:理解用户问题

  • 检索模块:查找相关信息

  • 提示词构建:组合问题和检索结果

  • 生成模块:LLM 生成回答

3. 数据层
  • 向量数据库:存储文档向量

  • 文档存储:原始文档

  • 嵌入模型:文本向量化


工作流程

完整流程

1. 用户提问
   ↓
2. 查询预处理
   - 文本清洗
   - 意图识别
   - 查询改写
   ↓
3. 向量检索
   - 查询向量化
   - 相似度搜索
   - 返回 Top-K 结果
   ↓
4. 结果重排序
   - 相关性评分
   - 去重
   - 选择最佳文档
   ↓
5. 构建提示词
   - 系统指令
   - 检索结果
   - 用户问题
   ↓
6. LLM 生成
   - 基于上下文生成
   - 控制输出格式
   ↓
7. 后处理
   - 格式化
   - 引用标注
   - 质量检查
   ↓
8. 返回答案

示例流程

用户问:公司 2024 年的销售目标是什么?

1. 查询向量化
   "公司 2024 年销售目标" → [0.1, 0.5, -0.3, ...]

2. 检索相关文档
   - 文档 1:2024 年销售计划.pdf(相似度 0.89)
   - 文档 2:年度目标会议纪要.docx(相似度 0.85)
   - 文档 3:Q1 销售报告.pdf(相似度 0.72)

3. 构建提示词
   """
   基于以下信息回答问题:
   
   【文档 1】2024 年销售目标为 1 亿元,同比增长 30%...
   【文档 2】会议确定年度目标:第一季度 2000 万...
   【文档 3】Q1 实际完成 2200 万...
   
   问题:公司 2024 年的销售目标是什么?
   """

4. LLM 生成回答
   "公司 2024 年的销售目标为 1 亿元,同比增长 30%。
   其中第一季度目标 2000 万,实际完成 2200 万..."

5. 返回答案(附引用)

关键组件

1. 嵌入模型(Embedding Model)

作用:将文本转换为向量

常用模型

模型

维度

特点

适用场景

text-embedding-3-small

1536

快速、便宜

一般场景

text-embedding-3-large

3072

精度高

专业场景

BGE

1024

中文优化

中文应用

M3E

768

轻量级

资源受限

2. 向量数据库

作用:存储和检索向量

主流选择

数据库

特点

规模

成本

Chroma

轻量、易用

中小

免费

Pinecone

托管服务

付费

Weaviate

功能丰富

中大

免费/付费

Milvus

高性能

超大

免费

FAISS

Facebook 开源

免费

3. 大语言模型

作用:生成最终回答

选择建议

  • 高质量:GPT-4、Claude 3

  • 性价比:GPT-3.5、Claude

  • 中文优化:文心一言、通义千问

  • 本地部署:LLaMA、ChatGLM

4. 文档加载器

支持格式

  • PDF、Word、Excel

  • TXT、Markdown

  • HTML、XML

  • JSON、CSV

  • 数据库

5. 文本分割器

作用:将长文档切分为片段

分割策略

# 按字符数分割
chunk_size = 1000
chunk_overlap = 200

# 按段落分割
保持段落完整性

# 按语义分割
使用 NLP 技术识别语义边界

应用场景

1. 智能客服

场景:企业产品咨询、售后支持

优势

  • 基于产品文档回答

  • 答案准确可靠

  • 可提供引用来源

案例

用户:这款手机的电池容量是多少?
AI:根据产品规格文档,这款手机配备 5000mAh 
     电池,支持 65W 快充。(来源:产品规格书 v2.3)

2. 知识库问答

场景:企业内部知识管理

优势

  • 整合分散文档

  • 快速查找信息

  • 降低培训成本

案例

员工:报销流程是什么?
AI:报销流程包括:1. 提交申请 2. 主管审批 
     3. 财务审核 4. 打款。(来源:财务制度手册)

3. 文档检索

场景:法律、医疗等专业领域

优势

  • 海量文档快速检索

  • 语义理解更精准

  • 支持复杂查询

4. 数据分析助手

场景:业务数据查询

优势

  • 自然语言查询

  • 自动生成报告

  • 数据可视化

5. 教育培训

场景:智能辅导、题库系统

优势

  • 个性化教学

  • 即时答疑

  • 知识点关联

6. 研发辅助

场景:代码检索、技术文档

优势

  • 代码片段检索

  • API 文档查询

  • 技术方案推荐


优势与挑战

优势

1. 准确性高
  • ✅ 基于事实生成

  • ✅ 减少幻觉问题

  • ✅ 可验证答案

2. 实时性强
  • ✅ 知识即时更新

  • ✅ 获取最新信息

  • ✅ 时效性好

3. 专业性好
  • ✅ 融入领域知识

  • ✅ 支持专业场景

  • ✅ 答案更精准

4. 可解释性强
  • ✅ 提供引用来源

  • ✅ 答案可追溯

  • ✅ 增强信任度

5. 成本效益
  • ✅ 无需重新训练

  • ✅ 知识可复用

  • ✅ 维护成本低

挑战

1. 检索质量
  • ❌ 检索不准确影响生成

  • ❌ 语义匹配有误差

  • ❌ 长尾问题难处理

2. 上下文长度
  • ❌ LLM 上下文限制

  • ❌ 信息过多影响效果

  • ❌ 需要精挑细选

3. 延迟问题
  • ❌ 多步骤增加延迟

  • ❌ 检索耗时

  • ❌ 实时性要求高场景难满足

4. 数据质量
  • ❌ 依赖知识库质量

  • ❌ 需要数据清洗

  • ❌ 更新维护成本

5. 复杂查询
  • ❌ 多跳推理困难

  • ❌ 需要多文档整合

  • ❌ 逻辑推理有限


实现方案

方案 1:使用 LangChain(推荐)

特点

  • 组件丰富

  • 生态完善

  • 易于上手

安装

pip install langchain langchain-community
pip install langchain-openai
pip install chromadb

方案 2:使用 LlamaIndex

特点

  • 专注 RAG

  • 性能优秀

  • 文档完善

安装

pip install llama-index

方案 3:自建系统

特点

  • 完全可控

  • 灵活定制

  • 技术门槛高

技术栈

  • 向量库:FAISS / Milvus

  • 嵌入模型:BGE / M3E

  • LLM:OpenAI API / 本地部署


代码示例

示例 1:使用 LangChain 实现基础 RAG

from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# 1. 加载文档
loader = TextLoader("documents/company_policy.txt")
documents = loader.load()

# 2. 分割文本
text_splitter = CharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
texts = text_splitter.split_documents(documents)

# 3. 创建向量存储
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
    texts,
    embeddings,
    persist_directory="./chroma_db"
)

# 4. 创建 QA 链
llm = ChatOpenAI(model="gpt-3.5-turbo")
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    return_source_documents=True
)

# 5. 提问
query = "公司的年假政策是什么?"
result = qa_chain({"query": query})

print(f"答案:{result['result']}")
print(f"来源:{result['source_documents']}")

示例 2:自定义 RAG 流程

from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
import chromadb

class CustomRAG:
    def __init__(self, db_path, model_name="gpt-3.5-turbo"):
        # 初始化组件
        self.embeddings = OpenAIEmbeddings()
        self.llm = ChatOpenAI(model=model_name)
        
        # 加载向量数据库
        self.client = chromadb.PersistentClient(path=db_path)
        self.collection = self.client.get_or_create_collection("docs")
    
    def retrieve(self, query, top_k=3):
        """检索相关文档"""
        # 查询向量化
        query_embedding = self.embeddings.embed_query(query)
        
        # 相似度搜索
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=top_k
        )
        
        # 返回文档内容
        return results['documents'][0]
    
    def build_prompt(self, query, contexts):
        """构建提示词"""
        template = """基于以下信息回答问题:

{context}

问题:{question}
答案:"""
        
        context_text = "\n\n".join(contexts)
        return template.format(context=context_text, question=query)
    
    def query(self, question):
        """完整查询流程"""
        # 检索
        contexts = self.retrieve(question)
        
        # 构建提示词
        prompt = self.build_prompt(question, contexts)
        
        # 生成回答
        response = self.llm.invoke(prompt)
        
        return {
            "answer": response.content,
            "sources": contexts
        }

# 使用示例
rag = CustomRAG(db_path="./chroma_db")
result = rag.query("公司产品有哪些?")
print(result["answer"])

示例 3:多文档检索

from langchain.document_loaders import (
    PyPDFLoader, 
    Docx2txtLoader,
    TextLoader
)
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 加载多种格式文档
loaders = [
    TextLoader("docs/policy.txt"),
    PyPDFLoader("docs/manual.pdf"),
    Docx2txtLoader("docs/guide.docx")
]

documents = []
for loader in loaders:
    documents.extend(loader.load())

# 创建向量库
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
    documents,
    embeddings,
    persist_directory="./multi_docs_db"
)

# 查询
query = "如何申请休假?"
results = vectorstore.similarity_search(query, k=3)

for doc in results:
    print(f"内容:{doc.page_content[:200]}")
    print(f"来源:{doc.metadata}")

示例 4:带引用的 RAG

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.prompts import ChatPromptTemplate

# 定义提示词
system_prompt = """你是一个专业的助手。请基于以下上下文回答问题。
如果上下文中没有答案,请说明。
回答时请引用相关文档。

上下文:
{context}
"""

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{input}")
])

# 创建链
question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

# 查询
response = rag_chain.invoke({"input": "公司的晋升机制是什么?"})

print(f"答案:{response['answer']}")
print(f"来源文档:{response['context']}")

最佳实践

1. 文档处理

文档加载
# 使用合适的加载器
from langchain.document_loaders import DirectoryLoader

# 批量加载
loader = DirectoryLoader(
    "docs/",
    glob="**/*.pdf",
    show_progress=True
)
documents = loader.load()
文本分割
# 优化分割策略
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,      # 每段 1000 字符
    chunk_overlap=200,    # 重叠 200 字符
    length_function=len,
    separators=["\n\n", "\n", "。", "!", "?", " ", ""]
)

2. 检索优化

混合检索
# 结合语义检索和关键词检索
from langchain.retrievers import EnsembleRetriever
from langchain.vectorstores import Chroma
from langchain.retrievers import BM25Retriever

# 向量检索
vector_retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 5}
)

# 关键词检索
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5

# 混合检索
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    weights=[0.5, 0.5]
)
重排序
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain.cross_encoder import CrossEncoder

# 使用 CrossEncoder 重排序
compressor = CrossEncoderReranker(
    model=CrossEncoder(model_name="cross-encoder/ms-marco-MiniLM"),
    top_n=3
)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vectorstore.as_retriever()
)

3. 提示词优化

from langchain.prompts import PromptTemplate

template = """你是一个专业的知识助手。请基于提供的上下文回答问题。

要求:
1. 答案要准确、简洁
2. 如果上下文没有答案,请说明"根据现有资料无法回答"
3. 引用相关文档来源
4. 使用清晰的格式

上下文:
{context}

问题:{question}

答案:"""

prompt = PromptTemplate(
    template=template,
    input_variables=["context", "question"]
)

4. 性能优化

缓存
from langchain.cache import InMemoryCache
from langchain.globals import set_llm_cache

# 启用缓存
set_llm_cache(InMemoryCache())
批量处理
# 批量嵌入
from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()
embeddings.embed_documents(large_text_list)

5. 质量评估

# 评估指标
- 检索准确率(Retrieval Precision)
- 答案相关性(Answer Relevance)
- 用户满意度(User Satisfaction)
- 响应时间(Response Time)

# A/B 测试
- 不同嵌入模型对比
- 不同分割策略对比
- 不同 LLM 对比

常见问题

Q1: RAG 和微调有什么区别?

RAG

  • 知识外置,动态更新

  • 无需训练

  • 适合知识密集型任务

微调

  • 知识内置,相对固定

  • 需要训练数据

  • 适合风格/任务适配

建议:优先使用 RAG,必要时结合微调。

Q2: 如何选择合适的嵌入模型?

考虑因素

  • 语言:中文选 BGE/M3E,英文选 OpenAI

  • 性能:精度 vs 速度

  • 成本:API 调用费用

  • 部署:云端 vs 本地

Q3: 向量数据库如何选择?

小规模(<10 万文档):

  • Chroma(简单)

  • FAISS(高性能)

中等规模(10-100 万):

  • Weaviate

  • Pinecone

大规模(>100 万):

  • Milvus

  • Qdrant

Q4: 如何提高检索准确率?

  1. 优化文本分割

    • 保持语义完整

    • 合适 chunk 大小

  2. 使用混合检索

    • 语义 + 关键词

  3. 重排序

    • CrossEncoder 精排

  4. 查询改写

    • 扩展同义词

    • 添加上下文

Q5: RAG 的成本如何?

主要成本

  • LLM API 调用:$0.002-0.06/1K tokens

  • 嵌入 API:$0.0001/1K tokens

  • 向量数据库:免费 - 数百$/月

优化方法

  • 缓存常用查询

  • 压缩上下文

  • 选择性价比模型

Q6: 如何处理多轮对话?

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True
)

# 在检索时考虑对话历史
query = f"{chat_history}\n{current_question}"

相关资源

官方文档

学习资源

  • RAG 技术论文

  • LangChain 官方教程

  • 向量数据库文档

社区资源

  • GitHub: RAG 相关项目

  • Hugging Face: 嵌入模型

  • Discord: LangChain 社区


总结

RAG 的核心价值

  1. 解决幻觉问题 - 基于事实生成

  2. 知识可更新 - 无需重新训练

  3. 专业领域应用 - 融入行业知识

  4. 可解释性强 - 提供引用来源

适用场景

推荐使用

  • 知识库问答系统

  • 智能客服

  • 文档检索

  • 专业领域咨询

不推荐

  • 创意写作

  • 开放式对话

  • 简单问答

  • 实时性要求极高场景

技术趋势

  1. 多模态 RAG - 支持图片、表格

  2. Graph RAG - 结合知识图谱

  3. Agentic RAG - 融合 Agent 能力

  4. 端侧 RAG - 本地部署优化


更多推荐