Skip to content

fix(analyzer): fix GLiNER multi-instance entity leakage and simplify config#2181

Draft
kalra-mohit wants to merge 1 commit into
data-privacy-stack:mainfrom
kalra-mohit:feat/gliner-multi-instance-consolidated
Draft

fix(analyzer): fix GLiNER multi-instance entity leakage and simplify config#2181
kalra-mohit wants to merge 1 commit into
data-privacy-stack:mainfrom
kalra-mohit:feat/gliner-multi-instance-consolidated

Conversation

@kalra-mohit

Copy link
Copy Markdown

Summary

Consolidates two other open approaches to this issue into one working, documented, tested fix, crediting both explicitly:

  • Auto-derived names (approach credited to Support multiple GLiNER YAML configurations #2018, @ynachiket): a class_name: GLiNERRecognizer YAML entry no longer requires an explicit unique name — when omitted, one is derived automatically from class_name + model_name.
  • Entity/threshold leakage fix (approach credited to fix(analyzer): allow GLiNER labels to be scoped per recognizer #2154, @ultramancode, reproducing @hexsm's original report): adds an include_requested_entities_as_labels option (default true, preserving existing behavior). GLiNER's ad-hoc-label support previously let a globally-requested entity type "leak" into a GLiNERRecognizer instance that wasn't configured for it, evaluated against the wrong instance's threshold, when multiple instances are configured with different entity_mapping/threshold values. Setting this to false per-instance closes the leak by restricting GLiNER's label input to only that instance's own configured entities.
  • Docs updated (gliner.md, recognizer_registry_provider.md) to document both, replacing an earlier docs-only PR's (docs(analyzer): document and test configuring multiple GLiNERRecognizer instances via YAML #2180, mine) caveat about the leakage bug with the actual fix.

Closes #1760

Why consolidated rather than three separate PRs

Posted on the issue thread before starting this work: three open PRs (#2018, #2154, #2180) were addressing complementary but separate slices of the same underlying problem. Rather than have maintainers review and merge three overlapping PRs, this folds the auto-naming behavior and the leakage fix together with the docs so a user configuring multiple GLiNERRecognizer instances gets working, documented, isolated behavior in one PR. Happy to split this back up, defer to #2018/#2154 directly, or adjust scope however maintainers prefer — flagged this intent on the issue first specifically to get out ahead of that.

Root cause (verified against current source, not assumed)

In GLiNERRecognizer.analyze(), __create_input_labels() appends every globally-requested entity type as an ad-hoc GLiNER label by default. Combined with the result filter (if entities and presidio_entity not in entities: continue), which checks against the global requested-entity list rather than this instance's own entity_mapping, an instance configured only for e.g. ADDRESS can still return an ORGANIZATION result if ORGANIZATION was requested elsewhere in the same analyze() call — evaluated against the ADDRESS instance's threshold, not the (possibly stricter) threshold configured for ORGANIZATION elsewhere.

flowchart TD
    A["YAML: 2x class_name: GLiNERRecognizer\nentries, different entity_mapping/threshold"] --> B["Loader: name auto-derived\nfrom class_name + model_name"]
    B --> C1["Instance A: entity_mapping={Address: ADDRESS}\nthreshold=0.65"]
    B --> C2["Instance B: entity_mapping={Organization: ORGANIZATION}\nthreshold=0.80"]
    D["analyze(entities=[ADDRESS, ORGANIZATION, PRODUCT])"] --> C1
    D --> C2
    C1 -. "include_requested_entities_as_labels=True (old default):\nORGANIZATION leaks in as ad-hoc label,\nreturned at Instance A's 0.65 threshold" .-> BUG["Wrong threshold applied"]
    C1 -- "include_requested_entities_as_labels=False:\nonly ever sends [Address] as labels" --> FIXED["Leak closed"]
Loading

Test plan

  • Regression test reproducing the exact leakage bug from the issue thread, using a mock that faithfully simulates GLiNER (only returns labels it was actually asked for) — this is the meaningful part: a naive mock returning fixed values regardless of input wouldn't actually exercise the fix
  • Test confirming include_requested_entities_as_labels=False prevents the leak
  • Test confirming the flag doesn't suppress the instance's own legitimate entity type
  • Unit tests for name auto-derivation: omitted name + model_name → derived name; two instances with different model_names → distinct names; explicit name not overridden; no name/no model_name → falls back to class_name
  • End-to-end test through RecognizerRegistryProvider with two full YAML-style configs, verifying both instances load with correct distinct names, thresholds, and the leakage flag applied
  • Ran the full affected test suite locally (test_gliner_recognizer.py, test_yaml_recognizer_models.py, test_recognizer_registry_provider.py, test_recognizers_loader_utils.py) — 152 passed, 0 failed
  • ruff check clean on both changed source files

…config (data-privacy-stack#1760)

Consolidates and builds on two other open PRs against this issue, crediting
both explicitly:

- Auto-derives a unique recognizer name from class_name + model_name when
  name is omitted on a class_name: GLiNERRecognizer YAML entry, so multiple
  instances no longer each require an explicit unique name. Approach
  credited to data-privacy-stack#2018 (ynachiket).
- Adds an include_requested_entities_as_labels option (default true) to
  GLiNERRecognizer. When multiple instances are configured with different
  entity_mapping/threshold values, GLiNER's ad-hoc-label support previously
  let a requested entity type "leak" into an instance that wasn't
  configured for it, evaluated against the wrong threshold. Setting this to
  false per-instance closes the leak by restricting that instance to only
  ever request labels it's configured for. Design credited to data-privacy-stack#2154
  (ultramancode), reproducing hexsm's original report.
- Updates the GLiNER sample docs and recognizer_registry_provider.md to
  document both, replacing the earlier docs-only PR's caveat about the
  leakage bug with the actual fix.

Closes data-privacy-stack#1760

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@kalra-mohit
kalra-mohit force-pushed the feat/gliner-multi-instance-consolidated branch from c9249fc to 56e4e4c Compare July 21, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can multiple GLiNERRecognizer instances be configured via YAML?

1 participant