@george_onx: Seeing a lot of comparisons of Jev w/ GLiNER models lately. If you're benchmarking, GLiNER2.5 is the latest version we'…

X AI KOLs Timeline Models

Summary

GLiNER2.5 is a multilingual boundary checkpoint for unified schema-based information extraction, supporting entities, classification, structured records, relations, and span attributes in one model.

Seeing a lot of comparisons of Jev w/ GLiNER models lately. If you're benchmarking, GLiNER2.5 is the latest version we've released. Tag @fastinoai with results so we can see how it holds up. 🤗 Model weights: https://t.co/WFyZXasPqw https://t.co/r18K0bTVUo
Original Article
View Cached Full Text

Cached at: 09/22/26, 07:53 AM

Seeing a lot of comparisons of Jev w/ GLiNER models lately.

If you’re benchmarking, GLiNER2.5 is the latest version we’ve released. Tag @fastinoai with results so we can see how it holds up.

🤗 Model weights: https://t.co/WFyZXasPqw https://t.co/r18K0bTVUo


fastino/gliner2.5-multi-v1 · Hugging Face

Source: https://huggingface.co/fastino/gliner2.5-multi-v1 Fastino Agent - Fine-tune GLiNER with a single prompt

Fine-tune and Deploy GLiNER2.5 with Fastino AgentarXiv PaperGitHubFollow @fastinoAI

https://huggingface.co/fastino/gliner2.5-multi-v1#gliner25-multi-unified-schema-based-information-extractionGLiNER2.5 Multi: Unified Schema-Based Information Extraction

Extract entities, classify text, parse structured records, score span attributes, and extract relations — all in one boundary architecture.

GLiNER2.5 Multi is the multilingual boundary checkpoint. It is built on mDeBERTa-v3-base and is the default choice when you need entities, classification, records, and relations in one model across languages. Load it withAutoExtractor: the checkpoint’sarchitecturefield selectsBoundaryExtractorautomatically.

Fine-tune viaFastino. Join discussions onReddit.

  • 🎯 One model, many tasks: entities, classification, structured records, relations, and span attributes in a single schema
  • 📐 Boundary architecture: sparse start/end pairing instead of a fixed span-width grid — any span length that fits in the encoded window
  • 🔗 Constrained decoding:Classifierfor cross-task label constraints,JointIEfor typed entity–relation graphs
  • 💻 Local inference: CPU, CUDA, or MPS throughgliner2\[local\]— no external API required

https://huggingface.co/fastino/gliner2.5-multi-v1#gliner25-familyGLiNER2.5 family

This card is for**fastino/gliner2\.5\-multi\-v1**. All three checkpoints share the same public API.

https://huggingface.co/fastino/gliner2.5-multi-v1#installationInstallation

pip install "gliner2[local]"

Python 3.10 or newer is required. The\[local\]extra pulls in PyTorch so you can load Hub checkpoints.

https://huggingface.co/fastino/gliner2.5-multi-v1#load-the-modelLoad the model

Always useAutoExtractorfor GLiNER2.5.GLiNER2\.from\_pretrained\(\.\.\.\)is the legacyspanloader and will not dispatch this checkpoint.

from gliner2 import AutoExtractor

model = AutoExtractor.from_pretrained("fastino/gliner2.5-multi-v1")

print(type(model).__name__)
print(model.config.architecture)
# BoundaryExtractor
# boundary

Optional device, fp16, and compile flags:

model = AutoExtractor.from_pretrained(
    "fastino/gliner2.5-multi-v1",
    map_location="cuda",   # or "cpu" / "mps"
    quantize=True,         # fp16 weights on GPU
    compile=True,          # torch.compile after the first tracing call
)
print(type(model).__name__, next(model.parameters()).device)
# BoundaryExtractor cuda:0

https://huggingface.co/fastino/gliner2.5-multi-v1#usageUsage

https://huggingface.co/fastino/gliner2.5-multi-v1#entity-extractionEntity extraction

text = "Apple CEO Tim Cook announced iPhone 15 in Cupertino yesterday."

