基于魔搭 MS-Swift 实现大模型微调落地指南
在大模型二次开发学习阶段,手写训练代码可以帮助我们吃透模型微调底层逻辑,做到知其然更知其所以然。但落地到企业生产环境,我们更追求标准化流程、高复用能力与稳定可靠的工程化方案。MS-Swift 作为阿里达摩院魔搭社区开源的一站式大模型开发框架,集成了模型训练、微调、推理、量化部署全链路能力,兼容数百款大主流模型与多种微调、对齐算法。本章我们就借助 MS-Swift 这类成熟工具,学习如何用标准化流程快速完成大模型二次训练,实现快速将模型能力深度集成进企业业务系统。

本章我们借助 MS‑Swift 框架,完整跑通一套面向行业 Agent 的大模型定制流水线,案例选用 Qwen3.5‑0.8B‑Base 基础模型,参数量仅 0.8B,硬件门槛低,可以完整跑通企业 Agent 微调全流程;实际业务中可以替换为 Qwen‑8B、14B 等更大规模基座。
本次大模型定制采用四阶段递进式微调流程,层层打磨模型能力,完整流程如下:
Qwen3.5‑0.8B‑Base
↓
CPT‑LoRA 增量预训练 → 推理测试 → LoRA合并(领域基座)
↓
SFT‑LoRA(基础对话能力) → 推理测试 → LoRA合并
↓
Agent SFT‑LoRA(工具调用能力) → 推理测试 → LoRA合并
↓
DPO‑LoRA 偏好对齐,修正Agent行为 → 推理测试 → LoRA合并(最终HF模型)
↓
转换为GGUF格式 → 权重量化 → GGUF回归测试 → 部署
在工程落地实践中,先增量预训练灌入无标签领域知识,再做指令微调,再 Agent 微调,最后偏好对齐。
- CPT 增量预训练:灌入大批量无标签领域文档,让基座学习行业术语、业务行文逻辑、领域事实;只做文本续写,不学对话;产出领域增强基座
- SFT 监督指令微调:教会领域基座听懂人类指令,学会问答对话、遵循 system 提示词,掌握对话模板;产出领域问答模型
- Agent SFT 工具调用微调:教会模型判断什么时候需要调用外部工具,输出格式合法的工具调用 JSON;接收工具返回结果后整理自然语言答案
- DPO 偏好对齐:修复 Agent 的缺陷,工具误调用、非法 JSON 输出、回答啰嗦、编造事实幻觉;用好坏成对样本矫正模型输出行为
每一个训练阶段结束,必须做人工推理测试,验证效果达标,再合并 LoRA,流入下一阶段;不要跳过测试直接训练下一流程,否则问题会层层叠加,最后很难定位 bug 出在哪一步。
一、环境配置
本章节完成系统底层依赖、Python虚拟环境、适配CUDA的PyTorch、MS-Swift源码部署、基座模型下载全套流程,采用国内镜像加速,解决海外源下载慢、超时问题。
1、基础系统依赖与虚拟环境搭建,适配MS-Swift官方推荐配置:Python3.13、CUDA12.8、Torch2.8.0,兼容全系微调、量化、推理功能。
root@localhost:~# apt install build-essential gcc g++
root@localhost:~# apt install -y software-properties-common
root@localhost:~# add-apt-repository -y ppa:deadsnakes/ppa
root@localhost:~# apt install -y python3.13 python3.13-venv python3.13-dev
root@localhost:~# python3.13 -m venv myvenv
root@localhost:~# source myvenv/bin/activate
2、基础 PyTorch 与工具库安装,使用国内清华源、上海交大 PyTorch 镜像,解决国内网络下载慢的问题。
root@localhost:~# pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 transformers==4.57.6 accelerate gradio \
-i https://pypi.tuna.tsinghua.edu.cn/simple \
--extra-index-url https://mirror.sjtu.edu.cn/pytorch-wheels/cu128
3、安装 ms‑swift 框架,采用源码本地可编辑模式安装‑e ".[all]",安装全部可选依赖;方便查看源码、修改框架逻辑。
root@localhost:~# git clone https://gitee.com/lyshark/ms-swift.git
Cloning into 'ms-swift'...
remote: Enumerating objects: 82161, done.
remote: Counting objects: 100% (82161/82161), done.
remote: Compressing objects: 100% (17883/17883), done.
remote: Total 82161 (delta 62894), reused 82161 (delta 62894), pack-reused 0 (from 0)
Receiving objects: 100% (82161/82161), 84.64 MiB | 4.83 MiB/s, done.
Resolving deltas: 100% (62894/62894), done.
root@localhost:~# cd ms-swift/
root@localhost:~/ms-swift# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -e ".[all]"
root@localhost:~# pip list
Package Version
----------------------------- ------------
absl-py 2.5.0
accelerate 1.15.0
addict 2.4.0
aiohappyeyeballs 2.7.1
aiohttp 3.14.3
aiosignal 1.4.0
aliyun-python-sdk-core 2.16.1
aliyun-python-sdk-kms 2.16.5
annotated-doc 0.0.5
annotated-types 0.8.0
anyio 4.15.1
async-timeout 5.0.1
attrdict 2.0.1
attrs 26.1.0
av 17.1.0
binpacking 2.0.1
certifi 2026.7.22
cffi 2.1.1
charset-normalizer 3.5.1
click 8.5.0
cloudpickle 3.1.2
contourpy 1.3.2
cpm-kernels 1.0.11
crcmod 1.7
cryptography 50.0.1
cuda-bindings 12.9.4
cuda-pathfinder 1.8.1
cuda-toolkit 12.6.3
cycler 0.12.1
dacite 1.9.2
datasets 4.8.4
defusedxml 0.7.1
dill 0.4.1
einops 0.8.2
exceptiongroup 1.3.1
fastapi 0.141.1
filelock 3.32.3
fonttools 4.65.0
frozenlist 1.8.0
fsspec 2026.2.0
grpcio 1.84.0
h11 0.16.0
hf-xet 1.6.0
httpcore 1.0.9
httpcore2 2.12.0
httpx 0.28.1
httpx2 2.12.0
huggingface_hub 1.31.0
idna 3.19
importlib_metadata 9.0.1
Jinja2 3.1.6
jiter 0.17.0
jmespath 1.1.0
joblib 1.6.0
json_repair 0.63.4
kiwisolver 1.5.1
Markdown 3.10.3
markdown-it-py 4.2.0
MarkupSafe 3.0.3
matplotlib 3.10.9
mdurl 0.1.2
modelscope 1.40.0
modelscope-hub 0.4.2
mpmath 1.3.0
ms_swift 4.6.0.dev0
multidict 6.8.0
multiprocess 0.70.19
networkx 3.4.2
nltk 3.10.3
numpy 2.2.6
nvidia-cublas-cu12 12.6.4.1
nvidia-cuda-cupti-cu12 12.6.80
nvidia-cuda-nvrtc-cu12 12.6.85
nvidia-cuda-runtime-cu12 12.6.77
nvidia-cudnn-cu12 9.10.2.21
nvidia-cufft-cu12 11.3.0.4
nvidia-cufile-cu12 1.11.1.6
nvidia-curand-cu12 10.3.7.77
nvidia-cusolver-cu12 11.7.1.2
nvidia-cusparse-cu12 12.5.4.2
nvidia-cusparselt-cu12 0.7.1
nvidia-nccl-cu12 2.29.3
nvidia-nvjitlink-cu12 12.9.86
nvidia-nvshmem-cu12 3.4.5
nvidia-nvtx-cu12 12.6.77
openai 3.13.0
oss2 2.19.1
packaging 26.3
pandas 2.3.3
peft 0.20.0
pillow 12.3.0
pip 22.0.2
propcache 0.5.2
protobuf 7.36.1
psutil 7.2.2
pyarrow 25.0.1
pycparser 3.0
pycryptodome 3.23.0
pydantic 2.13.5
pydantic_core 2.46.5
Pygments 2.21.0
pyparsing 3.3.2
python-dateutil 2.9.0.post0
pytz 2026.3.post1
PyYAML 6.0.3
qwen-vl-utils 0.0.14
regex 2026.9.10
requests 2.34.2
rich 15.0.0
rouge 1.0.1
safetensors 0.8.0
scipy 1.15.3
sentencepiece 0.2.2
setuptools 78.1.0
shellingham 1.5.4
simplejson 4.1.2
six 1.17.0
sniffio 1.3.1
sortedcontainers 2.4.0
starlette 1.6.0
sympy 1.14.0
tensorboard 2.21.0
tensorboard-data-server 0.7.2
tiktoken 0.14.0
tokenizers 0.23.2
torch 2.14.0+cu126
torchvision 0.29.0+cu126
tqdm 4.70.1
transformers 5.16.1
transformers-stream-generator 0.0.5
triton 3.8.0
trl 0.29.1
truststore 0.10.4
typer 0.27.2
typing_extensions 4.16.0
typing-inspection 0.4.4
tzdata 2026.4
urllib3 2.7.0
uvicorn 0.53.0
Werkzeug 3.1.8
xxhash 4.0.1
yarl 1.24.5
zipp 4.1.0
zstandard 0.25.0
4、创建工作目录/root/qwen并下载模型权重文件,所有数据集、模型权重、训练输出全部放在该目录下,方便统一管理。
root@localhost:~/qwen# mkdir -p /root/qwen/output
root@localhost:~/qwen# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple modelscope
root@localhost:~/qwen# modelscope download --model Qwen/Qwen3.5-0.8B-Base --local_dir /root/qwen/Qwen3.5-0.8B-Base
Downloading: 100%|█████████████████████████████████| 13/13 [04:52<00:00, 22.47s/file]
✓ Snapshot ready at /root/qwen/Qwen3.5-0.8B-Base
root@localhost:~/qwen# ls -lh
total 8.8M
drwxr-xr-x 2 root root 4.0K Sep 14 00:47 Qwen3.5-0.8B-Base
二、增量预训练(CPT-LoRA)
CPT(Continual Pre-Training)持续增量预训练,是在通用基座模型基础上,利用无标签行业长文本数据,继续执行next-token 文本续写训练。无需人工标注,仅需原始行业文档、合同、手册、白皮书等数据,快速让通用模型适配垂直领域知识体系,解决通用模型行业认知不足的问题。
这种方式适合大量无标签行业文档、产品手册、合同、病历、行业白皮书;不需要问答标注,只需要原始文本。不适合已经对齐好的 Instruct/chat 模型;对话问答样本。
标准数据集格式:
{"text":"这里是领域文档段落,例如合同条文、行业手册、产品说明长文本……"}
{"text":"第二篇领域长文本……"}
{"text":"第三篇领域长文本……"}
用户可以自行准备一批经过清洗后的文本内容,并按照一定的比例切割成训练集和验证集两部分,可以使用前80%为训练集,后20%为验证集的比例要求,新建train_cpt.jsonl、val_cpt.jsonl两个文件,并依次放入训练集和验证集。
root@localhost:~/qwen# python build_cpt_jsonl.py
加载原始数据总行数:2407
字段提取+文本清洗完成,共 2407 条样本
训练集样本数:1925,验证集样本数:482
root@localhost:~/qwen# ls -lh
total 9.1M
drwxr-xr-x 2 root root 4.0K Sep 14 00:47 Qwen3.5-0.8B-Base
-rw-r--r-- 1 root root 2.8K Sep 14 00:44 build_cpt_jsonl.py
-rw-r--r-- 1 root root 237K Sep 14 00:51 train_cpt.jsonl
-rw-r--r-- 1 root root 60K Sep 14 00:51 val_cpt.jsonl
执行 PT LoRA 训练,采用 bf16 精度、不启用量化,使用 peft 后端运行。整个训练过程大约需要半小时完成,实际耗时会随数据集大小产生变化,本次训练得到的最优版本为 V7。
root@localhost:~/qwen# export TRITON_KERNEL_BUILD=0
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift pt \
--model /root/qwen/Qwen3.5-0.8B-Base \
--check_model false \
--tuner_type lora \
--dataset /root/qwen/train_cpt.jsonl \
--val_dataset /root/qwen/val_cpt.jsonl \
--torch_dtype bfloat16 \
--num_train_epochs 1 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 4 \
--learning_rate 1e-4 \
--lora_rank 16 \
--lora_alpha 32 \
--target_modules all-linear \
--max_length 2048 \
--warmup_ratio 0.05 \
--save_steps 100 \
--eval_steps 100 \
--logging_steps 10 \
--save_total_limit 2 \
--output_dir /root/qwen/output/output_cpt_qwen35_08b \
--seed 42
Train: 100%|████████████████████████████████████████| 241/241 [19:59<00:00, 3.63s/it]
Val: 100%|██████████████████████████████████████████| 482/482 [01:54<00:00, 4.21it/s]
[INFO:swift] last_model_checkpoint: /root/qwen/output/output_cpt_qwen35_08b/v7-20260914-012237/checkpoint-241
[INFO:swift] best_model_checkpoint: /root/qwen/output/output_cpt_qwen35_08b/v7-20260914-012237/checkpoint-241
[INFO:swift] images_dir: /root/qwen/output/output_cpt_qwen35_08b/v7-20260914-012237/images
[INFO:swift] End time of running main: 2026-09-14 01:44:38.834684
root@localhost:~/qwen# tree -d
.
|-- Qwen3.5-0.8B-Base
`-- output
`-- output_cpt_qwen35_08b
|-- v0-20260914-005354
|-- v1-20260914-005730
|-- v2-20260914-005847
| |-- images
| `-- runs
|-- v3-20260914-010038
| |-- images
| `-- runs
|-- v4-20260914-010107
| |-- images
| `-- runs
|-- v5-20260914-010316
| |-- images
| `-- runs
|-- v6-20260914-011234
| |-- images
| `-- runs
`-- v7-20260914-012237
|-- checkpoint-200
|-- checkpoint-241
|-- images
|-- last-checkpoint -> checkpoint-241
`-- runs
开展推理测试,以文本续写的方式做效果验证。CPT 属于文本续写任务,并非对话任务,测试重点仅用来检验模型是否掌握相关行业术语与领域行文逻辑;将输出结果与原始 Base 模型做对比,判断续写内容在领域相关性上是否得到提升。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift infer \
--model /root/qwen/Qwen3.5-0.8B-Base \
--adapters /root/qwen/output/output_cpt_qwen35_08b/v7-20260914-012237/checkpoint-241 \
--max_new_tokens 512 \
--temperature 0.7
[INFO:swift] Start time of running main: 2026-09-14 01:48:42.634761
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] Input `exit` or `quit` to exit the conversation.
[INFO:swift] Input `multi-line` to switch to multi-line input mode.
[INFO:swift] Input `reset-system` to reset the system and clear the history.
[INFO:swift] The current template only supports single-round dialogues.
<<< 你好
,请根据以下信息创建一个关于“基于文本的推荐系统”的学术论文,同时考虑文本相似度作为推荐系统中的重要因素。
--------------------------------------------------
<<< 很好
,接下来我们考虑如何将上述结果与量子化学模拟结合起来,特别是对于不同性质的分子。
--------------------------------------------------
执行 LoRA 合并操作,该步骤仅在需要模型部署,或是要使用合并完成的模型开展后续 SFT 训练时才进行。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift export \
--adapters /root/qwen/output/output_cpt_qwen35_08b/v7-20260914-012237/checkpoint-241 \
--merge_lora true \
--output_dir /root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged
[INFO:swift] model_kwargs: {'device_map': 'cuda:0', 'dtype': torch.bfloat16}
Loading weights: 100%|████████████████████████████████████████████| 473/473 [00:00<00:00, 1209.27it/s]
[INFO:swift] default_system: None
[INFO:swift] max_length: 262144
[INFO:swift] response_prefix: None
[INFO:swift] agent_template: None
[INFO:swift] norm_bbox: norm1000
[INFO:swift] Merge LoRA...
[INFO:swift] Saving merged weights...
Writing model shards: 100%|████████████████████████████████████████| 1/1 [00:02<00:00, 2.20s/it]
[INFO:swift] Successfully merged LoRA and saved in `/root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged`.
[INFO:swift] End time of running main: 2026-09-14 01:51:05.791494
root@localhost:~/qwen# ls -lh output/
total 8.0K
drwxr-xr-x 2 root root 4.0K Sep 14 01:51 Qwen3.5-0.8B-Base-CPT-Merged
drwxr-xr-x 10 root root 4.0K Sep 14 01:22 output_cpt_qwen35_08b
产出模型路径:/root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged,该领域基座模型将作为阶段 2 训练时--model参数所指定的模型。
三、监督指令微调(SFT-LoRA)
经过CPT预训练的模型具备领域知识储备,但无法理解人类指令、不会规范对话、不识别系统提示词。SFT监督指令微调核心目标是:教会模型接收用户自然语言指令、输出标准化领域问答、适配chat_template对话格式。
采用行业通用ShareGPT对话格式,包含system系统提示、human用户提问、gpt标准回答,同样按8:2分割训练集与验证集。
标准样本格式:
{
"conversations":
[
{"from":"system","value":"你是领域助手,基于领域知识回答用户问题。"},
{"from":"human","value":"解释合同生效条件"},
{"from":"gpt","value":"合同生效需要满足主体适格、内容合法、双方达成合意。"}
]
}
这里需要准备两份数据集,分别为训练集与验证集,对应文件路径:/root/qwen/train_sft.jsonl、/root/qwen/val_sft.jsonl。
root@localhost:~/qwen# python build_sft_jsonl.py
加载原始数据总行数:2407
对话样本构建完成,共 2407 条
训练集样本数:1925,验证集样本数:482
root@localhost:~/qwen# ls -lh
total 12M
drwxr-xr-x 2 root root 4.0K Sep 14 00:47 Qwen3.5-0.8B-Base
-rw-r--r-- 1 root root 2.8K Sep 14 00:44 build_cpt_jsonl.py
-rw-r--r-- 1 root root 3.0K Sep 14 01:52 build_sft_jsonl.py
drwxr-xr-x 4 root root 83 Sep 14 01:51 output
-rw-r--r-- 1 root root 237K Sep 14 00:51 train_cpt.jsonl
-rw-r--r-- 1 root root 2.0M Sep 14 01:52 train_sft.jsonl
-rw-r--r-- 1 root root 60K Sep 14 00:51 val_cpt.jsonl
-rw-r--r-- 1 root root 497K Sep 14 01:52 val_sft.jsonl
运行训练命令,在Qwen3.5-0.8B-Base-CPT-Merged这个模型基础上继续执行 SFT 训练流程,本轮训练大致耗时 30 分钟。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift sft \
--model /root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged \
--check_model false \
--tuner_type lora \
--dataset /root/qwen/train_sft.jsonl \
--val_dataset /root/qwen/val_sft.jsonl \
--torch_dtype bfloat16 \
--num_train_epochs 1 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 4 \
--learning_rate 2e-4 \
--lora_rank 16 \
--lora_alpha 32 \
--target_modules all-linear \
--max_length 2048 \
--warmup_ratio 0.05 \
--save_steps 100 \
--eval_steps 100 \
--logging_steps 10 \
--save_total_limit 2 \
--output_dir /root/qwen/output/output_sft_qwen35_08b \
--seed 42
[INFO:swift] Saving model checkpoint to /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-200
Train: 100%|██████████████████████████████████████████████| 241/241 [22:39<00:00, 4.11s/it]
Val: 100%|████████████████████████████████████████████████| 482/482 [02:08<00:00, 3.76it/s]
[INFO:swift] Saving model checkpoint to /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-241
Train: 100%|██████████████████████████████████████████████| 241/241 [24:48<00:00, 6.18s/it]
[INFO:swift] last_model_checkpoint: /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-241
[INFO:swift] best_model_checkpoint: /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-241
[INFO:swift] images_dir: /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/images
[INFO:swift] End time of running main: 2026-09-14 02:19:00.188422
训练完成后,开展推理测试,采用普通对话指令对模型进行验证。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift infer \
--model /root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged \
--adapters /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-241 \
--max_new_tokens 512 \
--temperature 0.7
[INFO:swift] Start time of running main: 2026-09-14 02:21:17.722209
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] Input `exit` or `quit` to exit the conversation.
[INFO:swift] Input `multi-line` to switch to multi-line input mode.
[INFO:swift] Input `reset-system` to reset the system and clear the history.
[INFO:swift] Input `clear` to clear the history.
<<< 你好
<think>
</think>
您好,请问有什么可以帮助您吗
--------------------------------------------------
<<< 回答的很好
<think>
</think>
您不必担心,我会根据您的情况提供详细的解答和建议。
--------------------------------------------------
测试要点:能不能听懂指令、回答是否符合领域知识、对话格式正常。
执行 LoRA 合并操作,该步骤在模型测试合格之后再进行。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift export \
--model /root/qwen/output/Qwen3.5-0.8B-Base-CPT-Merged \
--adapters /root/qwen/output/output_sft_qwen35_08b/v0-20260914-015402/checkpoint-241 \
--merge_lora true \
--output_dir /root/qwen/Qwen3.5-0.8B-SFT-Merged
[INFO:swift] Global seed set to 42
[INFO:swift] Start time of running main: 2026-09-14 02:22:04.693962
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] merge_device_map: None
[WARNING:swift] Please install the package: `pip install "decord" -U`.
[INFO:swift] model_kwargs: {'device_map': 'cuda:0', 'dtype': torch.bfloat16}
Loading weights: 100%|██████████████████████████████████████████████████████████████| 473/473 [00:00<00:00, 1350.90it/s]
[INFO:swift] default_system: None
[INFO:swift] max_length: 262144
[INFO:swift] response_prefix: None
[INFO:swift] agent_template: qwen3_5
[INFO:swift] norm_bbox: norm1000
[INFO:swift] Merge LoRA...
[INFO:swift] Saving merged weights...
Writing model shards: 100%|█████████████████████████████████████████████████████████| 1/1 [00:02<00:00, 2.25s/it]
[INFO:swift] Successfully merged LoRA and saved in `/root/qwen/Qwen3.5-0.8B-SFT-Merged`.
[INFO:swift] End time of running main: 2026-09-14 02:22:10.411946
root@localhost:~/qwen# ls -lh Qwen3.5-0.8B-SFT-Merged/
total 1.7G
-rw-r--r-- 1 root root 18K Sep 14 02:22 args.json
-rw-r--r-- 1 root root 7.6K Sep 14 02:22 chat_template.jinja
-rw-r--r-- 1 root root 2.6K Sep 14 02:22 config.json
-rw-r--r-- 1 root root 138 Sep 14 02:22 generation_config.json
-rw------- 1 root root 1.6G Sep 14 02:22 model.safetensors
-rw-r--r-- 1 root root 390 Sep 14 02:22 preprocessor_config.json
-rw-r--r-- 1 root root 1.2K Sep 14 02:22 processor_config.json
-rw-r--r-- 1 root root 20M Sep 14 02:22 tokenizer.json
-rw-r--r-- 1 root root 1.2K Sep 14 02:22 tokenizer_config.json
产出模型路径:/root/qwen/output/Qwen3.5-0.8B-SFT-Merged,将其作为阶段 3 Agent SFT 训练所用的基座模型。
四、工具调用微调(Agent SFT-LoRA)
SFT 模型只拥有基础问答能力,不能联动外部工具、接口以及数据库。Agent SFT 微调的目的,是训练模型自主判断何时触发工具调用:当问题需要实时数据或者外部资源支持时,模型输出标准化 JSON 格式的工具调用参数;如果依靠自身知识库就能够作答,则直接返回自然语言回复。
这里需要注意 Agent-SFT 的作用仅为让模型能够输出合规的工具调用 JSON 字符串,模型自身无法发起请求或者执行函数调用。
完整 Agent 业务链路流程:
-
- 用户提问送入模型
-
- 模型输出工具调用 JSON
-
- 业务后端 Python 代码解析 JSON,调用真实工具并拿到返回结果
-
- 把工具返回结果以tool角色回填对话历史
-
- 把完整对话再次喂给模型,模型整理自然语言答案返回用户
数据集存在硬性要求:样本需要混合两类,一类是需要调用工具的样本,另一类是无需调用工具、可以直接作答的样本。若数据集全部为工具调用样本,模型面对任意问题都会无脑输出 tool-call,丧失直接回答的能力。
数据集一般采用 ShareGPT 格式并新增 tool 角色,使用 Qwen 原生工具对话 messages 格式:
{"messages": [
{"role": "system", "content": "你是工具调用助手,可以使用search工具。search工具用来检索外部实时信息。当无法凭已有知识回答时,调用search。不需要工具就直接回答。"},
{"role": "user", "content": "北京今天天气怎么样?"},
{"role": "assistant", "content": "[{\"name\":\"search\",\"parameters\":{\"query\":\"北京今日天气\"}}]"},
{"role": "tool", "content": "{\"result\":\"北京今日晴,气温15~24℃,微风\"}"},
{"role": "assistant", "content": "北京今天天气晴朗,气温15到24摄氏度,有微风,适合外出。"}
]}
必须同时加入不需要调用工具直接回答的样本:
{"messages": [
{"role": "system", "content": "你是工具调用助手,可以使用search工具。search工具用来检索外部实时信息。当无法凭已有知识回答时,调用search。不需要工具就直接回答。"},
{"role": "user", "content": "1+1等于几?"},
{"role": "assistant", "content": "1+1等于2。"}
]}
生成数据集文件:/root/qwen/train_agent_sft.jsonl(训练集)与/root/qwen/train_agent_val.jsonl(验证集)。
执行训练命令,基于前面得到的基座模型开展 Agent SFT 训练。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift sft \
--model /root/qwen/Qwen3.5-0.8B-SFT-Merged \
--check_model false \
--tuner_type lora \
--dataset /root/qwen/train_agent_sft.jsonl \
--val_dataset /root/qwen/train_agent_val.jsonl \
--torch_dtype bfloat16 \
--num_train_epochs 1 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 4 \
--learning_rate 2e-4 \
--lora_rank 16 \
--lora_alpha 32 \
--target_modules all-linear \
--max_length 2048 \
--warmup_ratio 0.05 \
--save_steps 100 \
--eval_steps 100 \
--logging_steps 10 \
--save_total_limit 2 \
--output_dir /root/qwen/output/output_agent_sft_qwen35_08b \
--dataloader_num_workers 4 \
--dataloader_prefetch_factor 2 \
--seed 42
[INFO:swift] model_parameter_info: PeftModelForCausalLM: 863.8086M Params (10.8227M Trainable [1.2529%]), 0.0001M Buffers.
[INFO:swift] use_reentrant: True
[INFO:swift] The logging file will be saved in: /root/qwen/output/output_agent_sft_qwen35_08b/v3-20260914-023552/logging.jsonl
[INFO:swift] Successfully registered post_encode hook: ['PeftModelForCausalLM'].
Val: 100%|███████████████████████████████████████████████████| 5/5 [00:00<00:00, 5.37it/s]
Train: 100%|███████████████████████████████████████████████████| 3/3 [00:13<00:00, 4.64s/it]
[INFO:swift] last_model_checkpoint: /root/qwen/output/output_agent_sft_qwen35_08b/v3-20260914-023552/checkpoint-3
[INFO:swift] best_model_checkpoint: /root/qwen/output/output_agent_sft_qwen35_08b/v3-20260914-023552/checkpoint-3
[INFO:swift] images_dir: /root/qwen/output/output_agent_sft_qwen35_08b/v3-20260914-023552/images
[INFO:swift] End time of running main: 2026-09-14 02:36:15.498939
root@localhost:~/qwen# tree -d
.
|-- Qwen3.5-0.8B-Base
|-- Qwen3.5-0.8B-SFT-Merged
`-- output
|-- Qwen3.5-0.8B-Base-CPT-Merged
|-- output_agent_sft_qwen35_08b
| |-- v0-20260914-022419
| |-- v1-20260914-022515
| |-- v2-20260914-022752
| | |-- checkpoint-2
| | |-- images
| | |-- last-checkpoint -> checkpoint-2
| | `-- runs
| `-- v3-20260914-023552
| |-- checkpoint-3
| |-- images
| |-- last-checkpoint -> checkpoint-3
| `-- runs
|-- output_cpt_qwen35_08b
| |-- v0-20260914-005354
| |-- v1-20260914-005730
| |-- v2-20260914-005847
| | |-- images
| | `-- runs
| |-- v3-20260914-010038
| | |-- images
| | `-- runs
| |-- v4-20260914-010107
| | |-- images
| | `-- runs
| |-- v5-20260914-010316
| | |-- images
| | `-- runs
| |-- v6-20260914-011234
| | |-- images
| | `-- runs
| `-- v7-20260914-012237
| |-- checkpoint-200
| |-- checkpoint-241
| |-- images
| |-- last-checkpoint -> checkpoint-241
| `-- runs
`-- output_sft_qwen35_08b
`-- v0-20260914-015402
|-- checkpoint-200
|-- checkpoint-241
|-- images
|-- last-checkpoint -> checkpoint-241
`-- runs
训练完成后开展 Agent 推理测试,重点验证模型的工具调用能力,需要规避 JSON 输出乱码问题。
当前输入文本量偏少,少量样本容易出现工具误触发、JSON 缺少引号、json 截断、多轮 tool 调用状态错乱,Agent-SFT 建议样本量至少几千条,工具调用样本和直接回答样本控制比例(例如 1:1 或者 6:4)
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift infer \
--model /root/qwen/Qwen3.5-0.8B-SFT-Merged \
--adapters /root/qwen/output/output_agent_sft_qwen35_08b/v2-20260914-022752/checkpoint-2 \
--max_new_tokens 512 \
--temperature 0.25
[INFO:swift] Start time of running main: 2026-09-14 02:38:29.684566
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] Input `exit` or `quit` to exit the conversation.
[INFO:swift] Input `multi-line` to switch to multi-line input mode.
[INFO:swift] Input `reset-system` to reset the system and clear the history.
[INFO:swift] Input `clear` to clear the history.
<<< 北京今天天气怎么样?
<think>
</think>
北京今天天气晴,气温22℃,湿度50,紫外线指数为2。
--------------------------------------------------
执行 LoRA 合并操作,待模型测试合格后再运行,合并后的模型将作为 DPO 训练阶段的基座。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift export \
--model /root/qwen/Qwen3.5-0.8B-SFT-Merged \
--adapters /root/qwen/output/output_agent_sft_qwen35_08b/v2-20260914-022752/checkpoint-2 \
--merge_lora true \
--output_dir /root/qwen/Qwen3.5-0.8B-Agent-SFT-Merged
Loading weights: 100%|█████████████████████████████████████| 473/473 [00:00<00:00, 1325.33it/s]
Writing model shards: 100%|████████████████████████████████| 1/1 [00:02<00:00, 2.18s/it]
[INFO:swift] Successfully merged LoRA and saved in `/root/qwen/Qwen3.5-0.8B-Agent-SFT-Merged`.
[INFO:swift] End time of running main: 2026-09-14 02:40:23.453382
root@localhost:~/qwen# ls -lh Qwen3.5-0.8B-Agent-SFT-Merged/
total 1.7G
-rw-r--r-- 1 root root 18K Sep 14 02:40 args.json
-rw-r--r-- 1 root root 7.6K Sep 14 02:40 chat_template.jinja
-rw-r--r-- 1 root root 2.6K Sep 14 02:40 config.json
-rw-r--r-- 1 root root 138 Sep 14 02:40 generation_config.json
-rw------- 1 root root 1.6G Sep 14 02:40 model.safetensors
-rw-r--r-- 1 root root 390 Sep 14 02:40 preprocessor_config.json
-rw-r--r-- 1 root root 1.2K Sep 14 02:40 processor_config.json
-rw-r--r-- 1 root root 20M Sep 14 02:40 tokenizer.json
-rw-r--r-- 1 root root 1.2K Sep 14 02:40 tokenizer_config.json
产出模型路径:/root/qwen/output/Qwen3.5-0.8B-Agent-SFT-Merged,将其作为阶段 3 Agent SFT 训练所用的基座模型。
五、偏好对齐(DPO-LoRA)
DPO(Direct Preference Optimization,直接偏好优化),属于 RLHF 轻量方案,不需要训练 reward 奖励模型。输入是成对偏好样本:同一个用户 prompt,一条高质量正确输出 chosen,一条差的错误输出 rejected。训练让模型提升生成 chosen 的概率,压低生成 rejected 的概率,矫正模型行为。
经过 Agent‑SFT 之后,模型已经学会输出工具调用 JSON,但依然存在很多行为缺陷:
-
- 不该调用工具的时候,错误触发 search 工具;
-
- 输出 JSON 存在语法错误;
-
- 回答啰嗦、重复、编造幻觉信息。
数据集格式,文件为/root/qwen/train_dpo.jsonl与/root/qwen/train_dpo_val.jsonl。
DPO 训练使用成对样本,包含 prompt 提示词、chosen 优选正确输出、rejected 劣选错误输出。
{
"messages": [
{
"role": "system",
"content": "你是工具调用助手,可以使用search工具。search工具用来检索外部实时信息。当无法凭已有知识回答时,调用search。不需要工具就直接回答。"
},
{
"role": "user",
"content": "查询青岛今日气温和青岛今日湿度"
}
],
"chosen_response": "[{\"name\":\"search\",\"parameters\":{\"query\":\"青岛今日气温和湿度\"}}]",
"rejected_response": "[{\"name\":\"search\",\"parameters\":{\"query\":\"青岛今日气温\"}}],[{\"name\":\"search\",\"parameters\":{\"query\":\"青岛今日湿度\"}}]"
}
运行 DPO 训练命令,基于Qwen3.5-0.8B-Agent-SFT-Merged基座开展 DPO 偏好对齐训练。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift rlhf \
--rlhf_type dpo \
--model /root/qwen/Qwen3.5-0.8B-Agent-SFT-Merged \
--check_model false \
--tuner_type lora \
--dataset /root/qwen/train_dpo.jsonl \
--val_dataset /root/qwen/train_dpo_val.jsonl \
--torch_dtype bfloat16 \
--num_train_epochs 1 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 4 \
--learning_rate 5e-5 \
--lora_rank 16 \
--lora_alpha 32 \
--target_modules all-linear \
--max_length 2048 \
--warmup_ratio 0.05 \
--save_steps 100 \
--eval_steps 100 \
--logging_steps 10 \
--save_total_limit 2 \
--beta 0.1 \
--output_dir /root/qwen/output_agent_dpo_qwen35_08b \
--seed 42
[INFO:swift] model_parameter_info: PeftModelForCausalLM: 863.8086M Params (10.8227M Trainable [1.2529%]), 0.0001M Buffers.
[INFO:swift] use_reentrant: True
[INFO:swift] The logging file will be saved in: /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/logging.jsonl
[INFO:swift] Successfully registered post_encode hook: ['PeftModelForCausalLM'].
Train: 100%|███████████████████████████████████████████████████████████████| 1/1 [00:02<00:00, 2.56s/it]
Val: 100%|████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 221.96it/s]
[INFO:swift] last_model_checkpoint: /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/checkpoint-1
[INFO:swift] best_model_checkpoint: /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/checkpoint-1
[INFO:swift] images_dir: /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/images
[INFO:swift] End time of running main: 2026-09-14 02:57:21.987156
root@localhost:~/qwen# tree -d
.
|-- Qwen3.5-0.8B-Agent-SFT-Merged
|-- Qwen3.5-0.8B-Base
|-- Qwen3.5-0.8B-SFT-Merged
|-- output
| |-- Qwen3.5-0.8B-Base-CPT-Merged
| |-- output_agent_sft_qwen35_08b
| | |-- v0-20260914-022419
| | |-- v1-20260914-022515
| | |-- v2-20260914-022752
| | | |-- checkpoint-2
| | | |-- images
| | | |-- last-checkpoint -> checkpoint-2
| | | `-- runs
| | `-- v3-20260914-023552
| | |-- checkpoint-3
| | |-- images
| | |-- last-checkpoint -> checkpoint-3
| | `-- runs
| |-- output_cpt_qwen35_08b
| | |-- v0-20260914-005354
| | |-- v1-20260914-005730
| | |-- v2-20260914-005847
| | | |-- images
| | | `-- runs
| | |-- v3-20260914-010038
| | | |-- images
| | | `-- runs
| | |-- v4-20260914-010107
| | | |-- images
| | | `-- runs
| | |-- v5-20260914-010316
| | | |-- images
| | | `-- runs
| | |-- v6-20260914-011234
| | | |-- images
| | | `-- runs
| | `-- v7-20260914-012237
| | |-- checkpoint-200
| | |-- checkpoint-241
| | |-- images
| | |-- last-checkpoint -> checkpoint-241
| | `-- runs
| `-- output_sft_qwen35_08b
| `-- v0-20260914-015402
| |-- checkpoint-200
| |-- checkpoint-241
| |-- images
| |-- last-checkpoint -> checkpoint-241
| `-- runs
`-- output_agent_dpo_qwen35_08b
|-- v0-20260914-024708
|-- v1-20260914-024843
|-- v2-20260914-025000
|-- v3-20260914-025101
|-- v4-20260914-025430
|-- v5-20260914-025601
`-- v6-20260914-025709
|-- checkpoint-1
|-- images
|-- last-checkpoint -> checkpoint-1
`-- runs
root@localhost:~/qwen# ls -lh /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/checkpoint-1
total 125M
-rw-r--r-- 1 root root 5.2K Sep 14 02:57 README.md
-rw-r--r-- 1 root root 1.2K Sep 14 02:57 adapter_config.json
-rw------- 1 root root 42M Sep 14 02:57 adapter_model.safetensors
-rw-r--r-- 1 root root 67 Sep 14 02:57 additional_config.json
-rw-r--r-- 1 root root 23K Sep 14 02:57 args.json
-rw-r--r-- 1 root root 83M Sep 14 02:57 optimizer.pt
-rw-r--r-- 1 root root 15K Sep 14 02:57 rng_state.pth
-rw-r--r-- 1 root root 1.4K Sep 14 02:57 scheduler.pt
-rw-r--r-- 1 root root 1.8K Sep 14 02:57 trainer_state.json
-rw-r--r-- 1 root root 7.2K Sep 14 02:57 training_args.bin
完成 DPO 训练后,执行推理测试,验证模型经过偏好对齐后的实际效果。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift infer \
--model /root/qwen/Qwen3.5-0.8B-Agent-SFT-Merged \
--adapters /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/checkpoint-1 \
--max_new_tokens 512 \
--temperature 0.25
[INFO:swift] Start time of running main: 2026-09-14 02:59:49.806803
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] Input `exit` or `quit` to exit the conversation.
[INFO:swift] Input `multi-line` to switch to multi-line input mode.
[INFO:swift] Input `reset-system` to reset the system and clear the history.
[INFO:swift] Input `clear` to clear the history.
<<< 你好
<think>
</think>
您好,请问有什么我可以帮您吗
--------------------------------------------------
测试重点:对比 DPO 训练前后,工具误触发率、JSON 错误率是否下降。
执行 DPO LoRA 合并操作,合并完成后得到最终成品模型。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift export \
--adapters /root/qwen/output_agent_dpo_qwen35_08b/v6-20260914-025709/checkpoint-1 \
--merge_lora true \
--output_dir /root/qwen/Qwen3.5-0.8B-Agent-Final-Merged
[INFO:swift] Global seed set to 42
[INFO:swift] Start time of running main: 2026-09-14 03:02:55.548430
[INFO:swift] swift.__version__: 4.6.0.dev0
[INFO:swift] merge_device_map: None
Loading weights: 100%|████████████████████████████████████████████| 473/473 [00:00<00:00, 1333.95it/s]
Writing model shards: 100%|███████████████████████████████████████| 1/1 [00:02<00:00, 2.37s/it]
[INFO:swift] Successfully merged LoRA and saved in `/root/qwen/Qwen3.5-0.8B-Agent-Final-Merged`.
[INFO:swift] End time of running main: 2026-09-14 03:03:01.458472
root@localhost:~/qwen# ls -lh /root/qwen/Qwen3.5-0.8B-Agent-Final-Merged/
total 1.7G
-rw-r--r-- 1 root root 23K Sep 14 03:03 args.json
-rw-r--r-- 1 root root 7.6K Sep 14 03:03 chat_template.jinja
-rw-r--r-- 1 root root 2.6K Sep 14 03:02 config.json
-rw-r--r-- 1 root root 138 Sep 14 03:02 generation_config.json
-rw------- 1 root root 1.6G Sep 14 03:03 model.safetensors
-rw-r--r-- 1 root root 390 Sep 14 03:03 preprocessor_config.json
-rw-r--r-- 1 root root 1.2K Sep 14 03:03 processor_config.json
-rw-r--r-- 1 root root 20M Sep 14 03:03 tokenizer.json
-rw-r--r-- 1 root root 1.2K Sep 14 03:03 tokenizer_config.json
最终产出模型文件为Qwen3.5-0.8B-Agent-Final-Merged,该模型可直接转换为 GGUF 格式。
root@localhost:~/qwen# CUDA_VISIBLE_DEVICES=0 swift export \
--model /root/qwen/Qwen3.5-0.8B-Agent-Final-Merged \
--export_format gguf \
--gguf_quantization q4_k_m \
--output_dir /root/qwen/gguf_output
说明:常用量化:q4_k_m 平衡速度与效果;q5_k_m 精度更高;q2_k 体积最小。
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

浙公网安备 33010602011771号