模型调优与数据工程:让AI真正懂你的业务


在开始之前

Hook

你有没有遇到过这种情况——花大力气搭了一套 RAG 系统,知识库也灌进去了,结果 AI 的回答还是”差点意思”?或者团队争论了一个月到底该微调还是该上 RAG,最后谁也说服不了谁?

更扎心的是:你们用的模型明明是市面上最强的,但放到你的业务场景里,效果就是比竞品差一截。问题出在哪?

问题出在”调优”和”数据”上。模型是通用大脑,但你的业务是特定领域。通用大脑不懂你的术语、不知道你的业务规则、没见过你的客户长什么样。你需要一套方法,让模型从”什么都懂一点”变成”你的业务专家”。

这就是这门课要讲的内容。

Promise

学完这门课,你将能够:

  • 理解模型调优的完整光谱,知道什么时候用提示词、什么时候用 RAG、什么时候必须微调
  • 掌握微调的核心原理(LoRA/QLoRA),理解背后的数学直觉而不只是调参
  • 自己估算硬件需求,知道什么样的卡能跑什么样的模型
  • 做好数据工程——包括数据验收、数据收集、数据质量把控
  • 设计和执行模型测评,不只会”跑个分数”,还能发现真问题
  • 做出向量库选型决策,搭建完整的数据管道
  • 从零到一完成一个端到端的模型调优项目

Roadmap

第1章 模型调优全景 ──── 建立完整认知框架,学会方法选择
    ↓
第2章 微调理论篇 ──── 搞懂原理,理解为什么而不只是怎么做
    ↓
第3章 微调实践篇 ──── 动手做,从部署到微调到评估
    ↓
第4章 数据工程 ──── 学会AI项目中最被低估的技能
    ↓
第5章 模型测评 ──── 用数据说话,而不是凭感觉
    ↓
第6章 向量库与数据管道 ──── RAG系统的基建能力
    ↓
第7章 综合实战 ──── 端到端完成一个完整项目

第1章 模型调优全景

章节目标

  • 理解为什么”直接用最强模型”不等于最好的业务效果
  • 掌握从提示词到后训练的完整方法光谱
  • 能根据业务场景做出正确的方法选择

1.1 为什么需要调优:预训练模型不是你的业务专家

预训练模型像一个读过整个互联网的”全科医生”——什么都知道一点,但在你的特定领域里,它比不上一个专注该领域十年的”专科医生”。

举几个实际的例子:

金融风控场景。你问模型”这个交易是否可疑”,模型可能给你一个泛泛的回答,因为它不理解你们银行特有的风控规则、黑名单模式、以及监管机构对你所在地区的特殊要求。这些信息不在训练数据里。

医疗问诊场景。模型知道教科书上的诊断流程,但它不知道你们医院特定的检验流程、不知道你的系统里患者能提供哪些检验报告、不知道哪些药在你们药房有库存。

客服场景。模型可以礼貌地回答用户问题,但它不知道你们当前的退换货政策(可能上周刚改过)、不知道特定 SKU 的库存状态、不知道你们的促销活动细节。

这些差距的本质是什么?三个缺乏

  1. 缺乏领域知识:模型没见过你的专业术语、业务规则、行业惯例
  2. 缺乏实时信息:模型的知识有截止日期,不知道昨天发生的事
  3. 缺乏行为规范:模型不知道在你这个场景下应该怎么回答、什么该说什么不该说、什么格式输出

调优的本质,就是弥补这三个缺乏。

要点

调优不是让模型变”聪明”,而是让模型变”懂你”。通用能力已经很强了,缺的是你的业务 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 提示词
  │
  └─ 否 ──→ 问题是否可以通过"告诉模型怎么回答"解决?
              │
              ├─ 是 ──→ 提示词能稳定控制吗?
              │          │
              │          ├─ 是 ──→ 用提示词工程
              │          └─ 否 ──→ 用微调
              │
              └─ 否 ──→ 模型本身能力是否足够?
                         │
                         ├─ 是 ──→ 用微调(深度行为改变)
                         └─ 否 ──→ 换更强的模型,或者评估是否需要后训练

