直接结论

**RAG 与微调改变的是大模型系统的不同层。**检索增强生成改变每次请求可见的证据,微调改变模型权重或适配器,长上下文则改变一次请求能直接携带多少证据。三者都不是通用赢家,也都不能保证事实正确。

应从能通过冻结评测的最小改动开始:

  • 语料边界明确、仍在探索工作流时,先测 Prompt 或长上下文;
  • 知识量更大、独立于模型更新、需要权限控制或引用时,再加 RAG;
  • Prompt 与 Schema 优化后仍反复出现同类行为错误,再评测微调;
  • 只有组合方案分别解决了可测量的故障,才同时使用 RAG 与微调。

原始 RAG 论文把参数化记忆与非参数化记忆结合,并在论文评测的知识密集型任务上取得改进,但它没有证明检索能消除幻觉。LoRA 论文展示了参数高效适配方法;其中参数量与显存结论来自特定模型和训练设置,不能直接推广到所有微调任务。

三种方案分别改变什么

长上下文改变请求

长上下文把来源材料直接放进请求,不需要检索索引,也不更新模型权重。它适合一次性分析、小而稳定的语料和早期原型,因为证据路径比较容易检查。

它的故障边界在注意力和上下文组织。材料即使装得进标称窗口,模型仍可能忽略、混淆或错误加权其中的段落。Lost in the Middle 研究在多文档问答与键值检索实验中观察到位置敏感的性能下降。这个结果应作为评测警告,而不是当前所有模型的固定阈值。

RAG 改变推理时证据

RAG 通常把离线知识路径与在线回答路径分开:

flowchart LR A["已授权的来源版本"] --> B["解析与分段"] B --> C["带来源和 ACL 的索引"] Q["问题 + 可信身份"] --> D["检索授权候选"] C --> D D --> E["重排与证据组装"] E --> F["生成或拒答"] F --> G["答案 + 引用 + 轨迹"]

模型本身没有变化。“更新来源”也不天然等于“立即生效”:摄取、解析、索引、缓存失效与删除传播都完成后,服务版本才算新鲜。引用同样不会自动正确,系统必须保存稳定来源标识,并验证论断是否真的得到引用片段支持。

微调改变模型行为

微调用样本、偏好或奖励优化参数。监督微调可改善分类、语气、格式、术语或重复性的工具调用行为;LoRA 等参数高效方法则冻结基座模型,只训练较小的适配参数。

如果事实需要单独纠正、引用、鉴权或删除,模型权重不是合适的权威存储。微调也不能让 Schema、政策或鉴权规则变成确定性约束,这些边界仍应由可信应用代码执行。

选型不只是“知识还是行为”

“RAG 管事实,微调管行为”适合作为第一层心智模型,但不足以直接做架构决策。

需求 最先评测的基线 可能失败的原因 下一项实验
分析一组边界明确的文档 长上下文 位置敏感、重复 Token 成本、窗口限制 同模型 RAG
回答持续变化的来源 RAG 检索遗漏、索引陈旧、无证据推断 混合检索、重排、拒答
稳定输出格式或标签 Prompt + 约束输出 长尾错误反复出现、指令过长 监督微调
学习领域术语 示例 Prompt 或术语检索 对未标注表达泛化不足 使用留出切片微调
用专业风格回答新鲜事实 RAG 基线 行为仍不稳定 RAG + 微调
执行高影响操作 确定性工作流 模型提议不等于授权 策略引擎与明确审批

微调可以改善生成器使用 RAG 证据的方式,检索也可以为微调模型提供新鲜事实。只有当组合方案在质量、延迟、成本、运维复杂度和新增失败模式都计入后,仍优于两个简单基线,混合架构才成立。

必须拆开测量的失败模式

RAG 的失败模式

RAG 至少有四个相互独立的质量边界:

  1. **语料覆盖:**权威答案可能缺失、过期、重复或尚未完成索引。
  2. **授权候选召回:**正确证据存在,但经过租户和对象过滤后没有进入候选集。
  3. **排序与上下文组装:**正确片段被裁掉、截断,或被高相似度噪声包围。
  4. **生成与归因:**模型可能违背证据、混合不同版本,或把引用挂到不支持该论断的来源上。

