实战微调gpt-oss-20b:Unsloth训练到Ollama部署全流程

用 QLoRA 在单张消费级显卡上微调 20B 参数模型,并解决 Harmony 模板导致 Ollama 无法正常推理的部署难题。
开发者 Khadim Hussain 记录了用 Unsloth 对 OpenAI 开源的 gpt-oss-20b(21B MoE 模型)进行 STEM 推理微调的完整流程。训练层面,QLoRA 将显存需求从 BF16 LoRA 的 44GB 压缩至约 14GB,使单张消费级显卡成为可行选择;4260 条带思维链的 STEM 问答数据训练一轮后,评估损失(0.837)低于训练损失(1.087),未见明显过拟合。部署层面,最大的坑是 gpt-oss 专属的 Harmony 聊天模板——必须将 `<|return|>` 设为停止 token,否则 Ollama 会输出乱码或无限生成。文章还指出 `ollama run hf.co` 不读取仓库 Modelfile 而依赖 GGUF 内嵌模板,以及 vLLM 需精确匹配 transformers 4.57.3 等版本陷阱。下载统计显示 GGUF 是最受用户欢迎的格式,建议优先发布带有正确模板的 GGUF 文件。

把一个 200 亿参数的大模型放在单张消费级显卡上微调,并最终跑进 Ollama 本地运行,这件事如今已不再是实验室专属。开发者 Khadim Hussain 用 Unsloth 对 OpenAI 开源的 gpt-oss-20b 做了一次面向 STEM 推理任务的微调,并把踩过的坑和可复用的配置完整记录了下来。核心结论很直接:训练本身用 QLoRA 只需约 14 GB 显存就能跑,真正让人头疼的反而是部署阶段的聊天模板(chat template)——如果没处理好 Harmony 格式,Ollama 要么输出乱码,要么永远停不下来。
QLoRA 微调配置:单卡也能训 20B
gpt-oss-20b 是一个 21B 参数的混合专家(MoE)模型。作者采用 QLoRA 方法,把基础权重量化到 4-bit,只训练一个小体积的 LoRA 适配器,从而让这个规模的模型塞进单张消费级显卡。
关键训练参数如下:
- 方法:QLoRA,4-bit 基础权重
- LoRA rank / alpha:32 / 64
- 学习率:1e-4
- 批大小:1,梯度累积 16
- 优化器:AdamW 8-bit
- 训练轮数:1 epoch
- 数据:4260 条训练样本 + 474 条评估样本,均为带思维链(chain-of-thought)的 STEM 问答
- 结果:训练损失 1.087,评估损失 0.837
- 框架:Unsloth + TRL
从损失曲线看,评估损失(0.837)低于训练损失(1.087),说明模型在验证集上泛化良好,没有明显过拟合迹象。完整训练配置被放在作者的开源工具包 kllm 的 configs/gpt_oss_20b.yaml 中。
QLoRA(Quantized Low-Rank Adaptation)是在 LoRA 基础上进一步压缩显存占用的技术。LoRA 的核心思路是冻结预训练模型的原始权重,只训练两个低秩矩阵(rank 分解),参数量可压缩到原始模型的不足 1%。QLoRA 在此之上引入 4-bit NormalFloat(NF4)量化,将冻结的基础权重从 16-bit 压缩到 4-bit 存储,同时为量化误差引入双重量化(Double Quantization)和分页优化器(Paged Optimizers)来维持训练稳定性。rank 值决定 LoRA 矩阵的「宽度」,rank=32 意味着每个被替换的权重矩阵被分解为两个秩为 32 的矩阵;alpha 是缩放系数,通常设为 rank 的 2 倍(此处 64)以控制适配器对原始权重的影响幅度。这套组合使得原本需要多张 A100 的 20B 级别模型训练,降到了消费级单卡可承受的范围。
微调 gpt-oss-20b 到底需要多少显存
这是最常被问到的问题。按照 Unsloth 官方 gpt-oss 指南的说法,用 QLoRA 微调 gpt-oss-20b 约需 14 GB 显存,并建议至少配备 16 GB 以保证训练稳定。作为对比,如果直接在未量化的 BF16 权重上做 LoRA,则需要约 44 GB 显存——这正是 QLoRA 成为单卡实际选择的原因。
作者本人验证的环境是 RTX 5090(32 GB),系统为 Ubuntu 24.04,搭配 CUDA 12.8 工具链、Python 3.12.3、PyTorch 2.9.1、Unsloth 2026.1.4 以及 transformers 4.57.3。
这里有一个容易被忽视的版本坑:vLLM 0.15.0 需要精确匹配 transformers 4.57.3,其他版本会直接报导入错误。作者给出的安装顺序是先装 vLLM,再装 Unsloth 相关依赖,最后强制固定 transformers 版本:
uv pip install -U vllm --torch-backend=cu128 # RTX 40 系列用 cu121
uv pip install unsloth unsloth_zoo bitsandbytes
uv pip install --force-reinstall "transformers==4.57.3"
一次训练,导出三种格式
训练完成后,同一个模型对象可以导出三种部署形态,分别对应不同的使用场景:
GGUF(GPT-Generated Unified Format)是 llama.cpp 项目在 2023 年引入的模型序列化格式,设计目标是将模型权重、分词器配置、元数据(包括 chat template)打包进单个文件,方便在 CPU 和消费级 GPU 上高效推理。它取代了早期的 GGML 格式,支持多种量化方案,命名规范中 Q4_K_M 表示 4-bit 量化、K-Quant 方法、M(medium)精度档位。K-Quant 是一种混合精度策略,对模型中更重要的层(如注意力层)保留更高精度,对其余层压缩更激进,相比均匀量化在相同文件大小下通常有更好的质量。Ollama、LM Studio、Jan 等本地推理工具均以 GGUF 为主要格式,这也解释了为什么下载数据中 GGUF 的数量远超其他格式。
# 1. LoRA 适配器(约 61 MB):适合已在运行基础模型的人
model.save_pretrained(output_dir)
tokenizer.save_pretrained(output_dir)
# 2. 合并后的 16-bit 模型(约 41 GB):供 Transformers 或 vLLM 使用,无需处理适配器
model.save_pretrained_merged(f"{output_dir}-merged", tokenizer, save_method="merged_16bit")
# 3. GGUF 格式:供 llama.cpp、Ollama、LM Studio 使用,每种量化调用一次
model.save_pretrained_gguf("gguf/gpt-oss-20b-stem", tokenizer, quantization_method="q4_k_m")
不同量化方案的文件大小差异明显:f16 为 41.9 GB,Q8_0 为 22.3 GB,Q4_K_M 仅 15.8 GB。如果 GGUF 导出步骤遇到内存不足,Unsloth 文档建议把 maximum_memory_usage 从默认的 0.75 降到 0.5 左右。
真正会出问题的:Harmony 聊天模板
这是整篇实践里最值得记住的一点。gpt-oss 不使用 ChatML,它是在 OpenAI 的 Harmony 格式上训练的。在这套格式里,每条消息都被特殊 token 包裹,助手会在不同的「通道」上输出内容:
analysis:模型的思维链,终端用户不应看到final:最终答案commentary:工具调用
关键细节在于停止 token:一个最终答案以 <|return|> 结尾,OpenAI 文档明确称其为「表示应当停止推理的有效停止符」;而保留在对话历史中的消息以 <|end|> 结尾,监督训练的目标则应以 <|return|> 结尾。OpenAI 的模型卡说得很直白——这些模型「只应配合 harmony 格式使用,否则无法正确工作」。
换句话说,部署时的模板必须和训练时一致。Unsloth 文档指出,模板不匹配是模型在其他平台上输出乱码或无限生成的最常见原因;而 <|return|> 必须被设为停止 token,否则生成会越过答案继续跑下去。值得一提的是,「如何为微调后的 gpt-oss 配置 Ollama 模板」这个问题,目前在 OpenAI 官方论坛上仍是未解帖,说明它确实是普遍痛点。
聊天模板(chat template)是大模型推理中一个容易被忽视的基础设施层。模型在训练时,每条对话消息都按特定格式被拼成一段纯文本序列,其中用特殊 token 标记角色边界和消息边界。推理时必须用完全相同的格式构造输入,模型才能「认出」对话结构并产生预期输出——这是因为模型本质上只看到 token 序列,格式不一致就等于给了它从未见过的输入分布。最常见的格式包括 ChatML(<|im_start|> / <|im_end|>)、Llama 的 [INST] 标记、Mistral 的 [INST]/[/INST] 等,而 OpenAI 的 Harmony 格式自成一套,使用 <|start|>、<|message|>、<|end|> 和 <|return|> 这组私有 token。停止 token 的作用是告诉推理引擎「此处应当截断输出」,若停止 token 设置错误,模型会在生成完合法答案后继续产生下一轮对话的内容,表现为「停不下来」。
可用的 Ollama Modelfile
作者给出的、随 GGUF 仓库一起发布的 Modelfile 是这样的:
FROM ./gpt-oss-20b-finetuned-q8_0.gguf
TEMPLATE """<|start|>system<|message|>You are a helpful assistant trained by OpenAI.
Reasoning: medium
# Valid channels: analysis, commentary, final. Channel must be included for every message.<|end|><|start|>user<|message|>{{ .Prompt }}<|end|><|start|>assistant"""
PARAMETER stop "<|return|>"
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 4096
PARAMETER num_predict 2048
其中 Reasoning: medium 控制模型在 analysis 通道里思考多少才给出答案。Harmony 接受 low、medium、high 三档,默认是 medium。Ollama 会把 analysis 通道显示为「Thinking...」,所以追求简短快速回答时可以设成 low。改动后记得重新执行 ollama create。
ollama run hf.co 还是 Modelfile?
两种加载方式有一个关键区别。用 Modelfile 时,生效的是你亲手写的模板:
ollama create gpt-oss-20b-stem -f Modelfile
ollama run gpt-oss-20b-stem
Ollama 也能直接从 Hugging Face 拉取:
ollama run hf.co/khadim-hussain/gpt-oss-20b-stem-reasoning-GGUF:Q4_K_M
但这条路径不会读取仓库里的 Modelfile。根据 Hugging Face 的 Ollama 文档,它使用的是 GGUF 文件里 tokenizer.chat_template 元数据中存储的模板,或仓库里名为 template 的文件。量化标签大小写不敏感,不带标签时 Ollama 默认选 Q4_K_M。因此如果你要发布一个 Harmony 模型,务必在仓库里放一个 template 文件,或明确引导用户使用 Modelfile。
大家实际会下载哪种格式
作者还统计了 Hugging Face 上的下载分布(截至 2026 年 10 月的历史总量),数据颇有参考价值:
| 格式 | gpt-oss-20b | Qwen3-14B |
|---|---|---|
| GGUF | 513 | 274 |
| 合并 16-bit | 70 | 42 |
| LoRA 适配器 | 46 | 51 |
结论很清楚:大多数人想要的是一个能直接在自己机器上运行的文件。如果你只发布一种格式,就发带可用模板的 GGUF;而 LoRA 适配器则值得为那些想继续训练的人额外附上。
常见故障排查
作者在 kllm 的排查指南里记录了几类典型失败:
- 训练进程无错误直接退出:几乎都是显存不足(OOM),可用
dmesg确认 - 报
UnboundLocalError且提到 dropout:把lora_dropout设为 0.0 ImportError: cannot import name ... from 'transformers':强制重装transformers==4.57.3Python.h: No such file or directory:安装python3.12-dev
整套流程的价值不在于某个单一技巧,而在于它把「训练能跑」和「部署能用」这两件常被割裂看待的事串成了一条完整链路。对想在本地落地开源大模型的开发者来说,Harmony 模板这个坑尤其值得提前记在心里。
相关推荐

Claude Code+Codex多智能体系统实测:缓存率98%背后的真问题
开发者公布Claude Code+Codex多智能体系统7天实测:缓存率98%、输入输出比354:1,作者却卡在组织调度与输出比例,并追问行业基准与成本度量方法。

Cursor SDK 新功能:实时操控运行中的 AI 代理
Cursor SDK 新增 run.steer() 功能,允许开发者在 AI 代理运行中实时注入消息,调整执行方向。子代理遇 steer 时自动转入后台继续任务,为 AI 编程工作流带来更灵活的运行时干预能力。

如何评估AI生成的研究摘要?三个关键维度
AI生成的研究摘要读起来流畅,但事实未必可靠。本文基于Reddit讨论,梳理评估AI研究摘要系统的三个核心维度:来源可追溯性、事实一致性与不确定性处理,并探讨其对深度学习从业者的实践意义。