一个真实案例

某电商平台的智能客服项目,经历了这样的演进:

  1. V1(提示词):直接用 GPT-4 + 系统提示词。效果:70% 的问题能答对,但格式不稳定,经常”说太多”。
  2. V2(提示词 + few-shot):加了10个示例。效果:格式稳定了,但遇到知识库外的政策问题还是乱答。
  3. V3(RAG):接入退换货政策、商品信息的知识库。效果:知识准确性提升到 85%,但语气还是太”AI”。
  4. V4(RAG + 微调):用 5000 条人工标注的客服对话微调了一个 7B 模型。效果:准确率 92%,语气自然,响应速度还更快。

这个演进路径非常典型:先轻后重,每一步都有明确的理由。

要点

永远从最轻量的方法开始。如果提示词能解决问题,不要上 RAG。如果 RAG 能解决问题,不要微调。每一层的升级都要有明确的数据支撑——上一层的瓶颈在哪里,新方法如何解决这个瓶颈。

常见坑点

  1. “越贵的方法效果越好”:错。方法选择看的是问题类型,不是预算大小。用微调去解决知识缺失问题,就像用大炮打蚊子——又贵又打不准。
  2. “我的场景很特殊,肯定需要微调”:大多数人高估了自己场景的特殊性。先试提示词和 RAG,如果不够再升级。
  3. “只选一种方法”:生产系统几乎都需要组合使用。不要把时间花在”到底选哪个”上,而是花在”怎么组合”上。

检查点问题

  1. 你的业务场景中,模型最大的三个不足是什么?属于”知识缺失”还是”行为不当”?
  2. 如果你的知识每天更新一次,你会选择微调还是 RAG?为什么?
  3. 一个”模型回答太啰嗦”的问题,应该用提示词工程还是微调来解决?

实操任务

拿出你当前或计划中的 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 是性价比最高的选择。

常见坑点

  1. LoRA 秩(rank)选太大:rank 越大不代表效果越好。rank=64 在大多数场景下已经足够,甚至 rank=16 就够了。过大的 rank 会增加过拟合风险。
  2. 忽视基础模型选择:LoRA 微调的效果上限取决于基础模型。在一个烂模型上做 LoRA,结果还是一个烂模型。
  3. 混淆 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)
  - 对训练集和测试集做去重(不只是精确去重,还要做语义去重)
  - 用模型从未见过的数据做最终评估

检查点问题

  1. LoRA 中 rank 参数的作用是什么?rank 选得太大或太小分别会有什么问题?
  2. 你的数据只有 100 条,应该选择全量微调还是 LoRA?为什么?
  3. 如果你发现微调后的模型在你的任务上表现很好,但通用能力明显下降了,这是什么问题?怎么解决?

实操任务

找一份你业务场景中的真实数据(比如客服对话记录、产品描述、技术文档),尝试按照上面的格式构建 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 32GBQLoRA 微调 3B 模型,推理 7B 模型
中端(1-3万)RTX 4090 24GBQLoRA 微调 7B 模型,推理 13B 模型
专业(5-10万)A6000 48GB / 2×RTX 4090QLoRA 微调 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 是安全的初始选择。

常见坑点

  1. OOM(显存不足):减小 batch_size 或增大 gradient_accumulation_steps。两者乘积不变,效果基本一致。
  2. Loss 不下降:检查学习率(太大会震荡,太小则不动)、数据格式(是否正确)、模型是否真的在训练(print_trainable_parameters() 确认有可训练参数)。
  3. 效果反而变差:可能是过拟合或数据质量差。检查数据,减少 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 评估流程

这是目前业界最常用的评估方法之一:

  1. 准备 100-200 条测试数据(输入 + 标准答案)
  2. 用微调后的模型生成回答
  3. 用一个更强的模型(如 GPT-4)作为评委,按预设标准打分
  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 测试上线验证。

