SentriScope LLM Architecture

Natural language to SQL pipeline, semantic registry, query modes, schema grounding, guardrails, and platform-level LLM configuration.

1. Purpose

The LLM layer enables security operators to query canonical data using natural language. It translates user questions into validated SQL, executes against the canonical database, and returns formatted, evidence-backed answers — without exposing the database schema directly or allowing unrestricted SQL execution.

Key design decision: LLM is never in the critical risk-scoring path. Risk calculation is deterministic. LLM only queries pre-existing canonical data.


2. NL→SQL Pipeline (10-Step Execution Model)

[1] User submits natural language question
    │
[2] Intent classification → IntentResult
    │   question_class, query_mode, is_count_intent, requires_correlation
    │
[3] Contract lookup from Semantic Registry
    │   ContractKey → QueryContract (table, join rules, evidence fields)
    │
[4] Scalar path check
    │   If query_mode=SCALAR_AGGREGATE and scalar compiler returns SQL:
    │   → Skip to [8] with deterministic SQL (no LLM)
    │
[5] LLM Query Planner (non-scalar path)
    │   Generates structured query_plan: table, filters, joins, evidence_fields
    │
[6] Query Plan Validation (authoritative — cannot be bypassed)
    │   validate_query_plan(plan, intent_result, contract)
    │   Reject on any failure — no auto-correct
    │
[7] SQL Generation from validated plan
    │   LLM or deterministic compiler generates SQL
    │
[8] SQL Validation
    │   validate_sql(sql, contract)
    │   Check allowed tables, no DDL/DML, injection patterns, column existence
    │
[9] Execute SQL (read-only, tenant-scoped)
    │   assert_tenant_context_set()
    │   Execute within tenant context
    │
[10] Format and return response with evidence

Rule: Validation is authoritative. If validation fails, execution is rejected. The LLM output is never trusted without validation.


3. Query Mode Model

The intent router classifies every question into a query mode in addition to a question class:

Mode Description Evidence Required LLM Planner Required
scalar_aggregate Single count ("How many exposures?") No No — deterministic compiler
grouped_aggregate Counts by dimension ("by severity") Per contract Yes
entity_listing List/show/top N entities Per contract Yes
investigation Correlate entities (IOC + asset + incident) Yes (strict) Yes

Scalar Aggregate Path

  1. classify_intent(question)IntentResult(query_mode="scalar_aggregate", is_count_intent=True)
  2. If is_scalar_count_supported(intent_result, contract) → scalar compiler generates deterministic SQL
  3. Validate with query_mode=SCALAR_AGGREGATE (evidence not required)
  4. Execute and return formatted count answer
  5. No LLM SQL generation — no planner

4. Semantic Registry and Contract Model

The Semantic Registry maps intent → contract. A contract defines:

Contract Field Description
table Primary canonical table for this question class
allowed_joins Tables that may be joined
required_evidence_fields Columns that must appear in SELECT
forbidden_columns Columns never permitted (PII, credentials)
masking_rules Column-level masking specifications
is_scalar_count_supported Whether scalar compiler can handle this class

Contracts are stored in apps/llm/registry/contracts.py. Every question class maps to exactly one contract.


5. SQL Guardrails

The SQL validator enforces these rules before any execution:

Rule Enforcement
Read-only No INSERT, UPDATE, DELETE, DROP, TRUNCATE, CREATE
Allowed tables only SQL may only reference tables defined in contract
Column existence All referenced columns must exist in canonical schema
No subquery injection Nested subqueries validated against allowed tables
Tenant context assert_tenant_context_set() before execution
Injection patterns Pattern-based detection of prompt injection attempts
Row limits All listing queries have MAX_ROWS cap enforced

6. LLM Schema Grounding

Before any LLM call, the canonical JSON schema bundle is loaded as context:

foundations/schema/canonical_bundle.json

This bundle contains all canonical model schemas in LLM-optimized format. Grounding prevents the LLM from hallucinating column names or relationships.

