不用 LLM 也能抽 JSON?GLiNER2 机制与工程落地文刚刚在掘金传开
【免费下载链接】gliner2.5-multi-v1项目地址: https://ai.gitcode.com/hf_mirrors/fastino/gliner2.5-multi-v1
2026 年 6 月 18 日,掘金上一篇题为《不用 LLM 抽 JSON?GLiNER2 机制与工程落地》的文章开始进入技术圈视野(作者:贵慜_Derek,信源指向论文 arXiv:2507.18546 与仓库 fastino-ai/GLiNER2)。标题本身就带着一个反直觉的提问:信息抽取不是已经被大模型承包了吗,为什么还要绕开 LLM?
答案藏在 GLiNER 这条被低估的技术路线上:用几亿参数的 encoder 模型,在纯 CPU 上完成实体识别、文本分类、关系抽取和结构化记录(JSON)抽取,不调 API、不上 GPU、数据不出本地。本文结合论文原文、Fastino 的 GLiNER2.5 多语言模型仓库与本仓库源码,把这套机制的来龙去脉和工程落地讲清楚。
一条线索,两个"GLiNER2":先澄清命名混淆
要读懂这篇文章,必须先处理一个真实的搜索陷阱:中文社区里叫"GLiNER2"的东西有两个,技术路线完全不同。
一个是 urchade/GLiNER 仓库演进出的 v2,走 bi-encoder 路线,约 6000 万参数,社区文章描述其主打边缘部署与推理加速;另一个是 Fastino AI 在 2025 年 7 月 24 日发表的论文《GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface》(arXiv:2507.18546)所对应的统一多任务抽取框架。掘金这篇文章指向的是后者——一个将 NER、文本分类、层级结构化抽取收进同一架构、以 schema 声明式接口驱动的系统。
这种命名撞车,恰恰解释了为什么 GLiNER2 的中文资料传播得如此零散:关键词检索总是同时命中两条叙事线。这也是下文"为什么中文开发者现在才注意到它"的线索之一。
机制拆解:从"span 网格"到"boundary 稀疏配对"
Fastino 的 GLiNER2 延续了原版 GLiNER 的核心思路——用自然语言标签"提示"一个预训练 encoder 做零样本抽取,而不是为每个标签单独训练。论文给出的统一输入格式是:
[Task Prompt] ⊕ [SEP] ⊕ [Input Text]任务提示词里写的是什么,模型就抽什么。这一点在本仓库的 tokenizer_config.json 里有直接证据:词表中新增了一批语义化的特殊 token——[P](任务提示起始)、[E](实体类型)、[C](结构字段/子组件)、[L](分类标签)、[R](关系)、[SEP_STRUCT]、[SEP_TEXT]等。模型在训练中学会用这些 token 的嵌入与文本 span 做相似度打分,打分高于阈值即输出实体或字段值。
但 GLiNER2 真正的机制升级在解码端。原版 GLiNER 枚举"最大宽度内所有 span",复杂度随文本宽度增长;GLiNER2 改为boundary 架构——只预测 start/end 边界,再做稀疏配对,任意长度的 span 只要落在编码窗口内都能表达,不再受固定宽度网格限制。本仓库 config.json 将这一设计落到了具体超参数上:
"architecture": "boundary",模型类为BoundaryExtractor;start_top_k: 24、end_top_k: 24、ends_per_start: 12:每侧只保留 Top-K 候选边界,再做配对,把 O(n²) 的枚举压缩成稀疏候选集;boundary_top_k_max: 128、candidate_budget: 192:全局候选预算控制;max_len: 4096:boundary 模式下 span 长度上限即编码窗口长度;overlap_policy: "flat":重叠 span 通过加权区间调度去重。
仓库中的gliner2.5-multi-v1正是这条路线的最新多语言检查点:287M 参数,编码器为 mDeBERTa-v3-base,权重约 594MB(README.md 的 Model details 一节),并已开启 classification、records、relations 三个任务头(config 中enable_records: true、enable_relations: true)。加载时需使用AutoExtractor——因为GLiNER2.from_pretrained是旧版 span 架构的加载器,不会分发这个检查点:
from gliner2 import AutoExtractor model = AutoExtractor.from_pretrained("fastino/gliner2.5-multi-v1") print(type(model).__name__) # BoundaryExtractor print(model.config.architecture) # boundary"不用 LLM 抽 JSON"的工程价值:成本与延迟
结构化抽取(论文称 hierarchical structure extraction,仓库称 structured records)是这篇文章标题里"抽 JSON"的落点。论文验证了它的可行性与代价:训练数据共 254,334 条,其中 135,698 条真实文档(新闻、法律、PubMed、ArXiv、Wikipedia,由 GPT-4o 自动标注)加 118,636 条合成数据,5 个 epoch、AdamW、任务层学习率 2×10⁻⁵。这样一个通用小模型的零样本成绩是:分类任务平均准确率 0.72(GPT-4o 为 0.84,但模型参数差了三个数量级);CrossNER 五个领域平均 F1 为 0.590,几乎贴住 GPT-4o 的 0.599。
真正拉开差距的是延迟与部署成本。论文 Table 4 的 CPU 延迟实测(单位毫秒):
| 标签数 | GPT-4o(API) | DeBERTa-v3 zero-shot | GLiNER2 |
|---|---|---|---|
| 5 | 358 | 1714 | 130 |
| 20 | 425 | 6758 | 163 |
| 50 | 463 | 16897 | 208 |
| 相对加速比 | 1.00× | 0.10× | 2.62× |
两个关键结论:一是 GLiNER2 在标准 CPU 上比 GPT-4o API 快约 2.6 倍;二是它把全部标签放进一次前向传播,延迟几乎不随标签数增长,而 DeBERTa 式逐标签前向的方法在 20 个标签时慢了 6.8 倍。对每天处理海量短文本、对 QPS 敏感的生产管线,这就是从"按 token 计费 + 网络往返"到"固定成本 + 本地推理"的切换。更现实的意义在数据主权:医疗、金融、政务场景要求 PII 不出域,GLiNER2 的本地部署能力直接踩中了 GDPR/HIPAA 合规诉求。
工程落地:从 schema 到 JSON,一次前向
仓库源码展示的落地方式比论文更细。结构化记录用声明式 schema 描述,natural模式配合锚点字段保持"实例身份"——谁买了什么,而不是把字段摊平成无关列表:
schema = ( model.create_schema() .structure("purchase", mode="natural", anchor="buyer") .field("buyer", dtype="str", cardinality="required_one") .field("item", dtype="str", cardinality="required_one") ) result = model.extract( "Alice bought apples and Bob bought oranges.", schema, ) # { # "purchase": [ # {"buyer": "Alice", "item": "apples"}, # {"buyer": "Bob", "item": "oranges"}, # ] # }这个输出就是文章标题里说的"JSON"——只是它由一个小型 encoder 在本地推理得出。同一套 API 还支持多任务组合:实体 + 文档级分类 + 关系 + 结构化记录在一次extract调用内完成(README.md 的 Task combination 一节给出了实体、sentiment 属性、topic 分类、works_for/announced关系与 announcement 结构同时输出的完整示例)。长文本场景下,extract_entities_long/extract_long以重叠分块扫描并按原文 offset 重映射 span,规避了max_len截断。
配套的还有托管训练链路:仓库里的 SKILL.md 记录了 Fastino 的托管 API 契约——上传数据集、提交训练任务、评估、部署检查点,覆盖"基础模型效果不够 → 用领域数据微调 → 部署"的完整闭环。也就是说,GLiNER2.5 既有 Apache 2.0 的开源权重(本仓库即其 Hugging Face 镜像),也有从零样本到微调的工程路径。
中文开发者为什么现在才注意到它
把情报与源码放在一起看,"迟到"的原因大致有三层。
第一层是认知惯性。过去两年信息抽取的叙事被 LLM 主导,多数工程团队默认"结构化抽取 = 调 API + 写 prompt",很少有人意识到 encoder 路线的 GLiNER 已在 PII 脱敏等场景成为事实标准——论文专门提到它被 Presidio、Gretel 等隐私工具采用。GLiNER2 把 NER 扩展到分类与结构化抽取后,覆盖的恰好是 RAG 预处理、客服意图识别、票据结构化这类高频、高量、对成本敏感的工程需求,但中文资料里长期只有零散的单点教程(多语言支持、微调手册、性能评估),缺少"机制 + 落地"的整合视角。
第二层是命名混乱抬高了检索成本。如上文所述,"GLiNER2"同时指向 urchade 的 bi-encoder 小模型与 Fastino 的 schema 驱动统一框架,搜索引擎给的两条线索互相稀释,读者很难第一时间定位到论文与仓库的对应关系。
第三层是价值锚点的迁移。随着 API 定价逐渐敏感、数据合规约束收紧,"免费额度内跑通 Demo"与"生产级成本可控"之间的鸿沟被放大。GLiNER2 给出的叙事恰好切中这个痛点:参数规模在 LLM 面前不值一提,但 CPU 可跑、Apache 2.0、数据不出域——在效率优先的场景里,小模型的竞争力从来不是"能力上限",而是"单位成本下的可用性"。掘金这篇文章踩中的,正是这个从"能不能"转向"划不划算"的节点。
回到标题的问题:不用 LLM 能不能抽 JSON?能,而且延迟更低、成本更可控、合规更干净。GLiNER2 的边界在于能力上限——复杂推理、开放域常识、模糊长文仍是 LLM 的主场;但在"标签可枚举、结构可声明"的抽取任务上,一个 2.87 亿参数、跑在 CPU 上的 BoundaryExtractor,已经把"结构化抽取"这件事从 API 账单里搬回了自己的服务器。
【免费下载链接】gliner2.5-multi-v1项目地址: https://ai.gitcode.com/hf_mirrors/fastino/gliner2.5-multi-v1
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考