共计 1295 个字符,预计需要花费 4 分钟才能阅读完成。
背景痛点:为什么需要 RAG?
在纯 LLM 生成模型中,我们经常遇到两个主要问题:

- 幻觉问题 :模型会生成看似合理但实际上不准确的信息
- 数据滞后性 :模型的知识受限于训练时的数据,无法获取最新信息
传统搜索 + 生成的方法虽然能解决部分问题,但存在明显的性能瓶颈:
- 搜索和生成是两个独立系统,响应延迟高
- 搜索结果与生成内容之间缺乏语义关联
- 难以处理复杂的多模态查询
技术方案对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Fine-tuning | 领域适配性好 | 需要大量标注数据 | 专业领域知识固化 |
| Prompt 工程 | 实施简单 | 上下文长度受限 | 简单任务快速验证 |
| RAG | 动态知识更新 | 系统架构复杂 | 需要最新知识的场景 |
核心实现
数据层处理
- 原始数据准备
- PDF 使用 PyPDF2 或 pdfplumber 提取文本
-
HTML 用 BeautifulSoup 清理标签
-
文本分块
- 按语义段落分割(LangChain 的 RecursiveCharacterTextSplitter)
-
理想 chunk 大小:300-500 字符
-
向量化处理
- 使用 HuggingFace 的 sentence-transformers 生成嵌入
- 示例代码:
from sentence_transformers import SentenceTransformer model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') embeddings = model.encode(chunks, convert_to_tensor=True)
检索层实现
- 向量数据库选型
- Faiss:适合内存索引
-
Elasticsearch:支持混合搜索
-
相似度检索
import faiss import numpy as np # 构建索引 d = 768 # 向量维度 index = faiss.IndexFlatIP(d) index.add(np.array(embeddings).astype('float32')) # 查询 D, I = index.search(query_embedding, k=3) # 返回 top3
生成层优化
- 提示词构造
- 将检索结果作为上下文注入
-
示例模板:
基于以下知识:\n{context}\n 请回答:{query}\n 如不确定请说 "我不知道" -
参数调优
- temperature=0.3 控制创造性
- max_length=512 限制生成长度
性能优化
缓存策略
- 本地缓存 :LRU 缓存高频 query
- 分布式缓存 :Redis 存储 embeddings
降级方案
- 设置 500ms 超时
- 超时后回退到:
- 本地缓存结果
- 基础 LLM 生成
避坑指南
- Chunk 大小
- 太小:丢失上下文
- 太大:噪声干扰
-
建议:通过 A / B 测试确定
-
查询改写
- 同义词扩展
-
问题分类
-
监控指标
- 检索命中率
- 人工评分(1- 5 分)
延伸思考
在实践中我们发现,top_k 值的选择需要权衡:
– 增大 top_k:提供更多上下文,但可能引入噪声
– 减小 top_k:更精准,但可能遗漏关键信息
建议尝试不同配置(k=3,5,7)并通过用户反馈评估效果。
总结
RAG 系统将传统搜索与生成模型的优势结合,通过本文介绍的数据处理、检索优化和生成调优方法,我们成功将系统响应速度提升了 3 - 5 倍。未来可以探索多模态检索、动态 chunk 调整等方向。
正文完
