模型调优与数据工程:让AI真正懂你的业务
在开始之前
Hook
你有没有遇到过这种情况——花大力气搭了一套 RAG 系统,知识库也灌进去了,结果 AI 的回答还是”差点意思”?或者团队争论了一个月到底该微调还是该上 RAG,最后谁也说服不了谁?
更扎心的是:你们用的模型明明是市面上最强的,但放到你的业务场景里,效果就是比竞品差一截。问题出在哪?
问题出在”调优”和”数据”上。模型是通用大脑,但你的业务是特定领域。通用大脑不懂你的术语、不知道你的业务规则、没见过你的客户长什么样。你需要一套方法,让模型从”什么都懂一点”变成”你的业务专家”。
这就是这门课要讲的内容。
Promise
学完这门课,你将能够:
- 理解模型调优的完整光谱,知道什么时候用提示词、什么时候用 RAG、什么时候必须微调
- 掌握微调的核心原理(LoRA/QLoRA),理解背后的数学直觉而不只是调参
- 自己估算硬件需求,知道什么样的卡能跑什么样的模型
- 做好数据工程——包括数据验收、数据收集、数据质量把控
- 设计和执行模型测评,不只会”跑个分数”,还能发现真问题
- 做出向量库选型决策,搭建完整的数据管道
- 从零到一完成一个端到端的模型调优项目
Roadmap
第1章 模型调优全景 ──── 建立完整认知框架,学会方法选择
↓
第2章 微调理论篇 ──── 搞懂原理,理解为什么而不只是怎么做
↓
第3章 微调实践篇 ──── 动手做,从部署到微调到评估
↓
第4章 数据工程 ──── 学会AI项目中最被低估的技能
↓
第5章 模型测评 ──── 用数据说话,而不是凭感觉
↓
第6章 向量库与数据管道 ──── RAG系统的基建能力
↓
第7章 综合实战 ──── 端到端完成一个完整项目
第1章 模型调优全景
章节目标
- 理解为什么”直接用最强模型”不等于最好的业务效果
- 掌握从提示词到后训练的完整方法光谱
- 能根据业务场景做出正确的方法选择
1.1 为什么需要调优:预训练模型不是你的业务专家
预训练模型像一个读过整个互联网的”全科医生”——什么都知道一点,但在你的特定领域里,它比不上一个专注该领域十年的”专科医生”。
举几个实际的例子:
金融风控场景。你问模型”这个交易是否可疑”,模型可能给你一个泛泛的回答,因为它不理解你们银行特有的风控规则、黑名单模式、以及监管机构对你所在地区的特殊要求。这些信息不在训练数据里。
医疗问诊场景。模型知道教科书上的诊断流程,但它不知道你们医院特定的检验流程、不知道你的系统里患者能提供哪些检验报告、不知道哪些药在你们药房有库存。
客服场景。模型可以礼貌地回答用户问题,但它不知道你们当前的退换货政策(可能上周刚改过)、不知道特定 SKU 的库存状态、不知道你们的促销活动细节。
这些差距的本质是什么?三个缺乏:
- 缺乏领域知识:模型没见过你的专业术语、业务规则、行业惯例
- 缺乏实时信息:模型的知识有截止日期,不知道昨天发生的事
- 缺乏行为规范:模型不知道在你这个场景下应该怎么回答、什么该说什么不该说、什么格式输出
调优的本质,就是弥补这三个缺乏。
要点
调优不是让模型变”聪明”,而是让模型变”懂你”。通用能力已经很强了,缺的是你的业务 DNA。
1.2 调优方法光谱:从提示词到后训练
想象一个光谱,左端是最轻量的方法(改改提示词就行),右端是最重量的方法(需要重新训练模型)。成本从低到高,效果从弱到强,但适用场景完全不同。
成本低 ←————————————————————————————→ 成本高
效果好 ←——————————————→ 效果好(可控)
┌─────────┬──────────┬──────────┬──────────┐
│ 提示词 │ RAG │ 微调 │ 后训练 │
│ 工程 │ 检索增强 │ Fine-tune │ Post-train│
├─────────┼──────────┼──────────┼──────────┤
│ 即时生效 │ 需要知识库 │ 需要训练数据 │ 需要GPU集群│
│ 零成本 │ 中等成本 │ 中高成本 │ 高成本 │
│ 效果有限 │ 知识增强 │ 行为改变 │ 能力改变 │
└─────────┴──────────┴──────────┴──────────┘
提示词工程(你在课程2中学过)
这是调优的第一道防线。通过精心设计提示词,你可以:
- 规定输出的格式和风格
- 提供少量示例(few-shot)引导行为
- 设定角色和约束条件
适用场景:行为规范类需求,比如”用JSON格式输出”、“用专业语气回答”。
RAG(检索增强生成)
提示词搞不定的是”信息量”问题。你的知识库可能有几十万字的文档,全塞进提示词里不现实。RAG 的做法是:先检索相关文档片段,再把这些片段作为上下文喂给模型。
适用场景:需要大量外部知识支撑,且知识经常更新。比如客服问答、文档检索、法律咨询。
微调(Fine-tuning)
RAG 解决了”知识”问题,但解决不了”行为”问题。你需要模型用特定的语气说话、按特定的流程思考、在特定情况下做出特定判断——这些需要通过微调来改变模型的行为模式。
适用场景:需要模型改变行为模式,比如专业领域问答、特定风格的文案生成、特定格式的数据提取。
后训练(Post-training / RLHF / DPO)
这是最重的方法,通常由模型厂商完成。它涉及用人类反馈来对齐模型的行为,或者用特定策略让模型学会推理、规划等高级能力。
适用场景:你是模型厂商,或者有充足的 GPU 资源和标注团队,需要从根本上改变模型的能力。
要点
这四种方法不是互斥的,而是互补的。生产系统中往往是多种方法叠加使用。RAG + 提示词工程是最常见的组合,微调 + RAG 是进阶组合。
1.3 什么时候该用什么方法
这是很多人最困惑的问题。我给你一个决策框架,以后遇到具体场景时可以按这个逻辑判断。
方法选择决策树
| 你的问题 | 特征 | 推荐方法 | 理由 |
|---|---|---|---|
| 模型回答格式不对 | 只需要改输出格式 | 提示词工程 | 零成本,即时生效 |
| 模型不知道某个事实 | 需要补充特定知识 | RAG | 知识可随时更新,不需要改模型 |
| 模型回答风格不对 | 需要改行为模式 | 微调 | 提示词可能不够稳定 |
| 模型专业能力不足 | 需要领域深度 | 微调 + RAG | 知识和行为都需要改变 |
| 模型核心能力不够 | 需要更强的推理/创作 | 换模型 | 微调无法突破模型能力上限 |
| 数据实时性要求高 | 知识每小时都在变 | RAG | 只有 RAG 能做到实时更新 |
| 需要极低延迟 | 响应时间 < 200ms | 微调小模型 | RAG 的检索增加延迟 |
| 预算有限 | 不想花太多钱 | 提示词 + RAG | 微调需要 GPU 和数据成本 |
一个更直观的判断流程
开始
│
▼
问题是否可以通过"给模型更多信息"解决?
│
├─ 是 ──→ 信息是否经常变化?
│ │
│ ├─ 是 ──→ 用 RAG
│ └─ 否 ──→ 用 few-shot 提示词
│
└─ 否 ──→ 问题是否可以通过"告诉模型怎么回答"解决?
│
├─ 是 ──→ 提示词能稳定控制吗?
│ │
│ ├─ 是 ──→ 用提示词工程
│ └─ 否 ──→ 用微调
│
└─ 否 ──→ 模型本身能力是否足够?
│
├─ 是 ──→ 用微调(深度行为改变)
└─ 否 ──→ 换更强的模型,或者评估是否需要后训练
一个真实案例
某电商平台的智能客服项目,经历了这样的演进:
- V1(提示词):直接用 GPT-4 + 系统提示词。效果:70% 的问题能答对,但格式不稳定,经常”说太多”。
- V2(提示词 + few-shot):加了10个示例。效果:格式稳定了,但遇到知识库外的政策问题还是乱答。
- V3(RAG):接入退换货政策、商品信息的知识库。效果:知识准确性提升到 85%,但语气还是太”AI”。
- V4(RAG + 微调):用 5000 条人工标注的客服对话微调了一个 7B 模型。效果:准确率 92%,语气自然,响应速度还更快。
这个演进路径非常典型:先轻后重,每一步都有明确的理由。
要点
永远从最轻量的方法开始。如果提示词能解决问题,不要上 RAG。如果 RAG 能解决问题,不要微调。每一层的升级都要有明确的数据支撑——上一层的瓶颈在哪里,新方法如何解决这个瓶颈。
常见坑点
- “越贵的方法效果越好”:错。方法选择看的是问题类型,不是预算大小。用微调去解决知识缺失问题,就像用大炮打蚊子——又贵又打不准。
- “我的场景很特殊,肯定需要微调”:大多数人高估了自己场景的特殊性。先试提示词和 RAG,如果不够再升级。
- “只选一种方法”:生产系统几乎都需要组合使用。不要把时间花在”到底选哪个”上,而是花在”怎么组合”上。
检查点问题
- 你的业务场景中,模型最大的三个不足是什么?属于”知识缺失”还是”行为不当”?
- 如果你的知识每天更新一次,你会选择微调还是 RAG?为什么?
- 一个”模型回答太啰嗦”的问题,应该用提示词工程还是微调来解决?
实操任务
拿出你当前或计划中的 AI 项目,用上面的决策树判断:
- 你目前用的什么方法?
- 按决策树应该用什么方法?
- 两者是否一致?如果不一致,差距在哪里?
第2章 微调理论篇
章节目标
- 准确理解微调的定义和边界
- 掌握全量微调与参数高效微调(LoRA/QLoRA)的原理和适用场景
- 知道什么样的数据才能用于微调
- 了解微调中的常见失败模式
2.1 什么是微调,什么不是微调
先澄清一个常见混淆:很多人把”给模型提供上下文”叫做微调,这不对。
不是微调:
- 在提示词里加了更多示例(那是 few-shot)
- 接入了知识库(那是 RAG)
- 在系统提示词里加了角色设定(那是 system prompt)
- 用了 CoT 让模型分步思考(那是推理策略)
是微调:
- 用你的数据对模型参数进行了更新
- 模型的权重(weights)发生了改变
- 下次推理时,不需要再提供那些训练数据,模型"记住"了
微调的本质:用一组标注好的数据(输入-输出对),通过反向传播算法,调整模型的参数,让模型在面对类似输入时,能产生你期望的输出。
打个比方:提示词是”考试时给参考材料”,微调是”考前上了培训课”。考试时给参考材料(提示词/RAG),你还要现查;上过培训课(微调),知识已经内化了,直接就能用。
微调能做什么
- 改变输出风格:让模型用法律文书风格写作
- 教会新任务:让模型学会从病历中提取特定字段
- 对齐业务规则:让模型在特定情况下给出特定判断
- 提升领域表现:让模型在医学问答上更准确
微调不能做什么
- 突破模型能力上限:7B 模型微调后不可能突然获得 GPT-4 级别的推理能力
- 灌入大量新知识:微调不适合注入大量事实性知识(那是 RAG 的活)
- 改变模型架构:微调只是调整参数,不会改变模型结构
要点
微调改变了模型的”行为”而不是”知识”。如果你的问题是”模型不知道某个事实”,用 RAG;如果你的问题是”模型知道但表现不对”,用微调。
2.2 全量微调 vs 参数高效微调(LoRA/QLoRA)
全量微调(Full Fine-tuning)
全量微调就是更新模型的所有参数。一个 7B 模型有 70 亿个参数,全量微调意味着这 70 亿个参数都可能被更新。
优点:
- 理论上效果最好,因为模型有最大的调整自由度
- 适合数据和算力都充足的场景
缺点:
- 显存需求巨大:不仅要存模型参数,还要存梯度、优化器状态。7B 模型全量微调可能需要 60-80GB 显存
- 训练时间长:参数越多,每一步计算量越大
- 灾难性遗忘风险高:模型可能”忘了”原来会的东西
参数高效微调(PEFT)
核心思想:不冻住所有参数,只更新其中一小部分。
LoRA(Low-Rank Adaptation)
LoRA 是目前最主流的微调方法。它的思路非常巧妙:
想象你有一个巨大的矩阵 W(比如 4096 x 4096),正常微调需要更新所有 1600 万个参数。LoRA 说:我不直接更新 W,我在 W 旁边挂两个小矩阵 A 和 B:
W' = W + B × A
其中:
A 的维度:4096 × r
B 的维度:r × 4096
r 是"秩"(rank),通常取 8、16、64
参数量对比(以 r=16 为例):
原始:4096 × 4096 = 16,777,216 个参数
LoRA:(4096 × 16) + (16 × 4096) = 131,072 个参数
减少比例:99.2%
这就是 LoRA 的精髓——用极少的参数撬动极大的模型。
QLoRA
QLoRA 在 LoRA 基础上更进一步:先把模型量化到 4 位(NF4),再在量化后的模型上做 LoRA。
这意味着:
- 原本需要 80GB 显存才能微调的 7B 模型
- QLoRA 模式下一张 24GB 的 4090 就能跑
显存估算对比(7B 模型):
┌───────────────┬───────────┬──────────────┐
│ 方法 │ 显存需求 │ 所需硬件 │
├───────────────┼───────────┼──────────────┤
│ 全量微调 FP16 │ ~60-80GB │ A100 80GB │
│ LoRA FP16 │ ~30-40GB │ A100 40GB │
│ QLoRA 4bit │ ~10-15GB │ RTX 4090 │
└───────────────┴───────────┴──────────────┘
要点
LoRA/QLoRA 不是”效果打折的微调”。大量实验表明,在数据质量足够的情况下,LoRA 的效果接近全量微调,但成本只有几分之一。对于大多数业务场景,QLoRA 是性价比最高的选择。
常见坑点
- LoRA 秩(rank)选太大:rank 越大不代表效果越好。rank=64 在大多数场景下已经足够,甚至 rank=16 就够了。过大的 rank 会增加过拟合风险。
- 忽视基础模型选择:LoRA 微调的效果上限取决于基础模型。在一个烂模型上做 LoRA,结果还是一个烂模型。
- 混淆 LoRA 权重和基础模型:部署时,你需要同时加载基础模型和 LoRA 适配器。丢了一个都不行。
2.3 微调数据的准备和质量要求
数据是微调成败的关键。不是参数,不是方法,不是硬件——是数据。
一条微调数据长什么样?以对话场景为例:
{
"messages": [
{"role": "system", "content": "你是一个专业的法律助手"},
{"role": "user", "content": "房东不退押金怎么办?"},
{"role": "assistant", "content": "根据《民法典》第五百八十七条..."}
]
}数据质量标准
| 维度 | 好数据 | 坏数据 |
|---|---|---|
| 准确性 | 回答事实正确,有依据 | 有事实错误或编造信息 |
| 一致性 | 同类问题回答风格统一 | 同类问题回答风格差异大 |
| 完整性 | 输入输出对完整,无缺失字段 | 只有输入没有输出,或格式残缺 |
| 多样性 | 覆盖各种场景和边界情况 | 大量重复的相似问题 |
| 清洁度 | 无乱码、无注入、无矛盾信息 | 包含 HTML 标签、系统指令残留 |
数据量需求
不同任务需要的数据量差异很大:
粗略参考(以 7B 模型、LoRA 为例):
┌────────────────────┬──────────┬───────────┐
│ 任务类型 │ 最低数据量 │ 推荐数据量 │
├────────────────────┼──────────┼───────────┤
│ 风格迁移(改语气) │ 200条 │ 500-1K │
│ 格式控制(结构化输出)│ 500条 │ 1K-3K │
│ 领域问答 │ 1000条 │ 3K-10K │
│ 复杂推理任务 │ 3000条 │ 10K+ │
└────────────────────┴──────────┴───────────┘
要点
100 条高质量数据的效果,远好于 10000 条低质量数据。数据标注的核心不是”多”,而是”准”。宁可花时间仔细标注 500 条,也不要批量生成 5000 条垃圾数据。
2.4 微调的坑:过拟合、灾难性遗忘、数据污染
微调翻车的概率比你想象的高。以下是三个最常见的失败模式:
过拟合(Overfitting)
模型”死记硬背”了训练数据,而不是学会了规律。表现为:
- 训练集上表现很好,测试集上表现很差
- 输入稍有变化,模型就不知道怎么回答了
过拟合的信号:
- 训练 loss 持续下降,验证 loss 开始上升 ← 最重要的信号
- 模型开始"复读"训练数据中的原话
- 对训练集之外的问题完全无法泛化
如何避免:
- 数据量要足够(经验法则:数据条数 > 10 × 模型可训练参数量的倒数)
- 使用验证集监控
- 设置合理的学习率和 epoch 数(通常 3-5 个 epoch)
- 使用 dropout、weight decay 等正则化手段
- 早停(Early Stopping):验证 loss 连续上升就停
灾难性遗忘(Catastrophic Forgetting)
微调后模型”忘了”原来会的东西。表现为:
- 在你的领域表现好了,通用能力变差了
- 模型变得只会回答某一类问题
如何避免:
- 在训练数据中混入通用数据(比例约 10-20%)
- 使用 LoRA 而非全量微调(LoRA 天然对遗忘有一定抵抗力)
- 控制学习率(不要太大)和训练步数(不要太多)
- 微调后用通用基准测试验证模型是否退化
数据污染(Data Contamination)
训练数据中包含了测试数据,导致评估结果虚高。
常见的数据污染场景:
- 从网上爬取的数据包含了标准测试集的题目和答案
- 人工标注时不自觉地"抄"了公开的评测题
- 数据集划分时没有去重,同一条数据同时出现在训练集和测试集
如何避免:
- 严格的数据集划分(训练/验证/测试 8:1:1)
- 对训练集和测试集做去重(不只是精确去重,还要做语义去重)
- 用模型从未见过的数据做最终评估
检查点问题
- LoRA 中 rank 参数的作用是什么?rank 选得太大或太小分别会有什么问题?
- 你的数据只有 100 条,应该选择全量微调还是 LoRA?为什么?
- 如果你发现微调后的模型在你的任务上表现很好,但通用能力明显下降了,这是什么问题?怎么解决?
实操任务
找一份你业务场景中的真实数据(比如客服对话记录、产品描述、技术文档),尝试按照上面的格式构建 50 条微调数据。重点关注:
- 数据是否准确?
- 格式是否一致?
- 是否覆盖了不同的场景类型?
第3章 微调实践篇
章节目标
- 掌握本地化模型部署的基础操作
- 能独立估算硬件需求
- 完成一个小模型的微调实战
- 掌握微调效果评估的基本方法
3.1 本地化模型部署基础
在微调之前,你先要能把模型跑起来。本地化部署是 AI 工程师的基本功。
Ollama:最简单的本地模型方案
Ollama 是目前最方便的本地模型运行工具。它封装了模型下载、量化、推理的全部流程,一条命令就能跑起一个模型。
# 安装 ollama(macOS/Linux)
curl -fsSL https://ollama.com/install.sh | sh
# 运行一个模型(自动下载)
ollama run qwen2.5:7b
# 查看已下载的模型
ollama list
# 查看模型详细信息
ollama show qwen2.5:7b量化:让大模型变小
量化是降低模型精度以减少内存占用的技术。通俗地说,就是用更少的位数来存储每个参数。
精度对比(以 7B 模型为例):
┌──────────┬──────────┬───────────┬────────────┐
│ 精度 │ 每参数位数 │ 模型大小 │ 效果损失 │
├──────────┼──────────┼───────────┼────────────┤
│ FP16 │ 16 bit │ ~14 GB │ 无损 │
│ Q8 │ 8 bit │ ~7 GB │ 极小 │
│ Q5 │ 5 bit │ ~5 GB │ 小 │
│ Q4 │ 4 bit │ ~3.5 GB │ 可接受 │
│ Q2 │ 2 bit │ ~2 GB │ 明显下降 │
└──────────┴──────────┴───────────┴────────────┘
关键认知:Q4 几乎是一个极限选择。低于 Q4,模型质量会明显下降;Q4 和 FP16 的差距在大多数场景下可以接受。这也是为什么后续的硬件估算公式都基于 Q4 量化。
要点
Ollama 不是唯一选择,但它是”上手最快的”。生产环境可能会用 vLLM、TGI(Text Generation Inference)等更专业的推理框架。但学习阶段,Ollama 完全够用。
3.2 硬件需求估算:参数量与内存公式
这是很多初学者最头疼的问题:我需要什么样的显卡?能跑多大的模型?
给你一个实用的估算公式:
推理内存估算(Q4 量化)
模型内存(GB) ≈ 参数量(B) / 2
例如:
- 7B 模型: 7 / 2 ≈ 3.5 GB
- 13B 模型: 13 / 2 ≈ 6.5 GB
- 70B 模型: 70 / 2 ≈ 35 GB
但这只是模型本身占的内存。推理时还需要额外的内存来存储 KV Cache 和激活值。
KV Cache 估算
KV Cache 是 Transformer 模型在推理时存储”注意力缓存”的内存。文本越长,KV Cache 越大。
KV Cache 大小 ≈ 2 × 层数 × 隐藏维度 × 序列长度 × 精度字节数 / (1024^3)
简化估算(以 Llama2-7B 为例,FP16):
每个 token 的 KV Cache ≈ 0.00052 GB
处理 2000 token ≈ 额外 1 GB
不同场景的 KV Cache 需求:
┌──────────────────┬────────────┬─────────────┐
│ 场景 │ 序列长度 │ 额外 KV Cache │
├──────────────────┼────────────┼─────────────┤
│ 短对话(日常聊天) │ ~500 │ ~0.25 GB │
│ 中等文档(摘要) │ ~2000 │ ~1 GB │
│ 长文档(报告分析) │ ~8000 │ ~4 GB │
│ 超长文档(代码库) │ ~32000 │ ~16 GB │
└──────────────────┴────────────┴─────────────┘
完整内存估算公式
总内存需求 = 模型参数内存 + KV Cache + 系统开销
总内存(GB) ≈ 参数量(B)/2 + KV_Cache(GB) + 1~2GB(系统)
实战计算示例:
场景:用 Qwen2.5-7B-Q4 做客服对话(平均输入输出 2000 token)
模型参数: 7 / 2 = 3.5 GB
KV Cache: 2000 × 0.00052 = 1.04 GB
系统开销: ~1 GB
─────────────────────────────────
总计: ≈ 5.5 GB
所以一张 8GB 显存的卡就够推理了。
场景:用 Qwen2.5-72B-Q4 做长文档分析(8000 token)
模型参数: 72 / 2 = 36 GB
KV Cache: 8000 × 0.00052 × (72/7) ≈ 42.9 GB ← 注意大模型的 KV Cache 成比例放大
系统开销: ~2 GB
─────────────────────────────────
总计: ≈ 81 GB
需要两张 A100 80GB 或四张 A6000 48GB。
训练内存估算(QLoRA)
QLoRA 训练内存 ≈ 模型内存(Q4) × 2.5 ~ 3
实战计算示例:
场景:QLoRA 微调 7B 模型(rank=16)
模型加载(Q4): 3.5 GB
LoRA 参数: ~0.05 GB(非常小)
梯度 + 优化器状态: ~5 GB
激活值: ~2 GB
系统开销: ~1 GB
─────────────────────────────────
总计: ≈ 11-12 GB
一张 RTX 4090(24GB)可以轻松跑 QLoRA 微调 7B 模型。
场景:QLoRA 微调 13B 模型
模型加载(Q4): 6.5 GB
其他开销: ~10 GB
─────────────────────────────────
总计: ≈ 17-18 GB
RTX 4090(24GB)勉强够,建议用 A6000(48GB)。
硬件选型参考
| 预算 | 推荐硬件 | 能做的事 |
|---|---|---|
| 入门(< 1万) | RTX 4060 16GB / Mac M2 32GB | QLoRA 微调 3B 模型,推理 7B 模型 |
| 中端(1-3万) | RTX 4090 24GB | QLoRA 微调 7B 模型,推理 13B 模型 |
| 专业(5-10万) | A6000 48GB / 2×RTX 4090 | QLoRA 微调 13B 模型,推理 70B 模型 |
| 企业(> 10万) | A100 80GB × 2-4 | 全量微调 7B,QLoRA 微调 70B |
要点
以上估算是近似值,实际需求会因为模型架构、框架实现、批处理大小等因素有所不同。建议按估算值的 1.2-1.5 倍准备余量。如果你的序列很长(> 4K token),KV Cache 可能成为内存瓶颈,这时要特别关注。
3.3 实战:微调一个小模型
现在我们来实际动手。目标:用 QLoRA 微调一个 1.5B 模型,让它学会用特定风格回答问题。
这个实战选择 1.5B 模型是因为它足够小,大部分电脑都能跑,适合学习流程。
步骤 1:环境准备
# 创建 Python 虚拟环境
python -m venv finetune-env
source finetune-env/bin/activate
# 安装依赖
pip install torch transformers peft trl datasets accelerate bitsandbytes
# 验证 CUDA 是否可用(NVIDIA GPU)
python -c "import torch; print(torch.cuda.is_available())"
# 如果输出 True,说明 GPU 可用步骤 2:准备训练数据
创建一个 JSONL 文件 train_data.jsonl:
{"messages": [{"role": "system", "content": "你是一个简洁的技术顾问,回答不超过50字。"}, {"role": "user", "content": "什么是微调?"}, {"role": "assistant", "content": "微调是用特定数据调整预训练模型参数,让模型适应特定任务或领域。"}]}
{"messages": [{"role": "system", "content": "你是一个简洁的技术顾问,回答不超过50字。"}, {"role": "user", "content": "什么是 RAG?"}, {"role": "assistant", "content": "RAG 是检索增强生成,先从知识库检索相关内容,再让模型基于检索结果回答。"}]}
{"messages": [{"role": "system", "content": "你是一个简洁的技术顾问,回答不超过50字。"}, {"role": "user", "content": "LoRA 是什么?"}, {"role": "assistant", "content": "LoRA 是低秩适应方法,只训练少量参数就能高效微调大模型,大幅降低算力需求。"}]}实际项目中你需要几百到几千条这样的数据。这里只展示格式。
步骤 3:微调代码
import torch
from datasets import Dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
)
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer
# 1. 加载 tokenizer
model_name = "Qwen/Qwen2.5-1.5B"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
# 2. QLoRA 量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
# 3. 加载模型(4bit 量化)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
# 4. LoRA 配置
lora_config = LoraConfig(
r=16, # 秩
lora_alpha=32, # 缩放因子(通常是 r 的 2 倍)
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], # 要微调的层
lora_dropout=0.05, # dropout 防过拟合
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出类似:trainable params: 8,388,608 || all params: 1,500,000,000 || trainable%: 0.56%
# 5. 加载数据
from datasets import load_dataset
dataset = load_dataset("json", data_files="train_data.jsonl", split="train")
# 6. 训练参数
training_args = TrainingArguments(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=4, # 等效 batch_size = 2 × 4 = 8
learning_rate=2e-4,
logging_steps=10,
save_steps=100,
eval_strategy="no", # 有验证集时改为 "steps"
fp16=False,
bf16=True, # A100/4090 支持 bf16
optim="paged_adamw_8bit", # 8bit 优化器省显存
)
# 7. 开始训练
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset,
processing_class=tokenizer,
max_seq_length=512,
)
trainer.train()
# 8. 保存 LoRA 权重
trainer.model.save_pretrained("./my-lora-adapter")
tokenizer.save_pretrained("./my-lora-adapter")步骤 4:测试微调效果
from peft import PeftModel
# 加载基础模型
base_model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
)
# 加载 LoRA 适配器
model = PeftModel.from_pretrained(base_model, "./my-lora-adapter")
# 测试
input_text = "什么是向量数据库?"
inputs = tokenizer(input_text, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=100)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))要点
这个示例用 1.5B 模型是为了让所有人都能跑通。实际项目中,7B-13B 是比较常用的微调起点。流程完全一样,只是模型名和硬件需求不同。关键参数:学习率 2e-4 是 QLoRA 的常用起点;rank=16 对大多数任务够用;3 个 epoch 是安全的初始选择。
常见坑点
- OOM(显存不足):减小 batch_size 或增大 gradient_accumulation_steps。两者乘积不变,效果基本一致。
- Loss 不下降:检查学习率(太大会震荡,太小则不动)、数据格式(是否正确)、模型是否真的在训练(
print_trainable_parameters()确认有可训练参数)。 - 效果反而变差:可能是过拟合或数据质量差。检查数据,减少 epoch 数,降低学习率。
3.4 微调效果评估方法
微调完了怎么知道效果好不好?这不是看一眼就行的,需要系统评估。
评估维度
| 维度 | 评估什么 | 怎么评 |
|---|---|---|
| 准确性 | 回答是否正确 | 人工标注的测试集 + 自动化指标 |
| 风格一致性 | 输出风格是否符合预期 | 人工抽检 + 规则检查 |
| 通用能力 | 微调后是否退化 | 通用基准测试(MMLU 等) |
| 边界情况 | 极端输入的表现 | 专门设计的 edge case 测试集 |
| 推理速度 | 延迟和吞吐量 | 压力测试 |
自动评估指标
# 对于生成任务,常用的自动评估方法
# 1. BLEU 分数(适合有参考答案的任务)
from nltk.translate.bleu_score import sentence_bleu
reference = [["微调", "是", "用", "数据", "调整", "模型"]]
candidate = ["微调", "就是", "用", "数据", "修改", "模型"]
bleu_score = sentence_bleu(reference, candidate)
# 2. ROUGE 分数(适合摘要任务)
# 需要安装 rouge-score 库
# 3. 使用 LLM-as-Judge(适合开放式问答)
judge_prompt = """
请评估以下回答的质量,从1-5分打分:
问题:{question}
参考答案:{reference}
模型回答:{prediction}
评分标准:1=完全错误 2=部分正确 3=基本正确 4=很好 5=完美
只输出分数。
"""LLM-as-Judge 评估流程
这是目前业界最常用的评估方法之一:
- 准备 100-200 条测试数据(输入 + 标准答案)
- 用微调后的模型生成回答
- 用一个更强的模型(如 GPT-4)作为评委,按预设标准打分
- 统计各分数段的分布
评估结果示例:
┌───────┬───────┬───────────────────────┐
│ 分数 │ 数量 │ 占比 │
├───────┼───────┼───────────────────────┤
│ 5分 │ 45 │ 22.5% 完美 │
│ 4分 │ 89 │ 44.5% 很好 │
│ 3分 │ 38 │ 19.0% 基本正确 │
│ 2分 │ 20 │ 10.0% 部分正确 │
│ 1分 │ 8 │ 4.0% 完全错误 │
└───────┴───────┴───────────────────────┘
4分以上占比:67%(还行,但需要优化)
要点
自动指标只能作为参考。最终效果必须通过人工评估来确认。一个好的评估流程是:自动评估筛选 → 人工抽检确认 → A/B 测试上线验证。
检查点问题
- 你有一张 RTX 4090(24GB),想 QLoRA 微调 7B 模型,处理平均 4000 token 的输入,请估算是否可行。
- 微调后发现训练 loss 在持续下降但验证 loss 在上升,你应该怎么做?
- 为什么 LLM-as-Judge 比 BLEU 更适合评估开放式问答?
实操任务
按第 3.3 节的步骤,用你自己的数据(可以是任何领域,哪怕只有 30-50 条)完成一次微调。记录以下信息:
- 使用了什么模型
- 数据量和数据质量
- 训练参数设置
- 微调前后的效果对比
第4章 数据工程具体作业
章节目标
- 理解 AI 项目中的数据工程与传统数据工程的本质区别
- 掌握数据验收的标准和方法
- 学会与业务专家协作收集高质量数据
- 理解为什么数据是 AI 项目最大的壁垒
4.1 AI 项目的数据工程不是传统数据工程
如果你做过传统的数据工程——ETL 管道、数据仓库、BI 报表——你需要先把那些习惯放一放。AI 项目的数据工程完全不是一回事。
传统数据工程 vs AI 数据工程
┌──────────────┬─────────────────────┬─────────────────────┐
│ │ 传统数据工程 │ AI 数据工程 │
├──────────────┼─────────────────────┼─────────────────────┤
│ 核心目标 │ 数据准确、及时、完整 │ 数据能教会模型正确行为 │
│ 数据格式 │ 结构化(表)为主 │ 非结构化(文本/对话) │
│ 质量标准 │ 精确到字段级别 │ 语义级别,需要人判断 │
│ 更新频率 │ 按计划批量更新 │ 随时发现随时更新 │
│ 工具链 │ SQL、Spark、Airflow │ 标注工具、LLM 辅助、 │
│ │ │ 人工审核 │
│ 最大挑战 │ 数据量大、管道稳定 │ 数据质量、标注一致性 │
└──────────────┴─────────────────────┴─────────────────────┘
AI 数据工程的核心工作:
- 定义”好”的标准:什么样的回答算”好”?这需要和业务方一起定义
- 收集和整理数据:从各处收集原始数据,清洗、标注、格式化
- 质量把关:每条数据都要人看过,确保准确和一致
- 持续维护:业务在变,数据也要跟着变
要点
AI 项目中,数据工程的投入通常占总投入的 40-60%。模型选择和调参反而是小头。很多团队失败不是因为模型不行,而是数据没做好。
4.2 数据验收:怎么判断数据”够好”
数据验收是 AI 数据工程中最重要也最容易被忽视的环节。
验收的四个维度
维度一:准确性
每条数据的”正确答案”是否真的正确?
检查方法:
- 抽检:随机抽取 5-10% 的数据,逐条人工核实
- 交叉验证:同一问题,两个标注者独立标注,计算一致性
- 自动检查:用规则引擎检查格式和基本逻辑
示例问题:
❌ "退换货期限是30天" → 实际政策已改为15天
❌ "我们支持所有银行的信用卡" → 实际只支持6家银行
✓ "退换货期限为15天,自签收之日起算"
维度二:一致性
不同数据之间是否存在矛盾?标注风格是否统一?
检查方法:
- 格式检查:所有数据是否遵循统一的 JSON schema
- 风格检查:回答的语气、长度、详细程度是否一致
- 矛盾检测:同一类问题是否给出了不同的答案
示例问题:
数据 A:"抱歉,该商品不支持退换"
数据 B:"您可以在15天内申请退换" ← 矛盾!是所有商品都不支持,还是部分?
维度三:覆盖度
数据是否覆盖了所有重要场景?
检查方法:
- 场景分类:先列出所有业务场景,然后检查每个场景的数据量
- 长尾分析:是否有足够的边缘情况数据
- 对比真实分布:数据集的分布是否反映了真实用户提问的分布
示例覆盖度矩阵:
┌──────────────┬──────────┬──────────┬──────────┐
│ 场景 │ 真实占比 │ 数据占比 │ 状态 │
├──────────────┼──────────┼──────────┼──────────┤
│ 退换货咨询 │ 35% │ 40% │ ✓ 充足 │
│ 物流查询 │ 25% │ 30% │ ✓ 充足 │
│ 商品推荐 │ 20% │ 15% │ △ 偏少 │
│ 投诉处理 │ 10% │ 3% │ ✗ 不足 │
│ 售后维修 │ 10% │ 12% │ ✓ 充足 │
└──────────────┴──────────┴──────────┴──────────┘
维度四:清洁度
数据中是否存在”脏”内容?
常见脏数据:
- HTML 标签残留:"<p>退换货</p>政策是..."
- 系统指令泄露:"作为一个AI助手,我建议..."
- 无意义字符:"asdfgh12345"
- 截断的回答:"退换货政策是......"(被截断了)
- 编造的事实:"根据《消费者权益保护法》第999条..."(没有第999条)
要点
数据验收不是一次性工作,而是持续过程。每次模型效果有异常,第一反应应该是检查数据而不是调参数。
4.3 数据收集:与各专业人员协作的技巧
AI 项目中的数据往往分散在不同的人手里:客服团队有对话记录、产品经理有业务规则、技术团队有系统文档、法务有合规要求。你的工作是把它们收齐、对齐、变成可用的训练数据。
协作收集的实操方法
第一步:建立数据地图
在收集之前,先搞清楚”数据在哪、谁有、什么格式”:
数据地图模板:
┌─────────────┬──────────┬──────────┬──────────┬──────────┐
│ 数据类型 │ 负责人 │ 存储位置 │ 当前格式 │ 获取难度 │
├─────────────┼──────────┼──────────┼──────────┼──────────┤
│ 客服对话 │ 客服主管 │ 工单系统 │ 纯文本 │ 中 │
│ 产品FAQ │ 产品经理 │ 飞书文档 │ Markdown │ 低 │
│ 退换货政策 │ 运营经理 │ 内部Wiki │ HTML │ 低 │
│ 用户反馈 │ 社区运营 │ 数据库 │ JSON │ 高 │
│ 法务合规条款 │ 法务顾问 │ 合同文件 │ PDF │ 高 │
└─────────────┴──────────┴──────────┴──────────┴──────────┘
第二步:制定标注规范
标注规范是数据质量的基础。一个好的标注规范应该包括:
- 任务定义:明确每条数据的输入是什么、期望输出是什么
- 标注示例:至少给 5 个正例和 5 个反例
- 边界情况处理:遇到模糊情况怎么处理
- 质量标准:什么算”合格”,什么算”不合格”
- 一致性要求:不同标注者之间的差异容忍度
第三步:标注协作流程
推荐流程:
1. 你先标 20 条样例,验证规范是否清晰
2. 找 2 个标注者,每人标 20 条相同的(交叉标注)
3. 计算一致性(Cohen's Kappa > 0.8 为合格)
4. 如果一致性不够,回去修改规范
5. 规范确认后,批量标注
6. 你负责最终审核
与业务专家沟通的技巧
- 不要说”给我一些数据”,要说”给我 20 个最常见的用户问题和正确回答”
- 不要让业务专家理解”训练数据”的概念,用他们熟悉的语言:“把你们日常怎么回答客户问题的记录给我看看”
- 永远先给示例,再让对方跟着做。示例比说明文档有效 10 倍
- 标注工作要融入他们的日常工作流,而不是额外加任务
4.4 数据壁垒:为什么数据比模型更值钱
这是一个行业共识,但很多人不理解为什么。
模型在趋同,数据在分化
2024-2026 年的趋势非常明显:
模型层(在上移):
- 开源模型能力快速追赶闭源模型
- Llama、Qwen、DeepSeek 等开源模型已经非常强
- 模型之间的差距在缩小
- 模型越来越"日用品化"
数据层(在分化):
- 每个企业的数据都是独特的
- 竞品无法复制你的用户对话数据
- 行业专有知识无法从公开渠道获取
- 数据质量决定了模型在你的场景中的表现上限
一个思维实验
假设两个团队用同样的模型做客服系统:
- 团队 A:用 100 条 GPT 生成的模拟数据训练
- 团队 B:用 1000 条真实客服对话(经过人工标注)训练
谁的效果好?毫无疑问是团队 B。因为团队 B 的数据包含了真实的用户表达方式、真实的业务场景、真实的边缘情况——这些是 GPT 生成不出来的。
数据壁垒的三个层次
- 数据获取壁垒:有些数据天然只能你获取(用户行为数据、交易数据、内部知识)
- 数据标注壁垒:即使有原始数据,标注成高质量训练数据需要领域专业知识
- 数据迭代壁垒:上线后持续收集用户反馈、不断优化数据——这是一个飞轮
数据飞轮:
好数据 → 好模型 → 好体验 → 更多用户 → 更多反馈数据 → 更好的数据
↑ │
└─────────────────────────────────────────────────────────┘
要点
如果你的团队在争论”用哪个模型”,你更应该关注的是”数据准备好了没有”。模型可以换,数据换不了。一个数据做得好的团队,用中等模型也能跑赢用顶级模型但数据做得差的团队。
常见坑点
- “数据越多越好”:1000 条高质量数据 > 10000 条未清洗的原始数据。质量永远优先于数量。
- “用 GPT 生成训练数据”:可以用于补充,但不能作为主力。GPT 生成的数据缺乏真实用户的表达多样性和错误模式。
- “数据做好了就不用管了”:业务在变,数据必须跟着变。至少每月review一次数据是否还”新鲜”。
检查点问题
- 如果你要做一个法律咨询 AI,你会从哪里获取训练数据?列出你的数据地图。
- 你的标注团队标注一致性只有 0.6(Cohen’s Kappa),你应该怎么做?
- 为什么说”数据飞轮”比”选对模型”更重要?
实操任务
选择你熟悉的一个领域,按照 4.3 节的方法:
- 画一张数据地图(列出所有可能的数据来源)
- 制定一份标注规范(包含 5 个正例和 3 个反例)
- 试标注 20 条数据,检验规范的清晰度
第5章 模型测评
章节目标
- 理解模型测评的真正目的(不只是”跑个分数”)
- 掌握行业 AI 应用的评测方法
- 学会准备高质量的测试数据集
- 掌握竞品调研的系统方法论
5.1 模型测评不只是”跑个分数”
很多人对模型测评的理解停留在”跑个 MMLU 分数”或者”试试看回答好不好”。这在生产环境中远远不够。
模型测评的三个层次
第一层:基准测试(Benchmark)
- 跑公开测试集(MMLU、HumanEval、C-Eval 等)
- 得到一个数字(如 MMLU 72.5%)
- 用途:模型选型时的初步筛选
- 限制:和你的业务几乎没有关系
第二层:领域评测(Domain Evaluation)
- 在你的业务数据上测试
- 评估模型在你的场景中的表现
- 用途:确认模型是否能满足业务需求
- 限制:需要自己准备测试数据
第三层:系统评测(System Evaluation)
- 评估整个 AI 系统的表现(不只是模型)
- 包括延迟、成本、用户满意度、错误率等
- 用途:上线前的最终确认和持续监控
- 这是生产级评测
要点
大多数团队只做了第一层就上线了,然后在生产环境中暴露各种问题。真正的生产级评测必须做到第二层和第三层。
5.2 行业AI应用评测标准
不同行业的 AI 应用有不同的评测重点。以下是几个常见行业的评测框架:
客服 AI 评测标准
┌──────────────┬──────────┬──────────────────────────┐
│ 指标 │ 权重 │ 说明 │
├──────────────┼──────────┼──────────────────────────┤
│ 意图识别准确率 │ 25% │ 是否正确理解用户意图 │
│ 回答准确率 │ 30% │ 给出的信息是否正确 │
│ 完整性 │ 15% │ 是否完整回答了用户的问题 │
│ 转人工率 │ 15% │ 多少比例需要转人工处理 │
│ 用户满意度 │ 10% │ 用户评分或反馈 │
│ 响应时间 │ 5% │ 首次响应时间 │
└──────────────┴──────────┴──────────────────────────┘
内容生成 AI 评测标准
┌──────────────┬──────────┬──────────────────────────┐
│ 指标 │ 权重 │ 说明 │
├──────────────┼──────────┼──────────────────────────┤
│ 事实准确性 │ 30% │ 内容中的事实是否正确 │
│ 风格一致性 │ 20% │ 是否符合要求的写作风格 │
│ 可读性 │ 15% │ 通顺程度、逻辑连贯性 │
│ 原创性 │ 15% │ 是否有抄袭或过度模仿 │
│ 品牌契合度 │ 10% │ 是否符合品牌调性 │
│ 合规性 │ 10% │ 是否包含敏感/违规内容 │
└──────────────┴──────────┴──────────────────────────┘
评测的实施流程
1. 确定评测指标和权重(和业务方一起定)
2. 准备测试数据集(下一节详述)
3. 运行评测(自动化 + 人工)
4. 分析结果(不只看总分,要看分布和个案)
5. 形成报告和改进建议
5.3 测试数据集准备
测试数据集的质量直接决定了评测的可信度。
测试数据集的构建原则
- 与训练数据严格隔离:测试数据绝对不能出现在训练数据中
- 代表真实分布:测试集的分布应该反映真实用户的使用模式
- 覆盖边界情况:故意包含一些”刁钻”的测试用例
- 有人工标注的参考答案:每条测试数据都有标准答案或评分标准
数据集规模建议
┌──────────────────┬──────────────┬───────────────┐
│ 应用类型 │ 最小测试集 │ 推荐测试集 │
├──────────────────┼──────────────┼───────────────┤
│ 简单分类/判断 │ 50 条 │ 200-500 条 │
│ 问答/对话 │ 100 条 │ 500-1000 条 │
│ 内容生成 │ 50 条 │ 200-500 条 │
│ 多轮对话 │ 50 组 │ 200-500 组 │
└──────────────────┴──────────────┴───────────────┘
测试数据的分类
测试集应该包含以下类型的数据:
1. 常规用例(60%):最常见的用户输入,预期模型应该能处理好
2. 边界用例(20%):不太常见但合法的输入,考验模型的泛化能力
3. 对抗用例(10%):故意设计的"刁钻"输入,测试模型的鲁棒性
- 拼写错误的输入
- 模棱两可的问题
- 包含错误前提的问题
- 超出范围的请求
4. 安全用例(10%):测试模型是否会输出有害/违规内容
- 敏感话题
- 隐私信息请求
- 恶意指令注入
要点
测试数据集是项目最重要的资产之一。它不仅用于上线前评测,还用于每次模型更新后的回归测试。投入时间构建一个好的测试集,收益是长期持续的。
5.4 竞品调研的方法论
竞品调研不是”玩一玩对方的产品”,而是一个系统化的分析过程。
调研框架
第一步:明确调研目标
- 不是"看看竞品怎么样"
- 而是"我们和竞品在 X 维度上的差距有多大"
第二步:选择竞品
- 直接竞品:做同样事情的(如同样是法律 AI)
- 间接竞品:做类似事情的(如通用 AI 助手在法律场景的表现)
- 参考竞品:行业标杆(如 ChatGPT 在该场景的表现)
第三步:设计评测方案
- 用同一套测试数据评测所有竞品
- 统一评分标准
- 每个竞品至少跑 2 遍,取平均
第四步:分析差距
- 定量分析:分数差距、响应时间、成本对比
- 定性分析:具体案例对比、错误类型分析
- 归因分析:差距来自模型、数据、还是工程实现
竞品对比矩阵模板
┌──────────────┬────────┬────────┬────────┬────────┐
│ 评测维度 │ 我们 │ 竞品A │ 竞品B │ GPT-4 │
├──────────────┼────────┼────────┼────────┼────────┤
│ 准确率 │ 78% │ 85% │ 72% │ 91% │
│ 响应时间 │ 1.2s │ 0.8s │ 2.1s │ 1.5s │
│ 用户体验 │ ★★★ │ ★★★★ │ ★★ │ ★★★★ │
│ 功能完整度 │ 70% │ 90% │ 60% │ 95% │
│ 单次调用成本 │ ¥0.01 │ ¥0.03 │ ¥0.005 │ ¥0.10 │
└──────────────┴────────┴────────┴────────┴────────┘
常见坑点
- 只用公开 benchmark 对比:公开 benchmark 和你的业务场景可能完全不相关。
- 评测数据不一致:不同竞品用不同的测试数据,结果不可比。
- 忽视非功能性指标:只看准确率,不看延迟、成本、稳定性。
- 一次调研就完事:竞品在快速迭代,调研应该定期进行(至少每季度一次)。
检查点问题
- 你的 AI 项目应该用哪些评测指标?权重怎么设?
- 为什么测试数据集必须和训练数据严格隔离?如果不隔离会怎样?
- 你要做一个竞品调研,应该用同一套测试数据还是各自准备测试数据?为什么?
实操任务
选择一个你熟悉的 AI 产品(可以是公开的,如 ChatGPT、文心一言、Kimi),按照 5.4 节的框架:
- 设计 20 条测试数据(包含常规用例和边界用例)
- 统一评测标准和评分维度
- 至少评测 2 个竞品产品
- 输出对比矩阵和分析结论
第6章 向量库选型与数据管道
章节目标
- 理解向量库在 AI 系统中的角色
- 掌握主流向量库的对比和选型方法
- 学会设计从原始数据到向量索引的完整数据管道
- 掌握数据更新和增量索引的策略
6.1 向量库的作用和常见选择
在 RAG 系统中(你在课程2中学过),向量库是基础设施。它的作用很简单但很关键:存储文本的向量表示,并在查询时快速找到最相关的文本片段。
RAG 流程中的向量库位置:
用户提问
│
▼
Embedding 模型(把问题变成向量)
│
▼
向量库(找最相似的文档片段) ←── 这就是向量库的位置
│
▼
检索到的文档片段 + 用户问题
│
▼
LLM(生成最终回答)
常见向量库
目前市面上主流的向量库有以下几种:
Milvus
- 开源、分布式架构
- 支持亿级向量检索
- 社区活跃,文档完善
- 适合大规模生产环境
Pinecone
- 全托管 SaaS 服务
- 零运维,API 简洁
- 按使用量计费
- 适合快速启动、不想管基础设施的团队
Weaviate
- 开源、支持混合搜索(向量 + 关键词)
- 内置多种向量化和 reranking 模块
- GraphQL API
- 适合需要复杂查询语义的场景
Chroma
- 开源、轻量级
- Python 原生,API 极简
- 适合原型验证和小规模应用
- 不适合大规模生产
pgvector(PostgreSQL 扩展)
- 基于已有的 PostgreSQL
- 向量检索能力 + SQL 的灵活性
- 适合已有 PG 基础设施的团队
- 性能不如专业向量库
6.2 向量库性能对比和选型建议
向量库对比矩阵:
┌──────────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ │ Milvus │ Pinecone │ Weaviate │ Chroma │ pgvector │
├──────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 开源 │ ✓ │ ✗ │ ✓ │ ✓ │ ✓ │
│ 托管服务 │ Zilliz │ 自身 │ ✓ │ ✗ │ ✓ │
│ 最大规模 │ 10亿+ │ 10亿+ │ 亿级 │ 百万级 │ 千万级 │
│ 混合搜索 │ ✓ │ ✓ │ ✓ │ ✗ │ ✓ │
│ 实时更新 │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │
│ 部署复杂度 │ 高 │ 低 │ 中 │ 低 │ 低 │
│ 学习曲线 │ 陡 │ 平 │ 中 │ 平 │ 平 │
│ 适合阶段 │ 生产 │ 快速启动 │ 生产 │ 原型 │ 中小规模 │
│ 社区活跃度 │ 高 │ 高 │ 中高 │ 中 │ 高 │
│ 成本模型 │ 自管成本 │ API计费 │ 自管成本 │ 免费 │ 自管成本 │
└──────────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
选型决策流程
开始
│
▼
是否已有 PostgreSQL 基础设施且数据量 < 1000万?
│
├─ 是 ──→ pgvector(最省事)
│
└─ 否 ──→ 是否愿意/能够自行管理基础设施?
│
├─ 否 ──→ Pinecone(全托管)
│
└─ 是 ──→ 数据规模预期?
│
├─ < 100万,原型阶段 ──→ Chroma
│
├─ 100万-1亿 ──→ Weaviate
│
└─ > 1亿 ──→ Milvus
要点
向量库选型的核心考量不是”哪个最好”,而是”哪个最适合你的阶段”。原型阶段用 Chroma,快速验证产品逻辑;验证通过后切换到 Milvus 或 Weaviate 支撑生产。不要在原型阶段就在基础设施上花太多时间。
6.3 数据管道设计:从原始数据到向量索引
向量库只是存储,数据才是灵魂。从原始数据到可检索的向量索引,需要一整套数据管道。
完整的管道流程
原始数据
│
▼
┌──────────────┐
│ 1. 数据获取 │ 从各种来源收集原始数据
└──────┬───────┘
│
▼
┌──────────────┐
│ 2. 数据清洗 │ 去噪、去重、格式化
└──────┬───────┘
│
▼
┌──────────────┐
│ 3. 文本切分 │ 把长文档切成合适大小的片段
└──────┬───────┘
│
▼
┌──────────────┐
│ 4. 向量化 │ 用 Embedding 模型将文本转为向量
└──────┬───────┘
│
▼
┌──────────────┐
│ 5. 存储索引 │ 将向量和元数据存入向量库
└──────┬───────┘
│
▼
可检索的向量索引
关键步骤详解
文本切分(Chunking)
这是最影响 RAG 效果的步骤之一。切得太长,检索不够精确;切得太短,丢失上下文。
常见的切分策略:
1. 固定长度切分(最简单)
- 每段 500-1000 字符,重叠 50-100 字符
- 适合:格式规整的文档
- 问题:可能在句子中间切断
2. 按段落/标题切分(推荐)
- 按自然段落或标题层级切分
- 适合:结构化文档
- 优点:保留语义完整性
3. 语义切分(高级)
- 用 Embedding 相似度找到语义边界
- 适合:对检索质量要求高的场景
- 缺点:处理速度慢
推荐配置:
- chunk_size: 512 tokens(约 350-700 个汉字)
- chunk_overlap: 50 tokens
- 按段落优先切分,段落超长时按固定长度二次切分
Embedding 模型选择
常用 Embedding 模型:
┌─────────────────────┬──────────┬───────────┬──────────────┐
│ 模型 │ 维度 │ 多语言 │ 特点 │
├─────────────────────┼──────────┼───────────┼──────────────┤
│ text-embedding-3-large│ 3072 │ ✓ │ OpenAI,效果好 │
│ text-embedding-3-small│ 1536 │ ✓ │ OpenAI,性价比 │
│ bge-large-zh-v1.5 │ 1024 │ 中文优 │ 开源,中文效果好│
│ bge-m3 │ 1024 │ 多语言 │ 开源,多语言通用│
│ gte-Qwen2-1.5B-instruct│ 1536 │ 多语言 │ 开源,效果很强 │
└─────────────────────┴──────────┴───────────┴──────────────┘
元数据设计
每个向量不仅存储向量本身,还要存储元数据。好的元数据设计能大幅提升检索质量。
{
"id": "doc_123_chunk_5",
"vector": [0.023, -0.015, ...], // 向量
"metadata": {
"source": "产品手册_v3.pdf",
"chunk_index": 5,
"total_chunks": 23,
"section": "退换货政策",
"page_number": 12,
"doc_type": "policy",
"updated_at": "2026-03-15",
"tags": ["退货", "退款", "售后"]
},
"text": "退换货政策:自签收之日起15天内..."
}要点
数据管道的设计往往被低估,但它直接决定了 RAG 系统的效果。一个设计良好的管道(好的切分策略 + 合适的 Embedding 模型 + 完善的元数据)可以让同一个向量库的检索准确率提升 20-30%。
6.4 数据更新与增量索引
知识库不是静态的。业务文档在更新、新产品在上线、政策在变化。你的向量索引也必须跟着变。
更新策略
策略一:全量重建(适合数据量小的场景)
- 定期(如每天凌晨)删除所有索引,从头重建
- 优点:简单,不会出现不一致
- 缺点:数据量大时很慢
- 适合:< 10万条向量
策略二:增量更新(推荐)
- 只更新变化的数据
- 需要维护一个"变更日志"
- 流程:
1. 检测哪些文档有更新(对比 hash 或时间戳)
2. 删除这些文档对应的旧向量
3. 对更新后的文档重新切分、向量化
4. 插入新向量
策略三:双缓冲(适合高可用场景)
- 维护两套索引:索引 A(在线)和索引 B(后台)
- 更新时在索引 B 上操作
- 更新完成后,原子切换 A 和 B
- 优点:零停机
- 缺点:存储翻倍
增量更新的实现要点
# 伪代码:增量更新流程
def incremental_update(documents, vector_db):
for doc in documents:
# 检查文档是否有变化
if doc.hash == get_stored_hash(doc.id):
continue # 没变化,跳过
# 有变化,先删除旧的
vector_db.delete(filter={"source_id": doc.id})
# 重新处理
chunks = split_text(doc.content, chunk_size=512, overlap=50)
for i, chunk in enumerate(chunks):
vector = embedding_model.encode(chunk)
vector_db.insert(
id=f"{doc.id}_chunk_{i}",
vector=vector,
text=chunk,
metadata={
"source": doc.filename,
"updated_at": doc.updated_at,
"hash": doc.hash,
# ...其他元数据
}
)
# 更新 hash 记录
update_stored_hash(doc.id, doc.hash)常见坑点
- 忘记删除旧数据:更新文档时只插入新向量,不删除旧的。结果搜索时会出现过期信息和新信息混在一起。
- Embedding 模型更换时不全量重建:换了一个新的 Embedding 模型,但只对新数据用新模型,旧数据还是旧模型的向量。新旧向量不在同一个空间里,检索结果会变差。
- 不考虑文档间的引用关系:文档 A 引用了文档 B 的内容,更新文档 B 时,文档 A 中对应的向量也需要更新。
检查点问题
- 你的 RAG 系统,数据规模大约 50 万条向量,每周有 5% 的数据会更新,你会选哪种更新策略?
- 为什么要对文本进行切分而不是直接存整个文档?
- 如果你的 Embedding 模型从 bge-large-zh 换成了 text-embedding-3-large,你需要做什么?
实操任务
选择一个向量库(推荐从 Chroma 开始),搭建一个完整的数据管道:
- 准备 10 份文档(可以是任何内容)
- 实现文本切分和向量化
- 存入 Chroma 并验证检索效果
- 模拟一次数据更新,验证增量更新流程
第7章 综合实战:端到端的模型调优项目
章节目标
- 掌握端到端项目从需求到上线的完整流程
- 能独立做出”模型选择 → 数据准备 → 调优 → 测评”的全链路决策
- 有一份可复用的项目 checklist
7.1 需求分析与方案选择
场景设定
假设你是一个电商平台的 AI 工程师,业务方提出了一个需求:
“我们的智能客服现在用的是 GPT-4 + RAG,准确率 82%。但成本太高(每月 ¥15 万),而且有时候回复太慢(> 3 秒)。能不能优化一下?”
需求分析
第一步:拆解问题
├── 准确率 82% → 有 18% 的问题答不好,是什么类型的问题?
├── 成本 ¥15万/月 → 主要来自 GPT-4 API 调用费用
└── 延迟 > 3秒 → 可能来自 RAG 检索 + GPT-4 推理的总时间
第二步:数据驱动分析
- 分析 18% 的错误案例:是知识缺失还是行为不当?
- 分析成本构成:哪些类型的问题消耗了最多的 token?
- 分析延迟瓶颈:是检索慢还是生成慢?
第三步:假设验证
- 假设 A:"80% 的常见问题可以用小模型回答,只有 20% 需要大模型"
- 验证:统计用户提问的分布,看是否存在长尾效应
- 如果假设成立:可以用"小模型兜底 + 大模型兜底"的策略
方案选择
基于分析,制定方案:
方案 A:微调小模型替代 GPT-4 处理常见问题
成本:一次性微调成本 ~¥5000,推理成本 ~¥2000/月
预期准确率:85-90%(常见问题上)
延迟:< 1 秒
风险:对不常见问题处理不好
方案 B:优化 RAG 管道 + 换更便宜的模型
成本:~¥5000/月(用 GPT-4o-mini 替代 GPT-4)
预期准确率:80-85%
延迟:~2 秒
风险:准确率可能反而下降
方案 C:方案 A + B 组合
常见问题 → 微调小模型(快速、便宜、准确)
复杂问题 → RAG + 大模型(知识增强、兜底)
成本:~¥7000/月
预期准确率:90%+
延迟:常见 < 1 秒,复杂 < 3 秒
选择:方案 C(成本降低 95%,体验不降反升)
要点
方案选择的关键不是”哪个技术更先进”,而是”解决了什么业务问题”。用数据说话:成本降了多少?准确率提升了多少?用户体验改善了什么?
7.2 数据准备与清洗
方案确定了,下一步是准备数据。
数据来源梳理
┌─────────────────────┬──────────┬──────────┬──────────┐
│ 数据来源 │ 数量 │ 质量 │ 用途 │
├─────────────────────┼──────────┼──────────┼──────────┤
│ 历史客服对话记录 │ 50,000 │ 中(有噪音)│ 训练+测试 │
│ 产品 FAQ 文档 │ 500 │ 高 │ RAG 知识库│
│ 退换货政策文档 │ 50 │ 高 │ RAG 知识库│
│ 商品信息数据库 │ 100,000 │ 高 │ RAG 知识库│
│ 人工标注的优质对话 │ 2,000 │ 高 │ 微调训练 │
└─────────────────────┴──────────┴──────────┴──────────┘
数据清洗流程
原始客服对话(50,000 条)
│
├─ 去重(完全相同的对话)
│ → 剩余 42,000 条
│
├─ 去噪(系统消息、广告、无意义对话)
│ → 剩余 35,000 条
│
├─ 筛选(只保留有明确问答的对话)
│ → 剩余 18,000 条
│
├─ 分类(按问题类型分组)
│ → 退换货 5000 / 物流 4000 / 商品 3000 / 支付 2500 / 其他 3500
│
├─ 抽样标注(每类标注 400 条,共 2000 条高质量标注数据)
│ → 训练集 1600 条 / 测试集 400 条
│
└─ 格式化(转换为微调所需的 JSONL 格式)
数据质量检查
# 自动化质量检查脚本示例
import json
def check_data_quality(data_path):
issues = []
with open(data_path, 'r') as f:
for i, line in enumerate(f):
data = json.loads(line)
messages = data['messages']
# 检查1:必须有 system + user + assistant
roles = [m['role'] for m in messages]
if 'system' not in roles or 'user' not in roles or 'assistant' not in roles:
issues.append(f"Line {i}: missing required role")
# 检查2:回答不能太短或太长
assistant_msg = [m for m in messages if m['role'] == 'assistant'][0]
if len(assistant_msg['content']) < 10:
issues.append(f"Line {i}: response too short")
if len(assistant_msg['content']) > 2000:
issues.append(f"Line {i}: response too long")
# 检查3:不能包含 HTML 标签
if '<' in assistant_msg['content'] and '>' in assistant_msg['content']:
issues.append(f"Line {i}: possible HTML tags")
# 检查4:不能包含系统指令泄露
leak_patterns = ['作为一个AI', '作为人工智能', '我不能']
for pattern in leak_patterns:
if pattern in assistant_msg['content']:
issues.append(f"Line {i}: contains leak pattern '{pattern}'")
print(f"Total issues: {len(issues)}")
for issue in issues[:20]: # 只打印前20条
print(f" {issue}")
check_data_quality("train_data.jsonl")7.3 微调或RAG方案实施
根据方案 C,我们需要同时搭建微调模型和 RAG 系统。
微调实施
模型选择:Qwen2.5-7B(中文能力强,社区支持好)
微调方法:QLoRA(rank=16,节省显存)
训练数据:1600 条标注数据
硬件:单张 RTX 4090(24GB)
关键参数:
- learning_rate: 2e-4
- epochs: 3
- batch_size: 4(gradient_accumulation_steps=4)
- LoRA rank: 16
- LoRA alpha: 32
- target_modules: q_proj, k_proj, v_proj, o_proj
预期结果:
- 训练时间:约 1-2 小时
- 显存占用:约 12-15GB
- 模型推理延迟:< 500ms(在 4090 上)
RAG 实施
向量库:Milvus(数据量大,需要生产级方案)
Embedding 模型:bge-large-zh-v1.5(中文效果好)
知识库数据:FAQ 500条 + 政策文档 50条 + 商品信息 10万条
切分策略:
- FAQ:每条作为一个 chunk(天然短文本)
- 政策文档:按标题切分,chunk_size=512
- 商品信息:每个商品作为一个 chunk
检索策略:
- 先在 FAQ 库中精确匹配(关键词命中)
- 未命中则在全文库中向量检索(top-5)
- 检索结果经 reranker 排序后取 top-3
路由逻辑
用户提问
│
▼
意图分类器(基于关键词 + 小模型)
│
├─ 常见问题(80%流量)→ 微调模型直接回答
│ │
│ ├─ 置信度 > 0.85 → 直接返回
│ └─ 置信度 ≤ 0.85 → 转大模型
│
└─ 复杂问题(20%流量)→ RAG 检索 + 大模型生成
7.4 测评与迭代优化
测评方案
测试集:400 条标注数据 + 100 条边界用例 + 50 条安全用例
对比实验:
┌──────────────┬──────────┬──────────┬──────────┐
│ 方案 │ 准确率 │ 平均延迟 │ 单次成本 │
├──────────────┼──────────┼──────────┼──────────┤
│ GPT-4 + RAG │ 82% │ 3.2s │ ¥0.05 │
│ 微调小模型 │ 87% │ 0.4s │ ¥0.001 │
│ RAG + 大模型 │ 85% │ 2.1s │ ¥0.02 │
│ 方案C(组合) │ 91% │ 0.8s* │ ¥0.005* │
└──────────────┴──────────┴──────────┴──────────┘
* 加权平均值
结果分析:
- 准确率从 82% 提升到 91%(+9%)
- 延迟从 3.2s 降到 0.8s(-75%)
- 成本从 ¥0.05/次降到 ¥0.005/次(-90%)
- 月成本从 ¥15 万降到 ~¥7000(-95%)
迭代优化方向
发现问题:
- 复杂问题的准确率只有 78%,低于预期
- 安全用例中有 3 个被绕过
优化动作:
1. 复杂问题:补充 200 条复杂场景的训练数据
2. 安全用例:增加安全相关的 system prompt 约束
3. RAG 检索:优化 reranker 模型
4. 路由逻辑:调整意图分类器的阈值
第二轮测评:
- 复杂问题准确率:78% → 84%
- 安全用例通过率:94% → 99%
- 整体准确率:91% → 93%
项目完整 Checklist
以下是端到端模型调优项目的完整 checklist,可以在实际项目中直接使用。
项目阶段 Checklist
═══════════════════
□ 一、需求分析
□ 明确业务目标(准确率/延迟/成本的具体指标)
□ 分析现有系统的瓶颈(用数据说话,不是凭感觉)
□ 确定评测标准和测试数据来源
□ 获得业务方的认可和资源承诺
□ 二、方案设计
□ 根据决策树选择调优方法
□ 确定模型选型(至少对比 2-3 个候选模型)
□ 确定技术栈(微调框架、向量库、Embedding 模型)
□ 估算硬件需求(用内存公式计算)
□ 制定项目时间表和里程碑
□ 三、数据准备
□ 梳理数据地图(数据在哪、谁有、什么格式)
□ 制定标注规范(含正例和反例)
□ 数据清洗(去噪、去重、格式化)
□ 数据标注(交叉标注 + 一致性验证)
□ 数据集划分(训练/验证/测试 8:1:1,严格隔离)
□ 数据质量验收(准确性、一致性、覆盖度、清洁度)
□ 四、模型开发
□ 环境搭建(GPU、框架、依赖)
□ 基础模型验证(微调前先跑基线分数)
□ 微调训练(按第3章的流程)
□ 训练过程监控(loss 曲线、验证集表现)
□ LoRA 权重保存和版本管理
□ 五、RAG 系统搭建(如果需要)
□ 向量库选型和部署
□ Embedding 模型选型
□ 文本切分策略确定
□ 数据管道搭建(清洗→切分→向量化→存储)
□ 检索策略调优(top-k、reranker、混合搜索)
□ 六、系统集成
□ 路由逻辑设计(哪些走小模型,哪些走大模型)
□ API 接口开发
□ 日志和监控埋点
□ 异常处理和降级方案
□ 七、测评
□ 自动评测(准确率、延迟、吞吐量)
□ 人工评测(抽检 100+ 条)
□ 安全测试(对抗用例、注入测试)
□ 竞品对比(同一套测试数据)
□ 性能测试(压力测试、稳定性测试)
□ 八、上线
□ A/B 测试方案设计
□ 灰度发布(5% → 20% → 50% → 100%)
□ 线上监控看板搭建
□ 回滚方案准备
□ 知识交接文档
□ 九、持续优化
□ 建立用户反馈收集机制
□ 定期数据质量 review(至少月度)
□ 定期模型效果回归测试
□ 定期竞品调研(至少季度)
□ 数据飞轮运转确认
要点
Checklist 的价值不在于”全部打勾”,而在于”不遗漏关键步骤”。每个项目的具体执行细节会不同,但框架是一样的。把这份 checklist 存下来,下一个项目直接用。
检查点问题
- 如果你只有一周时间和有限预算,你会优先做 checklist 中的哪些步骤?
- 方案 C 的路由逻辑中,置信度阈值设为 0.85。这个值调高或调低分别有什么影响?
- 上线后发现准确率从测试环境的 93% 降到了 88%,你会从哪些方面排查原因?
实操任务
这是最终的实战任务。选择以下任一场景,按照本章的完整流程(7.1-7.4)做一个端到端的项目方案:
场景 A:一个在线教育平台的 AI 答疑助手
场景 B:一个医疗健康 APP 的症状预诊助手
场景 C:你当前工作中的真实 AI 项目
输出内容:
- 需求分析报告(包含数据驱动的现状分析)
- 方案设计文档(模型选型、技术栈、硬件估算)
- 数据准备计划(数据地图、标注规范、质量标准)
- 测评方案(评测指标、测试数据集、对比实验设计)
课程总结
恭喜你完成了这门课。回顾一下你学到了什么:
核心认知
- 模型调优不是一招鲜——提示词、RAG、微调、后训练各有适用场景,关键是根据问题类型选对方法
- 数据是最大的壁垒——模型在趋同,数据在分化。投入数据工程的回报远高于投入模型调参
- 测评贯穿始终——不是最后才做的事,而是从需求分析阶段就要开始设计
关键技能
- 方法选择决策树:根据问题类型快速判断该用什么方法
- 硬件估算公式:参数量(B)/2 ≈ 内存(GB),再加上 KV Cache 和系统开销
- 数据验收四维度:准确性、一致性、覆盖度、清洁度
- 向量库选型:根据阶段和规模选择,不要在原型阶段就追求生产级方案
- 项目 checklist:从需求到上线的完整流程,不遗漏关键步骤
下一步建议
- 如果你想继续深入微调:从第 3 章的实操开始,用自己的业务数据做一次完整的微调实验
- 如果你想深入数据工程:重新审视你当前项目的数据质量,用第 4 章的验收标准做一次全面 audit
- 如果你想深入 RAG:结合课程 2 的 RAG 知识和本章的向量库内容,搭建一个生产级的知识库系统
- 准备好进入课程 5:你已经掌握了技术核心,下一步是思考怎么用这些能力实现职业跃迁
记住:模型是通用的大脑,数据是独特的 DNA,调优是连接两者的桥梁。你的价值不在于会调用哪个 API,而在于能把这三者有机结合,解决真实的业务问题。