为分类任务微调表示模型
深入讲解为分类任务微调表示模型的完整流程:分类头设计、全量微调 vs LoRA 的选择、小样本场景下的 SetFit 方案,以及过拟合防范与模型评估。
全面解析 RAG 技术栈:从基本原理、检索与生成流水线、切块与嵌入策略,到 GraphRAG、多轮检索、幻觉防治,以及 Transformer、Function Call、MCP 等相关知识点。
本文全面解析 RAG(检索增强生成)技术栈,覆盖从基本原理到高级范式、评估方法、实际部署挑战,以及 Transformer、Function Call、MCP 等相关知识点。
RAG(Retrieval-Augmented Generation) 是一种将信息检索和文本生成结合的技术范式。核心思想是:在 LLM 生成回答之前,先从外部知识库中检索相关文档,将检索到的内容作为上下文注入 Prompt,再让 LLM 基于这些上下文生成回答。
用户提问
↓
Query 向量化(Embedding)
↓
向量数据库检索 → Top-K 相关文档
↓
将文档拼接到 Prompt 中
↓
LLM 基于上下文生成回答
↓
返回给用户
| 维度 | RAG | 微调(Fine-tuning) |
|---|---|---|
| 知识更新 | 更新知识库即可,实时生效 | 需要重新训练模型 |
| 成本 | 低(无需训练 GPU) | 高(需要大量计算资源) |
| 可追溯性 | 可以引用来源文档 | 知识隐含在参数中 |
| 幻觉控制 | 有外部事实约束 | 仍可能产生幻觉 |
| 领域适应 | 添加领域文档即可 | 需要领域数据微调 |
| 数据隐私 | 数据留在本地 | 数据需参与训练 |
LLM 的上下文窗口是有限的(4K ~ 200K tokens),而企业知识库可能包含数百万甚至上亿的文档。不可能把所有文档都塞入 Prompt。
RAG 的核心思路是**"用检索代替记忆"**:
这样,即使知识库有 1TB 的数据,实际注入 Prompt 的只有几千 tokens 的精华内容。
RAG 将 LLM 从**"百科全书"模式转变为"开卷考试"模式**——不需要记住所有知识,只需要在需要时能找到正确的参考资料。
如上所述,RAG 是检索增强生成,让 LLM 在回答前先检索相关知识。
Function Call 是 LLM 调用外部工具/API 的能力。
用户:明天北京天气怎么样?
↓
LLM 判断:需要调用天气 API
↓
输出结构化调用:get_weather(city="北京", date="明天")
↓
应用层执行 API → 返回结果
↓
LLM 整合结果:明天北京晴,最高温 25°C...
MCP 是 Anthropic 提出的模型上下文协议,是一个开放标准,用于统一 LLM 与外部数据源和工具的连接方式。
MCP 采用 Client-Server 架构:
LLM 应用(MCP Client)
↕ JSON-RPC
MCP Server A(数据库)
MCP Server B(文件系统)
MCP Server C(API 服务)
| 概念 | 说明 |
|---|---|
| Resources | 数据暴露(文件、数据库记录等) |
| Tools | 可调用的函数/操作 |
| Prompts | 预定义的 Prompt 模板 |
| Sampling | Server 向 Client 请求 LLM 生成 |
| 维度 | Function Call | MCP |
|---|---|---|
| 范围 | 单一 LLM 供应商 | 跨供应商通用协议 |
| 标准化 | 各家格式不同 | 统一的 JSON-RPC |
| 发现机制 | 手动定义工具 | Server 自动暴露能力 |
| 双向通信 | 单向(LLM → 工具) | 双向(支持 Sampling) |
RAG:LLM + 知识检索
Function Call:LLM + 工具调用
MCP:统一的协议标准,让 LLM 与任意数据源/工具交互
这两种技术常用于 LLM 应用中的流式输出(Streaming)。
Client ──HTTP GET──→ Server
Client ←── data: token1 ── Server
Client ←── data: token2 ── Server
Client ←── data: [DONE] ── Server
Client ──Upgrade──→ Server(握手)
Client ←→ 双向消息 ←→ Server
| 维度 | SSE | WebSocket |
|---|---|---|
| 通信方向 | 单向(Server→Client) | 双向 |
| 协议 | HTTP | ws:// |
| 重连 | 自动 | 手动 |
| 数据类型 | 文本 | 文本 + 二进制 |
| 复杂度 | 低 | 高 |
| 代理/防火墙 | 兼容好(HTTP) | 可能被阻断 |
大部分 LLM API(OpenAI、Anthropic)的流式响应都使用 SSE。
| 策略 | 原理 | 适用场景 |
|---|---|---|
| 固定大小 | 按固定 token 数切分 | 通用场景,简单高效 |
| 递归字符 | 按段落→句子→字符递归切分 | 保持语义完整性 |
| 语义分割 | 用 Embedding 检测语义边界 | 高质量需求 |
| 文档结构 | 按标题/章节切分 | 结构化文档 |
| 句子窗口 | 检索句子,但返回周围上下文 | 精确检索 + 完整上下文 |
小 Chunk ←──────────────────────→ 大 Chunk
精确匹配 ←─ 检索精度 ─→ 更多上下文
上下文不足 ←─ 信息完整 ─→ 包含噪声
碎片化 ←─ 语义连贯 ─→ 主题混杂
数量多 ←─ 索引规模 ─→ 数量少
| 模型 | 维度 | 最大长度 | 特点 |
|---|---|---|---|
| OpenAI text-embedding-3-large | 3072 | 8191 | 商用首选,效果好 |
| BGE-M3 | 1024 | 8192 | 多语言,开源 |
| GTE-Qwen2 | 1536 | 8192 | 中文效果优秀 |
| E5-mistral-7b | 4096 | 32768 | 长文本,效果顶尖 |
| Cohere embed-v3 | 1024 | 512 | 商用,多语言 |
| 指标 | 含义 |
|---|---|
| Recall@K | Top-K 结果中包含正确文档的比例 |
| MRR | 第一个正确结果的排名倒数的平均值 |
| NDCG@K | 考虑排名位置的检索质量 |
| Precision@K | Top-K 中相关文档的比例 |
| 指标 | 含义 |
|---|---|
| STS(Semantic Textual Similarity) | 语义相似度任务得分 |
| Clustering | 聚类质量 |
| Classification | 向量用于分类的效果 |
用 LLM 将用户的口语化问题改写为更适合检索的形式。
原始:这个东西怎么用
改写:[产品名] 的使用方法和操作步骤
让 LLM 先生成一个"假设性答案",用这个答案的向量去检索,而非用问题的向量。
问题:"RAG 的优点是什么?"
假设答案:"RAG 的优点包括减少幻觉、知识实时更新..."
用假设答案的向量去检索 → 匹配更精准
将一个问题扩展为多个不同角度的子查询,分别检索后合并结果。
最终得分 = α × 向量相似度 + (1-α) × BM25 关键词得分
结合语义匹配和关键词匹配的优势。
使用 Cross-Encoder 模型对初步检索的结果进行精排。
初始检索(Bi-Encoder) → Top-50
↓
重排序(Cross-Encoder) → Top-5
Cross-Encoder 比 Bi-Encoder 更准确,但速度慢,所以先粗召回再精排。
利用文档的元数据(时间、类别、来源)进行预过滤,缩小检索范围。
先用摘要定位相关文档,再在文档内检索具体段落。
| 指标 | 计算方式 | 含义 |
|---|---|---|
| Recall@K | 相关文档在 Top-K 中的比例 | 检索的全面性 |
| Precision@K | Top-K 中相关文档的比例 | 检索的精确性 |
| MRR | 1/首个相关文档排名 | 排名质量 |
| NDCG | DCG/IDCG | 排序质量(考虑位置) |
| Hit Rate | 至少检索到 1 个相关文档的比例 | 检索覆盖率 |
| 指标 | 含义 |
|---|---|
| Faithfulness | 回答是否忠于检索到的上下文(不编造) |
| Relevance | 回答与问题的相关性 |
| Correctness | 回答的事实正确性 |
| Completeness | 回答是否完整覆盖了问题 |
| Harmfulness | 回答是否包含有害内容 |
| 指标 | 说明 |
|---|---|
| Answer Accuracy | 最终答案的正确率 |
| Latency | 从用户提问到返回答案的时间 |
| Cost | 每次查询的 Token / API 成本 |
Faithfulness = 回答中可归因于上下文的陈述比例
Context Relevancy = 检索内容中与问题相关的比例
Answer Relevancy = 回答与问题的语义相似度
Context Recall = 检索内容覆盖标准答案的程度
| 维度 | 向量数据库 | 知识图谱 |
|---|---|---|
| 检索方式 | 语义相似度 | 图遍历 / SPARQL |
| 擅长场景 | 模糊语义匹配 | 精确关系查询 |
| 多跳推理 | 弱 | 强 |
| 数据结构 | 非结构化文本 | 三元组(实体-关系-实体) |
| 构建成本 | 低(自动向量化) | 高(需要实体/关系抽取) |
用户问题
↓
├── 向量检索 → 相关文档段落
├── 图谱查询 → 相关实体和关系
└── 合并上下文
↓
LLM 生成回答
问题:"张三的经理是谁?他管理哪些项目?"
张三 →[汇报给]→ 李四 →[管理]→ [项目A, 项目B],直接得到精确答案检索 → 生成(一次性)
在生成过程中多次检索,每次用上一步的输出引导下一次检索。
Query → 检索1 → 初步回答 → 生成新 Query → 检索2 → 完善回答
LLM 自行决定是否需要检索以及何时检索。
代表工作:Self-RAG(Asai et al., 2023)
输入问题
↓
LLM 判断:是否需要检索?
├── 不需要 → 直接生成
└── 需要 → 检索 → 评估相关性 → 生成 → 评估是否需要更多信息
├── 够了 → 输出
└── 不够 → 再次检索
Self-RAG 训练模型输出特殊的 Reflection Token:
[Retrieve]:是否需要检索[IsRel]:检索结果是否相关[IsSup]:生成内容是否有支撑[IsUse]:回答是否有用在检索后增加纠正机制:
检索 → 评估检索质量
├── 质量好 → 使用检索结果
├── 质量差 → 转为 Web 搜索
└── 模糊 → 部分使用 + Web 补充
将 RAG 的各个环节模块化,可灵活组合:
[Query 模块] → [路由模块] → [检索模块] → [重排模块] → [生成模块]
↓
决定走 RAG 还是直接生成
在 RAG 场景中,幻觉指 LLM 生成了与检索到的上下文不一致或没有事实依据的内容。
| 类型 | 描述 |
|---|---|
| Intrinsic Hallucination | 与上下文矛盾的信息 |
| Extrinsic Hallucination | 上下文中没有、但模型自行编造的信息 |
| 混淆错误 | 把不同文档的信息混在一起 |
| 过度泛化 | 将个别案例错误地推广 |
系统指令:
"仅根据以下提供的上下文回答问题。
如果上下文中没有相关信息,请明确说'根据提供的资料,我无法回答这个问题'。
不要使用你自己的知识来补充。"
要求 LLM 在回答中标注每个陈述的来源文档,方便验证。
使用额外的 LLM 调用来验证生成内容是否忠于上下文:
验证 Prompt:
"以下回答是否完全基于提供的上下文?是否有任何编造的信息?"
训练模型自我评估生成内容是否有支撑。
文档 → 切块 → 向量化 → 向量数据库
查询 → 向量检索 → Top-K → LLM 生成
GraphRAG 在传统 RAG 基础上引入了知识图谱和社区结构。
文档 → LLM 抽取实体和关系 → 构建知识图谱
↓
图谱社区检测(Leiden 算法)→ 层级社区结构
↓
为每个社区生成摘要
适合具体问题:
Query → 实体匹配 → 相关社区 → 社区摘要 + 原始文本 → 生成
适合宏观总结性问题:
Query → 所有社区摘要 → Map(分段摘要) → Reduce(合并) → 生成
| 维度 | 传统 RAG | GraphRAG |
|---|---|---|
| 索引结构 | 向量索引 | 知识图谱 + 社区层级 |
| 检索方式 | 语义相似度 | 实体关系遍历 + 社区匹配 |
| 全局理解 | 弱(只看局部 Chunk) | 强(社区摘要提供全局视角) |
| 多跳推理 | 弱 | 强(图结构天然支持) |
| 构建成本 | 低 | 高(需要 LLM 抽取实体) |
| 索引更新 | 简单(增量向量化) | 复杂(需要重建图谱) |
| 适用场景 | 事实查询、局部信息 | 复杂关系、全局总结 |
当 RAG 系统返回 0 个检索结果时,按以下顺序排查:
# 1. 直接用已知文档的文本作为 query 检索自身
result = vector_db.search("知识库中已存在的一段文字")
# 如果这样都检索不到,说明索引有问题
# 2. 检查向量相似度分布
scores = [r.score for r in vector_db.search(query, top_k=100)]
print(f"最高分: {max(scores)}, 最低分: {min(scores)}")
# 如果所有分数都很低,说明 query 和文档语义差距大
Transformer(Vaswani et al., 2017)是现代 LLM 的基石架构,采用**编码器-解码器(Encoder-Decoder)**结构:
输入 → [Encoder] → 表示 → [Decoder] → 输出
核心公式:
Attention(Q, K, V) = softmax(QK^T / √d_k) V
让每个 token 都能"看到"序列中的所有其他 token,并根据相关性加权聚合信息。
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) W^O
其中 head_i = Attention(QW_i^Q, KW_i^K, VW_i^V)
多个注意力头并行计算,每个头关注不同的模式(语法、语义、位置等)。
Self-Attention 本身没有位置概念,需要额外注入位置信息。
FFN(x) = max(0, xW_1 + b_1)W_2 + b_2
两层线性变换 + ReLU 激活,为每个位置独立地进行非线性变换。
Output = LayerNorm(x + Sublayer(x))
在 Decoder 推理时,已生成的 token 的 K 和 V 可以缓存,避免重复计算。这是 LLM 推理优化的关键技术。
生成第 n 个 token 时:
- Q:只计算当前 token 的 Q
- K, V:使用缓存的 K, V + 当前 token 的 K, V
| 方向 | 方法 |
|---|---|
| 减少注意力复杂度 | Flash Attention、稀疏注意力 |
| 扩展上下文窗口 | RoPE 外推、长度外推 |
| 推理加速 | KV Cache、投机解码、量化 |
| 训练效率 | 混合精度、梯度检查点 |
RELATED