大模型应用实战

RAG调优实战:12个让检索增强生成从"能用"到"好用"的关键策略

从数据科学家的视角深度解析RAG系统的12种调优策略,涵盖数据索引和推理两大阶段,帮助你把RAG应用从原型推向生产环境

·19 分钟阅读·技术

写在前面

你有没有遇到过这样的尴尬:

你: 费了九牛二虎之力搭建了一个RAG系统
老板: 这检索结果怎么这么离谱?
你: (╯°□°)╯︵ ┻━┻ 明明demo挺好的啊!

这就是RAG原型和生产环境之间的鸿沟。很多开发者能快速搭建起一个RAG demo,但要让它在生产环境中稳定、准确地工作,却是另一个层次的挑战。

还记得数据科学中的**"没有免费午餐定理"**(No Free Lunch Theorem)吗?没有一种算法能适用于所有问题。RAG系统也是如此——不存在一套通用参数适用于所有场景

今天这篇文章,我将从数据科学家的视角,带你系统地看一遍RAG系统的12个关键"超参数",教你如何像调优深度学习模型一样,把RAG系统调教到最佳性能。

RAG调优的两大阶段

RAG系统的优化可以分为两个关键阶段:

📦 数据索引阶段 (Data Ingestion)

这是构建RAG的"准备阶段",类似于机器学习中的数据清洗和预处理:

  1. 数据清洗 - 保证数据质量
  2. 分块(Chunking) - 切分文档
  3. 嵌入模型 - 向量化
  4. 元数据 - 添加结构化信息
  5. 多索引 - 分类管理
  6. 索引算法 - 高效检索

🔍 推理阶段 (Inference)

这是RAG真正"工作"的阶段,包括检索和生成:

  1. 查询转换 - 优化搜索查询
  2. 检索参数 - 调整搜索行为
  3. 高级检索策略 - 句子窗口、自动合并
  4. 重排序模型 - 提高相关性
  5. LLM微调 - 优化生成质量
  6. 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_size200-300问答场景(需要精确答案)
chunk_size500-800摘要场景(需要更多上下文)
chunk_size1000+文档理解(需要完整语义)
chunk_overlap10-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-0021536⭐⭐⭐⭐💰💰通用场景
OpenAI text-embedding-3-small1536⭐⭐⭐⭐💰成本敏感
OpenAI text-embedding-3-large3072⭐⭐⭐⭐⭐💰💰💰高精度需求
all-MiniLM-L6-v2384⭐⭐⭐免费本地部署

微调嵌入模型的价值:

根据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微调LLMRAG + 微调
知识更新⭐⭐⭐⭐⭐ 实时⭐⭐ 需重新训练⭐⭐⭐⭐⭐
风格控制⭐⭐⭐ 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 UsageToken消耗(成本)

总结: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微调

参考资料

  1. Connor Shorten & Erika Cardenas (2023). An Overview on RAG Evaluation
  2. Jerry Liu (2023). Fine-Tuning Embeddings for RAG with Synthetic Data
  3. DeepLearning.AI. Building and Evaluating Advanced RAG Applications
  4. Liu et al. (2023). Lost in the Middle: How Language Models Use Long Contexts

记住:RAG不是一次性工程,而是需要持续迭代优化的系统。从最简单的baseline开始,逐步添加优化策略,用数据说话,才能打造出真正好用的RAG应用! 🚀


这篇文章对你有帮助吗?分享你的RAG调优经验,或者遇到的坑!