result = model.extract_entities(
    text,
    ["company", "person", "product", "location"],
    include_confidence=True,
    include_spans=True,
)
print(result)
# {
#     "entities": {
#         "company": [{"text": "Apple", "start": 0, "end": 5, "confidence": 0.98}],
#         "person": [{"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.97}],
#         "product": [{"text": "iPhone 15", "start": 29, "end": 38, "confidence": 0.96}],
#         "location": [{"text": "Cupertino", "start": 42, "end": 51, "confidence": 0.95}],
#     }
# }

Returned offsets are half-open character spans into the original string:text\[start:end\] == entity\["text"\].

Add descriptions when labels are domain-specific:

result = model.extract_entities(
    "Patient received 400mg ibuprofen for severe headache at 2 PM.",
    {
        "medication": "Names of drugs or pharmaceutical substances",
        "dosage": "Amounts such as 400mg, 2 tablets, or 5ml",
        "symptom": "Reported symptoms or conditions",
        "time": "Clock times or relative times",
    },
    include_spans=True,
)
print(result)
# {
#     "entities": {
#         "medication": [{"text": "ibuprofen", "start": 23, "end": 32}],
#         "dosage": [{"text": "400mg", "start": 17, "end": 22}],
#         "symptom": [{"text": "severe headache", "start": 37, "end": 52}],
#         "time": [{"text": "2 PM", "start": 56, "end": 60}],
#     }
# }

https://huggingface.co/fastino/gliner2.5-multi-v1#text-classificationText classification

Independent per-task decoding withclassify\_text:

result = model.classify_text(
    "This laptop has amazing performance but terrible battery life!",
    {"sentiment": ["positive", "negative", "neutral"]},
)
print(result)
# {"sentiment": "negative"}

result = model.classify_text(
    "Great camera quality, decent performance, but poor battery life.",
    {
        "aspects": {
            "labels": ["camera", "performance", "battery", "display", "price"],
            "multi_label": True,
            "cls_threshold": 0.4,
        }
    },
)
print(result)
# {"aspects": ["camera", "performance", "battery"]}

https://huggingface.co/fastino/gliner2.5-multi-v1#constrained-classificationConstrained classification

Usegliner2\.classification\.Classifierwhen labels on one task legally constrain another.classify\_textwill not enforce those rules.

from gliner2.classification import (
    Classifier,
    ClassificationSchema,
    ClassificationConfig,
)
from gliner2.classification import constraints as C

clf = Classifier.from_pretrained("fastino/gliner2.5-multi-v1")

schema = (
    ClassificationSchema()
    .single("intent", ["read", "write", "delete"])
    .multi("effects", ["read_only", "create", "modify", "delete"], min_labels=1)
    .constrain(
        C.implies(("intent", "delete"), ("effects", "delete")),
        C.excludes(("intent", "read"), ("effects", "delete")),
    )
)

result = clf.classify("Delete the temporary file from /tmp", schema)
print(result.value("intent"))
print(result.value("effects"))
print(result.feasible)
print(result.to_dict())
# delete
# ['delete']
# True
# {
#     "intent": {
#         "value": "delete",
#         "confidence": 0.93,
#         "probabilities": {"read": 0.02, "write": 0.05, "delete": 0.93},
#     },
#     "effects": {
#         "value": ["delete"],
#         "confidence": 0.88,
#         "probabilities": {
#             "read_only": 0.04, "create": 0.03, "modify": 0.05, "delete": 0.88
#         },
#     },
#     "_meta": {"feasible": True, "decoder": "exact"},
# }

Prediction knobs belong inClassificationConfigon the call, not infrom\_pretrained:

result = clf.classify(
    "Preview the report",
    schema,
    config=ClassificationConfig(decoder="beam", beam_size=16),
)
print(result.value("intent"), result.value("effects"), result.feasible)
# read ['read_only'] True

https://huggingface.co/fastino/gliner2.5-multi-v1#relation-extractionRelation extraction

This checkpoint was trained withenable\_relations=True. Independent decoding:

