Qwen3-VL 多模态大模型 LoRA 微调实战:Chat Template / 超参调优 / 效果评估 / 部署推理(附源码+面试考点)
如果你手头有一批带图的业务数据,想让 Qwen3-VL 真正读懂你们行业的截图、表格、票据或者产品图,直接拿来推理肯定不够,需要走一遍微调。这篇文章不讲空泛的概念,直接给出一套可落地的 LoRA 微调流程:从环境准备、数据构造、Chat Template 拼接,到训练参数调整、效果评估、vLLM 部署推理,每一步都给代码和判断标准。
Qwen3-VL 是继 Qwen2-VL 之后的新一代多模态大模型,在 OCR、视频理解、高分辨率图像感知和复杂推理上有明显升级。它保持了 Qwen 系列对中文场景的强支持,同时改进了视觉编码器与语言模型的融合方式。项目代码和权重主要在 HuggingFace 与 ModelScope 开源,不同尺寸有 2B、4B、8B、32B 等版本。
我们这次重点解决三个问题:第一,怎么把自己的图文数据组装成 Qwen3-VL 能吃的训练格式;第二,LoRA 微调时哪些参数真正影响效果,哪些可以照抄;第三,微调完怎么把模型跑成 API 服务,给业务系统调用。如果你是做 RAG 检索增强、AI 客服、OCR 结构化解析、图像内容审核这类场景的工程师,这篇文章可以直接作为操作手册收藏。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 模型系列 | Qwen3-VL,开源多模态大模型 |
| 主要能力 | 图像理解、OCR、视频理解、文档截图解析、多轮视觉对话 |
| 微调方案 | LoRA,适配器训练,不需要全量微调 |
| 显存需求 | 需按模型规模和量化方式测试;以 8B 模型为例,LoRA 训练通常在 16GB 到 24GB 显存可跑,4-bit 量化可进一步降低 |
| 支持平台 | Linux 为主,Windows 通过 WSL 或 Docker 也可运行 |
| 启动方式 | 命令行训练脚本 / vLLM API 服务 / Transformers 推理脚本 |
| 是否支持 API | 支持,训练后可基于 vLLM 或 FastAPI 封装 |
| 是否支持批量任务 | 支持,数据按 JSONL 组织,天然适合批量处理 |
| 适合场景 | 垂直领域 OCR、文档解析、电商图文理解、客服工单分类、图像内容审核等 |
说明:显存占用和训练速度与数据长度、batch size、LoRA rank、是否量化强相关。没有绝对的“一张卡跑所有模型”的说法,实际以本机测试为准。
2. 适用场景与使用边界
Qwen3-VL 微调最适合的场景,是你的业务数据分布和大模型原生能力之间存在“领域差距”的时候。
比如你有一堆医疗检验报告单、物流面单、工业质检截图、企业内部系统界面截图,Qwen3-VL 虽然原生能 OCR,但它不一定认识你们公司的模板、印章、特殊符号和字段排版。这时候用几十到几百条标注数据做 LoRA 微调,模型会快速适应你的版面结构和术语习惯。
另一个典型场景是 RAG 与多模态结合。传统的 RAG 只做文本向量检索,遇到图片、表格截图就无能为力。用 Qwen3-VL 对图文混排内容做结构化解析,输出 Markdown 或 JSON,再把结果送进向量库,能让检索系统真正具备“看懂图”的能力。
但要注意边界:
- 人脸图像、身份证、车牌等个人信息数据,微调和部署都要严格脱敏,获得合法授权。
- 版权图片、付费素材、他人原创内容,不要直接拿来训练。
- LoRA 微调改变的是模型对特定分布数据的适配能力,不是“换一个全新模型”,不要期待 100 条数据就学会复杂推理。
- 涉及内容审核、敏感识别类应用,上线前必须做充分的效果评估和合规审查。
3. 环境准备与前置条件
微调 Qwen3-VL 需要准备四样东西:GPU 环境、Python 依赖、模型权重、训练数据。
3.1 GPU 与系统
训练推荐使用 NVIDIA 显卡,显存建议从 16GB 起步。如果你只有 CPU,可以跑推理,但 LoRA 训练非常慢,不建议在生产环境用 CPU 训练。
系统层面,Ubuntu 22.04 是比较稳的选择。Windows 用户可以用 WSL2 + CUDA 环境,或者直接装 Docker 镜像。驱动方面,确保nvidia-smi能看到显卡,并且安装的 PyTorch CUDA 版本和驱动兼容。
nvidia-smi # 期望输出:能看到 GPU 型号、驱动版本、显存大小3.2 安装依赖
核心依赖是 PyTorch、Transformers、Accelerate、PEFT、Datasets,以及用于量化训练的 bitsandbytes。ModelScope 用户还需要安装 modelscope。
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install transformers accelerate peft datasets bitsandbytes pip install modelscope # 如果从 ModelScope 下载权重 pip install vllm # 部署推理用注意:PyTorch 版本和 CUDA 版本要匹配。如果显卡是 Ampere 架构(30 系、40 系)或更新的 Ada Lovelace,用 cu121 或 cu124 的 PyTorch 都没问题;老显卡要自己确认架构兼容性。
3.3 下载模型
从 HuggingFace 下载 Qwen3-VL,也可以从 ModelScope 下载镜像,国内网络环境更稳定。以 8B 模型为例:
from modelscope import snapshot_download model_dir = snapshot_download('Qwen/Qwen3-VL-8B-Instruct', cache_dir='./models') print(model_dir)模型文件较大,启动前需要确认磁盘空间足够。8B 模型 fp16 权重约 16GB,30B 以上模型请预留至少 60GB。
4. 数据准备与格式构造
LoRA 微调多模态模型,数据格式是整个流程里最容易出错的地方。Qwen3-VL 的训练数据组织方式和纯文本模型不同,它需要把图像以标记形式插入到对话内容中。
4.1 推荐的数据格式
Qwen3-VL 的指令微调数据通常采用 ChatML 风格的对话结构,图像通过特殊标记<image>注入。一个 JSONL 样本是下面这样:
{ "messages": [ { "role": "user", "content": [ {"type": "image", "image": "train_images/001.jpg"}, {"type": "text", "text": "请识别这张图片中的发票号码、开票日期和价税合计金额,以 JSON 格式返回。"} ] }, { "role": "assistant", "content": [ {"type": "text", "text": "{\"发票号码\": \"12345678\", \"开票日期\": \"2025-06-01\", \"价税合计\": \"1000.00\"}"} ] } ] }如果你的数据已经是本地路径,训练脚本加载时会把image字段读取为图像张量。多轮对话也支持,直接把messages数组往下接即可。
4.2 图像预处理
Qwen3-VL 内置了视觉处理器,会自动将不同尺寸的图片缩放到合适的分辨率并分块处理。但要注意,过大的原始图片会增加视觉 token 数量,直接推高显存占用。建议训练前将图片统一压缩到短边不低于 256px、长边不超过 2048px,既保留足够细节,又避免不必要的显存开销。
from PIL import Image def preprocess_image(path, max_edge=2048): img = Image.open(path) img.thumbnail((max_edge, max_edge)) return img4.3 最少需要多少数据
如果你想让模型稳定学会一个固定版面结构(比如票据字段识别),几百条高质量标注就够了。如果希望模型学会一种通用的“图文推理风格”,则需要几千条。材料越少,越要保证标注一致,指令和答案不能前后矛盾。
5. Chat Template:为什么必须用对
Chat Template 是 Qwen3-VL 微调过程中最容易踩坑但又最关键的一环。
Transformers 的apply_chat_template方法会把 messages 格式的对话数据转换成模型期望的 token 序列。Qwen3-VL 有自己的模板规则,如果你误用了 Qwen2.5 的纯文本模板,图像标记就不会被正确解析,训练时模型无法把图像与文本对齐。
正确做法是在 tokenizer 上显式调用 chat template:
from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True) text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=False )训练时,数据集的文本列必须经过这个模板转换,不能直接拿原始 messages 喂给模型。很多微调报错“input_ids 与 labels 长度不一致”,就是因为 chat template 没有应用或应用了两遍。
另一个经验:如果使用 LLaMA-Factory 等封装工具,需要确认工具版本内置的 Qwen3-VL 模板是否是最新的。封装工具升级滞后会导致图像标记错乱,这种情况下,自己写训练脚本反而更可控。
6. LoRA 微调实战
6.1 训练脚本主体
这里给出一个基于 PEFT 的 LoRA 微调脚本骨架。它包含模型加载、处理器初始化、数据映射和训练循环。实际使用时要根据你的数据路径和显存大小调整关键参数。
import torch from transformers import ( AutoModelForVision2Seq, AutoProcessor, TrainingArguments, Trainer ) from peft import LoraConfig, get_peft_model from datasets import load_dataset model_dir = "./models/Qwen3-VL-8B-Instruct" dataset_path = "./data/train.jsonl" processor = AutoProcessor.from_pretrained(model_dir, trust_remote_code=True) model = AutoModelForVision2Seq.from_pretrained( model_dir, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True ) lora_config = LoraConfig( r=16, lora_alpha=32, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() dataset = load_dataset("json", data_files=dataset_path)["train"] def process_fn(examples): texts = [] images = [] for msg in examples["messages"]: content = msg[0]["content"] # user 消息 image_path = content[0]["image"] images.append(Image.open(image_path).convert("RGB")) query = content[1]["text"] answer = msg[1]["content"][0]["text"] messages = [ {"role": "user", "content": [{"type": "image"}, {"type": "text", "text": query}]}, {"role": "assistant", "content": [{"type": "text", "text": answer}]} ] text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=False) texts.append(text) batch = processor(text=texts, images=images, return_tensors="pt", padding=True) batch["labels"] = batch["input_ids"].clone() return batch tokenized_dataset = dataset.map(process_fn, batched=True, remove_columns=dataset.column_names) args = TrainingArguments( output_dir="./qwen3vl_lora_checkpoints", num_train_epochs=3, per_device_train_batch_size=1, gradient_accumulation_steps=8, learning_rate=2e-4, lr_scheduler_type="cosine", warmup_ratio=0.05, logging_steps=10, save_steps=200, evaluation_strategy="no", save_total_limit=2, fp16=False, bf16=True, report_to="none" ) trainer = Trainer( model=model, args=args, train_dataset=tokenized_dataset, tokenizer=processor.tokenizer ) trainer.train() trainer.save_model("./qwen3vl_lora_weights") processor.save_pretrained("./qwen3vl_lora_weights")这个脚本的核心逻辑是:先加载视觉-语言模型,注入 LoRA 适配器,再把 JSONL 数据转成带图像 token 的输入。per_device_train_batch_size设为 1 是为了适配大图输入,实际有效批量大小通过梯度累积提升。
6.2 目标模块怎么选
Qwen3-VL 的 LoRA 目标模块,建议至少覆盖自注意力层的 q/k/v/o,这也是 LoRA 论文和大多数开源实践的标准选择。如果你想让模型更好地学习领域术语和输出格式,可以额外加入 MLP 层的 gate_proj、up_proj、down_proj。
不要一开始就全部模块加 LoRA。模块越多,可训练参数量越大,显存占用也越高,同时过拟合风险增加。先从 q/k/v/o 开始,效果不够再扩展。
6.3 显存不足时的降级方案
如果训练时 OOM,优先做三件事:
- 降低
per_device_train_batch_size,保持梯度累积步数不变。 - 使用 4-bit 量化加载基础模型,
BitsAndBytesConfig把模型压到 4-bit,再叠加 LoRA。 - 限制图片最大边,例如从 2048 降到 1024。
4-bit 量化示例:
from transformers import BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True ) model = AutoModelForVision2Seq.from_pretrained( model_dir, quantization_config=bnb_config, device_map="auto", trust_remote_code=True )量化训练会略微降低最终精度,但对 LoRA 低秩适配来说,影响通常在可接受范围内。
7. 超参调优:哪些参数真正重要
LoRA 微调的参数可以分为三层:训练策略参数、LoRA 结构参数、数据参数。很多初学者只调学习率,忽略另外两层,效果自然上不去。
7.1 训练策略参数
| 参数 | 推荐区间 | 说明 |
|---|---|---|
| learning_rate | 1e-4 到 5e-4 | LoRA 通常比全量微调学习率更高 |
| num_train_epochs | 2 到 5 | 数据少时先跑 3 epoch 观察 |
| per_device_train_batch_size | 1 到 4 | 多模态输入显存占用大,优先 1 |
| gradient_accumulation_steps | 4 到 16 | 保证有效批量在 8 到 32 之间 |
| warmup_ratio | 0.03 到 0.1 | 稳定训练初期 |
| lr_scheduler_type | cosine 或 linear | cosine 更稳妥 |
学习率是最敏感的参数。学习率太大,LoRA 适配器会破坏原始模型的视觉能力,Loss 曲线波动非常大;学习率太小,训练几轮后 Loss 不下降。建议先用 2e-4 跑一个 200 步的小实验,观察 Loss 下降速度再决定。
7.2 LoRA 结构参数
| 参数 | 推荐值 | 说明 |
|---|---|---|
| r | 8 到 32 | 数据量少用 8,数据量大用 16 或 32 |
| lora_alpha | r 的 1 到 2 倍 | 例如 r=16 时,alpha=32 |
| lora_dropout | 0 到 0.1 | 数据少时 dropout 设低一些 |
r的大小决定了适配器的表达能力。r=8 适合样式迁移或版式识别,r=32 适合需要模型记住大量新知识的场景。不要盲目追求大 r,r 过大会引入更多可训练参数,在小数据集上反而过拟合。
7.3 数据参数
max_length:多模态训练一般设置 2048 或 4096。如果输出是固定 JSON 结构,2048 足够。- 图片分辨率:保持训练和推理一致。训练时用 1024x1024,推理时也建议走同样的预处理。
- 指令多样性:同一张图配多种问法,可以提高模型的泛化能力。
8. 效果评估:不要只看 Loss
Loss 下降不代表业务效果达标。多模态模型微调后,最常见的问题是“模型学会了输出格式,但识别内容正确率不行”或“训练集表现好,验证集明显下降”。所以效果评估必须分三层做。
8.1 第一层:生成结果人工抽检
准备 20 到 50 条微调时没见过的验证数据,用微调后的模型跑生成,逐条检查输出是否满足预期。重点看三点:
- 字段是否提取正确。
- 输出格式是否严格符合 JSON 或 Markdown 要求。
- 面对模糊图片时是否合理拒绝回答,而不是乱编。
人工抽检脚本:
from transformers import AutoModelForVision2Seq, AutoProcessor import torch model_dir = "./qwen3vl_lora_weights" model = AutoModelForVision2Seq.from_pretrained(model_dir, torch_dtype=torch.bfloat16, device_map="auto") processor = AutoProcessor.from_pretrained(model_dir) image_path = "test_images/val_001.jpg" image = Image.open(image_path).convert("RGB") query = "识别图片中的关键信息,输出 JSON。" messages = [ {"role": "user", "content": [{"type": "image"}, {"type": "text", "text": query}]} ] text = processor.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt") inputs = processor(text=text, images=image, return_tensors="pt") inputs = {k: v.to(model.device) for k, v in inputs.items()} output_ids = model.generate(**inputs, max_new_tokens=512, do_sample=False) answer = processor.decode(output_ids[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True) print(answer)8.2 第二层:指标量化评估
如果任务是可解析的,比如 OCR 提取、分类、JSON 字段抽取,可以写评估脚本计算准确率或字段级 F1。一个常见的做法是:让模型输出 JSON,然后用json.loads解析,再和标注答案逐字段对比。
import json def eval_json_field(pred_text, gt_dict): try: pred = json.loads(pred_text) except Exception: return 0.0 correct = 0 total = len(gt_dict) for k, v in gt_dict.items(): if str(pred.get(k)) == str(v): correct += 1 return correct / total if total else 0.08.3 第三层:与基线模型对比
同一批验证数据,分别跑 Qwen3-VL 原始模型和 LoRA 微调模型。如果微调后指标没有提升,甚至下降,说明数据或参数设置有问题,常见原因有:标注不一致、训练轮次过多导致过拟合、LoRA rank 太小、chat template 拼接错误。
9. 模型合并与导出
LoRA 训练完,得到的是一个小体积的 adapter 权重文件。部署时有两种方式:合并回原模型保存为完整权重,或单独加载 adapter。
合并方式更利于生产部署,因为 vLLM 对合并后的完整模型支持更直接。合并代码:
from peft import PeftModel base_model = AutoModelForVision2Seq.from_pretrained(model_dir, torch_dtype=torch.bfloat16, device_map="cpu") merged_model = PeftModel.from_pretrained(base_model, "./qwen3vl_lora_weights") merged_model = merged_model.merge_and_unload() merged_model.save_pretrained("./qwen3vl_merged")合并后的模型可以再次推送到 HuggingFace 或 ModelScope,也可以直接本地加载推理。注意合并过程会占用一份完整权重的内存,建议用 CPU 合并或显存充足的机器执行。
10. 部署推理:vLLM API 与批量任务
10.1 vLLM 搭建 OpenAI 兼容接口
微调并合并后的模型,推荐用 vLLM 部署。vLLM 对 Qwen 系列支持比较好,能实现高吞吐推理,并且提供 OpenAI 风格的/v1/chat/completions接口,业务系统对接成本低。
python -m vllm.entrypoints.openai.api_server \ --model ./qwen3vl_merged \ --trust-remote-code \ --dtype bfloat16 \ --served-model-name qwen3vl-lora \ --host 0.0.0.0 \ --port 8000 \ --limit-mm-per-prompt image=5--limit-mm-per-prompt image=5表示每条请求最多传 5 张图。按需调整。
启动后,接口地址是http://127.0.0.1:8000/v1/chat/completions,可以用如下 Python 脚本测试:
import base64 import requests api_url = "http://127.0.0.1:8000/v1/chat/completions" with open("test_images/val_001.jpg", "rb") as f: img_b64 = base64.b64encode(f.read()).decode() payload = { "model": "qwen3vl-lora", "messages": [ { "role": "user", "content": [ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_b64}"}}, {"type": "text", "text": "请提取图片中的订单号和收货地址,输出 JSON。"} ] } ], "max_tokens": 512, "temperature": 0.1 } resp = requests.post(api_url, json=payload, timeout=60) print(resp.json()["choices"][0]["message"]["content"])如果返回正常 JSON,说明部署链路是通的。
10.2 Transformers 方式部署
不依赖 vLLM 时,也可以用 Transformers 直接做推理。适合单机小批量验证,但并发能力不如 vLLM。
from transformers import AutoModelForVision2Seq, AutoProcessor model = AutoModelForVision2Seq.from_pretrained( "./qwen3vl_merged", torch_dtype=torch.bfloat16, device_map="auto" ) processor = AutoProcessor.from_pretrained("./qwen3vl_merged")10.3 批量任务队列
把接口部署好之后,批量任务的处理就变成了一个标准的队列问题。推荐目录结构:
batch_task/ ├── inputs/ # 待处理图片 ├── outputs/ # 识别结果 JSON ├── failed/ # 失败任务,便于重试 ├── run_batch.py └── task.log批量脚本伪代码:
import os import json import requests from pathlib import Path input_dir = Path("batch_task/inputs") output_dir = Path("batch_task/outputs") failed_dir = Path("batch_task/failed") output_dir.mkdir(exist_ok=True) failed_dir.mkdir(exist_ok=True) api_url = "http://127.0.0.1:8000/v1/chat/completions" for img_path in input_dir.glob("*.jpg"): try: # 读取图片,转 base64,组织 payload,调用接口 # 成功后保存 JSON 到 output_dir pass except Exception as e: print(f"failed: {img_path}, error: {e}") img_path.rename(failed_dir / img_path.name)批量任务建议加三样东西:重试机制、结果校验、进度日志。不要裸奔跑几千张图,中间接口抖动一次,你不知道哪些已经处理完。
11. 资源占用与性能观察
LoRA 训练和部署推理的显存占用可以从nvidia-smi实时观察。
watch -n 1 nvidia-smi训练时的显存占用主要来自四个部分:视觉编码器、语言模型、LoRA 适配器参数、优化器状态。LoRA 本身参数量很小,显存大头在基础模型和图像特征。以 8B 模型为例,fp16 加载约 16GB,再加上优化器和激活值,24GB 显卡比较从容;如果只有 16GB,建议 4-bit 量化加载。
推理阶段显存压力小得多。vLLM 部署时可以通过--gpu-memory-utilization控制显存占用比例:
python -m vllm.entrypoints.openai.api_server \ --model ./qwen3vl_merged \ --gpu-memory-utilization 0.85 \ --max-model-len 4096影响性能的关键因素:
- 图片分辨率越高,视觉 token 越多,prefill 时间越长。
max_model_len越大,KV Cache 占用越高,并发时越容易 OOM。- 批量并发数越高,吞吐越高,但单请求延迟会上升。
- 输出最大长度对显存影响也很大,能用 512 token 解决的任务不要设置 2048。
12. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 训练时 Loss 为 NaN | 学习率过大或 bf16 不稳定 | 查看日志中的 loss 曲线 | 降低学习率;尝试 fp16 |
| 图像标记没有被解析 | chat template 用错 | 检查apply_chat_template输出是否包含<image> | 使用 Qwen3-VL 专用 processor |
| 显存不足 OOM | 批量大小过大或图片分辨率过高 | 观察 nvidia-smi | 降低 batch size;缩小图片;开启 4-bit 量化 |
| 微调后输出格式错误 | 训练数据格式不一致 | 抽检训练集标注 | 统一 JSON 格式;增加格式约束指令 |
| vLLM 启动报错 | 权重未合并或缺少 trust_remote_code | 查看启动日志 | 合并 LoRA 权重;加--trust-remote-code |
| API 返回 400 | base64 编码格式错误或图片过大 | 用 curl 测试接口 | 检查 Content-Type 和 base64 前缀 |
| 批量任务卡住 | 单张图片请求超时 | 查看服务日志 | 增加 timeout;设置失败重试 |
| 验证集效果低于原模型 | 过拟合或数据不足 | 对比训练集/验证集指标 | 减少 epoch;增加数据多样性;降低 LoRA rank |
13. 最佳实践与使用建议
训练前,先选定一个最小可运行样本集,跑通全流程,再逐步扩大数据量。这样能在最短时间内暴露环境问题和数据格式问题,而不是等 2 小时训练完才发现 chat template 写错了。
训练时保持数据文件和训练脚本目录分离。模型权重、训练数据、评估结果、批量任务输出分目录管理,方便复现和排查。
project/ ├── data/ │ ├── train.jsonl │ ├── val.jsonl │ └── images/ ├── scripts/ │ ├── train_lora.py │ ├── evaluate.py │ └── batch_infer.py ├── models/ │ ├── base/ │ └── merged/ ├── outputs/ │ ├── checkpoints/ │ └── batch_results/ └── logs/批量任务必须设计失败重试机制。图片解码失败、接口超时、JSON 解析失败都要单独处理,不要因为一条坏数据让整个队列挂掉。
如果模型在业务数据上表现不稳定,优先检查数据质量,不要急着加模块或调 LoRA rank。数据标注一致性对多模态模型的影响,比超参更大。
14. 总结与下一步
Qwen3-VL 的 LoRA 微调并没有想象中复杂,核心是四件事:把图文数据转成标准 messages 格式、用对 Chat Template、控制好 LoRA 结构和训练参数、部署后按业务指标评估效果。最容易踩的坑就是 chat template 拼接错误和数据格式不一致,这两点做好了,训练基本成功一半。
建议你先跑通这一套小实验流程,确认效果后,再考虑扩展方向:一是把微调后的模型接入 RAG 流水线,让检索系统支持图文理解;二是用 LoRA 训练多个垂直领域适配器,按需动态加载;三是结合 Qwen3-VL 的视频理解能力,探索长视频内容的自动化结构化。每一步都先小批量验证,再上生产。