Library / SDK
Knowledgator/GLiClass avatar
Knowledgator/GLiClass

GLiClass: zero-shot text classification in a single forward pass

Generalist and Lightweight Model for Text Classification

570 stars45 forksPythonApache-2.0

At a glance

What is it?
GLiClass is a generalist and lightweight sequence classification model that classifies text against label sets you supply at inference time, with hierarchical labels, few-shot examples, prompts, long-document chunking and a Ray Serve deployment path. The README claims roughly ten times the speed of traditional cross-encoder models, and the package itself is still on a 0.1 version line.
Who is it for?
GLiClass fits a team that wants to classify text into categories it did not train on, such as support ticket routing or content moderation, and that needs the same model to handle many different label sets without retraining.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One forward pass instead of one pass per label

GLiClass is described as an efficient, zero-shot sequence classification model inspired by the GLiNER framework, and it achieves comparable performance to traditional cross-encoder models while being significantly more computationally efficient, offering classification results approximately ten times faster by performing classification in a single forward pass.

The mechanism behind that number is the whole design. A cross-encoder scores a text against a label by encoding both together, which means a separate forward pass per label and a cost that grows with the size of the label set. GLiClass encodes the text once and scores all the labels from that single representation, so a classifier with fifty labels costs roughly what a classifier with one label costs.

That matters for the zero-shot setting specifically, where the label set is a runtime input rather than something baked into the weights. A pipeline that has to route every incoming ticket into one of two hundred categories cannot afford two hundred forward passes per ticket, and this is the case the architecture is built for.

The comparison to a cross-encoder is also the right benchmark to keep in mind when reading the claim. Comparable performance to traditional cross-encoder models is not the same as beating a fine-tuned one, and for a fixed label set with labelled data, a fine-tuned cross-encoder is still the stronger choice.

The project publishes Apache-2.0 licensed code, the models are on Hugging Face under the knowledgator organisation, and there is a browser demo on a Hugging Face Space, a blog post explaining the approach and a Discord for questions.

Install from pip or from the source tree

The quick start is one pip command:

bash
pip install gliclass

The source route is spelled out in full, and it is the one to use if you want to train or fine-tune:

bash
git clone https://github.com/Knowledgator/GLiClass
cd GLiClass

python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

pip install -r requirements.txt
pip install .

There is then a verification step worth doing, because the package version is what tells you which release you actually have:

python
import gliclass
print(gliclass.__version__)

The version is dynamic in the packaging metadata, taken from the gliclass.__version__ attribute, so it reflects the source tree rather than a number typed into the manifest.

The runtime dependencies are deliberately narrow. The manifest requires Python 3.10 or newer, and lists torch 2.0.0 or newer, transformers 5.0.0 or newer, scikit-learn 1.0.0 or newer and numpy 2.0.0 or newer. The Transformers 5 floor is the one to look at closely, because that major version is recent and a lot of existing environments are still on the 4.x line.

Two optional extras extend that. The streaming extra pulls in torch and transformers again, and the serve extra adds ray with the serve component, requests and pyyaml.

The pipeline takes labels at call time

The usage example shows the shape of the API, and it is a Hugging Face style pipeline rather than a bespoke object model.

python
from gliclass import GLiClassModel, ZeroShotClassificationPipeline
from transformers import AutoTokenizer

model = GLiClassModel.from_pretrained("knowledgator/gliclass-small-v1.0")
tokenizer = AutoTokenizer.from_pretrained("knowledgator/gliclass-small-v1.0")

pipeline = ZeroShotClassificationPipeline(
    model, tokenizer, classification_type='multi-label', device='cuda:0'
)

text = "One day I will see the world!"
labels = ["travel", "dreams", "sport", "science", "politics"]
results = pipeline(text, labels, threshold=0.5)[0]

for result in results:
    print(f"{result['label']} => {result['score']:.3f}")

Three things in that snippet are structural rather than incidental. The model and the tokenizer are loaded separately from the same checkpoint, which is the standard Hugging Face arrangement and means you can swap the checkpoint without touching the pipeline code. The classification_type is set to multi-label, so a text can come back with several labels above the threshold rather than exactly one. And the device is passed to the pipeline, so the model runs on the GPU.

The labels are a plain list of strings passed on each call. That is the zero-shot contract: nothing about the label set is baked into the model, and the same loaded pipeline can classify a support ticket against one taxonomy and a news article against another.