text = "Alice works for Acme in Paris."
result = model.extract_relations(
    text,
    ["works_for", "located_in"],
    include_spans=True,
    include_confidence=True,
)
print(result)
# {
#     "relation_extraction": {
#         "works_for": [{
#             "head": {"text": "Alice", "start": 0, "end": 5, "confidence": 0.91},
#             "tail": {"text": "Acme", "start": 16, "end": 20, "confidence": 0.91},
#         }],
#         "located_in": [{
#             "head": {"text": "Acme", "start": 16, "end": 20, "confidence": 0.87},
#             "tail": {"text": "Paris", "start": 24, "end": 29, "confidence": 0.87},
#         }],
#     }
# }

Or through a schema:

schema = model.create_schema().relations(
    {"works_for": {"threshold": 0.6}, "located_in": {"threshold": 0.6}}
)
result = model.extract(text, schema, include_spans=True)
print(result)
# {
#     "relation_extraction": {
#         "works_for": [{
#             "head": {"text": "Alice", "start": 0, "end": 5},
#             "tail": {"text": "Acme", "start": 16, "end": 20},
#         }],
#         "located_in": [{
#             "head": {"text": "Acme", "start": 16, "end": 20},
#             "tail": {"text": "Paris", "start": 24, "end": 29},
#         }],
#     }
# }

Independent extraction doesnotguarantee thatworks\_forheads are people and tails are organizations.

https://huggingface.co/fastino/gliner2.5-multi-v1#joint-information-extractionJoint information extraction

JointIEscores mention and relation candidates, then searches a globally consistent graph with typed endpoints and uniqueness constraints.

from gliner2.joint_ie import JointIE, JointIEConfig

joint = JointIE.from_pretrained("fastino/gliner2.5-multi-v1")

schema = (
    joint.create_schema()
    .entities(["person", "organization", "location"])
    .relation("works_for", "person", "organization", unique_head=True)
    .relation("located_in", "organization", "location")
    .no_self_loops()
)

result = joint.extract(
    "Alice works for Acme in Paris. Bob joined Acme last year.",
    schema,
    config=JointIEConfig(optimizer="beam", beam_size=32),
)

print(result.feasible)
print(result.to_dict())
# True
# {
#     "entities": [
#         {"id": "e1", "type": "person", "text": "Alice", "start": 0, "end": 5, "confidence": 0.94},
#         {"id": "e2", "type": "organization", "text": "Acme", "start": 16, "end": 20, "confidence": 0.92},
#         {"id": "e3", "type": "location", "text": "Paris", "start": 24, "end": 29, "confidence": 0.90},
#         {"id": "e4", "type": "person", "text": "Bob", "start": 31, "end": 34, "confidence": 0.91},
#     ],
#     "relations": [
#         {"type": "works_for", "head": "e1", "tail": "e2", "confidence": 0.88},
#         {"type": "works_for", "head": "e4", "tail": "e2", "confidence": 0.81},
#         {"type": "located_in", "head": "e2", "tail": "e3", "confidence": 0.86},
#     ],
# }

Always checkresult\.feasible.Falsemeans the hard constraints could not be satisfied (distinct from “the text contains no facts”).

for rel in result.relations:
    head = result.entity(rel.head)
    tail = result.entity(rel.tail)
    print(f"{head.text} -{rel.type}-> {tail.text}")
# Alice -works_for-> Acme
# Bob -works_for-> Acme
# Acme -located_in-> Paris

https://huggingface.co/fastino/gliner2.5-multi-v1#span-attributes-people-with-sentimentSpan attributes: people with sentiment

Attributes arespan-conditioned. The model finds entities first, then scores attribute labels at those exact spans. They are not extra entity types and they are not document-level classification.

from gliner2 import AutoExtractor, AttributeGroup

model = AutoExtractor.from_pretrained("fastino/gliner2.5-multi-v1")

text = (
    "Alice was delighted with the promotion, "
    "but Bob sounded frustrated about the delay."
)

schema = (
    model.create_schema()
    .entities(["person"])
    .entity_attributes({
        "sentiment": AttributeGroup(
            ["positive", "negative", "neutral"],
            applies_to=["person"],
            qualify_labels=True,
        )
    })
)