Schema loading strategy:
1. Full bundle loaded on LLM service initialization
2. Per-question, a relevant subset is injected into the prompt (context window optimization)
3. Bundle version hash verified in CI to prevent stale schema


7. LLM Configuration (Platform Level)

Platform administrators configure LLM providers via PLATFORM_LLM_CONFIGURATION:

Setting Description
llm_provider openai, anthropic, azure_openai, bedrock
model_name Provider-specific model identifier
api_key_reference Encrypted credentials reference — never plaintext
max_tokens Per-query token budget
temperature 0.0 for deterministic SQL generation
timeout_seconds Query timeout

Tenant operators may select from platform-approved LLM profiles. No tenant configures their own API key.


8. Risk Snapshot Listing Constraints

Listing risk snapshots and risk snapshot items requires specific contract constraints:

  • RiskSnapshot queries scope to tenant_id automatically.
  • RiskSnapshotItem queries must always filter by an explicit snapshot_id.
  • GROUP BY on snapshot items is always secondary to tenant + snapshot scope.
  • Top-N item queries use ORDER BY residual_risk_score DESC LIMIT N.
  • The scalar compiler handles count(snapshots) and latest snapshot deterministically.

9. LLM Security and Privacy Controls

Control Implementation
Prompt injection protection Input sanitization + injection pattern detection
Data masking CONFIDENTIAL fields masked; RESTRICTED fields never sent to LLM
LLM training isolation Queries never used to train models (opt-out enforced in provider config)
Query logging Stored without raw PII; query intent and question class stored only
Tenant isolation LLM queries always execute within tenant_context(tenant)
No cross-tenant data LLM never receives data from another tenant

10. Suggest Fix vs Automated Query

Design rationale: "Suggest Fix" mode (LLM provides remediation recommendation as text) is safer and more reliable than "Automated Query" (LLM generates and executes arbitrary SQL) because:

  1. Remediation recommendations require understanding context, not schema traversal.
  2. SQL generation errors in a fix context produce wrong results silently; in a query context they produce wrong data.
  3. The LLM's strength is language reasoning, not schema navigation.
  4. Suggest Fix can be validated by the operator before action; automated query executes immediately.

For investigation queries (IOC correlation, attack path), the investigation deterministic compiler is preferred over free-form LLM SQL.


11. Feedback and Quality System

Component Purpose
LLMQueryLog Every query logged: question, intent, SQL, execution time, row count
LLMQueryFeedback Operator feedback: thumbs up/down + optional comment
LLMQueryBenchmark Regression test suite: reference questions + expected SQL patterns
QA scoring Benchmark run scores: intent accuracy, SQL validity, evidence correctness

Feedback feeds continuous improvement of contracts and intent classification.


12. Code Locations

Module Purpose
apps/llm/intent_router.py classify_intent(), classify_question()
apps/llm/query_modes.py Mode constants, IntentResult dataclass
apps/llm/registry/contracts.py Semantic registry, contract definitions
apps/llm/scalar_compiler.py Deterministic SQL for scalar aggregates
apps/llm/contract_validator.py Query plan validation
apps/llm/planner_validator.py Planner output validation
apps/llm/masking.py Column-level data masking
apps/llm/services/chat_service.py End-to-end pipeline orchestration

13. Attack Path Intelligence Integration (planned)

Attack path questions (e.g. “How could this identity reach SAP?”) must not use free-form LLM SQL or graph traversal.

Planned integration:

  1. Intent router classifies as investigation + sub-intent attack_path.
  2. LLM tool layer calls deterministic Attack Path Intelligence APIs (API_ATTACK_PATH_INTELLIGENCE.md).
  3. Response narrative is bound to AttackPathIntelligenceDTO evidence — no invented hops.

See ARCHITECTURE_ATTACK_PATH_INTELLIGENCE.md §11 for tool mapping.

Rule: Graph BFS remains authoritative in apps/attack_graph; LLM is narrative-only for path questions.
| apps/llm/models.py | LLMQueryLog, LLMQueryFeedback, LLMQueryBenchmark |


Related Articles