The threshold of 0.5 decides which scores survive into the results. It is a filter on confidence rather than a probability in any strict sense, and for multi-label work it is the parameter you will spend the most time tuning.

Hierarchical taxonomies and in-context examples

Two features go beyond a flat label list, and both are aimed at real labelling schemes rather than at a demo.

Hierarchical labels use dot notation, so a taxonomy is passed as a dictionary of categories to subcategories:

python
hierarchical_labels = {
    "sentiment": ["positive", "negative", "neutral"],
    "topic": ["product", "service", "shipping"]
}

text = "The product quality is amazing but delivery was slow"
results = pipeline(text, hierarchical_labels, threshold=0.5)[0]

for result in results:
    print(f"{result['label']} => {result['score']:.3f}")
# Output:
# sentiment.positive => 0.892
# topic.product => 0.921
# topic.shipping => 0.763

The dotted path is the label, so sentiment.positive and topic.shipping are distinct outputs from two different branches of the taxonomy in one call. Passing return_hierarchical=True changes the shape of the answer to match the input, giving you a nested dictionary of category to subcategory to score instead of a flat list.

Few-shot examples work through an example parameter and a special token. The examples are a list of text and label pairs, and the model reads them as in-context demonstrations:

python
examples = [
    {
        "text": "Love this item, great quality!",
        "labels": ["positive", "product"]
    },
    {
        "text": "Customer support was unhelpful",
        "labels": ["negative", "service"]
    }
]

text = "Fast delivery and the item works perfectly!"
labels = ["positive", "negative", "product", "service", "shipping"]

results = pipeline(text, labels, examples=examples, threshold=0.5)[0]

The README attributes the accuracy improvement to the <<EXAMPLE>> token, so the examples are encoded in a form the model was trained to recognise rather than being concatenated as ordinary text. The trade-off is that the demonstrations consume context, so the number you can pass is bounded by the model's input length.

A third feature is task description prompts. A prompt argument lets you tell the model what it is classifying, for example Classify the sentiment of this product review:, and the prompt can also be a list, one per text, when you are processing a batch of differently framed items.

Long documents, chunking, and retrieval-augmented classification

Documents that do not fit in the context window are handled by a second pipeline, ZeroShotClassificationWithChunkingPipeline, which chunks the text automatically:

python
from gliclass import ZeroShotClassificationWithChunkingPipeline

chunking_pipeline = ZeroShotClassificationWithChunkingPipeline(
    model,
    tokenizer,
    text_chunk_size=8192,
    text_chunk_overlap=256,
    labels_chunk_size=8
)

long_document = "..." # Very long text
labels = ["category1", "category2", "category3"]

results = chunking_pipeline(long_document, labels, threshold=0.5)

Three parameters describe the strategy. The text chunk size is how much of the document goes into one pass, the overlap stops a sentence that straddles a boundary from being lost, and the labels chunk size caps how many labels are scored at once, which is a second lever on the memory cost.

That last parameter is the one to notice. Chunking the labels means a large taxonomy is scored in batches rather than in one shot, which keeps memory bounded at the cost of more passes over the text. Whether that trade is right depends on your label count.

Retrieval-augmented classification is the other half of the accuracy story. The README points at models trained with retrieval-augmented classification, such as gliclass-base-v2.0-rac-init, and shows an example passed as rac_examples, where the entry carries the full label set and the labels that were correct:

python
example = {
    "text": "A new machine learning platform automates complex data workflows but faces integration issues.",
    "all_labels": ["AI", "automation", "data_analysis", "usability", "integration"],
    "true_labels": ["AI", "integration", "automation"]
}

Note the difference from the plain few-shot examples. A rac_examples entry carries the full label set and the true labels, so it teaches the model both what the labels mean and how they are meant to be assigned, rather than showing a text with a couple of labels attached. The threshold used in the README example is 0.1 rather than 0.5, which is what you would expect when the model is being asked to separate a small number of labels from a wide set.

Serving it with Ray Serve

The production path is an optional extra, installed with:

bash
pip install gliclass[serve]

and started as a module. There are three documented invocations, the default model, a named model on a chosen port, and a config file:

bash
# Default model
python -m gliclass.serve

# Specify model and port
python -m gliclass.serve --model knowledgator/gliclass-edge-v3.0 --port 8000

# With config file
python -m gliclass.serve --config serve_configs/serve_config.yaml

The README describes the deployment as using Ray Serve with dynamic batching and memory-aware processing, and the repository carries a serve_configs directory with the yaml file the config option points at.

