OGuardAI
Architecture

Detector Capabilities

Entity detection capabilities by runtime mode, language support matrix, performance characteristics, and deployment modes

Entity Detection by Runtime Mode

Entity TypeBuiltin (Regex)+ GLiNER+ spaCy
EmailHighHighHigh
PhoneHigh (intl + DE)HighHigh
SSNHighHighHigh
IBANHighHighHigh
VAT ID (EU)HighHighHigh
Credit CardHigh (Luhn)HighHigh
IP AddressHigh (v4 + v6)HighHigh
URLHighHighHigh
Customer IDHigh (pattern)HighHigh
Order NumberHigh (pattern)HighHigh
PassportMedium (pattern)HighMedium
Health IDMedium (pattern)HighMedium
Date of BirthHigh (with context)HighHigh
German Tax IDHighHighHigh
German Social SecurityHighHighHigh
Money (ISO 4217)HighHighHigh
Quote IDHigh (pattern)HighHigh
Case ReferenceHigh (pattern)HighHigh
Person NameNoneGoodGood
Company NameNoneGoodModerate
LocationNoneGoodGood
Address (street)Medium (DE/US)BetterBetter

German Tax ID, German Social Security, Money, Quote ID, and Case Reference are the five always-on builtin_custom detectors: they run in every mode (including builtin) and emit typed custom:<name> entities. Together with the named builtin formats, these are the builtin entity types available before any NER, config, or policy additions.

Entity Source Provenance

Every entity type in GET /v1/capabilities carries a source field so a client can tell the fixed built-in floor apart from the policy and config extensible surface. It answers "is this type baked into the runtime, or did this deployment add it?" without reading the policy files back.

sourceMeaningExtensible by
builtinA universal PII format detector (email, phone, IBAN, SSN, IP, URL, credit card, ...). The safe floor.Not removable; always on
builtin_customA shipped custom regex detector (money, German tax ID, German social security, ...).Not removable; always on
nerDetected by the NER model (person, company, location, or a policy mapped zero-shot label). Present only when detector.mode is both or advanced.detection.ner_labels + ner_label_map
config_customAdded by this deployment's detector config (custom_detectors or vocab.extra_patterns).Server config, no recompile
policy_customDefined by a loaded policy's custom_patterns.Policy YAML, no recompile

The builtin and builtin_custom types are The Line: they always run and cannot be switched off by config. Everything tagged config_custom or policy_custom is what this deployment added on top, so a developer can confirm a new policy or vocab entry is live by querying capabilities. The field is additive: an older server that omits it is read as builtin by the SDKs.

Language Support

Language support is not a fixed list; it is derived from the running deployment. There is no hardcoded set of supported languages. Three layers combine:

  • Structured PII (builtin) is language-independent: email, IBAN, IP, URL, SSN, credit card, customer ID, and order numbers are matched by pattern in any language. Phone and address have locale-specific format coverage (international plus German, US, French, Italian, Spanish, Dutch, UK formats today), extendable per locale via detector.vocab.extra_patterns with no recompile.
  • NER detection (person, company, location) covers whatever the Python sidecar reports. GLiNER is broadly multilingual; the exact set is the enrichment registry plus any loaded GUARDAI_LANGUAGE_PACKS. Every language is data (a built-in JSON lexicon, no per-language code); operators add, extend, or override (_mode: replace) any language from data, with extend guaranteed to only widen the built-in floor. The server fetches this from the sidecar at startup.
  • Restoration (honorifics, gendered titles, abstract labels) ships built-in templates for ~30 languages and is extended or overridden for any locale via restore_templates.

Do not rely on a static table: query GET /v1/capabilities for the live list this deployment advertises. Each language reports detection_support (present when the NER sidecar covers it) and rehydration_support (present when a restore template covers it). GET /v1/diagnostics (admin) shows the deployment's vocab additions, custom detectors, suppressions, and restore-template overrides.

NER Noise Suppression (Precision Floor)

Zero-shot NER (GLiNER) tends to over-tag common greeting and function words as person, company, or location entities. To keep precision high, OGuardAI applies a built-in noise floor after NER, additive over the raw model output:

  • A universal acronym stoplist (~50 entries such as PII, API, CEO, IBAN, SWIFT, HR, SSN) drops NER spans that are just a known acronym.
  • A per-language noise floor, shipped as data (German and Arabic today), suppresses NER spans whose tokens are all noise words, stopwords, or proclitics. This also catches glued phrases where the model tags a whole run of function words as one entity.
  • A minimum-confidence floor for NER-only types (built-in 0.65) drops low-confidence names.

This is a precision floor, not a ceiling. A deployment may add acronyms to the stoplist, un-suppress a specific built-in acronym so an acronym-shaped real organization name is detected, or raise the confidence floor (stricter only). It cannot lower the floor or weaken detection below the built-in baseline, and invalid overrides are rejected at startup. The active suppressions are visible via GET /v1/diagnostics.

Performance Characteristics

Latency figures are indicative and hardware-dependent. The builtin path runs in low single-digit milliseconds; NER modes (GLiNER, spaCy) add model inference and are an order of magnitude slower.

MetricBuiltin Only+ GLiNER+ spaCy
Cold start<1ms5-30s (model load)3-15s (model load)
Idle memory~10MB~500MB (CPU) / ~2GB (GPU)~200MB
Latency p50low single-digit ms~80ms (up to several hundred ms p99)~80ms (hardware-dependent)
DeterministicYesMostlyMostly
GPU requiredNoOptional (faster)No

Deployment Modes

ModeConfigWhat RunsBest For
builtindetector.mode: builtinRust regex onlyLow-latency, structured data
advanceddetector.mode: advanced + detector.advanced_urlRust regex + required Python NER (fail-closed)Maximum accuracy
bothdetector.mode: both + URLRust regex + Python NER mergedBest coverage

Degraded Mode Behavior

Behavior on NER sidecar unavailability depends on the configured mode.

both mode (graceful fallback):

  1. Server logs: ner_service_unavailable_falling_back_to_builtin
  2. Detection continues with builtin regex only
  3. No crash, no hang, no data loss
  4. Entity types requiring NER (Person, Company, Location) will not be detected

advanced mode, or any policy required_for type (fail closed):

  1. NER is mandatory and is not downgraded to builtin
  2. The request fails closed with GUARDAI_DETECTION_FAILED
  3. A policy's required_for gates on whether NER actually ran, not on the configured mode, so a required_for type that NER did not produce rejects the request rather than passing the input through undetected

Health endpoint: GET /v1/health reports the CONFIGURED mode, not live NER reachability. It never flips to a detector degraded status on a live NER outage (this keeps Kubernetes liveness/readiness probes stable). The detector component message reflects configuration only: builtin_only (...) in builtin mode, builtin_and_ner (full entity detection) in both mode, and ner_required (...) in advanced mode. To check whether NER is configured, read the ner_active field from GET /v1/capabilities; to see whether NER actually ran for a given request, read the detector_mode and warnings fields on the transform response.