先测 Recall@k 或人工判定的证据覆盖率,再测答案质量。随后补充论断支持率、引用精度、拒答、延迟和成本。一个系统可以靠拒绝几乎所有请求获得极低的已发布错误率,因此风险必须与覆盖率一起报告。

微调的失败模式

微调的风险不同:

  • 训练/测试泄漏会让狭窄任务看起来已经解决;
  • 低质量样本会教会模型不受支持的表达和行为;
  • 模型可能在调优分布之外遗忘原有能力;
  • 基座模型升级可能破坏适配器兼容性或历史评测;
  • 敏感样本进入权重后很难逐条识别和删除;
  • Prompt 变短不等于计入训练、托管和复核后的总成本更低。

应保留未参与开发的测试集、对抗与多语言切片、基座对照和可回滚制品,并记录基座 Checkpoint、Tokenizer、数据版本、目标函数、适配器配置、随机种子策略与 Serving Runtime。

一套可逆的决策流程

把选型设计成实验,而不是路线之争。

1. 冻结任务契约

每个测试样例至少记录输入、授权来源版本、期望证据、答案验收条件、禁止出现的论断,以及拒答是否正确。用户、文档家族或时间上存在近重复时,应按实体或时间切分,不能随机拆分后制造泄漏。

2. 建立可比较基线

至少比较:

  • 基座模型 + 精简 Prompt;
  • 语料可容纳时的长上下文;
  • 固定检索与重排配置的 RAG;
  • 不带检索的微调模型;
  • 只有前四项暴露互补故障时,才加入混合方案。

在实验允许范围内固定模型快照、输出契约、超时、重试与评测器。若某个候选更换了模型,必须把它标为复合变量,不能把收益全部归因给 RAG 或微调。

3. 测量整个系统

层级 有用指标
检索 授权证据 Recall@k、MRR 或 nDCG、陈旧来源率、删除传播
回答 任务成功率、论断支持率、引用精度、拒答质量、高影响错误率
运维 p50/p95/p99 延迟、超时与重试率、队列深度、索引新鲜度
经济性 摄取、训练、存储、推理、复核与单个合格任务成本
治理 租户隔离、来源许可证、保留周期、适配器血缘与回滚

不能拿一个系统的训练账单,与另一个系统的单次 Token 账单直接比较。应按预期流量、语料规模、更新周期和 SLO,统一折算为合格业务结果。

可运行的 Go 验收门禁

下面的标准库程序把显式产品政策应用到一组模拟实验结果。数字只是测试 Fixture,不是行业基准。候选必须同时满足质量、延迟、删除和证据约束,程序才会从合格项中选择单个合格任务成本最低的方案。

go
package main

import (
	"fmt"
	"sort"
)

type Candidate struct {
	Name                 string
	TaskSuccess          float64
	EvidenceRecall       float64
	UnsupportedClaimRate float64
	P95LatencyMS         int
	CostPerAcceptedTask  float64
	DeletionTestPassed   bool
}

type Policy struct {
	MinTaskSuccess          float64
	MinEvidenceRecall       float64
	MaxUnsupportedClaimRate float64
	MaxP95LatencyMS         int
}

func passes(candidate Candidate, policy Policy) bool {
	return candidate.TaskSuccess >= policy.MinTaskSuccess &&
		candidate.EvidenceRecall >= policy.MinEvidenceRecall &&
		candidate.UnsupportedClaimRate <= policy.MaxUnsupportedClaimRate &&
		candidate.P95LatencyMS <= policy.MaxP95LatencyMS &&
		candidate.DeletionTestPassed
}

