写在前面
你有没有遇到过这样的尴尬:
你: 费了九牛二虎之力搭建了一个RAG系统
老板: 这检索结果怎么这么离谱?
你: (╯°□°)╯︵ ┻━┻ 明明demo挺好的啊!这就是RAG原型和生产环境之间的鸿沟。很多开发者能快速搭建起一个RAG demo,但要让它在生产环境中稳定、准确地工作,却是另一个层次的挑战。
还记得数据科学中的**"没有免费午餐定理"**(No Free Lunch Theorem)吗?没有一种算法能适用于所有问题。RAG系统也是如此——不存在一套通用参数适用于所有场景。
今天这篇文章,我将从数据科学家的视角,带你系统地看一遍RAG系统的12个关键"超参数",教你如何像调优深度学习模型一样,把RAG系统调教到最佳性能。
RAG调优的两大阶段
RAG系统的优化可以分为两个关键阶段:
📦 数据索引阶段 (Data Ingestion)
这是构建RAG的"准备阶段",类似于机器学习中的数据清洗和预处理:
- 数据清洗 - 保证数据质量
- 分块(Chunking) - 切分文档
- 嵌入模型 - 向量化
- 元数据 - 添加结构化信息
- 多索引 - 分类管理
- 索引算法 - 高效检索
🔍 推理阶段 (Inference)
这是RAG真正"工作"的阶段,包括检索和生成:
- 查询转换 - 优化搜索查询
- 检索参数 - 调整搜索行为
- 高级检索策略 - 句子窗口、自动合并
- 重排序模型 - 提高相关性
- LLM微调 - 优化生成质量
- Prompt工程 - 优化提示词
让我们逐一深入!
阶段一:数据索引的6个调优点
1. 数据清洗:垃圾进,垃圾出
为什么重要?
你的RAG系统再强大,如果输入的数据质量差,输出也好不到哪去。这就是经典的"Garbage In, Garbage Out"。
关键检查清单:
| 维度 | 检查内容 | 示例 |
|---|---|---|
| 整洁性 | 特殊字符正确编码 | 确保中文、emoji正常显示 |
| 正确性 | 信息一致准确 | 避免同一问题的矛盾答案 |
| 完整性 | 上下文完整 | 避免句子截断、段落不全 |
实战技巧:
import re
from unidecode import unidecode
def clean_text(text):
"""数据清洗示例"""
# 1. 移除多余空白字符
text = re.sub(r'\s+', ' ', text)
# 2. 修正特殊字符编码
text = text.encode('utf-8', errors='ignore').decode('utf-8')
# 3. 统一标点符号
text = text.replace('…', '...')
# 4. 移除冗余信息
text = re.sub(r'Page \d+ of \d+', '', text) # 移除页码
return text.strip()
# 使用示例
raw_text = "这是一段 测试文本… Page 1 of 10"
clean = clean_text(raw_text)
print(clean) # "这是一段 测试文本..."💡 我踩过的坑: 曾经遇到过PDF提取的文本中混杂大量换行符和空格,导致embedding质量很差。最后写了个清洗脚本,检索准确率立刻提升了15%。
2. 分块(Chunking):切得好,检索才能好
为什么需要分块?
想象你要在一本1000页的书里找"如何配置Kubernetes集群"。如果直接把整本书塞给LLM:
- ❌ 超出上下文窗口限制
- ❌ 包含大量无关信息
- ❌ 成本高昂($$$)
分块的三个关键参数:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块大小
chunk_overlap=50, # 块间重叠
separators=["\n\n", "\n", "。", " ", ""] # 分割符优先级
)
chunks = text_splitter.split_text(long_document)参数调优指南:
| 参数 | 推荐值 | 使用场景 |
|---|---|---|
chunk_size | 200-300 | 问答场景(需要精确答案) |
chunk_size | 500-800 | 摘要场景(需要更多上下文) |
chunk_size | 1000+ | 文档理解(需要完整语义) |
chunk_overlap | 10-20% | 保持连贯性 |
不同文档类型的分块策略:
from langchain.text_splitter import (
PythonCodeTextSplitter, # 代码文件
MarkdownTextSplitter, # Markdown文档
RecursiveCharacterTextSplitter # 通用文本
)
# 示例:为代码文件使用专用分割器
code_splitter = PythonCodeTextSplitter(
chunk_size=500,
chunk_overlap=50
)
code_chunks = code_splitter.split_text(python_code)"滚动窗口"技巧:
[块1: 第1-5段]
[块2: 第4-8段] ← 注意overlap
[块3: 第7-11段]这种重叠可以避免关键信息被"切断"在两个块的边界。
💡 实战经验: 我曾经为一个技术文档问答系统调优chunk_size,发现:
- chunk_size=200时,回答很精确但缺乏上下文
- chunk_size=1000时,检索到太多无关信息
- 最终选择chunk_size=500 + overlap=50,达到最佳平衡
3. 嵌入模型:检索的灵魂
核心原则:高维度=高精度
嵌入模型的维度越高,通常表示能力越强,但同时也意味着:
- ✅ 更精准的语义理解
- ❌ 更大的存储空间
- ❌ 更慢的检索速度
如何选择嵌入模型?
参考 MTEB排行榜(Massive Text Embedding Benchmark),目前已涵盖164+个模型。
常用模型对比:
| 模型 | 维度 | 性能 | 成本 | 适用场景 |
|---|---|---|---|---|
OpenAI text-embedding-ada-002 | 1536 | ⭐⭐⭐⭐ | 💰💰 | 通用场景 |
OpenAI text-embedding-3-small | 1536 | ⭐⭐⭐⭐ | 💰 | 成本敏感 |
OpenAI text-embedding-3-large | 3072 | ⭐⭐⭐⭐⭐ | 💰💰💰 | 高精度需求 |
all-MiniLM-L6-v2 | 384 | ⭐⭐⭐ | 免费 | 本地部署 |
微调嵌入模型的价值:
根据LlamaIndex的实验,微调嵌入模型可以让检索指标提升5-10%[2]。
from sentence_transformers import SentenceTransformer
from sentence_transformers import InputExample, losses
from torch.utils.data import DataLoader
# 准备训练数据
train_examples = [
InputExample(texts=['查询1', '相关文档1']),
InputExample(texts=['查询2', '相关文档2']),
]
# 加载基础模型
model = SentenceTransformer('all-MiniLM-L6-v2')
# 定义损失函数
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)
train_loss = losses.MultipleNegativesRankingLoss(model)
# 微调
model.fit(
train_objectives=[(train_dataloader, train_loss)],
epochs=3
)⚠️ 注意: 并非所有模型都支持微调。例如,OpenAI的
text-embedding-ada-002目前不开放微调接口。
4. 元数据:为向量添加"索引卡片"
什么是元数据?
元数据就是给每个文档块贴上的"标签",方便后续过滤和筛选。
实战示例:
from langchain.vectorstores import Weaviate
from langchain.embeddings import OpenAIEmbeddings
# 为文档添加元数据
documents = [
{
"content": "Kubernetes是容器编排系统...",
"metadata": {
"source": "k8s-official-docs",
"category": "infrastructure",
"date": "2025-01-01",
"section": "入门指南",
"version": "v1.28"
}
}
]
# 存储时保留元数据
vectorstore = Weaviate.from_documents(
documents=documents,
embedding=OpenAIEmbeddings(),
metadatas=[doc["metadata"] for doc in documents]
)
# 检索时使用元数据过滤
results = vectorstore.similarity_search(
query="如何部署K8s?",
filter={"category": "infrastructure", "version": "v1.28"},
k=3
)元数据的妙用:
| 用途 | 示例 |
|---|---|
| 时间过滤 | 只检索2024年后的文档 |
| 来源筛选 | 只搜索官方文档,排除社区内容 |
| 章节定位 | "这段内容来自第3章第2节" |
| 版本管理 | 根据产品版本返回对应文档 |
5. 多索引:给不同类型的数据"分班"
什么时候需要多索引?
如果你的知识库包含完全不同类型的内容,单一索引可能不够:
知识库结构:
├── 技术文档/ ← 索引1: tech_docs
├── 产品手册/ ← 索引2: product_manuals
├── API参考/ ← 索引3: api_reference
└── 常见问题/ ← 索引4: faq实现多索引路由:
from langchain.vectorstores import Weaviate
# 创建多个索引
tech_docs_index = Weaviate(..., index_name="tech_docs")
api_index = Weaviate(..., index_name="api_reference")
faq_index = Weaviate(..., index_name="faq")
# 智能路由函数
def route_query(query: str):
"""根据查询内容路由到合适的索引"""
if "API" in query or "接口" in query:
return api_index
elif "?" in query or "如何" in query:
return faq_index
else:
return tech_docs_index
# 使用路由
query = "如何调用登录API?"
selected_index = route_query(query)
results = selected_index.similarity_search(query)💡 高级技巧: 可以使用LLM来做智能路由决策,而不是简单的关键词匹配。
6. 索引算法:速度与精度的平衡
ANN vs KNN
为了在大规模场景下实现快速检索,向量数据库通常使用近似最近邻(ANN)而非精确最近邻(KNN):
KNN: 精确但慢 (O(n))
ANN: 近似但快 (O(log n))
精度损失: 通常<5%
速度提升: 10-100倍常见ANN算法:
| 算法 | 原理 | 代表库 | 适用场景 |
|---|---|---|---|
| HNSW | 分层图 | Weaviate, Qdrant | 高精度需求 |
| IVF | 倒排索引 | Faiss | 超大规模 |
| Annoy | 随机森林 | Spotify Annoy | 内存受限 |
| ScaNN | 向量压缩 | Google ScaNN | 存储优化 |
HNSW可调参数:
import weaviate
client = weaviate.Client("http://localhost:8080")
# 创建collection时配置HNSW参数
client.schema.create_class({
"class": "Document",
"vectorIndexConfig": {
"ef": 64, # 搜索时的候选数量
"efConstruction": 128, # 构建时的候选数量
"maxConnections": 64 # 每个节点的最大连接数
}
})⚠️ 实践建议: 大多数情况下,使用向量数据库的默认参数即可。除非你有明确的性能瓶颈,否则不建议随意调整。
阶段二:推理阶段的6个调优点
推理阶段是RAG真正"发挥作用"的时刻。这个阶段的优化对最终效果影响更大。
7. 查询转换:让问题更"好搜"
问题场景:
用户的原始查询可能不适合直接用于向量检索:
用户问题: "这玩意儿咋用啊?"
→ 太口语化,embedding效果差
用户问题: "介绍一下Docker和K8s的区别,以及它们各自的优缺点和适用场景"
→ 太复杂,一次检索很难覆盖所有方面三种查询转换技术:
技巧1: 查询重写(Query Rewriting)
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
# 查询重写Prompt
rewrite_prompt = ChatPromptTemplate.from_template(
"""将下面的口语化问题改写为更正式、更适合检索的表达:
原始问题: {query}
改写后的问题:"""
)
llm = ChatOpenAI(temperature=0)
# 示例
original_query = "这玩意儿咋用啊?"
rewritten = llm(rewrite_prompt.format(query=original_query))
# 输出: "如何使用这个工具?"技巧2: HyDE(假设性文档嵌入)
先让LLM生成一个假设性的答案,然后用这个答案去检索:
# HyDE Prompt
hyde_prompt = ChatPromptTemplate.from_template(
"""请为以下问题生成一个详细的假设性答案:
问题: {query}
假设性答案:"""
)
# 生成假设答案
query = "Kubernetes的核心组件有哪些?"
hypothetical_answer = llm(hyde_prompt.format(query=query))
# 用假设答案 + 原始查询一起检索
combined_query = f"{query}\n{hypothetical_answer}"
results = vectorstore.similarity_search(combined_query)为什么HyDE有效?
因为答案的语义空间往往比问题更接近文档内容!
技巧3: 子查询分解
将复杂查询拆分成多个简单查询:
# 子查询分解
decompose_prompt = ChatPromptTemplate.from_template(
"""将以下复杂问题分解为3-5个简单的子问题:
复杂问题: {query}
子问题列表:
1."""
)
complex_query = "介绍Docker和K8s的区别、优缺点和适用场景"
sub_queries = llm(decompose_prompt.format(query=complex_query))
# 输出:
# 1. Docker是什么?
# 2. Kubernetes是什么?
# 3. Docker和Kubernetes有什么区别?
# 4. Docker的优缺点是什么?
# 5. Kubernetes的优缺点是什么?
# 分别检索后合并结果
all_results = []
for sub_q in sub_queries:
results = vectorstore.similarity_search(sub_q, k=2)
all_results.extend(results)8. 检索参数:搜索行为的精细控制
参数1: 搜索技术选择
语义搜索 vs 混合搜索
# 纯语义搜索
results = vectorstore.similarity_search(
query="机器学习",
k=5
)
# 混合搜索(语义 + 关键词)
from langchain.retrievers import BM25Retriever, EnsembleRetriever
bm25_retriever = BM25Retriever.from_documents(documents)
vector_retriever = vectorstore.as_retriever()
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.3, 0.7] # alpha=0.7表示70%语义,30%关键词
)
results = ensemble_retriever.get_relevant_documents("机器学习")混合搜索的优势:
| 场景 | 纯语义搜索 | 混合搜索 |
|---|---|---|
| 专有名词查询 | ❌ 可能找不到 | ✅ 关键词补充 |
| 概念性查询 | ✅ 语义理解好 | ✅ 更全面 |
| 缩写词查询 | ❌ embedding困难 | ✅ 精确匹配 |
参数2: 检索数量(Top-K)
# 调整返回结果数量
retriever = vectorstore.as_retriever(
search_kwargs={"k": 5} # 返回Top 5结果
)Top-K选择建议:
k=3-5: 适合问答场景,上下文窗口小
k=5-10: 适合摘要场景,需要更多信息
k=10+: 配合重排序使用,先召回再精排参数3: 相似度度量
# 选择相似度计算方法
vectorstore = Weaviate.from_documents(
documents=docs,
embedding=embeddings,
distance_metric="cosine" # cosine, dot_product, euclidean
)⚠️ 重要提示: 相似度度量应该根据嵌入模型的推荐设置,而不是随意实验。
9. 高级检索策略:检索块≠生成块
核心思想:
用于检索的文本块,不一定要和用于生成的文本块相同!
理想做法:
检索用小块(精准定位) → 生成用大块(完整上下文)策略1: 句子窗口检索(Sentence Window Retrieval)
# 示例:检索到第5句后,返回第3-7句
retrieved_sentence_id = 5
window_size = 2
context = sentences[
retrieved_sentence_id - window_size :
retrieved_sentence_id + window_size + 1
]可视化:
文档: [句1] [句2] [句3] [句4] [句5] [句6] [句7] [句8]
检索命中: [句5] ✅
实际返回: [句3] [句4] [句5] [句6] [句7] ← 带窗口策略2: 自动合并检索(Auto-Merging Retrieval)
文档以树状结构组织:
文档树:
章节1
├── 小节1.1
│ ├── 段落1.1.1
│ └── 段落1.1.2
└── 小节1.2
├── 段落1.2.1
└── 段落1.2.2合并规则:
# 如果检索到的多个段落属于同一小节,则合并返回整个小节
检索结果:
- 段落1.1.1 ✅
- 段落1.1.2 ✅
自动合并 → 返回整个"小节1.1"10. 重排序模型:从"相似"到"相关"
问题:
语义搜索返回的是"最相似"的结果,但相似≠相关!
查询: "如何优化Docker镜像大小?"
检索结果(按相似度):
1. "Docker镜像的构建过程..." ← 相似但不太相关
2. "优化Docker镜像的5个技巧..." ← 高度相关 ✅
3. "Docker镜像的安全性..." ← 相似但不相关解决方案:重排序模型
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
# 初始检索器
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 20})
# Cohere重排序模型
compressor = CohereRerank(
model="rerank-english-v2.0",
top_n=5 # 从20个结果中重排后选Top 5
)
# 组合检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever
)
# 使用
docs = compression_retriever.get_relevant_documents(
"如何优化Docker镜像大小?"
)工作流程:
1. 初始检索: Top 20 (召回率优先)
↓
2. 重排序模型: 计算相关性分数
↓
3. 精选输出: Top 5 (精准度优先)重排序的价值:
根据实践经验,使用重排序模型可以让最终答案的准确率提升10-20%。
11. LLM微调:让生成更懂你的领域
什么时候需要微调LLM?
✅ 特定领域术语很多(医疗、法律、金融) ✅ 需要特定的回答风格和格式 ✅ 对响应速度有极高要求
微调 vs RAG
| 维度 | RAG | 微调LLM | RAG + 微调 |
|---|---|---|---|
| 知识更新 | ⭐⭐⭐⭐⭐ 实时 | ⭐⭐ 需重新训练 | ⭐⭐⭐⭐⭐ |
| 风格控制 | ⭐⭐⭐ Prompt控制 | ⭐⭐⭐⭐⭐ 深度定制 | ⭐⭐⭐⭐⭐ |
| 成本 | ⭐⭐⭐⭐ 较低 | ⭐⭐ 较高 | ⭐⭐⭐ 中等 |
最佳实践:RAG + 微调
微调LLM: 调整模型风格、指令遵循能力
+
RAG系统: 提供最新知识和事实信息
=
最优方案12. Prompt工程:生成质量的最后一道关卡
RAG的Prompt模板:
prompt_template = """你是一个专业的技术问答助手。
重要指示:
1. 请**仅基于**下面提供的上下文信息回答问题
2. 如果上下文中没有相关信息,明确说"根据提供的信息无法回答"
3. 回答时请引用上下文中的具体内容
4. 保持简洁,最多3-4句话
上下文信息:
{context}
用户问题: {question}
你的回答:"""关键Prompt技巧:
技巧1: 强制引用来源
❌ 差的Prompt: "回答问题"
✅ 好的Prompt: "基于上下文回答,并说明你的答案来自哪一段"技巧2: Few-Shot示例
prompt_with_examples = """你是技术问答助手。参考以下示例回答:
示例1:
问题: Docker和VM的区别?
上下文: Docker使用容器技术...VM使用虚拟机...
回答: 根据上下文,Docker使用容器技术共享主机内核,而VM使用虚拟机技术有独立内核。Docker更轻量,VM隔离性更好。
示例2:
问题: 如何扩展Kubernetes集群?
上下文: [无相关信息]
回答: 抱歉,提供的上下文中没有关于Kubernetes集群扩展的信息。
现在请回答:
问题: {question}
上下文: {context}
回答:"""技巧3: 上下文长度调优
"中间迷失"问题(Lost in the Middle):
研究发现[6],当相关信息位于大量上下文的中间位置时,LLM可能无法注意到它!
上下文结构:
[文档1] ← LLM注意力高
[文档2]
[文档3] ← 关键信息在这里,但LLM可能忽略!
[文档4]
[文档5] ← LLM注意力高解决方案:
# 策略1: 限制上下文数量
retriever = vectorstore.as_retriever(
search_kwargs={"k": 3} # 不要超过5个
)
# 策略2: 重排序,把最相关的放在开头和结尾
def reorder_documents(docs):
"""将最相关的文档放在开头和结尾"""
if len(docs) <= 2:
return docs
# 最相关的放开头
# 次相关的放结尾
# 其余放中间
return [docs[0]] + docs[2:-1] + [docs[1]]实战:构建一个生产级RAG系统
把上面的策略整合起来:
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Weaviate
from langchain.chat_models import ChatOpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser
# 1. 数据清洗和分块
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", " "]
)
chunks = text_splitter.split_documents(documents)
# 2. 向量化和存储(使用高质量嵌入模型)
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vectorstore = Weaviate.from_documents(
documents=chunks,
embedding=embeddings,
metadatas=[chunk.metadata for chunk in chunks]
)
# 3. 混合检索 + 重排序
base_retriever = vectorstore.as_retriever(
search_type="mmr", # 使用MMR提高多样性
search_kwargs={
"k": 20,
"fetch_k": 50,
"lambda_mult": 0.7
}
)
# 重排序
reranker = CohereRerank(top_n=5)
compression_retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=base_retriever
)
# 4. 优化的Prompt
prompt = ChatPromptTemplate.from_template("""你是一个专业的技术问答助手。
重要规则:
1. 仅基于下面的上下文信息回答
2. 如果信息不足,明确说明
3. 引用具体的上下文内容
4. 保持简洁(3-4句话)
上下文:
{context}
问题: {question}
回答:""")
# 5. LLM
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
# 6. 构建RAG链
rag_chain = (
{
"context": compression_retriever,
"question": RunnablePassthrough()
}
| prompt
| llm
| StrOutputParser()
)
# 使用
response = rag_chain.invoke("如何优化Docker镜像大小?")
print(response)调优实验跟踪:像ML项目一样管理RAG
为什么需要实验跟踪?
RAG有这么多"超参数",如何知道哪个组合最好?答案是:系统地实验和记录。
使用MLflow跟踪RAG实验:
import mlflow
# 开启实验跟踪
mlflow.set_experiment("rag-optimization")
with mlflow.start_run():
# 记录参数
mlflow.log_params({
"chunk_size": 500,
"chunk_overlap": 50,
"embedding_model": "text-embedding-3-large",
"retrieval_k": 20,
"rerank_top_n": 5,
"llm_model": "gpt-4-turbo",
"llm_temperature": 0
})
# 运行RAG系统
results = evaluate_rag_system(test_queries)
# 记录指标
mlflow.log_metrics({
"avg_retrieval_precision": results['precision'],
"avg_answer_accuracy": results['accuracy'],
"avg_latency_ms": results['latency']
})评估指标:
| 指标类别 | 具体指标 | 说明 |
|---|---|---|
| 检索质量 | Precision@K | 前K个结果中相关的比例 |
| Recall@K | 检索到的相关文档占总相关文档的比例 | |
| MRR | 第一个相关结果的平均排名倒数 | |
| 生成质量 | Answer Accuracy | 答案的准确性(人工评估) |
| Faithfulness | 答案是否忠实于上下文 | |
| Answer Relevance | 答案与问题的相关性 | |
| 系统性能 | Latency | 端到端响应时间 |
| Token Usage | Token消耗(成本) |
总结:RAG调优的12个关键点
数据索引阶段(6个)
✅ 数据清洗
→ 确保数据整洁、正确、完整
✅ 分块
→ chunk_size: 200-1000(根据场景)
→ chunk_overlap: 10-20%
→ 选择合适的分割器
✅ 嵌入模型
→ 参考MTEB排行榜
→ 考虑微调(可提升5-10%)
✅ 元数据
→ 添加时间、来源、分类等标签
→ 支持后续过滤
✅ 多索引
→ 为不同类型数据创建独立索引
→ 实现智能路由
✅ 索引算法
→ HNSW, IVF等ANN算法
→ 通常使用默认配置即可推理阶段(6个)
✅ 查询转换
→ 查询重写
→ HyDE(假设性文档嵌入)
→ 子查询分解
✅ 检索参数
→ 语义搜索 vs 混合搜索(alpha参数)
→ Top-K数量(3-20)
→ 相似度度量(根据embedding模型)
✅ 高级检索策略
→ 句子窗口检索
→ 自动合并检索
✅ 重排序模型
→ Cohere Rerank等
→ 先召回(k=20),再精排(top_n=5)
✅ LLM微调
→ 调整风格和指令遵循
→ 与RAG结合使用
✅ Prompt工程
→ 强制基于上下文回答
→ 使用Few-Shot示例
→ 注意"中间迷失"问题下一步行动
本周任务:
- 审计你的RAG系统的数据质量
- 实验2-3种不同的chunk_size
- 尝试混合检索(语义+关键词)
- 添加重排序模型
本月目标:
- 建立RAG实验跟踪系统
- 对嵌入模型进行微调
- 实施高级检索策略
- 完善Prompt模板
长期优化:
- 持续收集用户反馈
- 建立自动化评估流程
- 探索最新的RAG研究
- 考虑LLM微调
参考资料
- Connor Shorten & Erika Cardenas (2023). An Overview on RAG Evaluation
- Jerry Liu (2023). Fine-Tuning Embeddings for RAG with Synthetic Data
- DeepLearning.AI. Building and Evaluating Advanced RAG Applications
- Liu et al. (2023). Lost in the Middle: How Language Models Use Long Contexts
记住:RAG不是一次性工程,而是需要持续迭代优化的系统。从最简单的baseline开始,逐步添加优化策略,用数据说话,才能打造出真正好用的RAG应用! 🚀
这篇文章对你有帮助吗?分享你的RAG调优经验,或者遇到的坑!