使用 Swift 微调 Qwen3-4b 模型:TaoToken 统一 Key 接入与 config.toml 配置实战
1. 微调 Qwen3-4b 时Key 和配置为什么总在打架如果你正在用 Swiftms-swift微调 Qwen3-4b大概率会遇到这样一个尴尬局面训练脚本、推理脚本、评测脚本、WebUI 启动脚本各写各的模型路径散落在四五个文件里而一旦接入外部大模型 API 做数据清洗、答案蒸馏或者自动评测API Key 又开始到处复制粘贴。今天在train.sh里写一个 Key明天在eval.py里再写一个后天同事拉走代码发现跑不起来因为 Key 没跟着走。这个问题的本质不是 Swift 不好用而是「训练框架」和「模型服务接入」这两件事被混在了一起。Swift 负责的是 Qwen3-4b 的 LoRA/QLoRA 微调、推理、合并、量化它本身不关心你从哪里调用外部模型而数据构造、自动打分、多模型对比这些环节又确实需要调用大模型 API。于是 Key 分散、base_url 不统一、模型名写错、超时参数各写一套就成了工程化落地时最烦人的部分。我这次的做法是把「模型服务接入」抽出来统一走 TaoToken 的 Key再用一份config.toml把训练、推理、评测、外部调用四类配置收口。这样 Swift 侧只关心--model、--dataset、--output_dir这些训练参数而所有对外请求的地址、Key、模型名、超时、重试都从同一个配置文件读取。下面按「先接 Key再写 config再跑训练再验证」的顺序走一遍你可以直接照着改。2. TaoToken 统一 Key 接入把分散的凭证收成一处TaoToken 在这里扮演的角色是「统一的大模型 API 入口」。你不需要在每台机器、每个脚本里维护不同的 Key而是拿一个 Key通过统一的 base_url 去调用不同模型。对 Swift 微调场景来说最典型的用途有三个一是用外部模型批量生成或清洗 SFT 数据二是训练完成后做自动评测打分三是把微调后的 Qwen3-4b 和基线模型放在一起对比。第一步是拿到 Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。创建时建议按用途命名比如swift-data-clean、swift-eval方便后面排查是哪个环节在消耗额度。拿到 Key 之后不要直接写进训练脚本。正确做法是写进环境变量或本地配置文件然后让config.toml去引用。API 的基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数直接作为 OpenAI 兼容的 base_url 使用即可。如果你用的是 OpenAI SDK 或兼容 OpenAI 协议的客户端把base_url指向它api_key填你的 Key就能调用。这里有个容易踩的坑很多人把 Key 写进train.sh后提交到 Git结果 Key 泄露。我的建议是本地用.env或系统环境变量config.toml里只写${TAOTOKEN_API_KEY}这样的占位符运行时再注入。这样代码可以安全地分享给同事Key 留在各自机器上。3. 可复制的 config.toml 骨架与 Swift 训练配置下面这份config.toml是我实际在用的骨架分成[api]、[train]、[infer]、[eval]四段。你可以直接复制把模型路径和数据集路径改成自己的。# config.toml [api] base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} default_model qwen3-4b timeout 120 max_retries 3 [train] model Qwen/Qwen3-4b train_type lora dataset dataset/dataset-train.json torch_dtype bfloat16 num_train_epochs 3 per_device_train_batch_size 1 per_device_eval_batch_size 1 learning_rate 1e-4 lora_rank 8 lora_alpha 32 target_modules all-linear gradient_accumulation_steps 16 eval_steps 50 save_steps 50 save_total_limit 2 logging_steps 5 max_length 2048 output_dir output warmup_ratio 0.05 dataloader_num_workers 4 model_author swift model_name swift-robot [infer] adapters output/vx-xxx/checkpoint-xxx stream true temperature 0 max_new_tokens 2048 infer_backend pt [eval] judge_model qwen3-4b judge_base_url https://taotoken.net/api judge_api_key ${TAOTOKEN_API_KEY}这份配置的关键点是[api]和[eval]里的base_url都指向 TaoTokenKey 用环境变量占位[train]里的参数和 Swift 命令行一一对应方便脚本读取。接下来把 Swift 训练命令和这份配置对齐。安装 ms-swift 很简单pip install ms-swift -U然后基于 Qwen3-4b 做 LoRA 微调。下面这条命令在 Windows 下用^换行Linux/macOS 换成\set CUDA_VISIBLE_DEVICES0 swift sft ^ --model Qwen/Qwen3-4b ^ --train_type lora ^ --dataset dataset/dataset-train.json ^ --torch_dtype bfloat16 ^ --num_train_epochs 3 ^ --per_device_train_batch_size 1 ^ --per_device_eval_batch_size 1 ^ --learning_rate 1e-4 ^ --lora_rank 8 ^ --lora_alpha 32 ^ --target_modules all-linear ^ --gradient_accumulation_steps 16 ^ --eval_steps 50 ^ --save_steps 50 ^ --save_total_limit 2 ^ --logging_steps 5 ^ --max_length 2048 ^ --output_dir output ^ --warmup_ratio 0.05 ^ --dataloader_num_workers 4 ^ --model_author swift ^ --model_name swift-robot--model_author和--model_name只有在数据集包含swift/self-cognition时才生效普通自定义数据集可以不加。默认从 ModelScope 下载模型和数据集如果你想用 HuggingFace加--use_hf true。自定义数据集的格式是 JSONL每行一个样本结构如下{messages: [{role: system, content: system}, {role: user, content: query1}, {role: assistant, content: response1}]} {messages: [{role: system, content: system}, {role: user, content: query1}, {role: assistant, content: response1}]}如果你要用 TaoToken 上的模型来批量生成这些response可以写一个 Python 脚本读取config.toml用 OpenAI SDK 调用。这样数据构造和训练就通过同一份配置串起来了。4. 验证请求微调前后各跑一次确认链路通配置写完先别急着开训。第一步是验证 TaoToken 的 Key 能不能正常调用。用 curl 或 Python 都行Python 更贴近后面脚本的写法import os from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) resp client.chat.completions.create( modelqwen3-4b, messages[{role: user, content: 用一句话说明什么是 LoRA 微调}], temperature0, ) print(resp.choices[0].message.content)如果返回正常文本说明 Key 和 base_url 没问题。这一步失败的话先检查环境变量是否真的注入再检查 Key 是否复制完整。第二步是验证 Swift 训练后的推理。训练完成后output目录下会有类似vx-xxx/checkpoint-xxx的文件夹。用交互式命令行推理CUDA_VISIBLE_DEVICES0 swift infer \ --adapters output/vx-xxx/checkpoint-xxx \ --stream true \ --temperature 0 \ --max_new_tokens 2048因为 adapters 文件夹里包含args.jsonSwift 会自动读取模型和系统参数不需要再指定--model。如果你想显式指定基础模型可以这样CUDA_VISIBLE_DEVICES0 swift infer \ --model Qwen/Qwen3-4b \ --adapters output/vx-xxx/checkpoint-xxx \ --stream true \ --infer_backend pt \ --temperature 0 \ --max_new_tokens 2048想用 vLLM 加速并合并 LoRACUDA_VISIBLE_DEVICES0 swift infer \ --adapters output/vx-xxx/checkpoint-xxx \ --stream true \ --merge_lora true \ --infer_backend vllm \ --max_model_len 8192 \ --temperature 0 \ --max_new_tokens 2048第三步是合并模型并做最终验证。合并命令CUDA_VISIBLE_DEVICES0 swift export \ --model Qwen/Qwen3-4b \ --adapters output/v18-20250512-205806/checkpoint-123 \ --max_length 2048 \ --merge_lora true合并后用合并后的权重再推理一次输入数据集里的问题看回答是否符合预期CUDA_VISIBLE_DEVICES0 swift infer \ --model output/v18-20250512-205806/checkpoint-123-merged \ --stream true \ --temperature 0 \ --max_new_tokens 2048如果你更喜欢 WebUI可以启动CUDA_VISIBLE_DEVICES0 swift app \ --model Qwen/Qwen3-4b \ --adapters output/qwen3-4b-lora \ --stream true \ --infer_backend pt \ --max_length 2048 \ --lang zh微调前后的对比验证建议固定同一批测试问题分别用基座模型和合并后的模型跑一遍把输出并排看。这一步用 TaoToken 的模型做自动打分也可以把两组回答和参考答案一起发给评测模型让它按维度打分。5. 本篇常见错排查报错一openai.AuthenticationError或 401。九成是 Key 没注入或复制时带了空格。先echo $TAOTOKEN_API_KEY确认环境变量存在再检查config.toml里是不是写成了字面量${TAOTOKEN_API_KEY}而没有做替换。如果你用的是 Python 读取 toml记得手动做环境变量展开。报错二--adapters路径找不到。Swift 的 checkpoint 目录名带时间戳每次训练都不一样。不要硬编码用ls output看一下实际目录名。另外--adapters指向的是 checkpoint 文件夹本身不是它的父目录。报错三推理时显存不够。Qwen3-4b 用 bfloat16 加载大约需要 8GB 以上显存加上 KV Cache 和 vLLM 的预分配会更高。如果显存紧张把--infer_backend从vllm换回pt或者降低--max_model_len。训练侧则可以把--per_device_train_batch_size保持 1靠--gradient_accumulation_steps堆等效 batch。报错四数据集格式不对导致训练启动即报错。自定义数据集必须是 JSONL每行一个完整 JSONmessages里的 role 只能是 system/user/assistant。常见错误是用了 JSON 数组而不是 JSONL或者一行里塞了多个样本。用head -n 1 dataset/dataset-train.json | python -m json.tool验证第一行能否解析。报错五TaoToken 调用超时。默认超时 120 秒长文本生成可能不够。在config.toml的[api]段把timeout调大同时确认max_retries至少为 2避免偶发网络抖动直接失败。批量数据清洗时建议加并发控制不要一次性打太多请求。报错六合并后的模型回答异常。先确认--merge_lora true是否真的执行成功再检查合并时用的 base model 和训练时是否一致。如果训练用了--model Qwen/Qwen3-4b合并时也要用同一个。合并后建议先用swift infer跑一条简单问题确认模型能正常加载再批量评测。6. 把 Key 和配置收口之后Swift 微调才真正可复现走到这里你应该已经有一套能跑通的链路TaoToken 提供统一 Key 和 base_urlconfig.toml把 API、训练、推理、评测四类参数收在一处Swift 负责 Qwen3-4b 的 LoRA 微调、推理、合并和 WebUI。下次换模型只改[train]里的model下次换数据集只改dataset下次换评测模型只改[eval]里的judge_model。Key 不再散落配置不再打架。如果你在接入阶段卡住优先看 API Keys 管理和接入文档https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 和 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。想先验证模型对话效果可以直接用模型对话页https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你后面要把微调、评测、Agent 调用做成长期流程Coding Plan 更适合统一管理https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。ClaudeCodeAnthropic 相关接入参考https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。