本地模型Extraction对比评测:文本抽取与建筑足迹提取实战指南

📅 2026/8/27 5:32:01
本地模型Extraction对比评测:文本抽取与建筑足迹提取实战指南
这次我们要聊的题目有点特别不是推荐某个单一模型而是把本地模型放在同一个 extraction 任务里做 head to head 对比。extraction 这个词在工程里非常常见文本侧是文档字段抽取视觉侧是像 building footprint extraction建筑足迹提取这样的图像分割任务。它区别于普通的 ChatBot 问答要用结果质量、响应速度、显存占用、批量吞吐和接口稳定度来综合打分。为什么要关注本地模型因为 extraction 任务往往涉及敏感数据。合同里的金额、票据里的发票号、遥感影像里的建筑轮廓这些数据如果走公有云 API必然要考虑数据传输和第三方模型服务的合规成本。本地模型的好处是模型文件在本地推理过程不出内网批量任务可以按自己的节奏排队跑单次调用也没有按 token 计费的压力。这篇博客会做三件事第一给出一套本地 extraction 评测框架把文本抽取和图像分割两类任务统一成可量化的指标第二写出通用的模型部署、启动和 API 调用流程覆盖 Ollama、vLLM 和视觉分割模型的常见启动方式第三给出功能测试、批量任务、资源占用观测和问题排查清单。如果你正在做本地模型选型或者需要把信息抽取能力接进自己的系统这篇文章可以直接作为操作手册。1. 核心能力速览能力项说明评测任务类型文档字段抽取文本 extraction与建筑足迹提取building footprint extraction模型路线文本抽取用本地 LLM视觉提取用语义分割模型或 SAM 系列变体部署方式Ollama、vLLM、Transformers 推理脚本、图像分割推理脚本是否支持 API可选Ollama/vLLM 均可暴露 HTTP API视觉分割可封装 Flask/FastAPI 服务是否支持批量任务需要自行设计按文件目录遍历或按 JSONL 任务队列处理关键指标准确率、召回率、F1、单条耗时、峰值显存、批处理吞吐、接口成功率硬件门槛文本小模型可在 CPU 运行7B 以上建议 8G 显存图像分割建议 6G 以上显存运行平台Linux 服务器或 Windows WSL推荐 Docker 隔离环境配置可复现适合人群后端工程师、数据工程师、GIS 算法工程师、AI 应用开发这里的参数是通用经验值不针对某个具体版本。实际部署时同样的模型在不同设备上的启动速度和显存占用差异很大最终要以本机测试为准。2. 适用场景与使用边界extraction 任务落到实际业务中大致可以分成两个方向。2.1 文本字段抽取典型场景是文档自动化处理。业务人员每天会收到大量 PDF、Word、图片格式的合同、订单、发票、身份证件、银行回单。人工录入效率低且容易出错。用本地 LLM 做字段抽取可以先把文档转成文本或结构化切片再让模型按照预定义字段输出 JSON例如合同编号、签署日期、甲方名称、乙方名称、金额。发票代码、发票号码、开票日期、税额。收货地址、订单号、客户电话。这类任务的关键不是对话能力而是模型是否稳定输出符合 schema 的结果。很多通用模型聊天表现不错但一旦要求它输出严格 JSON 字段就可能出现字段缺失、日期格式错乱、金额单位错误。2.2 建筑足迹提取building footprint extraction 是遥感影像方向的经典任务目标是从卫星图或航拍图中把每一栋建筑的轮廓分割出来。这类结果通常用于城市管理、违章建筑监测、地图更新和人口密度估算。本地部署的价值在于数据隔离。高分辨率遥感影像往往有使用授权和保密要求把影像上传到外部平台存在合规风险。本地推理可以保证影像文件不离开单位网络。2.3 合规边界无论做哪种 extraction都必须注意数据来源合法。文档数据如果是用户提交的私人信息需要获得明确授权并做好脱敏处理。遥感影像必须来自合法采购或公开数据集不能使用来源不明的影像。如果后续对提取结果做商用发布还要确认原始数据集是否允许衍生使用。模型本身的开源协议也值得注意部分模型虽然权重免费但商用有附加条款。3. 本地模型评测环境准备本地模型评测不需要最贵的硬件但需要一套稳定的环境。先按下面的检查清单核对。3.1 硬件检查操作系统Ubuntu 22.04 及以上或者 Windows 11 WSL2。Linux 对显存管理和进程控制更方便。GPUNVIDIA 显卡优先驱动和 CUDA 版本要匹配 PyTorch 要求。显存小于 8G 时优先选 1.5B 到 8B 的量化模型8G 以上可以尝试更大模型。CPU 内存至少 16G批量抽取场景建议 32G。磁盘空间模型文件动辄 4G 到 30G建议保留 50G 以上可用空间。3.2 软件依赖建议用 Docker 或 conda 创建独立环境避免多个项目依赖冲突。基础依赖通常包括# 使用 conda 创建 Python 3.10 环境 conda create -n extract-eval python3.10 -y conda activate extract-eval # 安装 PyTorch实际版本以官方命令为准 pip install torch torchvision # 常用依赖 pip install transformers accelerate pandas numpy如果使用 Ollama安装非常直接curl -fsSL https://ollama.com/install.sh | sh如果是 vLLM 方案安装参考官方文档pip install vllm3.3 测试数据集准备评测模型不能只看一两个例子建议准备一份分层测试集。文本抽取方面准备 100 到 500 份文档或文本片段覆盖不同格式、不同长度、不同噪声场景。每份样本要人工标注标准字段结果。建筑足迹提取方面准备包含建筑标注掩码的遥感影像数据集。公开数据集可以使用社区常见的 building footprint 数据集比如 Massachusetts Buildings Dataset 或 SpaceNet但下载和使用前要确认许可证。评测数据集建议单独放置不要和训练数据混在一起。4. 本地模型部署与启动方式extraction 任务中文本和视觉两部分部署方式不同。下面给出一套可复用的部署框架。4.1 用 Ollama 启动本地文本模型Ollama 是目前最快的本地 LLM 启动方式之一。通过命令行拉取模型然后启动服务。# 拉取一个小尺寸模型实际模型名以要测试的模型为准 ollama pull qwen2.5:7b # 启动 Ollama 服务默认监听 11434 端口 ollama serve如果希望服务在后台运行可以设置环境变量export OLLAMA_HOST127.0.0.1:11434 nohup ollama serve ollama.log 21 启动后先做一次简单的连通性测试curl http://127.0.0.1:11434/api/chat -d { model: qwen2.5:7b, messages: [{role: user, content: 提取下面句子中的日期合同于2024年8月15日签署。}], stream: false }如果返回了带 content 的 JSON说明服务正常。4.2 用 vLLM 启动高吞吐模型服务对批量抽取任务vLLM 的吞吐优势更明显。它支持 OpenAI 兼容接口方便接入现有代码。vllm serve Qwen/Qwen2.5-7B-Instruct \ --host 127.0.0.1 \ --port 8000 \ --gpu-memory-utilization 0.85 \ --max-model-len 8192关键参数说明--gpu-memory-utilization控制显存使用上限避免显存写满导致 OOM。--max-model-len控制最大上下文长度长文本抽取任务需要提高这个值但会占用更多显存。--host和--port设置服务监听地址。vLLM 启动后接口路径是/v1/chat/completions。调用示例curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: Qwen/Qwen2.5-7B-Instruct, messages: [{role: user, content: 提取下面合同中的甲方和乙方名称。合同内容... }], temperature: 0.1, max_tokens: 512 }4.3 视觉分割模型推理脚本建筑足迹提取的模型推理和文本不同。如果使用基于 PyTorch 的分割模型可以写成标准脚本。import torch from PIL import Image from transformers import AutoImageProcessor, AutoModelForSemanticSegmentation # 这里以通用语义分割模型加载为例实际模型名按项目选择 model_name nvidia/segformer-b0-finetuned-ade-512-512 processor AutoImageProcessor.from_pretrained(model_name) model AutoModelForSemanticSegmentation.from_pretrained(model_name) image_path ./test_images/building_001.tif image Image.open(image_path).convert(RGB) inputs processor(imagesimage, return_tensorspt) with torch.no_grad(): outputs model(**inputs) logits outputs.logits # [batch, num_classes, height, width] pred logits.argmax(dim1).squeeze(0) # 保存预测掩码 from PIL import Image as PILImage pred_mask pred.byte().cpu().numpy() result PILImage.fromarray(pred_mask) result.save(./outputs/building_001_mask.png)这个脚本是通用模板。实际模型名、预处理方式和类别数都要根据你选的模型调整。5. 功能测试与效果验证部署成功后下一步是用统一的测试集验证效果。这一节要解决一个问题同一份数据怎么让不同模型在这个测试集上公平地跑完。5.1 文本字段抽取测试文本抽取测试建议固定一个 prompt 模板让模型输出 JSON。import json import requests OLLAMA_URL http://127.0.0.1:11434/api/chat MODEL_NAME qwen2.5:7b extract_prompt 请从下面的合同中提取指定字段仅输出 JSON不要添加解释。 字段合同编号、签署日期、甲方名称、乙方名称、合同金额、金额单位。 合同内容 samples [ { id: case_001, text: 采购合同。合同编号HT-2024-00123签署日期2024年8月15日 甲方北京某某科技有限公司乙方上海某某供应链有限公司 合同金额5,000,000元人民币。 } ] results [] for sample in samples: payload { model: MODEL_NAME, messages: [ {role: system, content: 你是一个文档字段抽取助手。}, {role: user, content: extract_prompt sample[text]} ], stream: False, temperature: 0.0, format: json } try: response requests.post(OLLAMA_URL, jsonpayload, timeout60) content response.json()[message][content] parsed json.loads(content) results.append({id: sample[id], predict: parsed}) except Exception as e: results.append({id: sample[id], error: str(e)}) with open(ollama_results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2)判断成功的标准返回能通过json.loads解析。所有必填字段都存在。日期格式统一比如YYYY-MM-DD。金额数字与原文一致单位没有错乱。常见失败原因prompt 里没给出 JSON 示例模型自由发挥。原文太长超出上下文窗口导致关键字段被截断。温度设置过高生成内容不稳定。抽取任务建议temperature0或接近 0。5.2 建筑足迹提取测试视觉模型的测试重点是分割掩码质量。测试时对每张影像生成预测掩码然后与标注掩码对比。评估脚本可以这样写import numpy as np from sklearn.metrics import precision_score, recall_score, f1_score def calculate_metrics(pred_mask, gt_mask): pred_flat pred_mask.flatten() gt_flat gt_mask.flatten() precision precision_score(gt_flat, pred_flat, zero_division0) recall recall_score(gt_flat, pred_flat, zero_division0) f1 f1_score(gt_flat, pred_flat, zero_division0) iou np.sum(pred_flat gt_flat) / np.sum(pred_flat | gt_flat) return precision, recall, f1, iou pred np.load(./outputs/building_001_mask.npy) gt np.load(./annotations/building_001_mask.npy) # 处理类别建筑类别的像素值通常为 1背景为 0 pred_binary (pred 1).astype(np.uint8) gt_binary (gt 1).astype(np.uint8) p, r, f, iou calculate_metrics(pred_binary, gt_binary) print(fPrecision: {p:.4f}, Recall: {r:.4f}, F1: {f:.4f}, IoU: {iou:.4f})IoU 是建筑足迹提取最常用的核心指标。一般来说IoU 大于 0.7说明提取结果和标注重合度较高。IoU 在 0.5 到 0.7说明轮廓基本正确边缘可能有偏差。IoU 小于 0.5说明模型召回或定位有较大问题。不要把单张图的 IoU 当结论。至少跑 50 张以上测试图片取平均值同时观察不同建筑密度区域的差异。5.3 批量测试入口不管是文本还是视觉都要有一个可复现的批量入口。推荐用 JSONL 文件组织任务{task_id: case_001, type: text, input: data/contracts/001.pdf} {task_id: case_002, type: image, input: images/building_002.tif} {task_id: case_003, type: text, input: data/contracts/002.pdf}然后写一个统一的分发脚本每处理完一条就写入结果文件这样中途失败也不会丢失全部进度。5.4 结果统计与模型对比多模型对比时建议把每个模型的结果汇总成一个表模型名称参数量量化方式F1/IoU平均单条耗时峰值显存接口成功率模型 A7Bfp16待测待测待测待测模型 B3Bint8待测待测待测待测这里的“待测”是有意留空因为不同显卡、不同批大小、不同精度下结果差异非常大。不要直接抄别人的数字要在自己的环境下跑一遍。6. 接口 API 与批量任务extraction 只跑一次 Demo 没有意义最终要接入业务系统。所以接口能力是一个重要对比维度。6.1 Ollama 接口能力Ollama 提供 HTTP API常用于轻量接入curl http://127.0.0.1:11434/api/chat \ -H Content-Type: application/json \ -d { model: qwen2.5:7b, messages: [{role: user, content: 提取这句话中的日期项目交付日期为2025年2月14日。}], stream: false, format: json }Ollama 也支持/api/embed做向量化可以用于后续做 embedding 对比。6.2 vLLM OpenAI 兼容接口vLLM 的接口兼容 OpenAI 格式业务代码里可以把 base_url 替换成 vLLM 地址from openai import OpenAI client OpenAI( base_urlhttp://127.0.0.1:8000/v1, api_keyEMPTY ) response client.chat.completions.create( modelQwen/Qwen2.5-7B-Instruct, messages[ {role: system, content: 你是文档字段抽取助手只输出 JSON。}, {role: user, content: 提取合同中的金额字段合同总金额为人民币120.5万元。} ], temperature0.0, max_tokens256 ) print(response.choices[0].message.content)这个接口非常适合接入已有业务系统不需要改太多代码。6.3 批量任务队列设计批量抽取任务建议做成“读取任务列表 → 逐条推理 → 写入结果 → 记录日志”的循环。import json import time from pathlib import Path task_file Path(./tasks.jsonl) result_file Path(./results.jsonl) result_file.touch(exist_okTrue) processed_ids set() if result_file.exists(): for line in result_file.open(encodingutf-8): try: processed_ids.add(json.loads(line)[task_id]) except: pass with task_file.open(encodingutf-8) as t_in, result_file.open(a, encodingutf-8) as r_out: for line in t_in: task json.loads(line) if task[task_id] in processed_ids: continue start time.time() try: # 这里替换成实际推理函数 predict_result run_inference(task) duration time.time() - start record { task_id: task[task_id], status: succeeded, result: predict_result, duration_s: round(duration, 3) } except Exception as exc: record { task_id: task[task_id], status: failed, error: str(exc) } r_out.write(json.dumps(record, ensure_asciiFalse) \n) r_out.flush()这个设计的优点是支持断点续跑失败任务不会清掉。每条结果实时落盘不需要等全部跑完。失败时保留错误信息方便排查。批量任务建议加上最大重试次数比如失败 3 次后跳过该任务。7. 资源占用与性能观察资源占用是本地模型选型的核心关注点。同一个模型用不同推理框架、不同量化方式表现差别很大。7.1 显存占用观察方法最直接的方法是使用nvidia-smi观察实时显存watch -n 1 nvidia-smi如果要记录推理过程中的峰值显存可以写一个小脚本import subprocess import re def get_gpu_memory_mb(): output subprocess.check_output([nvidia-smi, --query-gpumemory.used, --formatcsv,noheader,nounits]) return [int(x) for x in output.decode().strip().split(\n) if x.strip()] # 在推理前后各调用一次取差值作为本次任务显存占用 before get_gpu_memory_mb() # 执行推理 result run_inference(sample) after get_gpu_memory_mb() print(GPU used diff:, [a - b for a, b in zip(after, before)])显存占用不是固定值它和批量大小、上下文长度、图像分辨率直接相关。批量大小翻倍显存不一定翻倍但通常会明显上涨。7.2 影响性能的关键因素文本抽取任务里输入文本越长显存占用越高。长文本场景建议先做分块。max_tokens设置越大生成阶段显存峰值越容易出现。batch size 增大能提升吞吐但显存不足时需要回退。使用 int8 或 int4 量化可以大幅降低显存但可能带来少量效果损失。图像提取任务里输入图像分辨率越高显存占用越大。建筑足迹提取通常只需要 512 或 1024 分辨率不需要原图直接整张推理。大图建议切块预测然后拼接结果避免显存溢出。推理时关闭梯度计算可以明显节省显存。7.3 如何降低资源占用优先配置gpu-memory-utilization或max_memory限制显存上限。这样即使有其他服务在跑也不会挤爆显存。如果显存仍然不足按顺序尝试换更小的量化版本模型。降低批量大小。降低图像分辨率。启用 CPU offload。换更小的模型。实际占用的数据要放在自己的环境里测。不要因为别人的截图写“占用 6G 可以跑”就认为自己的设备一定可以。8. 常见问题与排查方法问题现象可能原因排查方式解决方案启动后页面或接口打不开端口被占用、服务没起来查看日志检查端口占用更换端口并重启服务依赖安装失败Python 版本不匹配、缺少编译依赖查看 pip 完整报错换 conda 环境按官方文档安装模型文件缺失权重未下载完成、路径不对检查模型缓存目录重新拉取模型确认路径显存不足 OOM批量参数太高、模型太大nvidia-smi观察显存降低 batch size改用量化版本CPU 推理很慢模型没有使用 GPU、或机器本来无 GPU检查日志和nvidia-smi确认 CUDA 可用或换更小的模型JSON 输出格式不稳定没有设置formatjson或 prompt 缺少示例查看原始输出固定 temperature 为 0给一个期望输出示例批量任务中途卡住单条请求超时、服务无响应查看服务日志和进程状态设置超时时间给推理接口加超时时长输出结果重复或空白上下文窗口不足、提示词混淆单独测试该条输入缩短输入或提高 max-model-len建模速度正常但图像分割结果错乱标签类别映射不对检查训练时类别定义调整掩码到目标类别的映射给接口加超时是最容易被忽略的一点。本地模型推理时间波动很大第一次可能 2 秒返回第 100 次可能因为上下文变长而跑到 30 秒。调用端建议配置较长的超时比如 60 到 300 秒而不是默认的 5 秒。9. 最佳实践与使用建议评测之前先定基准不要同时对比 5 个模型。建议先选 2 到 3 个模型用最小参数量版本跑通整个评测流程再逐步加模型。第一次评测应该关注“流程能不能跑完”而不是“哪个模型效果最好”。数据和模型分开管理一个典型的本地项目目录extract-eval/ ├── models/ # 本地权重 ├── data/ │ ├── raw/ # 原始文档或影像 │ ├── processed/ # 预处理后的数据 │ └── annotations/ # 标注文件 ├── outputs/ │ ├── predictions/ # 模型预测结果 │ └── logs/ # 运行日志和错误记录 └── scripts/ ├── run_text_extract.py ├── run_image_extract.py └── eval.py不要把模型文件、原始数据和输出结果混在一起。否则批量任务重跑时很容易误删或覆盖关键文件。批量任务必须有日志和重试批量 extraction 的耗时通常以小时计。没有日志就无法定位哪个任务失败没有重试就无法保证长时间任务的稳定性。推荐每处理一条就追加写入一行结果并记录耗时和状态。断点续跑时跳过已完成的任务 ID。这样既不会重复计算也避免了一次崩溃导致全部重来。接口服务要限制访问范围本地模型 API 默认可能监听在 0.0.0.0容易暴露到局域网。明确设置绑定地址为127.0.0.1或内网访问范围如果需要跨机器调用要加鉴权或放在内网网关后面。数据合规和授权不能省文档抽取可能涉及个人隐私、商业机密建筑足迹提取可能涉及高分辨率遥感影像。使用前必须确认是否有权处理这些数据。是否可以在本机保存和推理。提取结果是否可以商用。模型开源协议是否允许商用。一旦数据来源不合法无论模型效果多好都不能进入生产环境。10. 总结与下一步“Local models head to head for extraction”这个主题最值得尝试的点是把多个本地模型拉到同一个测试集上做横向对比而不是只看某一个模型的单条输出。你把第一份测试集跑完后至少能回答三个问题哪个模型在我的数据上准确率最高、哪个模型最省显存、哪个模型接口接入成本最低。最先应该验证的功能是一个最简抽取任务选一个小尺寸模型准备 20 份测试样本写一个带temperature0的 prompt让它返回 JSON同时用nvidia-smi记录显存。一条链路跑通后再扩大到完整测试集。最容易踩的坑有三个第一没有固定 prompt 模板导致模型输出格式不稳定第二批量任务没有断点续跑跑到一半失败只能从头再来第三忽略了显存峰值与 batch size 的关系批量一开就 OOM。后续可以扩展的方向很多文本抽取可以加 RAG让模型先检索再抽取图像提取可以加后处理算法把分割掩码转成矢量多边形方便 GIS 软件直接使用多个模型对比可以做成一个自动化的评测流水线每次更新模型权重后自动出对比报告。只要评测规范和数据管理做扎实这个流程就可以复用很长时间。