
手头只有一块6GB显存的显卡能不能跑通“微调一个大语言模型再把它部署成服务对外提供推理”的完整链路这个问题我过去一年里被问过很多次每次我都直接回答能前提是别按数据中心那套思路来。6GB显存这个量级恰好卡在“玩具”和“生产”之间的尴尬地带。你说它不行吧跑个1.5B到3B参数的模型很从容你说它行吧稍微有点野心的7B模型都能把显存撑爆。这篇博文我会把从LoRA微调到vLLM部署的完整流程拆开讲清楚包括每一步的选型原因、显存预算、参数设置以及我实际踩过的坑比如GPU Crash Dump、vLLM老版本chunk_size的Bug、模型合并后格式对不上这类问题。全文基于常见的消费级显卡实践硬件就是你手头这张6GB卡软件栈是PyTorch PEFT/QLoRA vLLM模型以Qwen系列为主。这套流程适合谁想在小显存环境里跑通全流程的开发者准备低成本做垂直领域小模型的技术爱好者或者公司里只有一台普通Windows/Linux机器、想快速落地私有化小模型的人。看完你不仅能复现还能理解每一步背后的显存计算逻辑遇到问题自己会排查。1. 6GB 显存能做到什么先想清楚路线再动手1.1 6GB显存下的现实约束与核心思路先说结论6GB显存能训练的上限大约是3B参数模型配合QLoRA能推理的上限大约是7B参数模型配合GPTQ/AWQ 4bit量化。这块硬约束决定了整个技术路线的走向也决定了你不能像云端一样直接全量微调一个大模型。核心思路一句话总结用4bit量化把模型压缩到能放进显存用LoRA把训练时的可训练参数压到总量的0.5%到1%用vLLM的PagedAttention把推理时的KV Cache管理好。这三步环环相扣。如果没有QLoRA光是加载一个3B模型的fp16权重就要6GB显存训练时压根没有余量如果没有LoRA反传梯度带来的显存开销直接翻倍如果没有vLLM部署时KV Cache会跟权重抢显存并发一高就OOM。在动手之前我强烈建议你先做一个显存规划。公式不复杂训练显存 ≈ 模型权重 优化器状态 梯度 激活值 LoRA适配器。QLoRA的意义在于把“模型权重”这一项从fp16变成了4bit一个3B模型从6GB直接压缩到1.5GB左右剩下4.5GB留给梯度、激活值和KV Cache。这就是6GB卡能跑微调的根本原因。1.2 全量微调、Freeze微调与LoRA优劣势对比很多人第一次接触微调看到全量微调、Freeze微调、LoRA这三个词容易懵。我直接拿实际训练场景做个对比帮你搞清楚为什么6GB显存下只能选LoRA。全量微调所有参数都参与梯度更新。一个3B模型就算是用AdamW优化器显存开销大概是模型权重的12到16倍fp16权重2倍 梯度1倍 Adam状态8倍 激活值若干。3B模型全量微调至少需要20GB以上显存6GB卡直接不用想。而且全量微调有个隐藏风险——灾难性遗忘模型学了新知识把原有的通用能力冲掉了小数据集上尤其明显。Freeze微调冻结大部分层只训练最后几层或者特定层。这个方法的好处是显存开销比全量小但它不改变模型内部的表征只是调整了“输出头的映射”对领域适配的效果很有限。我试过用Freeze微调做一段风格转换结果模型学到的只是“改措辞”而不是真正理解新领域的表达方式。LoRALow-Rank Adaptation冻结原始权重只训练注入的低秩矩阵。以Qwen2.5-1.5B为例如果设r8可训练参数通常只有2000万到3000万占总参数的1%出头。这意味着什么训练显存里模型权重即便以4bit加载也只占1GB左右优化器状态和梯度的开销全部集中在LoRA参数上小到可以忽略剩下的显存可以大方地分配给序列长度和Batch Size。三者对比下来6GB显存的正确答案就是LoRA再往前一步加上4bit量化就是QLoRA。如果你连LoRA都不想装那基本没有训练空间。1.3 全链路流程微调到部署的五个阶段整个流程可以拆成五个阶段环境准备、数据与训练、模型合并、量化、部署。顺序不能乱每一步的输出是下一步的输入。环境准备阶段要搞定的是驱动、CUDA、PyTorch GPU版以及PEFT、Transformers、Datasets、vLLM这些依赖库。数据与训练阶段用QLoRA跑微调产出LoRA适配器权重。模型合并阶段把LoRA适配器合并回原始模型生成一个完整的Safetensors模型目录。量化阶段用AutoGPTQ或AWQ把合并后的fp16模型压到4bit。部署阶段用vLLM加载量化后的模型启动OpenAI兼容服务。这套链路里最容易翻车的是中间两个阶段很多人合并模型时选择“先合并再量化”但合并完不检查文件直接丢给vLLM结果报“tensor parallelism requires div by 3”之类的错误其实只是模型目录缺了文件。后面我会专门讲怎么用模型检查器验证。2. 环境准备先让 PyTorch 和 CUDA 正常起来2.1 显卡驱动与CUDA版本检查环境准备是整个流程里最枯燥但最容易出问题的环节。我见过太多人栽在环境上微调代码写得很对结果PyTorch根本用不了GPU白白浪费一整天。第一步确认显卡。NVIDIA显卡用nvidia-smi查看驱动版本和CUDA版本nvidia-smi重点看右上角的“CUDA Version”这是驱动支持的最高CUDA版本不是当前激活的版本。以6GB卡常见的RTX 2060、RTX 3050、GTX 1660 Super为例2024年后的驱动一般支持CUDA 12.x。第二步确认PyTorch需要的CUDA版本。这里有个常见的误区PyTorch官方预编译包自带CUDA runtime不需要你单独装完整CUDA Toolkit只要显卡驱动足够新就行。比如你装的是pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121这个cu121表示PyTorch内置了CUDA 12.1的runtime你机器上驱动只要支持CUDA 12.1以上就能跑通。提示如果你在Linux服务器上操作特别是CentOS 7.9安装GPU驱动时注意内核版本和gcc版本兼容性。CentOS 7.9默认内核可能偏旧装新版驱动会报“Unable to load the nvidia-drm kernel module”。解决方案是升级内核到3.10.0-1160以上或者用--no-opengl-files参数装驱动以避免跟系统已有的OpenGL库冲突。第三步验证CUDA能用。安装完驱动后重启系统重新执行nvidia-smi确认能正常显示显卡信息。2.2 PyTorch GPU版安装与验证驱动准备好之后创建Python环境并安装PyTorch。我推荐用conda管理环境避免系统Python环境被搞乱。conda create -n llm python3.10 -y conda activate llm pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121这里有个细节Python版本建议3.10因为vLLM对Python 3.12的支持有过一段时间的滞后而3.8又太低很多新版依赖不支持。3.10是当前兼容性最好的折中选择。安装完之后用下面这段代码验证GPU是否可用import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0)) print(torch.cuda.get_device_capability(0)) print(torch.cuda.mem_get_info())如果输出torch.cuda.is_available()为True说明PyTorch已经正确识别到GPU。mem_get_info()返回的是总显存和剩余显存单位是字节6GB卡通常显示(6442450944, 6043721728)左右。如果返回False排查顺序是这样的第一nvidia-smi能否正常输出不能则驱动没装好第二PyTorch的CUDA版本是否高于驱动支持的CUDA版本是则需要换低版本的PyTorch或升级驱动第三是否用了CPU版的torchpip list | grep torch看一下若显示torch-cpu字样说明装错了包。2.3 依赖库安装与数据准备微调阶段还需要PEFT、Transformers、Datasets、Accelerate、Bitsandbytes、HuggingFace Hub等库。这里我直接给一组经过验证的版本组合能避免大部分兼容性问题pip install transformers4.45.0 datasets2.21.0 peft0.12.0 accelerate0.34.0 bitsandbytes0.43.3注意bitsandbytes在Windows上一直比较折腾0.43.3之后官方才逐步支持。如果你是Windows环境务必确认已经安装了Microsoft C Build Tools否则会出现load library error之类的报错。Linux一般没这个问题。数据准备方面微调需要的数据格式取决于你用的脚本。如果自己写训练循环推荐JSONL格式每一行一个样本最常见的指令微调结构是{instruction: 请把下面的句子翻译成英文, input: 今天天气真好, output: The weather is nice today.}数据量方面LoRA微调不是数据越多越好。1万条以内的高质量数据效果远好于10万条爬来的噪声数据。我做过一个实验同一个数据集清理前训练后模型驴唇不对马嘴清理后训练效果直接提升了一大截。数据质量永远排在数据量前面。3. LoRA 微调实战6GB 显存下的参数选择与避坑3.1 QLoRA方案与显存预算拆解环境备好了数据也整理好了接下来进入核心环节微调。我这里推荐QLoRA而不是纯LoRA原因很直接纯LoRA需要把模型权重以fp16形式加载一个3B模型就吃掉6GB显存训练时的激活值、梯度根本没地方放。QLoRA把模型权重重压到4bit一个3B模型只占1.5GB左右训练时才能有余量。QLoRA的主意是Meta在2023年提出的核心三件套4bit NormalFloat量化、Double Quantization双重量化对量化常数再量化一次、Paged Optimizer分页优化器把优化器状态临时换出到CPU内存。效果上QLoRA在保持与LoRA相当效果的同时显存占用降低了三分之一到一半。显存预算可以这么算。以Qwen2.5-1.5B模型在6GB显存上训练为例4bit量化后的模型权重约1GBLoRA适配器参数约0.08GBr8target_modules全开梯度约0.08GB优化器状态AdamW约0.2GB激活值取决于Batch Size和输入长度约1到2GB中间缓冲区、CUDA context等杂项约0.5GB实际看下来Batch Size1、序列长度512时峰值显存大约3.5GB还有约2.5GB的余量用于增大Batch或序列长度。如果序列长度拉到2048激活值会暴涨到3GB以上总显存直接逼近6GB这时候就需要调低Batch或开启梯度累积。3.2 关键训练参数如何定微调效果的很大一部分取决于参数设置。以下是我多次实验后总结的实用配置可以直接套用from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments ) from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training from datasets import load_dataset from trl import SFTTrainer import torch model_name Qwen/Qwen2.5-1.5B-Instruct # 4bit量化配置 bnb_config BitsAndBytesConfig( load_in_4bitTrue, bnb_4bit_quant_typenf4, bnb_4bit_use_double_quantTrue, bnb_4bit_compute_dtypetorch.bfloat16, ) model AutoModelForCausalLM.from_pretrained( model_name, quantization_configbnb_config, device_mapauto, trust_remote_codeTrue, ) tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) tokenizer.pad_token tokenizer.eos_token model prepare_model_for_kbit_training(model) # LoRA配置 lora_config LoraConfig( r8, lora_alpha16, target_modules[q_proj, k_proj, v_proj, o_proj], lora_dropout0.05, biasnone, task_typeCAUSAL_LM, ) model get_peft_model(model, lora_config) model.print_trainable_parameters()先解释一下LoRA的三大参数r秩决定了低秩矩阵的维度。r8是小型任务风格转换、特定格式输出的常用起点r16适合需要学习更多新知识的场景r4适合数据量小、任务简单的场景。不是r越大越好过大的r会引入噪声过小则容量不够。6GB卡上建议从r8开始跑通了再调。lora_alpha缩放系数控制LoRA注入权重的缩放比例一般设为r的1到2倍。alpha/r的值相当于学习率放大系数设置在2到4之间比较常见。我习惯设alpha16、r8对应缩放系数2。target_modules目标模块指定哪些模块注入LoRA适配器。对Qwen系列q_proj、k_proj、v_proj、o_proj这四个注意力头投影层是标配。加不加gate_proj、up_proj、down_projFFN层取决于你想改动模型的程度。加全了可训练参数会变多效果不一定更好但显存占用会涨。我自己的经验做指令微调只用注意力层就够做领域适配比如让它学会特定文章风格可以试试把FFN层也加上。训练超参数我用TRL的SFTTrainer管理training_args TrainingArguments( output_dir./qwen-lora, num_train_epochs3, per_device_train_batch_size1, gradient_accumulation_steps8, gradient_checkpointingTrue, logging_steps10, save_steps100, learning_rate2e-4, lr_scheduler_typecosine, warmup_ratio0.03, bf16True, max_seq_length512, packingFalse, )重点说几个关键的per_device_train_batch_size1是我在6GB卡上测试过的安全值想调大就先观察显存占用gradient_accumulation_steps8是等效Batch Size为8的关键实际Batch1乘以累加步数8gradient_checkpointingTrue会牺牲约30%训练速度换取60%以上激活值显存下降6GB卡上必须开max_seq_length512是初次跑的安全长度等稳定后再拉长。3.3 训练过程实录与显存监控启动训练之后你以为就完事了远没有。训练过程要盯着显存和Loss曲线看。建议开一个单独的终端用watch命令持续观察显存占用watch -n 1 nvidia-smi正常情况下你会看到显存占用在3000MB到5000MB之间波动。如果接近6000MB说明要OOM了需要立刻采取措施。我遇到过最典型的OOM表现不是直接报错而是训练好几个step之后突然崩溃这种最让人崩溃。原因通常是激活值在长序列下突然暴涨或者梯度累积到某一轮触发了更大的中间张量。解决思路是按顺序尝试把max_seq_length从512降到256或把per_device_train_batch_size锁定为1或把gradient_accumulation_steps从8降到4。训练过程中的Loss曲线怎么看初次跑的时候Loss不减甚至上升是正常的因为学习率还在warmup阶段。warmup结束后Loss应该缓慢下降。如果跑了200步Loss纹丝不动先检查数据有没有问题比如是不是所有label都是padding token或者instruction和output拼错了。一个容易忽视的点LoRA训练时务必要冻结所有非目标层LoraConfig里biasnone就是干这个的。如果设成biasall所有bias参数都会参与训练显存和可训练参数都会增加效果提升有限属于不划算的买卖。3.4 模型合并与检查训练结束你得到的是LoRA适配器权重存放在output_dir里的adapter_config.json和adapter_model.safetensors。这两个文件不能直接用于vLLM部署需要把它合并回原模型。合并代码from transformers import AutoModelForCausalLM, AutoTokenizer from peft import PeftModel import torch base_model_name Qwen/Qwen2.5-1.5B-Instruct lora_model_path ./qwen-lora/checkpoint-500 model AutoModelForCausalLM.from_pretrained( base_model_name, torch_dtypetorch.bfloat16, device_mapauto, ) model PeftModel.from_pretrained(model, lora_model_path) merged_model model.merge_and_unload() merged_model.save_pretrained(./qwen-merged) tokenizer AutoTokenizer.from_pretrained(base_model_name) tokenizer.save_pretrained(./qwen-merged)这里有个关键点merge_and_unload()执行的是把低秩矩阵乘积B * A融合进原始权重然后卸载LoRA结构。合并完成后必须用model_checkpoint或者HuggingFace的from_pretrained重新加载验证一次确保模型文件没有损坏。我一般会跑一个简单的“模型检查器”流程from transformers import AutoModelForCausalLM, AutoTokenizer model AutoModelForCausalLM.from_pretrained(./qwen-merged, trust_remote_codeTrue) tokenizer AutoTokenizer.from_pretrained(./qwen-merged) inputs tokenizer(你好请自我介绍一下, return_tensorspt) outputs model.generate(**inputs, max_new_tokens50) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))如果输出正常说明合并成功。如果报错最常见的原因是save_pretrained时目录里缺少config.json导致重新加载时找不到模型结构。另一个坑是tokenizer文件缺失加载后生成会崩溃。提示6GB卡上加载合并后的fp16模型1.5B约3GB进行验证是可行的但如果你微调的是3B模型fp16权重约6GB很可能在验证时就OOM。这种情况建议直接用vLLM加载原模型加LoRA或者先量化再验证。4. vLLM 部署把微调好的模型变成可用服务4.1 vLLM 安装与部署启动微调完成、模型合并通过验证接下来进入部署环节。这里我用的方案是vLLM而不是FastAPI Transformers裸写原因只有一个vLLM的PagedAttention能把显存利用率提升好几倍尤其是在并发请求场景下。安装vLLMpip install vllmvLLM依赖特定版本的PyTorch和CUDA所以建议在干净的虚拟环境里安装避免跟训练环境冲突。若遇到版本冲突可以用pip install vllm --upgrade先解决依赖。Windows环境vLLM支持度稍差建议用WSL2或者直接上Linux。启动服务python -m vllm.entrypoints.openai.api_server \ --model ./qwen-merged \ --served-model-name qwen-local \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.92 \ --max-model-len 2048解释一下关键参数--model直接指定本地模型目录vLLM会自动加载--tensor-parallel-size 1表示单卡部署6GB卡只能设置为1--gpu-memory-utilization 0.92是vLLM允许使用的显存比例设置为0.92意味着给KV Cache留出最大空间同时保留约8%的显存用于模型权重和活跃请求--max-model-len 2048限制最大上下文长度这个值直接影响KV Cache的预分配大小。启动成功后服务默认监听8000端口访问http://localhost:8000/v1/models能看到模型信息。用curl测一下对话接口curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen-local, messages: [{role: user, content: 你好请介绍一下你自己}], max_tokens: 200, temperature: 0.7 }如果返回JSON格式的响应说明部署成功。4.2 量化从fp16到GPTQ/AWQ部署1.5B模型不需要量化但如果你的目标是3B、7B模型或者想让1.5B模型的KV Cache能开得更大那量化就是必经之路。vLLM支持GPTQ和AWQ两种主流量化格式。两者的核心区别GPTQ是一次性校准量化基于误差最小化做逐层量化AWQ则基于激活值的重要性分析保留对模型输出影响大的权重通道的精度。实测下来AWQ在同等bit数下质量略好但GPTQ的生态兼容性更强。用AutoAWQ把合并后的模型转成AWQ格式pip install autoawqfrom awq import AutoAWQForCausalLM model_path ./qwen-merged quant_path ./qwen-awq quant_config {zero_point: True, q_group_size: 128, w_bit: 4} model AutoAWQForCausalLM.from_pretrained(model_path) model.quantize(tokenizerNone, quant_configquant_config) model.save_quantized(quant_path)量化后模型体积从约3GB降到约1GB。然后vLLM直接加载python -m vllm.entrypoints.openai.api_server \ --model ./qwen-awq \ --served-model-name qwen-local \ --quantization awq \ --gpu-memory-utilization 0.92注意vLLM加载AWQ模型时--quantization awq参数可以省略vLLM会自动从config.json中识别量化方式但如果识别失败手动指定是有效的排查手段。4.3 显存利用率与缓存优化vLLM的显存管理核心是PagedAttention它把KV Cache分成固定大小的块像操作系统分页一样按需分配。这个机制的最大好处是传统方案中KV Cache是连续分配的预分配过大浪费显存过小则并发上限低PagedAttention按块分配后KV Cache的碎片化问题得到很大缓解。在6GB卡上部署显存调配的优先级是模型的权重占用是固定的KV Cache的可调整上限由--gpu-memory-utilization决定而--max-model-len则限制了每个请求能占用的KV Cache上限。我实测过一个场景6GB卡上部署Qwen2.5-1.5B-AWQ约1GB权重设--gpu-memory-utilization 0.92后实际可用KV Cache约4.5GB--max-model-len 2048时理论并发可以从个位数涨到几十甚至上百取决于每个请求的实际长度。这就是vLLM相比原生Transformers推理性能提升数十倍的来源。关于缓存命中率vLLM引入了Prefix Cache机制对相同前缀的请求复用KV Cache。这对“多轮对话前几轮内容相同”的场景效果显著。实测下来如果请求的前128个token相同TTFT首token生成时间可以降低50%以上。若你想进一步优化可以关注vLLM的自动前缀缓存实现它默认是开启的通过计算哈希来匹配前缀。聊天机器人、客服这类高频重复前缀的场景收益尤其大。4.4 高并发与OpenAPI兼容验证部署完成后要验证服务在高并发下是否稳定。这里用Python的openai库做并发测试from openai import OpenAI import concurrent.futures client OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY, ) def test_call(i): response client.chat.completions.create( modelqwen-local, messages[ {role: user, content: f你好请用一句话介绍你自己这是第{i}次请求}, ], max_tokens100, ) return response.choices[0].message.content with concurrent.futures.ThreadPoolExecutor(max_workers20) as executor: futures [executor.submit(test_call, i) for i in range(100)] for future in concurrent.futures.as_completed(futures): print(future.result()[:30])如果100个并发请求全部返回且没有超时说明部署配置基本合理。如果出现显存溢出vLLM报GPU OOM优先调低--gpu-memory-utilization到0.85或者降低--max-model-len。注意vLLM的OOM报错样式跟原生PyTorch不太一样它会直接说Error in model.execute: CUDA out of memory但服务进程不一定退出有可能卡在假死状态这时候需要重启服务进程。提示vLLM服务对输入长度非常敏感。如果你收到Prompt length exceeds max model length之类的错误是因为请求的prompt token数超过了--max-model-len的设置。解决办法是把--max-model-len调大但代价是KV Cache预分配也会变大。小显存场景下建议在客户端层面做长度截断而不是无限调大max-model-len。5. 常见问题与排错实录5.1 GPU Crash Dump Triggered 与 CUDA 报错训练或者部署过程中最让人绝望的错误之一就是“GPU Crash Dump Triggered”。出现这个提示说明CUDA内核在执行过程中触发了硬件级别的异常通常是非法内存访问或驱动级错误。我遇到过几次场景各不同但排查思路是一致的第一先用dmesg看系统日志sudo dmesg | tail -30如果有NVRM: GPU at 0000:01:00.0 has fallen off the bus之类的信息多半是显卡供电或散热问题。6GB卡大多是老旧二手卡比如P106、GTX 1660 Super矿卡长时间高负载跑到快满载供电跟不上就会出现这种问题。解决思路降低功耗墙用nvidia-smi -pl 150把功耗限制到150W具体数值取决于显卡型号清理机箱积灰确保散热正常。第二检查显存是否确实超了。训练时如果设置不当激活值会在某个瞬间冲破6GBGPU直接Crash。正常OOM还好如果Crash说明是内核直接访问了非法显存地址多见于bitsandbytes的4bit反传和某些CUDA算子在低显存边缘的不稳定。第三升级或降级驱动。我实测过某些版本的NVIDIA驱动在Linux下跟CUDA 12.1的兼容性有坑会导致偶发性Crash。换一个认证驱动版本比如535系列能解决大部分问题。另外Windows下报“GPU Crash Dump Triggered”的另一个常见原因是显卡驱动TDRTimeout Detection and Recovery机制触发。Windows会默认认为GPU执行超过2秒就是卡死自动重置驱动。这个可以改注册表解决但不建议通过系统层面强行拉长TDR因为治标不治本根源还是显存或计算负载过高。5.2 vLLM 老版本 chunk_size Bug 与升级建议vLLM迭代非常快但快也意味着Bug多。我印象最深的是vLLM 0.23.0版本里的chunk_size相关Bug。那个版本引入了chunked prefill机制允许把长Prompt拆成多个chunk处理设计目的是提高调度效率但实际使用时某些配置会导致空chunk被反复调度CPU占用飙升甚至卡死。当时社区里的解决方案主要有两条路一条是把vLLM升级到0.23.0之后的修复版本另一条是显式设置--chunked-prefill-size参数老版本默认值在某些模型上会触发Bug。我的建议是部署别追新。vLLM是一个快速迭代的项目新版本虽然功能多但稳定性不一定比老版本好。目前比较稳妥的做法是选择一个长时间没有重大Bug的版本比如vLLM 0.10系列或更新的稳定版本。如果Pytorch环境兼容的话装完别急着升。如果你在启动vLLM时报了一堆看不懂的C堆栈错大概率是版本和模型/config不兼容。这时候别硬调参数直接pip show vllm看版本然后到官方Release Notes里找对应版本有没有已知问题。5.3 加载本地模型的格式问题与兼容性vLLM加载本地模型时最容易踩的坑是目录不完整。HuggingFace模型目录里config.json、tokenizer.json、tokenizer_config.json、model.safetensors这四个文件缺一不可有一点缺失vLLM要么直接报错要么加载后行为异常。另一个经典问题是你在训练环境中用AutoModelForCausalLM.from_pretrained能加载模型但vLLM报错。这往往是因为训练时设置了trust_remote_codeTrue而Qwen模型的config.json里指定了auto_map需要远程代码。vLLM加载Qwen系列时直接指定--trust-remote-code参数即可python -m vllm.entrypoints.openai.api_server \ --model ./qwen-merged \ --trust-remote-code还有一种情况微调后合并出的模型vocab size跟tokenizer里实际的special_token数量对不上导致Embedding维度错误。这种错误通常表现为embedding size mismatch。解决办法是合并前确保tokenizer的special token没有新增或者用resize_token_embeddings手动对齐。5.4 微调与部署问题速查表把上面所有问题整理成一张速查表方便实际排查时快速定位问题现象可能原因解决思路torch.cuda.is_available()为False驱动未装好或PyTorch用了CPU版检查nvidia-smi输出重装GPU版torch训练中OOM崩溃Batch Size过大、序列过长、未开gradient checkpointing调小Batch、缩短max_seq_length、开启gradient checkpointingGPU Crash Dump Triggered显存溢出、供电不足、驱动不稳看dmesg日志降功耗墙换认证驱动合并模型后加载失败config.json或tokenizer文件缺失检查merged目录完整性用模型检查器验证vLLM启动报C堆栈版本不兼容、模型目录不完整检查版本补全模型文件升级/降级vLLM请求提示Prompt超过长度max-model-len设太小调大max-model-len或客户端截断输入并发一高就超时显存利用率过高导致KV Cache不足调低gpu-memory-utilization到0.85降低max-model-len输出token被截断max_tokens设太小或max-model-len限制调大max_tokens参数或确认服务端max-model-len这些坑我都实际踩过其中GPU Crash Dump那个排查最耗时花了整整一个下午才发现是显卡供电不稳。所以我建议你动手之前先确认自己显卡的供电和散热6GB卡大多是老卡别在高负载训练时把硬件搞挂了那才是真正的灾难。6. 一些小经验这套流程走下来我最大的体会是6GB显存不是限制而是帮你做减法的工具。显存小你就不会想着全量微调不会硬上7B模型反而更容易产出小而美的成果。我见过很多44GB大显存卡的用户跑了一堆实验最后能落地的反而不多。如果你想在这个方向上继续扩展有几个思路可以参考。一是把LoRA微调的数据集做得再精细一些小模型对数据质量非常敏感一条坏数据的破坏力远超你的想象。二是试试Quantization Aware TrainingQAT先量化再微调让模型在低bit精度下学习通常是进一步压缩模型体积的同时保住效果的手段。三是把部署链路接到更复杂的应用里比如用vLLM的OpenAI兼容接口配合LangChain或Dify做Agent应用模型的“最后价值”是在实际场景里交付的。最后再分享一个实用小技巧训练完的LoRA适配器先别删保留全部checkpoint。因为LoRA文件很小几十MB你可以随时换一组超参数重新训练而不需要重新加载原始大模型。这在调试时能省下大量时间。我自己的流程是基线模型固定不动十几个LoRA适配器分别对应不同任务按需加载或合并。这套工作流在6GB卡上很稳定希望你也跑得顺。