Self-hosting GLiNER2¶
Anonymizer uses fastino/gliner2-privacy-filter-PII-multi
for first-pass entity detection. The bundled model configuration sends detector requests to an
OpenAI-compatible endpoint at http://127.0.0.1:8001/v1; it does not start a server automatically.
This keeps plain Anonymizer() suitable for applications that manage their own services. Start a
compatible GLiNER2 endpoint before calling run(), or use the notebook helper below for an ephemeral
in-kernel development server.
Server contract¶
Anonymizer does not perform a separate model-discovery probe for externally managed providers. The
configured service is responsible for serving the requested detector model; connection and response
errors surface through the normal Data Designer model request. The notebook-managed runtime is
different: its owner uses authenticated GET /v1/models readiness checks to verify the exact model
ID and pinned revision before returning an Anonymizer.
The detection workflow calls POST /v1/chat/completions and passes detector-specific fields alongside
the normal OpenAI-compatible request. Anonymizer always sends labels, threshold, and flat_ner.
chunk_length and overlap are optional: they are sent only when the detector model's
inference_parameters.extra_body sets them, so servers must apply their own defaults when they are absent:
{
"model": "fastino/gliner2-privacy-filter-PII-multi",
"messages": [{"role": "user", "content": "<input text>"}],
"labels": ["first_name", "last_name", "email"],
"threshold": 0.3,
"chunk_length": 128,
"overlap": 32,
"flat_ner": false
}
Chunk defaults and units
The bundled GLiNER2 server defaults to 128 native word tokens per chunk with 32 tokens of overlap. These tokens include punctuation; they are not characters or encoder subword tokens.
Both the notebook helper and plain Anonymizer() use these defaults with the
bundled server. For a custom service, check that service's units and defaults.
Chunk values set in the detector model's inference_parameters.extra_body pass
through unchanged; omitted fields use the server's defaults.
The native splitter preserves source offsets and avoids cutting words. Unspaced Chinese or Japanese text can form a single long token, so word-window size does not guarantee a subword-token limit; evaluate chunk sizes for your language. Returned entities must match the original source text at their reported offsets.
The response must use the chat-completion shape. message.content is a JSON string containing an
entities list. Each entity has text, label, start, end, and score fields:
{
"choices": [{
"message": {
"role": "assistant",
"content": "{\"entities\": [{\"text\": \"Alice\", \"label\": \"first_name\", \"start\": 0, \"end\": 5, \"score\": 0.94}]}"
},
"finish_reason": "stop"
}]
}
A production deployment should provide the chat-completion contract through a separately managed,
authenticated service and configure its provider endpoint in providers.yaml. The native PyTorch
server bundled with Anonymizer is intended only for notebooks and development. A vLLM-based
production serving path is planned separately; this release does not depend on it.
Local notebook runtime¶
Install the notebook extra and create the client through create_anonymizer():
pip install "nemo-anonymizer[notebooks]"
from anonymizer.notebooks import create_anonymizer, stop_local_runtime
anonymizer = create_anonymizer()
# Run notebook work here.
stop_local_runtime()
The helper:
- creates a cached, dependency-isolated server environment containing
gliner2[local]on first use; - downloads the exact Hugging Face revision
59894c087cb2923b01f337d4ee72f6ff84d5bdd6offastino/gliner2-privacy-filter-PII-multi; - starts an authenticated server on an ephemeral loopback port;
- selects CUDA, MPS, or CPU automatically;
- injects only the detector provider and model selection, leaving configured LLM roles unchanged;
- reuses the process for compatible calls and stops it at interpreter exit.
The isolated server environment is necessary because GLiNER2 2.0's local inference stack and the
current Data Designer release require incompatible huggingface-hub major versions. The helper hides
that packaging detail from the notebook kernel. It also creates a local adapter copy of the pinned
snapshot that translates the checkpoint's Transformers v5 tokenizer field name to the Transformers
v4 name required by GLiNER2 2.0; model weights and source cache files remain unchanged. The revision
pin applies only to this packaged notebook runtime. Production services control and pin their own
model artifact independently.
Notebook CI runs on a CPU runner and constrains its isolated runtime to the CPU
build of PyTorch through .github/constraints/notebook-ci.txt. It caches only
Hugging Face model files; platform-specific runtime packages are rebuilt per job
and reused across tutorials within that job. These CI installation settings do
not change the local helper's automatic device selection or GPU support.
To request a device explicitly:
anonymizer = create_anonymizer(gliner_device="cuda") # also: "mps", "cpu", or "auto"
Calling the helper again with an incompatible device or configuration replaces the previous local runtime. The most recent request wins.
Local detection is not an all-local pipeline
Only GLiNER2 detection runs in the notebook process. Validation, augmentation, replacement, rewriting, repair, and evaluation still use the configured LLM providers and may send them original or tagged input text.
Running the development server directly¶
A compatibility entry point remains available from a source checkout:
uv sync --extra notebooks
uv run python tools/serve_gliner.py --host 127.0.0.1 --port 8001
The wrapper prepares the same isolated dependency set used by the notebook helper, then starts the packaged server. It uses the pinned model but does not add production hardening. Keep it bound to loopback unless you provide an authenticated network boundary.
Plain Anonymizer() uses this server's defaults without a manual override. To
request explicit chunk settings for a custom endpoint, add them to the detector
entry in your complete model configuration:
inference_parameters:
extra_body:
chunk_length: 128
overlap: 32
The notebook helper supplies these settings automatically. The threshold still
comes from Detect(gliner_threshold=...).
Configuring a managed endpoint¶
Custom provider and model files replace the bundled lists, so include the detector plus every LLM provider and model alias your selected workflow uses.
```yaml title="providers.yaml" providers: - name: my-gliner2-service endpoint: https://gliner2.internal.example/v1 provider_type: openai api_key: GLINER2_API_KEY
- name: nvidia
endpoint: https://integrate.api.nvidia.com/v1
provider_type: openai
api_key: NVIDIA_API_KEY
```yaml title="models.yaml" model_configs: - alias: gliner-pii-detector model: fastino/gliner2-privacy-filter-PII-multi provider: my-gliner2-service skip_health_check: true inference_parameters: max_parallel_requests: 8 timeout: 120 # Include the LLM aliases used by your selected detection, replacement, # rewrite, and evaluation roles here too.
from anonymizer import Anonymizer
anonymizer = Anonymizer(
model_providers="providers.yaml",
model_configs="models.yaml",
)
Set skip_health_check: true for the detector alias because a generic text-generation health probe
does not contain the required GLiNER2 labels field. Anonymizer performs a detector-specific endpoint
check immediately before the default detection workflow runs.
Tune recall and precision with Detect(gliner_threshold=...). The default threshold is 0.3; lower
values increase recall, while higher values generally increase precision.