func main() {
	policy := Policy{
		MinTaskSuccess:          0.84,
		MinEvidenceRecall:       0.88,
		MaxUnsupportedClaimRate: 0.05,
		MaxP95LatencyMS:         1200,
	}

	candidates := []Candidate{
		{Name: "long-context", TaskSuccess: 0.82, EvidenceRecall: 0.87, UnsupportedClaimRate: 0.04, P95LatencyMS: 1500, CostPerAcceptedTask: 0.019, DeletionTestPassed: true},
		{Name: "rag", TaskSuccess: 0.86, EvidenceRecall: 0.91, UnsupportedClaimRate: 0.04, P95LatencyMS: 920, CostPerAcceptedTask: 0.012, DeletionTestPassed: true},
		{Name: "fine-tuned", TaskSuccess: 0.83, EvidenceRecall: 0.56, UnsupportedClaimRate: 0.09, P95LatencyMS: 410, CostPerAcceptedTask: 0.010, DeletionTestPassed: false},
		{Name: "rag-plus-fine-tuning", TaskSuccess: 0.89, EvidenceRecall: 0.93, UnsupportedClaimRate: 0.03, P95LatencyMS: 1380, CostPerAcceptedTask: 0.023, DeletionTestPassed: true},
	}

	eligible := make([]Candidate, 0, len(candidates))
	for _, candidate := range candidates {
		if passes(candidate, policy) {
			eligible = append(eligible, candidate)
		}
	}
	if len(eligible) == 0 {
		fmt.Println("no candidate passed; keep the current system")
		return
	}

	sort.Slice(eligible, func(i, j int) bool {
		return eligible[i].CostPerAcceptedTask < eligible[j].CostPerAcceptedTask
	})
	fmt.Printf("selected=%s cost_per_accepted_task=%.3f\n",
		eligible[0].Name,
		eligible[0].CostPerAcceptedTask,
	)
}

预期输出:

text
selected=rag cost_per_accepted_task=0.012

请用产品真实测量值与业务政策替换 Fixture 和阈值。不能为了让偏好的架构通过,而反向降低质量门槛。

安全与生命周期边界

RAG 必须在检索前鉴权,而不是等生成后再过滤。索引应携带租户与对象范围,缓存键也要包含授权上下文,禁止未授权候选进入 Prompt、日志或重排器。检索文本仍是不可信输入,因为文档可以携带 Prompt Injection。

微调需要数据来源、许可证与同意审查、Secret 扫描、删除策略,以及从适配器到基座 Checkpoint 和训练集版本的映射。训练任务不是合法性判断;从源库删掉一行,也不能证明其影响已经从模型制品消失。

无论使用哪种方案,模型输出都只是提议。付款、发消息、账户变更、医疗编码和法律决策仍需模型之外的权威校验,以及与影响相匹配的人工复核。

常见问题

RAG 一定比微调便宜吗?

没有通用答案。RAG 增加摄取、索引、检索、重排和输入 Token;微调增加数据整理、训练、制品管理、Serving 和回归测试。请在预期流量、语料规模、更新频率与 SLO 下比较单个合格任务成本。

RAG 能保证引用正确吗?

RAG 可以保存候选来源,但生成器可能挂错引用,或提出比证据更宽泛的论断。应评测引用精度与论断级支持关系,并把“证据不足”设计为合法结果。

团队是否应该永远先做 RAG?

不是。应先做最能代表任务的简单基线。边界明确的文档可能适合长上下文;确定性分类可能不需要检索;稳定而重复的行为也可能适合微调。只有 RAG 能解决可测量的知识问题时,才值得引入。

LoRA 能达到全量微调的效果吗?

LoRA 论文在其评测模型和任务上报告了有竞争力的结果,并在 GPT-3 实验中大幅减少可训练参数。但这不能保证任意目标模块、Rank、数据集、基座模型和部署上都等价。应与基座和可行的全量微调基线比较。

什么时候应该组合 RAG 与微调?

当 RAG 已满足证据要求,却反复违反某项行为契约,而微调能稳定修复该问题;或者微调模型满足行为要求,却需要新鲜、授权的证据时,可以组合。必须保留消融实验,避免看不出每个组件的真实贡献。

一手资料