result = model.extract(
    text,
    schema,
    include_spans=True,
    include_confidence=True,
)
print(result)
# {
#     "entities": {
#         "person": [
#             {
#                 "text": "Alice",
#                 "start": 0,
#                 "end": 5,
#                 "confidence": 0.96,
#                 "sentiment": {"label": "positive", "confidence": 0.89},
#             },
#             {
#                 "text": "Bob",
#                 "start": 44,
#                 "end": 47,
#                 "confidence": 0.95,
#                 "sentiment": {"label": "negative", "confidence": 0.84},
#             },
#         ]
#     }
# }

applies\_to=\["person"\]keeps sentiment off other entity types.qualify\_labels=Trueencodes model-facing queries assentiment: positivewhile returning the short labelpositive.

Restrict sentiment to people while still extracting companies:

schema = (
    model.create_schema()
    .entities(["person", "organization"])
    .entity_attributes({
        "sentiment": AttributeGroup(
            ["positive", "negative", "neutral"],
            applies_to=["person"],
            qualify_labels=True,
        )
    })
)

result = model.extract(
    "Alice praised Microsoft, but Bob criticized OpenAI.",
    schema,
    include_spans=True,
    include_confidence=True,
)
print(result)
# {
#     "entities": {
#         "person": [
#             {
#                 "text": "Alice",
#                 "start": 0,
#                 "end": 5,
#                 "confidence": 0.96,
#                 "sentiment": {"label": "positive", "confidence": 0.88},
#             },
#             {
#                 "text": "Bob",
#                 "start": 29,
#                 "end": 32,
#                 "confidence": 0.95,
#                 "sentiment": {"label": "negative", "confidence": 0.86},
#             },
#         ],
#         "organization": [
#             {"text": "Microsoft", "start": 14, "end": 23, "confidence": 0.97},
#             {"text": "OpenAI", "start": 44, "end": 50, "confidence": 0.96},
#         ],
#     }
# }

Organization spans have nosentimentfield. Person spans do.

https://huggingface.co/fastino/gliner2.5-multi-v1#structured-recordsStructured records

Record mode keeps instance identity (who bought what) instead of flattening fields into unrelated lists. Enablenaturalmode with an anchor field:

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,
)
print(result)
# {
#     "purchase": [
#         {"buyer": "Alice", "item": "apples"},
#         {"buyer": "Bob", "item": "oranges"},
#     ]
# }

This checkpoint was trained withenable\_records=True.

https://huggingface.co/fastino/gliner2.5-multi-v1#task-combinationTask combination

Compose entities, span attributes, classification, relations, and structures inoneextractcall:

from gliner2 import AttributeGroup

schema = (
    model.create_schema()
    .entities({
        "person": "Named people",
        "organization": "Companies or teams",
        "product": "Named products or services",
    })
    .entity_attributes({
        "sentiment": AttributeGroup(
            ["positive", "negative", "neutral"],
            applies_to=["person"],
            qualify_labels=True,
        )
    })
    .classification("topic", ["technology", "business", "sports", "politics"])
    .relations(["works_for", "announced"])
    .structure("announcement", mode="natural", anchor="product")
        .field("company", dtype="str")
        .field("product", dtype="str", cardinality="required_one")
)

text = "Apple CEO Tim Cook unveiled the iPhone 15 Pro for $999."
result = model.extract(text, schema, include_spans=True, include_confidence=True)
print(result)
# {
#     "entities": {
#         "person": [{
#             "text": "Tim Cook",
#             "start": 10,
#             "end": 18,
#             "confidence": 0.97,
#             "sentiment": {"label": "positive", "confidence": 0.82},
#         }],
#         "organization": [{"text": "Apple", "start": 0, "end": 5, "confidence": 0.98}],
#         "product": [{"text": "iPhone 15 Pro", "start": 32, "end": 45, "confidence": 0.96}],
#     },
#     "topic": {"label": "technology", "confidence": 0.94},
#     "relation_extraction": {
#         "works_for": [{
#             "head": {"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.86},
#             "tail": {"text": "Apple", "start": 0, "end": 5, "confidence": 0.86},
#         }],
#         "announced": [{
#             "head": {"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.84},
#             "tail": {"text": "iPhone 15 Pro", "start": 32, "end": 45, "confidence": 0.84},
#         }],
#     },
#     "announcement": [{
#         "company": "Apple",
#         "product": "iPhone 15 Pro",
#     }],
# }

