
简介这份资源面向具备深度学习基础、熟悉Python的AI研发与NLP技术人员聚焦如何借助LlamaFactory对Qwen2.5进行高效微调使其适配法律与医疗等垂直领域解决通用大模型在专业任务中术语理解不足、业务逻辑薄弱的问题。压缩包内仅含1个docx文档体积约39KB内容围绕环境搭建、数据收集与预处理、配置文件编写、模型训练、效果评估及服务部署的完整链路展开并对比微调前后模型在法律判断与医疗诊断任务中的表现差异。文中结合LoRA、QLoRA等参数高效微调策略说明如何在有限显存下降低微调门槛同时给出可视化界面与全流程监控的实践思路。目前已有94人学习适合希望低成本实现大模型定制化部署、并关注数据质量与参数设置对性能影响的工程师与研究人员参考。1. 法律与医疗专家模型为什么通用大模型在这两个领域总翻车你拿 Qwen2.5-7B 直接问「劳动合同法第八十二条的适用条件」它大概率给你一段看着像法条、实则张冠李戴的回答。换成医疗场景问「二甲双胍在 eGFR 低于 45 时的调整方案」它可能把肾病禁忌和肝功能调整混在一起讲。这不是模型笨是通用语料里法律和医疗的高质量文本占比太低模型学到的是「像法律/像医疗」的语言风格而不是可核验的专业知识。基于 LlamaFactory 的 Qwen2.5 微调解决的正是这个问题用领域指令数据把通用底座改造成「法律顾问」或「医疗助手」的角色。LlamaFactory 把 LoRA、QLoRA、全参微调这些大模型微调技术封装成配置驱动你不用手写 Trainer 循环Qwen2.5 的中文底座能力加上领域数据是当前中文专家模型最稳的组合之一。这篇面向想动手做大模型微调实战的工程师从数据构造一路讲到 adapter 合并与效果验证新手能照着跑熟手能看到参数边界和踩坑点。2. 环境与底座选型LlamaFactory 装完到 Qwen2.5 能跑通的最小路径2.1 为什么是 LlamaFactory Qwen2.5 这个组合选 LlamaFactory 的理由很实际它把模型加载、数据模板、LoRA 注入、训练循环、推理验证串成一条流水线改一个 YAML 就能切换底座和微调方式。对法律、医疗这种需要反复迭代数据的场景省下来的工程时间比什么都值钱。底座选 Qwen2.5 而不是别的核心是中文法律文书和医疗病历的 token 效率。Qwen2.5 的 tokenizer 对中文专业术语的切分比多数开源底座细同样一段判决书token 数更少等效上下文更长。7B 版本在单张 24G 显存卡上做 LoRA 微调绰绰有余14B 需要 QLoRA 或双卡32B 以上建议直接上多卡全参或走云端。微调方式上法律和医疗的指令数据通常几千到几万条LoRA 是性价比最高的选择。全参微调需要的数据量和算力都高一个量级除非你要做底座级的领域继续预训练否则没必要。2.2 环境安装与底座下载先建虚拟环境装 LlamaFactory。注意 torch 版本要和 CUDA 对齐这是最常见的翻车点。# 创建环境python 3.10 是 LlamaFactory 当前最稳的版本 conda create -n llama_factory python3.10 -y conda activate llama_factory # 安装 torchcu121 对应 CUDA 12.1按你驱动实际版本改 pip install torch2.3.0 torchvision0.18.0 --index-url https://download.pytorch.org/whl/cu121 # 源码安装 LlamaFactory git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip install -e .[torch,metrics] # 验证安装 llamafactory-cli version逻辑说明-e是可编辑安装方便你改源码里的模板[torch,metrics]会拉齐训练和评估依赖。如果llamafactory-cli version报 command not found八成是虚拟环境没激活或 pip 装到了系统 Python。底座下载用 modelscope 或 huggingface 都行国内建议 modelscope。# 下载 Qwen2.5-7B-Instruct约 15G modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir ./models/Qwen2.5-7B-Instruct参数说明--local_dir指定本地路径后面训练配置里的model_name_or_path要指向这里。别用Qwen2.5-7B基座版做指令微调基座版没经过对话对齐微调后指令遵循能力反而更差这是新手最容易踩的坑。2.3 显存与精度参数怎么定显存不够时按这个顺序降级先开 gradient_checkpointing再上 4bit 量化QLoRA最后才考虑换小模型。不要一上来就量化4bit 会损失一部分精度法律条文这种要求精确的场景能不用就不用。底座规模微调方式最低显存推荐精度7BLoRA16Gbf167BQLoRA10G4bit bf16 计算14BLoRA24Gbf1614BQLoRA16G4bit bf16 计算32BQLoRA24G4bit bf16 计算提示bf16 需要 Ampere 及以上架构的卡V100 及更早的卡只能用 fp16且要开 loss scaling否则梯度会溢出。3. 领域数据构造法律与医疗指令集的格式、切分与配比3.1 数据格式alpaca 还是 sharegptLlamaFactory 支持 alpaca 和 sharegpt 两种主流格式。法律和医疗的单轮问答用 alpaca 就够多轮问诊或案情追问用 sharegpt。alpaca 格式长这样[ { instruction: 劳动合同法第八十二条规定的二倍工资适用条件是什么, input: , output: 该条适用于用人单位自用工之日起超过一个月不满一年未与劳动者订立书面劳动合同的情形…… } ]sharegpt 格式适合多轮[ { conversations: [ {from: human, value: 患者男58岁eGFR 42正在服用二甲双胍需要调整吗}, {from: gpt, value: eGFR 低于 45 时二甲双胍需减量并密切监测肾功能……}, {from: human, value: 如果降到 30 以下呢}, {from: gpt, value: eGFR 低于 30 属于禁忌应停用并换用其他降糖方案……} ] } ]逻辑说明instruction是任务描述input是补充上下文法律场景可放案情摘要医疗场景可放检查指标output是标准答案。多轮数据里from字段必须是human和gpt写成user和assistant会报错。3.2 数据切分与配比法律和医疗数据都要按「知识点」切分不能随机切。同一个法条的不同问法、同一个疾病的不同分期要保证训练集和验证集不交叉否则验证 loss 会虚低你以为模型学会了其实它只是背过了。配比上通用指令数据占 10% 到 20% 能有效防止灾难性遗忘。纯领域数据微调出来的模型通用对话能力会明显退化问它「今天天气怎么样」都可能答成法律意见。我一般按领域 8 : 通用 2 来混。import json import random def split_by_topic(data, topic_key, ratio0.9): 按知识点切分保证同一知识点的样本不跨集 topics {} for item in data: topic item.get(topic_key, default) topics.setdefault(topic, []).append(item) train, val [], [] for topic, items in topics.items(): random.shuffle(items) cut int(len(items) * ratio) train.extend(items[:cut]) val.extend(items[cut:]) return train, val # topic_key 法律用「法条编号」医疗用「疾病分期」 with open(legal_raw.json, r, encodingutf-8) as f: raw json.load(f) train, val split_by_topic(raw, topic_keylaw_article) json.dump(train, open(legal_train.json, w, encodingutf-8), ensure_asciiFalse, indent2) json.dump(val, open(legal_val.json, w, encodingutf-8), ensure_asciiFalse, indent2)参数说明ratio0.9是训练集占比数据量少于 2000 条时建议调到 0.85给验证集留够样本。topic_key必须是你数据里真实存在的字段没有就自己加别用随机切分糊弄。3.3 数据质量的三条硬标准第一答案必须可溯源。法律答案要能指到具体法条医疗答案要能指到指南或说明书。编造的答案喂进去模型学会的就是编造。第二拒绝「正确的废话」。像「建议咨询专业律师」「请及时就医」这种答案对模型能力提升为零还会稀释有效信号。第三长度分布要合理。法律答案通常 100 到 500 字医疗 50 到 300 字如果大量样本超过 1000 字要检查是不是把整篇判决书塞进去了这种样本要拆成多个问答。4. LoRA 微调实战从 YAML 配置到训练启动的完整命令4.1 数据集注册LlamaFactory 不会自动扫描你的 json 文件要在data/dataset_info.json里注册。{ legal_train: { file_name: legal_train.json, formatting: alpaca, columns: { prompt: instruction, query: input, response: output } }, medical_train: { file_name: medical_train.json, formatting: sharegpt, columns: { messages: conversations } } }逻辑说明formatting必须和你的数据格式一致alpaca 用prompt/query/response映射sharegpt 用messages映射。file_name是相对data/目录的路径把 json 文件放进data/下最省事。4.2 LoRA 训练 YAML 配置### model model_name_or_path: ./models/Qwen2.5-7B-Instruct trust_remote_code: true ### method stage: sft do_train: true finetuning_type: lora lora_rank: 16 lora_target: all lora_alpha: 32 lora_dropout: 0.05 ### dataset dataset: legal_train template: qwen cutoff_len: 2048 max_samples: 100000 overwrite_cache: true preprocessing_num_workers: 8 ### output output_dir: ./saves/qwen2.5-7b-legal-lora logging_steps: 10 save_steps: 200 plot_loss: true overwrite_output_dir: true ### train per_device_train_batch_size: 2 gradient_accumulation_steps: 8 learning_rate: 1.0e-4 num_train_epochs: 3.0 lr_scheduler_type: cosine warmup_ratio: 0.1 bf16: true gradient_checkpointing: true参数说明这几个是必须调对的lora_rank控制 LoRA 矩阵的秩16 是法律医疗场景的常用起点。数据量大、任务复杂可以上 32 或 64但超过 64 收益递减明显还容易过拟合。lora_alpha一般设成 rank 的两倍16 配 32 是经典组合。lora_target: all表示对所有线性层注入 LoRA。只注入 q_proj、v_proj 能省显存但法律医疗这种需要精确知识注入的场景all 的效果明显更好代价是显存多占 20% 左右。learning_rate用 1e-4 是 LoRA 的甜点区。全参微调要降到 1e-5 到 2e-5LoRA 因为只训练低秩矩阵学习率可以高一个量级。设成 1e-3 会震荡不收敛设成 1e-5 则学得太慢。cutoff_len: 2048对法律医疗够用。如果你的数据里有长判决书或完整病历调到 4096但显存占用会翻倍要相应降 batch size。gradient_accumulation_steps: 8配合per_device_train_batch_size: 2等效 batch size 是 16。显存够就加大 per_device不够就加 accumulation别动 learning rate 来凑。4.3 启动训练与日志观察# 单卡启动 llamafactory-cli train configs/legal_lora_sft.yaml # 多卡启动2 卡为例 FORCE_TORCHRUN1 CUDA_VISIBLE_DEVICES0,1 llamafactory-cli train configs/legal_lora_sft.yaml逻辑说明FORCE_TORCHRUN1让 LlamaFactory 走 torchrun 分布式启动多卡必须加。CUDA_VISIBLE_DEVICES指定用哪几张卡别让训练占了别人在用的卡。训练启动后重点看三个指标loss 是否稳定下降、grad_norm 是否在 1 附近、learning_rate 是否按 cosine 衰减。loss 降到 0.5 以下还继续降要警惕过拟合看验证集 loss 是否开始回升。grad_norm 突然飙到几十说明有脏数据或学习率太高先查数据再调参。注意法律医疗数据里如果有超长样本被 cutoff_len 截断截断位置可能把答案切掉一半模型会学到「答到一半就停」。训练前用脚本统计一下 token 长度分布超过 cutoff_len 的样本要么截断输入保留答案要么直接丢弃。5. 避坑与排查法律医疗微调里最容易翻车的五件事5.1 现象训练 loss 正常下降推理却答非所问原因模板不匹配。Qwen2.5 有专属的对话模板训练时template: qwen推理时如果没指定同样的模板模型看到的 prompt 格式和训练时不一致输出自然乱。解决推理配置里显式写template: qwen并且确认训练和推理用的是同一个底座路径。用llamafactory-cli chat时也要带上模板参数。5.2 现象模型把法律和医疗知识混在一起答原因两个领域的数据混在一个数据集里训练且没有领域标识。模型分不清当前该用哪套知识。解决要么分开训练两个 LoRA adapter推理时按场景加载要么在 instruction 里加领域前缀比如「[法律]」「[医疗]」让模型学会根据前缀切换。我一般选前者adapter 微调的好处就是可以热插拔。5.3 现象验证集 loss 很低人工抽检却错误百出原因验证集和训练集同源问法几乎一样模型只是记住了表面模式。法律医疗场景尤其严重同一个法条换个问法模型就露馅。解决验证集要人工构造「同知识点不同问法」的样本比如训练集问「第八十二条适用条件」验证集问「什么情况下员工可以主张二倍工资」。两者考的是同一个知识点但表述完全不同。5.4 现象微调后模型开始胡编法条编号和药品剂量原因训练数据里本身就有错误答案或者数据量太少导致模型在低频知识点上过拟合出错误模式。解决法律数据逐条核对法条编号和内容医疗数据核对剂量单位和适应症。数据量少于 500 条的知识点宁可不训也别让模型瞎猜。可以加一条「不确定时回答不知道」的样本教模型承认边界。5.5 现象显存溢出报 CUDA out of memory原因cutoff_len 设太大、batch size 太高、或者没开 gradient_checkpointing。解决按顺序排查——先开gradient_checkpointing: true再把per_device_train_batch_size降到 1然后降cutoff_len到 1024最后才考虑上 4bit 量化。量化是最后手段不是第一选择。6. Adapter 合并与效果验证把 LoRA 权重焊回底座的具体操作训练完的 LoRA 权重是独立的小文件推理时要和底座一起加载。生产环境更推荐合并成一个完整模型省去加载两个文件的麻烦也避免推理框架对 LoRA 支持不一致的问题。# 合并 LoRA 到底座导出完整模型 llamafactory-cli export \ --model_name_or_path ./models/Qwen2.5-7B-Instruct \ --adapter_name_or_path ./saves/qwen2.5-7b-legal-lora \ --template qwen \ --finetuning_type lora \ --export_dir ./models/qwen2.5-7b-legal-merged \ --export_size 2 \ --export_legacy_format false参数说明export_size是导出分片大小2 表示每片 2G大模型导出必须分片否则单文件过大加载慢。export_legacy_format false导出 safetensors 格式比 bin 格式加载快且更安全。合并后验证别只看 loss要跑真实场景的抽检。from transformers import AutoModelForCausalLM, AutoTokenizer model_path ./models/qwen2.5-7b-legal-merged tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_path, device_mapauto, trust_remote_codeTrue, torch_dtypeauto ) # 用训练时相同的模板构造 prompt prompt 劳动合同法第八十二条规定的二倍工资适用条件是什么 messages [{role: user, content: prompt}] text tokenizer.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue) inputs tokenizer(text, return_tensorspt).to(model.device) outputs model.generate(**inputs, max_new_tokens512, temperature0.1, do_sampleFalse) print(tokenizer.decode(outputs[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue))逻辑说明apply_chat_template必须和训练时的 template 一致这是保证推理格式正确的关键。temperature0.1加do_sampleFalse走贪心解码法律医疗场景要的是确定性不是创造性。max_new_tokens512对多数法律医疗回答够用不够就加到 1024但要注意底座的最大上下文限制。验证要覆盖三类样本训练集里见过的知识点换问法、训练集里没有但同领域的知识点、完全无关的通用问题。第三类用来检查灾难性遗忘如果模型连「你好」都答不利索说明通用数据配比太低回去调数据重训。我自己的习惯是每次合并完模型先跑 50 条人工抽检法律看条文引用是否准确医疗看剂量和禁忌是否对得上。抽检通过率低于 90% 就不上线回去查数据。这个习惯帮我拦下过好几次「loss 很漂亮但答案全是编的」的翻车。微调这件事数据质量永远比参数调优重要法律和医疗尤其如此。希望帮到你。本文还有配套的精品资源点击获取