检查点问题

  1. 你有一张 RTX 4090(24GB),想 QLoRA 微调 7B 模型,处理平均 4000 token 的输入,请估算是否可行。
  2. 微调后发现训练 loss 在持续下降但验证 loss 在上升,你应该怎么做?
  3. 为什么 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 数据工程的核心工作:

  1. 定义”好”的标准:什么样的回答算”好”?这需要和业务方一起定义
  2. 收集和整理数据:从各处收集原始数据,清洗、标注、格式化
  3. 质量把关:每条数据都要人看过,确保准确和一致
  4. 持续维护:业务在变,数据也要跟着变

要点

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       │  高       │
└─────────────┴──────────┴──────────┴──────────┴──────────┘

第二步:制定标注规范

标注规范是数据质量的基础。一个好的标注规范应该包括:

  1. 任务定义:明确每条数据的输入是什么、期望输出是什么
  2. 标注示例:至少给 5 个正例和 5 个反例
  3. 边界情况处理:遇到模糊情况怎么处理
  4. 质量标准:什么算”合格”,什么算”不合格”
  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 生成不出来的。

数据壁垒的三个层次

  1. 数据获取壁垒:有些数据天然只能你获取(用户行为数据、交易数据、内部知识)
  2. 数据标注壁垒:即使有原始数据,标注成高质量训练数据需要领域专业知识
  3. 数据迭代壁垒:上线后持续收集用户反馈、不断优化数据——这是一个飞轮
数据飞轮:
  好数据 → 好模型 → 好体验 → 更多用户 → 更多反馈数据 → 更好的数据
       ↑                                                         │
       └─────────────────────────────────────────────────────────┘

要点

如果你的团队在争论”用哪个模型”,你更应该关注的是”数据准备好了没有”。模型可以换,数据换不了。一个数据做得好的团队,用中等模型也能跑赢用顶级模型但数据做得差的团队。

常见坑点

  1. “数据越多越好”:1000 条高质量数据 > 10000 条未清洗的原始数据。质量永远优先于数量。
  2. “用 GPT 生成训练数据”:可以用于补充,但不能作为主力。GPT 生成的数据缺乏真实用户的表达多样性和错误模式。
  3. “数据做好了就不用管了”:业务在变,数据必须跟着变。至少每月review一次数据是否还”新鲜”。

检查点问题

  1. 如果你要做一个法律咨询 AI,你会从哪里获取训练数据?列出你的数据地图。
  2. 你的标注团队标注一致性只有 0.6(Cohen’s Kappa),你应该怎么做?
  3. 为什么说”数据飞轮”比”选对模型”更重要?

实操任务

选择你熟悉的一个领域,按照 4.3 节的方法:

  1. 画一张数据地图(列出所有可能的数据来源)
  2. 制定一份标注规范(包含 5 个正例和 3 个反例)
  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 测试数据集准备

测试数据集的质量直接决定了评测的可信度。

测试数据集的构建原则

  1. 与训练数据严格隔离:测试数据绝对不能出现在训练数据中
  2. 代表真实分布:测试集的分布应该反映真实用户的使用模式
  3. 覆盖边界情况:故意包含一些”刁钻”的测试用例
  4. 有人工标注的参考答案:每条测试数据都有标准答案或评分标准

数据集规模建议

┌──────────────────┬──────────────┬───────────────┐
│     应用类型      │  最小测试集   │  推荐测试集     │
├──────────────────┼──────────────┼───────────────┤
│ 简单分类/判断     │    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  │
└──────────────┴────────┴────────┴────────┴────────┘

常见坑点

  1. 只用公开 benchmark 对比:公开 benchmark 和你的业务场景可能完全不相关。
  2. 评测数据不一致:不同竞品用不同的测试数据,结果不可比。
  3. 忽视非功能性指标:只看准确率,不看延迟、成本、稳定性。
  4. 一次调研就完事:竞品在快速迭代,调研应该定期进行(至少每季度一次)。

检查点问题

  1. 你的 AI 项目应该用哪些评测指标?权重怎么设?
  2. 为什么测试数据集必须和训练数据严格隔离?如果不隔离会怎样?
  3. 你要做一个竞品调研,应该用同一套测试数据还是各自准备测试数据?为什么?

实操任务