The client is a small wrapper, GLiClassClient, that takes a url and exposes classify:

python
from gliclass.serve import GLiClassClient

client = GLiClassClient(url="http://localhost:8000/gliclass")

result = client.classify(
    text="This is a great product!",
    labels=["positive", "negative", "neutral"],
    threshold=0.3,
)
print(result)  # [{"label": "positive", "score": 0.95}, ...]

Over plain HTTP the endpoint is a POST to /gliclass with a JSON body of texts, labels and threshold, and the README notes that it processes one text per request. That last constraint is the one to plan around, because a batch endpoint that fans out over several texts would remove most of the overhead of going over the network. The dynamic batching on the server side exists precisely to absorb that, but the client contract is still one text per call.

A 0.1 version line with a Transformers 5 floor

The release history shows what the project has been working on. v0.1.18 added Transformers v5 support in May 2026, v0.1.19 added serving support in July 2026, and v0.1.20 added streaming support in July 2026. The last push to the repository was on 2026-10-16.

Those three releases in order describe the trajectory of the codebase: first the dependency floor moved to a new major version of Transformers, then the serving layer was added, then streaming. The version numbers are still in the 0.1 range, which under semantic versioning means the API is not promised to be stable, and that is worth weighing against a project whose whole point is being a drop-in dependency.

The repository layout shows the research side of the project as well as the library. There is train.py, train_rl.py for reinforcement learning training, calibrate.py for calibrating the outputs, demo.py, test_gliclass.py, a tests directory, a notebooks directory and a docs directory. The presence of a calibration script matters for anyone using the scores as thresholds, because a model's raw scores are not probabilities and calibration is how you make a threshold such as 0.5 mean something defensible.

The development tooling is small and modern. Pytest with pytest-asyncio and ruff for the dev group, with pytest configured to put the repository root on the path and to look in tests, and ruff configured with a line length of 120, a py310 target and a rule set covering pyflakes, pycodestyle, isort, pydocstyle, pyupgrade, bugbear, simplify, unused arguments and print statements.

The licence is Apache-2.0, which requires you to keep the licence and notices when you redistribute, and the project documentation lives at docs.knowledgator.com. The author field in the packaging metadata is knowledgator.com rather than an individual, so the maintenance commitment sits with the company behind the models.

Editorial conclusion

GLiClass fits a team that wants to classify text into categories it did not train on, such as support ticket routing or content moderation, and that needs the same model to handle many different label sets without retraining. It is the wrong choice if you need the accuracy of a fine-tuned cross-encoder on a fixed label set, since the model's selling point is generality rather than peak performance on one task, and it is the wrong choice if your environment is pinned to Transformers 4.x, because the package requires transformers 5.0.0 or newer. Verify first the accuracy on your own labels, since the comparison in the README is against cross-encoder models in the abstract, and check the model you pick on Hugging Face, since the small, base and edge variants are different sizes.

Frequently asked questions

What is GLiClass?

It is a generalist and lightweight model for sequence classification, and a zero-shot one, inspired by the GLiNER framework. The README claims performance comparable to traditional cross-encoder models at roughly ten times the speed, because classification happens in a single forward pass rather than one pass per label.

How do I install GLiClass?

With pip install gliclass, or from source by cloning the repository, creating a virtual environment and running pip install -r requirements.txt followed by pip install . The package requires Python 3.10 or newer, torch 2.0.0 or newer, transformers 5.0.0 or newer, scikit-learn 1.0.0 or newer and numpy 2.0.0 or newer.

Does GLiClass support hierarchical label sets?

Yes. You pass a dictionary of categories to subcategories and the labels come back as dotted paths such as sentiment.positive. Passing return_hierarchical=True returns a nested dictionary matching the structure you supplied.

How do I classify a document that is too long for the model?

Use ZeroShotClassificationWithChunkingPipeline with text_chunk_size, text_chunk_overlap and labels_chunk_size set on the constructor. It chunks the text automatically, with the overlap preventing a sentence split across a boundary from being lost.

Can GLiClass be deployed as a service?

Yes. Install the serve extra with pip install gliclass[serve], then run python -m gliclass.serve, optionally with --model, --port or --config pointing at a yaml file. The README describes it as Ray Serve with dynamic batching and memory-aware processing, and the HTTP endpoint processes one text per request.

Official sources

  1. Knowledgator/GLiClass on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/knowledgator-gliclass.svg)](https://hysenlabs.com/projects/knowledgator-gliclass)

Was this useful?