Document-leveltopicis independent of per-personsentiment.

https://huggingface.co/fastino/gliner2.5-multi-v1#batch-inferenceBatch inference

texts = [
    "Google hired Jane Doe in London.",
    "Tesla launched the Model 3 in California.",
]
results = model.batch_extract_entities(
    texts,
    ["company", "person", "product", "location"],
    batch_size=8,
    include_spans=True,
)
print(results)
# [
#     {
#         "entities": {
#             "company": [{"text": "Google", "start": 0, "end": 6}],
#             "person": [{"text": "Jane Doe", "start": 13, "end": 21}],
#             "product": [],
#             "location": [{"text": "London", "start": 25, "end": 31}],
#         }
#     },
#     {
#         "entities": {
#             "company": [{"text": "Tesla", "start": 0, "end": 5}],
#             "person": [],
#             "product": [{"text": "Model 3", "start": 19, "end": 26}],
#             "location": [{"text": "California", "start": 30, "end": 40}],
#         }
#     },
# ]

batch\_extractaccepts one schema or a list of schemas (one per document).

https://huggingface.co/fastino/gliner2.5-multi-v1#long-documentsLong documents

extract\(\.\.\.\)withmax\_lentruncates. Long-context helpers scan overlapping word chunks and remap spans to document offsets.

long_text = ("Quarterly overview. " * 40) + "Satya Nadella spoke in Redmond about Microsoft."

result = model.extract_entities_long(
    long_text,
    ["person", "organization", "location"],
    chunk_size=384,
    chunk_overlap=64,
    include_spans=True,
)
print(result)
# {
#     "entities": {
#         "person": [{"text": "Satya Nadella", "start": 800, "end": 813}],
#         "organization": [{"text": "Microsoft", "start": 837, "end": 846}],
#         "location": [{"text": "Redmond", "start": 823, "end": 830}],
#     }
# }

result = model.extract_long(long_text, schema, chunk_size=384, chunk_overlap=64)
print(result["topic"])
# technology

The same idea applies toClassifier\.classify\_longandJointIE\.extract\_long.

Limits:

  • A span is kept only if its start and end fall in thesame chunk.
  • A relation is kept only if both endpoints were extracted in the same chunk.
  • Boundary models can represent arbitrarily long spansinside one encoded window; they do not stitch a mention whose endpoints never co-occur.

https://huggingface.co/fastino/gliner2.5-multi-v1#model-detailsModel details

  • Architecture:GLiNER2boundaryextractor (BoundaryExtractor)
  • **Candidate search:**sparse start/end pairing (not a dense\[L, W\]width grid)
  • **Span length:**any length that fits in the encoded window (max\_len=4096)
  • Encoder:microsoft/mdeberta\-v3\-base
  • **Parameters:**287M
  • Weights:~594 MB (mostly FP16)
  • **Language:**Multilingual
  • **Heads enabled:**classification, records (enable\_records=True), relations (enable\_relations=True)
  • Overlap default:flat(weighted interval scheduling); override per call withoverlap\_policy
  • **Input / output:**text → entities, labels, span attributes, records, and relation edges

Do not load this checkpoint withGLiNER2/SpanExtractor. Those classes expect the legacy span architecture.

https://huggingface.co/fastino/gliner2.5-multi-v1#citationCitation

If you use this model, please cite:

@misc{zaratiana2025gliner2efficientmultitaskinformation,
      title={GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface},
      author={Urchade Zaratiana and Gil Pasternak and Oliver Boyd and George Hurn-Maloney and Ash Lewis},
      year={2025},
      eprint={2507.18546},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2507.18546},
}

https://huggingface.co/fastino/gliner2.5-multi-v1#licenseLicense

Apache License 2.0.

https://huggingface.co/fastino/gliner2.5-multi-v1#linksLinks

Similar Articles