选择一个你熟悉的 AI 产品(可以是公开的,如 ChatGPT、文心一言、Kimi),按照 5.4 节的框架:

  1. 设计 20 条测试数据(包含常规用例和边界用例)
  2. 统一评测标准和评分维度
  3. 至少评测 2 个竞品产品
  4. 输出对比矩阵和分析结论

第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)

常见坑点

  1. 忘记删除旧数据:更新文档时只插入新向量,不删除旧的。结果搜索时会出现过期信息和新信息混在一起。
  2. Embedding 模型更换时不全量重建:换了一个新的 Embedding 模型,但只对新数据用新模型,旧数据还是旧模型的向量。新旧向量不在同一个空间里,检索结果会变差。
  3. 不考虑文档间的引用关系:文档 A 引用了文档 B 的内容,更新文档 B 时,文档 A 中对应的向量也需要更新。

检查点问题

  1. 你的 RAG 系统,数据规模大约 50 万条向量,每周有 5% 的数据会更新,你会选哪种更新策略?
  2. 为什么要对文本进行切分而不是直接存整个文档?
  3. 如果你的 Embedding 模型从 bge-large-zh 换成了 text-embedding-3-large,你需要做什么?

实操任务

选择一个向量库(推荐从 Chroma 开始),搭建一个完整的数据管道:

  1. 准备 10 份文档(可以是任何内容)
  2. 实现文本切分和向量化
  3. 存入 Chroma 并验证检索效果
  4. 模拟一次数据更新,验证增量更新流程

第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 存下来,下一个项目直接用。

检查点问题

  1. 如果你只有一周时间和有限预算,你会优先做 checklist 中的哪些步骤?
  2. 方案 C 的路由逻辑中,置信度阈值设为 0.85。这个值调高或调低分别有什么影响?
  3. 上线后发现准确率从测试环境的 93% 降到了 88%,你会从哪些方面排查原因?

实操任务

这是最终的实战任务。选择以下任一场景,按照本章的完整流程(7.1-7.4)做一个端到端的项目方案:

场景 A:一个在线教育平台的 AI 答疑助手
场景 B:一个医疗健康 APP 的症状预诊助手
场景 C:你当前工作中的真实 AI 项目

输出内容:

  1. 需求分析报告(包含数据驱动的现状分析)
  2. 方案设计文档(模型选型、技术栈、硬件估算)
  3. 数据准备计划(数据地图、标注规范、质量标准)
  4. 测评方案(评测指标、测试数据集、对比实验设计)

课程总结

恭喜你完成了这门课。回顾一下你学到了什么:

核心认知

  1. 模型调优不是一招鲜——提示词、RAG、微调、后训练各有适用场景,关键是根据问题类型选对方法
  2. 数据是最大的壁垒——模型在趋同,数据在分化。投入数据工程的回报远高于投入模型调参
  3. 测评贯穿始终——不是最后才做的事,而是从需求分析阶段就要开始设计

关键技能

  1. 方法选择决策树:根据问题类型快速判断该用什么方法
  2. 硬件估算公式:参数量(B)/2 ≈ 内存(GB),再加上 KV Cache 和系统开销
  3. 数据验收四维度:准确性、一致性、覆盖度、清洁度
  4. 向量库选型:根据阶段和规模选择,不要在原型阶段就追求生产级方案
  5. 项目 checklist:从需求到上线的完整流程,不遗漏关键步骤

下一步建议

  • 如果你想继续深入微调:从第 3 章的实操开始,用自己的业务数据做一次完整的微调实验
  • 如果你想深入数据工程:重新审视你当前项目的数据质量,用第 4 章的验收标准做一次全面 audit
  • 如果你想深入 RAG:结合课程 2 的 RAG 知识和本章的向量库内容,搭建一个生产级的知识库系统
  • 准备好进入课程 5:你已经掌握了技术核心,下一步是思考怎么用这些能力实现职业跃迁

记住:模型是通用的大脑,数据是独特的 DNA,调优是连接两者的桥梁。你的价值不在于会调用哪个 API,而在于能把这三者有机结合,解决真实的业务问题。