书生浦语InternLM2-7B是上海AI实验室开源的对话模型,在中文理解和推理任务上表现不错,但通用模型面对垂直领域时往往力不从心。想要让它在法律咨询、医疗问答或者企业客服场景下发挥真正实力,微调几乎是必经之路。XTuner是浦语生态中专门负责高效微调的工具,支持LoRA、QLoRA等轻量方案,一张24G显卡就能完成7B模型的训练。这篇文章会把整个流程拆开讲清楚,特别是很多教程一笔带过的数据集格式转换环节,我会给出可直接运行的脚本。

一、XTuner环境准备与模型下载
先说环境。XTuner依赖PyTorch,建议在独立的conda环境中安装,避免污染主环境。安装命令很简单:
# 创建并激活虚拟环境 conda create -n xtuner python=3.10 -y conda activate xtuner # 安装xtuner,推荐源码安装获取最新特性 git clone https://github.com/InternLM/xtuner.git cd xtuner pip install -e '.[all]' # 验证安装 xtuner version xtuner list-cfg
执行xtuner list-cfg会列出所有官方配置模板,找到以internlm2_7b开头的那些,比如internlm2_7b_qlora_alpaca_e3.py,这就是我们的起点。接下来下载模型权重,国内用户建议走ModelScope,速度比HuggingFace快很多。假设权重放在/root/models/internlm2-chat-7b目录,后面配置文件里要指向这个路径。
显存方面多说一句。7B模型以bf16加载大约占14GB显存,全参数微调还要加上梯度和优化器状态,至少需要80GB的A100才够。所以消费级显卡请直接用QLoRA方案,4bit量化加载后模型只占约5GB,加上训练开销,一张16GB的卡就能跑起来,这也是XTuner对低资源用户最友好的地方。
二、数据集格式要求:预训练与对话微调的区别
XTuner支持两类微调任务,数据格式完全不同。第一类是增量预训练,目的是灌入领域知识,数据就是纯文本;第二类是对话指令微调,目的是让模型学会以特定方式回答,数据必须是结构化的问答对。新手最常见的错误就是把两种格式混着用,导致loss不降或者模型输出混乱。
增量预训练的数据很简单,一个txt文件,每段文本之间用空行分隔即可。指令微调的数据则要整理成JSON数组,XTuner原生支持Alpaca格式和OpenAI Messages格式。以OpenAI格式为例,标准结构如下:
[
{
"messages": [
{
"role": "system",
"content": "你是一名专业的法律咨询助手"
},
{
"role": "user",
"content": "劳动合同里没有写明薪资,这份合同有效吗?"
},
{
"role": "assistant",
"content": "劳动合同缺少薪资条款属于约定不明,合同本身仍然有效,但劳动者可以要求补充约定,协商不成时可参照同岗位标准确定。"
}
]
}
]
注意几个细节:system字段可以省略;多轮对话时user和assistant交替出现即可;整个文件是一个JSON数组,文件编码必须是UTF-8。如果你的原始数据只有一问一答两列Excel,就需要写脚本转换,这正是下一节的内容。
三、编写自定义数据集格式转换脚本
实际业务中拿到的数据五花八门,可能是JSONL、CSV,甚至是从数据库导出的表格。核心思路是统一转换成XTuner要求的messages结构。下面这个脚本处理最常见的场景:原始数据是JSONL格式,每行一个JSON对象,包含instruction和output两个字段,转成OpenAI Messages格式。
import json
def jsonl_to_messages(input_path, output_path, system_prompt=None):
"""把JSONL格式的一问一答数据转成XTuner的Messages格式"""
results = []
with open(input_path, 'r', encoding='utf-8') as f:
for line_no, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
item = json.loads(line)
except json.JSONDecodeError:
print(f"第 {line_no} 行解析失败,已跳过")
continue
# 字段名兼容处理,不同来源命名可能不同
question = item.get('instruction') or item.get('question') or ''
answer = item.get('output') or item.get('answer') or ''
question = str(question).strip()
answer = str(answer).strip()
# 过滤无效样本
if not question or not answer:
print(f"第 {line_no} 行存在空字段,已跳过")
continue
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": question})
messages.append({"role": "assistant", "content": answer})
results.append({"messages": messages})
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"转换完成,共 {len(results)} 条有效数据")
if __name__ == '__main__':
jsonl_to_messages(
input_path='./raw_data.jsonl',
output_path='./train_data.json',
system_prompt='你是一名专业的法律咨询助手,回答要准确简洁。'
)
这个脚本做了几件容易被忽略的事。第一是字段名兼容,不同渠道导出的数据字段命名不统一,用or链式取值可以兼容多种情况。第二是脏数据过滤,空问题和空答案如果不过滤,训练时会造成loss异常。第三是ensure_ascii=False,保证中文以原样写入而不是被转成unicode编码,方便人工检查。第四是错误容忍,单行解析失败只跳过该行而不中断整个转换过程。
如果你手上的是CSV文件,只需把读取部分换成csv.DictReader,后面的组装逻辑完全一致。反过来,如果你想把XTuner格式的数据转回JSONL做其他用途,写一个反向函数遍历messages数组、按role提取内容即可,原理相同。
四、修改配置文件并启动训练
数据准备好后,复制官方配置模板到工作目录并修改关键参数:
mkdir -p /root/ft-workspace cd /root/ft-workspace xtuner copy-cfg internlm2_7b_qlora_alpaca_e3 ./
打开复制出来的配置文件,需要改动的只有两处:模型路径和数据路径。把pretrained_model_name_or_path改成你的本地权重目录,把data_files指向转换好的JSON文件,同时把dataset_map_fn换成openai_map_fn来匹配Messages格式。配置文件中默认的max_length是2048,如果数据都很短可以适当调小以节省显存。
启动训练的命令非常简洁:
cd /root/ft-workspace xtuner train internlm2_7b_qlora_alpaca_e3_copy.py --work-dir ./output
训练过程中观察终端输出的loss变化,一般前几百步快速下降,之后趋于平缓。3个epoch跑完后,输出目录会生成adapter权重,这时候还不能直接推理,需要先和基座模型合并:
xtuner convert merge /root/models/internlm2-chat-7b \
./output/iter_1500.pth \
./merged_model --safe-serilize
合并后的merged_model目录就是一个完整的模型,可以用transformers或者LMDeploy直接加载对话,测试微调效果。如果效果不理想,优先检查数据质量而不是急着调参,杂乱的数据换多少个超参数都救不回来。
五、常见问题与优化建议
训练阶段有几个高频报错值得一说。一是CUDA OOM,解决办法包括把batch_size调小、开启梯度检查点、或者把LoRA改QLoRA。二是loss居高不下,多半是数据格式没转对,回去检查JSON结构是否符合Messages规范。三是显存够但速度极慢,检查是否开启了flash attention,XTuner配置里设置flash_attn=True(需要先安装flash-attn包)通常能提速一倍以上。
数据层面还有个提升效果的小技巧:样本数量不是越多越好,几百条高质量的领域问答往往比几千条低质量数据效果更好。训练前建议人工抽查转换后的JSON文件,确认问题和答案的配对没有错位,system提示词与业务场景匹配。做完这些,InternLM2-7B在垂直领域的表现会明显上一个台阶。
InternLM2-7B微调XTuner数据集格式转换修改时间:2026-09-04 16:03:29