当一个跑了一年多的基于 LLM 自动化流程积累了超过万条真实数据后,我产生一个想法:能不能用这些数据训练一个专用小模型,然后把 API 调用替换成本地推理,这样能够显著减少数据外出风险,同时也能学习到模型微调相关的知识(我承认这是一个主要目的)?因此有了本文,记录了从动机到落地的完整思路。

一、背景:一个已经跑了很久的基于 LLM 的自动化流程

过去一年多,我维护着一个银行结单自动识别归档的自动化工作流工程[基于飞书集成平台利用AI和多维表格的一个自动化工作案例](:

邮件/系统拉取结单 PDF    → OCR 转文本    → LLM 提取 {账号, 报告期}    → 标准化重命名    → 按约定目录存入 SharePoint

这个流程在一年半时间内处理了超过 16000 多份文档,提取准确率达到 99.95% 以上,而且我通过智能对文档分割只取有效的单页,还能将 token 消耗控制在 600 - 1300 tokens/文档,同时避免整个文档数据泄露。从业务角度看,它已经是相当成熟稳定。

但维护久了,两个问题越来越明显:

  1. 数据外出风险:每份文档都要发到云端 API(从 GPT-4 到 DeepSeek-V4 都试过),虽然做了文档分割,只暴露单页数据,但金融文档天然敏感,"数据能被外网获取"始终是个心理负担。
  2. 固定任务用大模型是浪费:这个任务极其固定——就是从固定格式的结单里找两个字段。让一个千亿参数的通用模型来做,好比用飞机送外卖。

于是问题变成了:能不能用已经积累的数据,训练参数量非常小的模型,把这些工作全部收回到本地,甚至可以用 CPU 推理就完成任务?


二、可行性分析:为什么这件事可以做成

不是所有任务都适合用小模型替代。我逐项评估了这个任务的特性:

评估维度判断说明
任务是否固定✅ 极其固定就是找账号和日期,格式可枚举
是否有高质量标注数据✅ 超万条经过多种方式验证过的正确结果,等于免费标注
是否需要复杂推理❌ 不需要定位 + 格式化输出,不是推理题
是否能接受偶尔出错✅ 可容错归档系统有人工处理兜底方案
是否有训练硬件✅ Arc B570千元级消费显卡,10GB 显存

结论:这是一个理想的小模型微调场景。 任务固定、数据充足、不需要复杂推理、有硬件——所有条件都满足。

为什么不选择已有的专门用于数据提取的模型呢?千元级消费显卡也能跑 AI?Intel Arc B570 本地部署 + 四模型对比实战


三、基座模型选择:不是越大越好

3.1 选择逻辑

因为是"替换 API 调用",目标是争取能在 CPU 上也能跑得快。所以参数量的上限是"能在普通服务器上用纯 CPU 推理,平均响应时间不超过 3 秒"。

这个约束天然排除了 7B 以上的模型。在 0.5B-3B 的范围内,我评估了三个候选:

模型参数量中文理解指令遵循在 Arc B570 上训练
NuExtract-2.0-4B4B⭐⭐⭐⭐⭐QLoRA 可
Qwen2.5-3B-Instruct3B⭐⭐⭐⭐⭐⭐⭐⭐LoRA 可
Qwen3-0.6B0.6B⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐LoRA 轻松

3.2 为什么是 Qwen3-0.6B

三个关键理由:

第一,中文是母语。结单文档绝大多数是中文(含繁体),NuExtract 系列虽然专攻抽取但在中文场景水土不服。Qwen 系列对中文金融术语的理解天然更准确。

第二,指令遵循能力突出。Qwen3 在 instruction following 上的提升是代际性的。对于"必须输出严格 JSON 格式"这个约束,它几乎不会出错——这对后面的自动化流程至关重要(解析失败 = 整个归档链条中断)。

第三,体量刚好。0.6B 在 Arc B570 上用 LoRA 训练只需约 1 小时,推理时 379MB 的 Q4_K_M 量化版在 CPU 上单次推理平均不到 3 秒。

3.3 为什么不选更大的

1.7B 也试了,准确率相同,但训练慢一倍,推理慢一倍,量化后体积大 3 倍。任务复杂度决定了所需参数量,超过阈值的参数都是浪费,从 0.6B 开始是个更优选择。


四、数据集:最好的标注来自生产验证

4.1 数据来源的特殊性

跟通常的微调项目最大的不同是:没有做额外的数据标注

过去一年多的 API 调用,每次都有指令、输入(OCR 文本)和输出(LLM 提取的 JSON)。这些结果在归档流程中天然地存储下来了,自动化处理正确率在 99.95% 以上,而且失败的案例也经过人工调整后被记录下来。也就是说,超万条"已经验证过的问答对"天然就是训练数据

4.2 从原始记录到可用数据集

不是所有生产数据都适合直接拿来训练。清洗过程花了最多的精力:

  • 去重:同一份结单可能因为流程重跑产生多条相同记录,从完整结果中抽取约四分之一,去重后得到 4,200 条样本,即使再多数据其实也是形式上的重复效果并不会提升太多
  • 标签冲突检测:发现了 13 组相同文本不同日期的样本,经排查是同一张报表的不同月份版本(日期不同但账号相同的合法情况),予以保留但记录在案

最终得到 4,200 多条高质量训练样本。

4.3 为什么不追求"更多数据"

4,000 条对信息抽取来说已经足够。继续增加数据的边际收益很低:3,000 条之后每增加 1,000 条提升不到 0.5%,且大量样本高度相似(同一银行不同月份格式相同),冗余数据只会增加训练时间。


五、训练:Unsloth Studio + 消费级显卡

5.1 硬件和平台

训练的硬件是一块 Intel Arc B570(10GB 显存),2025 年发布的千元级消费显卡。

选 Unsloth Studio 而非直接手写训练代码的原因很实际Intel Arc 显卡 Unsloth Studio 安装配置指南

  • 它提供了开箱即用的 LoRA/QLoRA 支持
  • Qwen3 系列有专门的优化
  • 训练过程的 checkpoint 管理、评估日志都是自动的
  • 对新手足够友好,对老手足够灵活

5.2 训练配置

实际使用的配置 Qwen3-0.6B_lora_dataset_2026-08-10.yaml

training:  max_seq_length: 4096  num_epochs: 3  learning_rate: 0.0002  batch_size: 2  gradient_accumulation_steps: 8  warmup_steps: 30  max_steps: 670  save_steps: 170  eval_steps: 170  # ...lora:  lora_r: 16  lora_alpha: 32  lora_dropout: 0.05  target_modules: [k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj, q_proj]

参数推导过程:

训练样本: 3,575 条 (85%)batch_size: 2 (Arc B570 10GB 的安全值)gradient_accumulation: 8有效 batch: 2 × 8 = 16每轮步数: ceil(3575 / 16) = 224总步数: 224 × 3 轮 = 672 → 取整 670save_steps: 170 (约每轮 4 个 checkpoint)

这套参数在 Arc B570 上大约 70 分钟跑完 3 轮,显存占用约 6GB。

说明:原始数据集通过分拆脚本按照二拆模式 85:15 拆分为训练集和评估集。split_data.py 也支持三拆模式(70:15:15,额外产出独立 test.jsonl),支持更规范的数据管理。但测试用的 289 条测试用例是后来单独手工精选的,与训练数据零重叠。

5.3 Unsloth Studio 训练过程

六、工程化:构建可复用的流水线

这是本文的重点。训练一个模型不难,难的是让整个流程可复现、可迁移。

6.1 设计思路

整套工具链遵循三个核心原则:

一切皆文件:脚本之间通过文件交换数据(xlsx → jsonl → yaml → gguf → report),不通过函数调用。每个脚本独立可运行、独立可测试。

一切皆参数:路径、比例、种子、量化格式全部通过命令行参数或环境变量控制。换一个任务、换一台机器,只需改参数,不用改代码。

一切皆可恢复:导出脚本检测产物是否存在自动跳过;测试脚本每完成一条即写入 checkpoint,中断后从断点继续。

6.2 工作流总览

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐│ 原始数据  │ → │ 数据拆分  │ → │ 训练配置  │ → │ 模型训练  │ → │ 模型导出  │ → │ 效果测试  ││  xlsx    │   │ jsonl    │   │  yaml    │   │ LoRA     │   │  GGUF    │   │ 报告     │└──────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘ split_data.py  split_data.py  gen_config.py     train.py    export_gguf.sh  run_test.py

六个脚本覆盖从原始数据到测试报告的全流程。其中 train.py 是最新加入的一环——它通过 unsloth 库直接调用训练 API,让训练也纳入了自动化工具链,不再依赖 Unsloth Studio 的 Web 界面手动操作。

6.3 项目目录结构与脚本说明

model-fine-tuning/                     # 项目根目录│├── data/                              # === 数据层 ===│   ├── raw/                           # 原始训练数据(只读)│   │   ├── dataset.xlsx               #   输入:手工维护的 4,200+ 条标注数据│   │   └── dataset.csv                #   输入:CSV 格式副本│   ├── split/                         # 拆分产物 → split_data.py 输出│   │   ├── train.jsonl                #   训练集(二拆 85% / 三拆 70%)│   │   ├── eval.jsonl                 #   评估集(二拆 15% / 三拆 15%)│   │   └── test.jsonl                 #   测试集(仅三拆模式,15%)│   └── test/                          # 独立测试用例│       └── test_cases.xlsx            #   289 条手工精选测试用例│├── configs/                           # Unsloth Studio 训练 YAML│   ├── Qwen3-0.6B_lora_*.yaml         #   0.6B 训练配置│   └── Qwen3-1.7B_lora_*.yaml         #   1.7B 训练配置(实验用)│├── scripts/                           # === 工具脚本 ===│   ├── split_data.py                  # 输入: data/raw/*.xlsx → 输出: data/split/*.jsonl│   │                                  #   支持 --mode three (70:15:15) / --mode two (85:15)│   ├── gen_config.py                  # 输入: data/split/train.jsonl → 输出: configs/*.yaml│   │                                  #   读取样本数 + 显存大小,自动推导训练超参数│   ├── train.py                       # 输入: config YAML + jsonl → 输出: outputs/training/* (checkpoint)│   │                                  #   通过 unsloth 库直接执行 LoRA/QLoRA 训练,无需 Web 界面│   │                                  #   支持 --config YAML 加载 + --mode lora/qlora 切换│   ├── export_gguf.sh                 # 输入: HF缓存 + LoRA adapter → 输出: ${MODELS_DIR}/export/model-*/*.gguf│   │                                  #   merge → convert → quantize 四步流水线│   ├── run_test.py                    # 输入: GGUF模型 + 测试用例 → 输出: outputs/results/* + outputs/logs/*│   │                                  #   自动发现模型、模糊匹配、断点续跑、双格式(xlsx/jsonl)测试│   └── utils/                         # 共享工具模块│       ├── data_io.py                 #   xlsx / jsonl 统一读取,自动识别格式│       ├── model_discovery.py         #   扫描导出目录,自动注册模型(零硬编码)│       └── eval_metrics.py            #   准确率计算、JSON + Markdown 报告生成│├── outputs/                           # === 产物 ===│   ├── training/                      # 训练输出 → train.py 输出│   │   └── {model}-{timestamp}/       #   checkpoint-* 目录 + 训练日志│   ├── results/│   │   ├── result.json                #   JSON 格式完整测试结果│   │   └── report.md                  #   Markdown 格式可读报告│   └── logs/                          # 每次测试运行的 DEBUG 日志│├── docs/                              # 文档 + 参考资料├── .claude/skills/                    # Claude Code Skill 定义│   ├── fine-tuning-pipeline/          #   流水线编排(Agent 自动执行)│   └── unsloth-config-generator/      #   训练配置生成├── Makefile                           # 统一入口(make split / config / export / test)└── .gitignore

输出目录(项目外,MODELS_DIR 默认 ~/Models):

${MODELS_DIR}/├── hub/                               # HF 缓存(离线模式)│   └── models--{org}--{model}/│       └── snapshots/{sha}/└── export/                            # GGUF 导出产物 → export_gguf.sh 输出    └── model-qwen3-0.6b-bill-s670/        ├── *-f16.gguf                 #   原始精度 (1.1 GB)        ├── *-Q4_K_M.gguf              #   量化版 (379 MB,推荐部署)        ├── *-Q5_K_M.gguf              #   量化版 (424 MB)        ├── *-Q8_0.gguf                #   量化版 (610 MB)        └── *-export-meta.json         #   溯源:基座/步数/llama.cpp版本/时间戳

6.4 命令行训练:不再依赖 Web 界面

Unsloth Studio 的 Web 界面适合初次实验,但工程化流程中每次都手动上传数据、调整参数、点击启动,效率太低。实际上,Unsloth Studio 底层使用的是 unsloth Python 库(v2026.7.5),它提供了完整的编程接口——FastLanguageModelUnslothTrainerUnslothTrainingArguments——可以直接从命令行启动训练。

train.py 封装了这一能力,核心设计:

YAML 驱动,命令行覆盖

# 直接用已有的训练配置python scripts/train.py --config configs/Qwen3-0.6B_lora_2026-08-10.yaml# QLoRA 模式(4bit 量化训练,4GB 显存就够)python scripts/train.py --model unsloth/Qwen3-0.6B --mode qlora \  --train data/split/train.jsonl --eval data/split/eval.jsonl# 命令行覆盖 YAML 中的参数python scripts/train.py --config ... --epochs 4 --lr 1e-4

参数优先级:命令行 > YAML > 脚本默认值。这意味着可以用 gen_config.py 生成的 YAML 作为基础,再按需调整。

训练模式

模式激活显存需求适用
LoRA(16bit)--mode lora (默认)~8GB显存充足时,精度最高
QLoRA(4bit)--mode qlora~4GB显存受限或快速验证

完整 Makefile 入口

make train        # LoRA 训练make train-qlora  # QLoRA 训练(显存友好)

训练产物输出到 outputs/training/{model}-{timestamp}/,包含 checkpoint 目录,可直接被 export_gguf.sh 通过 ADAPTER=/path/to/checkpoint-xxx 使用。

至此,六阶段流水线全部打通:

split → config → train → export → test

每一步都有可独立运行的脚本,也支持 make 一键串联。

6.5 模型测试:自动发现,模糊匹配

早期我的做法是每导出一个模型就在测试脚本里加一行配置。后来换了一个思路:让脚本自己扫描目录发现模型

导出一个新模型后,run_test.py 自动感知它的存在。用户只需要一个模糊片段来指定:

--model 0.6b-bill  → 扫描到 4 个变体 (Q4/Q5/Q8/f16) → 全部测试--model 0.6b-Q4    → 命中 1 个                       → 只测这个--list             → 列出所有可用模型

测试结果自动生成 JSON(机器可读)和 Markdown(人可读)两种报告。

6.6 让 AI 替你跑流程

更进一步,我为 Claude Code 编写了 Skill 文件,让 Agent 能理解自然语言意图:

用户:"用 QLoRA 模式训练 Qwen3-0.6B"      → Agent 激活 venv → 执行 train.py --mode qlora --config configs/xxx.yaml用户:"把 step-670 导出为 Q4_K_M 和 Q8_0"      → Agent 激活 venv → 组装参数 → 执行导出 → 报告结果用户:"测试所有 0.6b 的模型"      → Agent 自动运行 run_test.py,返回报告摘要

工程的终点不是代码,是让不熟悉代码的人也能操作。


七、成果:100% 准确率 + CPU 反而比 GPU 更快

7.1 测试结果

用 289 条独立手工精选的测试用例(包含各种边界情况:15 位长账号、字母编码、繁体中文、英文报表),覆盖三种量化格式 × 两种硬件(GPU / CPU 推理)共 7 组对比实验。

测试环境:GPU 推理使用 Intel Arc B570 (10GB),llama.cpp Vulkan 后端,ngl=99;CPU 推理使用 AMD 5700X 纯 CPU(ngl=0)和 Intel i7-12700;推理参数统一为 temperature=0, max_tokens=2048。

Q4_K_M GPUQ4_K_M CPUQ5_K_M GPUQ5_K_M CPU (AMD)Q5_K_M CPU (i7)Q8_0 GPU
硬件Arc B570AMD 5700XArc B570AMD 5700Xi7-12700Arc B570
耗时1,615 ms1,326 ms1,632 ms1,400 ms2,739 ms1,632 ms
Token/s542661537626320537
准确率100%100%100%100%100%100%

7.2 分析

准确率:三种量化格式无损

从 Q8_0 → Q5_K_M → Q4_K_M,模型体积从 610 MB 压缩到 379 MB(压缩比 1.6:1),而 289 个测试用例的准确率始终是 100%。说明对于这类信息抽取任务,量化带来的精度损失几乎可以忽略不计。推荐部署 Q4_K_M——体积最小、速度最快、准确率保持优秀。

CPU vs GPU:AMD 5700X 反而更快

三组 CPU vs GPU 对比中,AMD 5700X 的纯 CPU 推理全部赢过 Arc B570 的 Vulkan 推理:

量化格式GPU (Arc B570)CPU (AMD 5700X)CPU 优势
Q4_K_M1,615 ms1,326 ms快 18%
Q5_K_M1,632 ms1,400 ms快 14%
AMD vs Intel:缓存和架构的差距

同为纯 CPU 推理的 Q5_K_M,AMD 5700X (DDR4) 比 i7-12700 (DDR4) 快 **96%**(1,400 ms vs 2,739 ms):

  1. L3 缓存:5700X 的 32 MB 比 12700 的 25 MB 多 28%,对 memory-bound 的推理任务,更多权重热区命中缓存意味着少走 DDR 延迟(L3 ~10ns vs DDR4 ~70ns)
  2. 同构核心:5700X 全 8 核性能均等,而 12700 的 8P+4E 中 E-core 成了线程池的短板
  3. 单 CCD 低延迟:5700X 核间通信在片内完成,12700 跨簇需走 Ring Bus

启示:选 llama.cpp 推理 CPU 时,"大缓存 + 同构核心"比"多核 + 大小核"更重要。

7.3 实践意义

在 289 条多场景测试中,CPU 推理 1,326 ms 的平均耗时完全满足业务需求(单份文档 OCR + 推理 < 5 秒)。相比 API 方案:

维度之前(API)现在(本地模型)
数据安全文档出网全程本地
成本按量付费零边际成本
延迟网络+推理 5-10s本地推理 <3s(CPU)
可控性模型不可调可按需重训
准确率~99.95%100%(在目标格式上)

甚至还可以利用之前的 API 调用方式为本地推理结果错误的情况兜底——这么一统计,每年实际需要调用 API 的也就不到 5 份文档,数据外出风险降到几乎为零。

7.4 从 GPU 训练到 CPU 部署

训练的模型导出为 GGUF 格式后,可以在任意有 CPU 的机器上运行:

llama-cli -m model-qwen3-0.6b-bill-s670-Q4_K_M.gguf \  -ngl 0 -no-cnv \  -p "从下列账单中抽取账号和日期..." -n 128

379 MB 的模型文件,不需要 GPU,不需要 Python 环境,一个 C++ 编译的二进制就能跑。


八、可迁移性:这套方案不只适用于银行结单

8.1 迁移步骤

整套流水线设计之初就考虑了可迁移性,迁移到新任务只需四步:

步骤操作示例(合同抽取)
1. 数据准备准备相同格式的 xlsx(instruction/input/output 三列)合同文本 → {甲方, 乙方, 签署日期}
2. 数据拆分python scripts/split_data.py --input data/raw/contracts.xlsx自动按 85:15 拆分
3. 生成配置python scripts/gen_config.py --model-size 0.6B --vram 10根据样本数自动推导训练步数
4. 执行流水线make split → make train → make export → make test一键训练 + 导出 + 测试

8.2 迁移实例(假设场景)

假设要训练一个"从购销合同中提取甲乙方和签署日期"的模型:

# 1. 准备数据#    contracts.xlsx 包含 instruction / input / output 三列#    示例 output: {"party_a": "北京科技公司", "party_b": "上海贸易公司", "date": "2026-08-10"}# 2. 拆分python scripts/split_data.py --input data/raw/contracts.xlsx# 3. 生成配置(仍用 Arc B570 10GB)python scripts/gen_config.py --model-size 0.6B --vram 10 --output configs/contract_extraction.yaml# 4. 训练python scripts/train.py --config configs/contract_extraction.yaml# 5. 导出 + 测试MODEL_REPO=unsloth/Qwen3-0.6B bash scripts/export_gguf.shpython scripts/run_test.py --model contract --input data/test/contract_cases.xlsx

预计训练时间:1-2 小时(取决于样本数)。

8.3 适用场景判断

并非所有任务都适合这套方案:

判断项✅ 适合❌ 不适合
任务类型信息抽取、分类、格式化输出开放式生成、复杂推理
数据量1,000+ 条高质量标注< 500 条或标注质量差
输出格式结构化(JSON/CSV)自然语言段落
部署环境有 CPU/GPU 服务器纯浏览器或移动端

反例:“生成营销文案”、"回答开放性问题"这类任务仍需要大模型。


九、总结与展望

9.1 核心收获

这次实践回答了三个问题:

小模型能不能替代大模型 API?
能,但前提是任务足够固定、有足够的高质量训练数据。通用能力交给大模型,固定能力交给专用小模型——这是务实的工程思路。

消费级硬件能不能做微调?
能。Arc B570 10GB 显存完全胜任 0.6B 模型的 LoRA 训练。而且模型导出后可以用纯 CPU 推理,部署门槛为零。

工程化的投入值不值得?
值得。脚本参数化、幂等性、自动发现这些工作,每次迭代从半小时降到一行命令。而且整套工具链可以直接复制到下一个微调任务。

9.2 局限性与未来方向

当前局限

  1. 领域专用性强:当前模型针对中文银行结单,跨领域需重新训练
  2. 测试覆盖有限:289 条测试用例虽经精选,但边界 case 覆盖可能不完整
  3. 离线依赖:工具链依赖 HF 模型缓存,首次需联网下载基座模型

可能的改进方向

  • 模型蒸馏:尝试将 0.6B 蒸馏到 0.3B,进一步降低推理延迟
  • 增量学习:新格式结单出现时,少量样本即可快速适配
  • 多任务微调:同一模型上训练多个相关任务(结单 + 发票 + 合同),提升泛化能力
  • 量化感知训练:训练阶段引入量化,可能进一步提升 Q4_K_M 准确率

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