MM-Doc-Agent 是一个面向中文文档图像的多模态文档理解项目,基于 Qwen2.5-VL-3B-Instruct 构建,目标是完成文档图像问答、结构化证据抽取和证据区域定位。
项目覆盖数据转换、多模态 SFT 数据导出、LoRA/projector 训练、结构化输出解析、grounding 指标评估、OCR-assisted grounding、错误分析和本地 Docker/GPU 复现实验。
系统将文档理解拆分为两个可独立评估的子任务:答案抽取和证据定位。
文档图像 + 问题
-> Qwen2.5-VL 生成 answer / evidence
-> 结构化 JSON 解析
-> Answer EM/F1 与 evidence 指标评估
预测 evidence.text + OCR 文本框
-> 文本归一化与匹配
-> OCR bbox 选择
-> 替换生成式 bbox
-> 重新评估证据定位指标
该设计避免只用答案准确率评价文档 VQA,并能够明确区分“模型答对了”和“模型是否定位到正确证据区域”。
- 基于 Qwen2.5-VL-3B-Instruct 构建中文文档 VQA 流水线,输出
answer、evidence.text和evidence.bbox。 - 实现 XFUND-ZH 数据转换、固定基准集构造、LLaMA-Factory 多模态 SFT 数据导出、批量推理和评估脚本。
- 扩展 grounding-aware 评估指标,包括 Answer EM/F1、BBox Coverage、Evidence IoU All 和 Evidence IoU at Answer EM。
- 在本地 RTX 3060 12GB + Docker 环境下完成 base、language-side LoRA、strict-bbox LoRA 和 projector-adaptation 对比实验。
- 诊断出 language-side LoRA 可提升答案抽取,但直接生成 bbox 仍难以稳定完成证据定位。
- 实现 OCR-assisted grounding,将模型生成的
evidence.text与 OCR 文本框匹配,用检索式定位修正生成式 bbox。 - 提供错误样本分析和 bbox overlay 可视化,用于检查证据定位失败模式。
评估集:data/processed/xfund_zh_val_50.jsonl
| 方法 | Answer EM | Answer F1 | BBox Coverage | Evidence IoU All |
|---|---|---|---|---|
| Qwen2.5-VL-3B base | 0.3600 | 0.5434 | 0.7200 | 0.0183 |
| 500-sample LoRA | 0.5000 | 0.6585 | 1.0000 | 0.0048 |
| 1000-sample strict-bbox LoRA | 0.4600 | 0.6220 | 1.0000 | 0.0041 |
| 500-sample projector + LoRA | 0.4600 | 0.6377 | 0.9800 | 0.0266 |
| 500-sample LoRA + OCR grounding | 0.5000 | 0.6585 | 1.0000 | 0.4207 |
| 500-sample projector + OCR grounding | 0.4600 | 0.6377 | 0.9800 | 0.3696 |
实验结论:
- 500-sample LoRA 将 Answer F1 从
0.5434提升到0.6585,Answer EM 从0.3600提升到0.5000。 - LoRA 训练后 BBox Coverage 达到
1.0000,说明模型可以稳定输出 bbox 字段,但坐标本身仍不可靠。 visual.mergerprojector adaptation 将 Evidence IoU All 从0.0048提升到0.0266,说明 projector 训练对定位有正向作用,但幅度有限。- OCR-assisted grounding 将最佳答案模型的 Evidence IoU All 提升到
0.4207,说明在当前任务中,基于证据文本检索 OCR 框比直接生成 bbox 更稳定。
下图展示同一样本在 direct VLM bbox 与 OCR-assisted grounding 下的证据定位差异。绿色为 gold bbox,红色为预测 bbox。该样本中 direct bbox 的 Evidence IoU 为 0.00,OCR-assisted grounding 后 Evidence IoU 为 1.00。
下图汇总了两个核心指标:Answer F1 体现答案抽取能力,Evidence IoU All 体现证据定位能力。
mm-doc-agent/
app.py # Gradio / application 入口
configs/ # 模型与 LoRA 训练配置
data/samples/ # 轻量示例数据
scripts/
convert_xfund.py # XFUND -> 项目 JSONL
export_llamafactory.py # 多模态 SFT 数据导出
train_lora.py # LLaMA-Factory 训练命令生成
infer_jsonl.py # 批量推理
evaluate_jsonl.py # 单模型评估
compare_experiments.py # 多实验对比
export_xfund_ocr_index.py # OCR 文本框索引导出
apply_ocr_grounding.py # OCR-assisted grounding
render_error_overlays.py # bbox 可视化
src/mmdoc_agent/
data/ # 数据结构与 JSONL IO
models/ # Qwen-VL 加载、adapter 加载与输出解析
eval/ # 指标与报告
alignment/ # 偏好样本与规则校验
serve/ # Gradio UI 与 bbox 绘制
tests/ # 单元测试
每条 JSONL 样本表示一个文档问答样本:
{
"id": "zh_val_10_qa_214_199",
"image": "data/external/xfund/zh.val/zh_val_10.jpg",
"question": "表单中“固定电话”对应的值是什么?",
"answer": "021-51981368",
"evidence": {
"text": "021-51981368",
"page": 1,
"bbox": [1916.0, 1570.0, 2205.0, 1617.0]
},
"task_type": "field_extraction"
}转换 XFUND-ZH 标注:
python scripts/convert_xfund.py \
--annotation data/external/xfund/zh.train.json \
--image-dir data/external/xfund/zh.train \
--output data/processed/xfund_zh_train.jsonl构造固定基准集:
python scripts/make_fixed_benchmark.py \
--input data/processed/xfund_zh_val.jsonl \
--output-dir data/benchmarks/xfund_zh \
--seed 20260809 \
--val-count 200 \
--test-count 200导出 LLaMA-Factory 多模态 SFT 数据:
python scripts/export_llamafactory.py \
--input data/processed/xfund_zh_train_500.jsonl \
--output-dir outputs/llamafactory_data_xfund_zh_500_strictbbox生成 LoRA 训练命令:
python scripts/train_lora.py \
--dataset-dir outputs/llamafactory_data_xfund_zh_500_strictbbox \
--dataset-name mm_doc_agent \
--quantization-bit 0生成 projector-adaptation 训练命令:
python scripts/train_lora.py \
--dataset-dir outputs/llamafactory_data_xfund_zh_500_strictbbox \
--dataset-name mm_doc_agent \
--quantization-bit 0 \
--unfreeze-projector \
--additional-target visual.merger已验证训练环境:
GPU: NVIDIA RTX 3060 12GB
Base model: Qwen2.5-VL-3B-Instruct
Training backend: LLaMA-Factory
Container image: mm-doc-agent-lf:local
批量推理:
python scripts/infer_jsonl.py \
--input data/processed/xfund_zh_val_50.jsonl \
--output outputs/pred_xfund_zh_val_50_lora500.jsonl单模型评估:
python scripts/evaluate_jsonl.py \
--gold data/processed/xfund_zh_val_50.jsonl \
--pred outputs/pred_xfund_zh_val_50_lora500.jsonl多模型对比:
python scripts/compare_experiments.py \
--gold data/processed/xfund_zh_val_50.jsonl \
--run base=outputs/pred_xfund_zh_val_50_base.jsonl \
--run lora500=outputs/pred_xfund_zh_val_50_lora500.jsonl \
--run projector500=outputs/pred_xfund_zh_val_50_projector_additional.jsonl导出 OCR 文本框索引:
python scripts/export_xfund_ocr_index.py \
--annotation data/external/xfund/zh.val.json \
--image-dir data/external/xfund/zh.val \
--output data/processed/xfund_zh_val_ocr.jsonl使用 OCR 文本框修正生成式 bbox:
python scripts/apply_ocr_grounding.py \
--pred outputs/pred_xfund_zh_val_50_lora500.jsonl \
--ocr data/processed/xfund_zh_val_ocr.jsonl \
--gold data/processed/xfund_zh_val_50.jsonl \
--output outputs/pred_xfund_zh_val_50_lora500_ocr_grounded.jsonl渲染 gold/pred evidence bbox:
python scripts/render_error_overlays.py \
--gold data/processed/xfund_zh_val_50.jsonl \
--pred outputs/pred_xfund_zh_val_50_lora500_ocr_grounded.jsonl \
--image-root . \
--output-dir outputs/error_overlays/xfund_zh_val50_lora500_ocr_grounded可视化颜色约定:
green = gold bbox
red = predicted bbox
项目包含针对数据转换、输出解析、指标计算、训练命令生成、OCR grounding 和 bbox 可视化的单元测试。
PYTHONPATH=src python -m pytest -q最近一次本地验证:
23 tests passed

