Skip to main content
v2

Semantic Query Deep Dive

Text -> Intent -> SQLDB semantic model (ce_semantic_*)Read-only + validation + retry
One-line mental model

Semantic runtime is not direct text-to-SQL.
It is Question -> CanonicalIntent -> constrained SQL -> execution -> answer.

Pipeline Architecture

Semantic Runtime

Planner -> Interpret -> Query -> Postgres -> Answer

React Flow mini map

Minimal anchors

Chat + Trace

What to look atWhy it matters
Tool call order + stage transitionsTells you where behavior diverged

Canonical Intent + SQL

What to inspectWhy it matters
Intent JSON and compiled SQLExplains exactly why this SQL was produced

Config + Table Dependencies

What to inspectWhy it matters
`ce_semantic_*` rows used in this requestMost wrong outputs are metadata issues

Prompt Suite

What to inspectWhy it matters
Interpret prompt + SQL prompt + retry promptShows what the LLM was allowed to do

Running example

User question
TEXT
find all requests where notes text says cancelled due to duplicate
User
find all requests where notes text says cancelled due to duplicate

Runtime tables used in this trace (sample rows)

ce_semantic_concept (10 sample rows)

ce_semantic_concept

IDCONCEPT_CODEDESCRIPTION
1DisconnectRequestCustomer disconnect request
2DisconnectOrderDownstream disconnect order
3AccountCustomer account
4SubAccountSub-account
5ConnectionPhysical connection
6BillingBilling records
7PaymentPayment records
8SupportTicketSupport cases
9InstallationInstall request
10ServicePlanService plan

ce_semantic_synonym (10 sample rows)

ce_semantic_synonym

IDSYNONYMMAPS_TO
1requestDisconnectRequest
2requestsDisconnectRequest
3notesnotesText
4notenotesText
5remarksnotesText
6commentsnotesText
7cancelledCANCELLED_SIGNAL
8duplicateDUPLICATE_SIGNAL
9last dayLAST_24_HOURS
10todayTODAY

ce_semantic_query_class (10 sample rows)

ce_semantic_query_class

IDQUERY_CLASSDESCRIPTION
1LISTlist results
2FAILURE_ANALYSISfailure analytics
3COUNTcount
4TRENDtrend
5SUMMARYsummary
6DETAILdetail
7JOIN_VIEWjoin-heavy lookup
8ALERTalert lookup
9STATUSstatus lookup
10RECENTrecent lookup

ce_semantic_mapping (10 sample rows)

ce_semantic_mapping

IDENTITYFIELDTABLECOLUMN
1DisconnectRequestrequestIdzp_disco_requestzp_request_id
2DisconnectRequeststatuszp_disco_requeststatus
3DisconnectRequestcreatedAtzp_disco_requestcreated_ts
4DisconnectRequestsubAccountIdzp_disco_requestsub_account_id
5DisconnectRequestcityzp_disco_requestcity
6DisconnectTransDatarequestIdzp_disco_trans_datazp_request_id
7DisconnectTransDatanotesTextzp_disco_trans_datanotes_text
8DisconnectTransDataactionzp_disco_trans_dataaction
9DisconnectTransDatacreatedAtzp_disco_trans_datacreated_ts
10DisconnectOrderorderIdzp_disconnect_orderorder_id

ce_semantic_query_failures (10 sample rows)

ce_semantic_query_failures

IDBAD_SQL_PATTERNCORRECTION_HINTROOT_CAUSE
1r.notes_textuse t.notes_textWRONG_TABLE_COLUMN
2missing trans joinjoin on zp_request_idMISSING_JOIN
3SELECT without DISTINCTuse DISTINCT for request-level resultsDUPLICATE_ROWS
4wrong alias for trans tablealias trans table as t consistentlyALIAS_MISMATCH
5unsafe write keywordread-only select onlyDENY_OPERATION
6wrong timestamp columnuse mapped created_tsWRONG_TIME_COLUMN
7missing limitapply semantic max limitLIMIT_POLICY
8invalid field spellinguse mapped field namesFIELD_MAPPING_ERROR
9bad join directionfollow relationship pathJOIN_PATH_ERROR
10literal concatenationuse named paramsPARAM_BINDING_POLICY

Step-by-step deep trace (who does what)

Step 1: question enters runtime

Java entry
JAVA
// Java does this:
String question = request.getQuestion();

// LLM not called yet.
// DB not read yet.

Current state

Java stateLLM stateDB state
question is presentnot calledno read yet

Step 2: planner chooses tool sequence

Planner outcome
JSON
{
"mcpAction": "CALL_TOOL",
"toolOrder": [
"db.semantic.interpret",
"db.semantic.query",
"postgres.query"
]
}

Who did what

ComponentDidConcluded
Java (McpPlanner)loaded tool metadatasemantic chain should run
LLMnot deciding SQL herenone
DBread planner/tool configavailable tools + order

Step 3: Java loads semantic metadata for interpret stage

Java metadata load
JAVA
// Java does this:
var concepts = conceptRepo.findAllEnabled();
var synonyms = synonymRepo.findAllEnabled();
var queryClasses = queryClassRepo.findAllEnabled();
var mappings = mappingRepo.findAllEnabled();

// LLM still not called.
// DB returns rows from ce_semantic_* tables.

Tables read now

TableUsed for
ce_semantic_conceptallowed concept vocabulary
ce_semantic_synonymlanguage normalization hints
ce_semantic_query_classquery shape options
ce_semantic_mappingallowed semantic fields

Step 4: Java builds interpret prompt

Interpret prompt package
TEXT
System prompt contains:
- Allowed entities from ce_semantic_concept
- Allowed query classes from ce_semantic_query_class
- Field vocabulary from ce_semantic_mapping
- Synonym hints from ce_semantic_synonym

User prompt contains:
find all requests where notes text says cancelled due to duplicate

Who did what

ComponentDidConcluded
Javaassembled strict prompt + output schemainterpret call is ready
LLMnot run yetnone
DBalready provided metadata rowsconstraints available

Step 5: LLM interpret call happens

Interpret call
JAVA
// Java does this call.
var llmOutput = llmClient.generateJsonStrict(systemPrompt, userPrompt, interpretSchema);

// LLM does this inside the call:
// - chooses entity
// - chooses queryClass
// - chooses filters
// Java does NOT manually parse words into business meaning here.
LLM interpret output
JSON
{
"entity": "DisconnectRequest",
"queryClass": "LIST",
"filters": [
{
"field": "notesText",
"op": "CONTAINS",
"value": "cancelled due to duplicate"
}
],
"confidence": 0.91,
"needsClarification": false
}
db.semantic.interpret
intent: SEMANTIC_QUERYstate: SEMANTIC_INTERPRET
Interpret completed. Canonical meaning selected from allowed model terms.

Step 6: Java validates interpret output

Validation
JAVA
// Java validates that LLM output is legal against DB metadata.
boolean entityOk = conceptRepo.existsByConceptCode(intent.getEntity());
boolean classOk = queryClassRepo.existsByQueryClass(intent.getQueryClass());
boolean fieldsOk = intent.getFilters().stream()
.allMatch(f -> mappingRepo.existsByFieldCode(f.getField()));

// If invalid -> reject / clarify.

Current state

Java stateLLM stateDB state
canonicalIntent acceptedcompleted interpret stepvalidated entity/class/field existence

Step 7: CanonicalIntent becomes official runtime contract

CanonicalIntent
JSON
{
"entity": "DisconnectRequest",
"queryClass": "LIST",
"filters": [
{
"field": "notesText",
"op": "CONTAINS",
"value": "cancelled due to duplicate"
}
],
"sort": [
{
"field": "createdAt",
"dir": "DESC"
}
],
"limit": 100
}
Important

At this point, runtime has semantic meaning only. SQL is still not generated.

Step 8: Java loads query-stage metadata

Query-stage metadata load
JAVA
// Java does this before SQL generation:
var mappings = mappingRepo.findAllEnabled();
var failures = failureRepo.findRecent();

// DB does this:
// - returns field -> table.column mappings
// - returns prior SQL failure/correction memory

Tables read now

TableContribution
ce_semantic_mappingphysical column resolution + join feasibility
ce_semantic_query_failuresretry guidance from past mistakes
ce_semantic_relationshipjoin-path preference when relevant

Step 9: Java builds SQL prompt from CanonicalIntent + metadata

SQL prompt package
TEXT
Includes:
- CanonicalIntent JSON (entity, queryClass, filters)
- mapping rows (field -> table.column)
- failure hints (what previously failed)
- read-only requirement
- strict SQL JSON output schema

Who decided what so far

DecisionDecider
Meaning of user textLLM in interpret stage
Allowed fields/tablesDB metadata + Java validation
SQL not yet finalpending query-stage LLM call

Step 10: LLM query call generates SQL candidate

SQL generation call
JAVA
// Java does this call:
var sqlOutput = llmClient.generateJsonStrict(sqlSystemPrompt, sqlUserPrompt, sqlSchema);

// LLM does this inside:
// - drafts SQL from CanonicalIntent
// - chooses joins from mapping context
// - returns sql + params + flags
SQL candidate
SQL
select
DISTINCT r.zp_request_id, r.status,
r.created_ts
from zp_disco_request r
JOIN zp_disco_trans_data t
on r.zp_request_id = t.zp_request_id
where t.notes_text ILIKE :notesText
order by r.created_ts DESC
limit :__limit; -- params -- :notesText = "%cancelled due to duplicate%" -- :__limit = 100
db.semantic.query
intent: SEMANTIC_QUERYstate: SEMANTIC_QUERY
SQL candidate compiled using CanonicalIntent + mappings + failure memory.

Step 11: Java validates SQL candidate

Validation + guardrail
JAVA
// Java safety checks before execution:
sqlGuardrail.assertReadOnly(sqlOutput.getSql());
sqlValidator.validateAgainstMappings(sqlOutput.getSql(), mappings);

// If validation fails:
// Java triggers retry with corrective feedback.

Validation responsibility

CheckOwner
Read-only enforcementJava guardrail
Column/table legality vs mappingJava validator + ce_semantic_mapping
Retry decisionJava orchestration

Step 12: Postgres executes named-parameter SQL

Execution
JAVA
// Java executes SQL against Postgres using named params.
var rows = namedParameterJdbcTemplate.queryForList(sqlOutput.getSql(), sqlOutput.getParams());

Current state

Java stateLLM stateDB state
execution completenot active in this stepbusiness rows returned

Step 13: final answer synthesis

Final Response
intent: SEMANTIC_QUERYstate: COMPLETED
Found 2 requests whose notes text contains cancelled due to duplicate.

Why this SQL was generated (exact reason chain)

Reason chain

SignalDecided bySQL effect
`entity = DisconnectRequest`Interpret-stage LLM`FROM zp_disco_request r`
`field = notesText`Interpret-stage LLMneed mapped notes column
`notesText -> zp_disco_trans_data.notes_text`ce_semantic_mapping`WHERE t.notes_text ...`
shared request key mappingce_semantic_mapping`JOIN ... ON r.zp_request_id = t.zp_request_id`
duplicate risk memoryce_semantic_query_failures`SELECT DISTINCT`
read-only policyJava guardrail + deny rulesno update/delete SQL allowed

If output is wrong: who decided it

Root-cause map

Observed issuePrimary deciderFirst place to debug
Wrong entityInterpret-stage LLMinterpret prompt + `ce_semantic_concept`/`ce_semantic_synonym`
Wrong field in intentInterpret-stage LLMintent JSON + `ce_semantic_mapping` coverage
Missing joinQuery-stage LLMSQL prompt + mapping availability
Invalid column blockedJava validator (correctly)mapping completeness
Unexpected empty rowsBusiness data/filterexecuted SQL + runtime params
Clarification asked unexpectedlyInterpret stage confidence logicambiguity options + intent confidence

Prompt suite (concise)

Interpret prompt shape
TEXT
Goal: return CanonicalIntent JSON only.
Inputs: question + allowed entities/classes/fields/synonyms.
Constraint: choose only from allowed semantic model terms.
Output: entity, queryClass, filters, confidence, needsClarification.
SQL prompt shape
TEXT
Goal: compile read-only SQL from CanonicalIntent.
Inputs: canonicalIntent + mapping + relationship context + failure hints.
Constraint: named params only, read-only only, mapped columns only.
Output: sql, params, needsClarification, unsupported.
Retry prompt shape
TEXT
Goal: fix previous invalid SQL.
Inputs: previous SQL + exact validation error + allowed mapping.
Constraint: preserve intent meaning while fixing legality.
Output: corrected sql + params.

Drill set (clean, unique, no repetition)

Drill 1: clarification path

User
show status for request R1001
Semantic Agent
intent: SEMANTIC_QUERYstate: CLARIFICATION
Do you mean request status or downstream order status?

Drill 2: count path

User
count failed requests in last 24 hours
Semantic Agent
intent: SEMANTIC_QUERYstate: SEMANTIC_QUERY
Resolved queryClass=COUNT and compiled aggregate SQL.

Drill 3: unsupported write intent

User
delete duplicate requests
Semantic Agent
intent: SEMANTIC_QUERYstate: BLOCKED
Write operation rejected. Semantic runtime is read-only.

Drill 4: retry recovery

User
find notes containing duplicate for recent requests
Semantic Agent
intent: SEMANTIC_QUERYstate: RETRY
Attempt 1 failed validation; attempt 2 succeeded after failure-memory hint.

Final checklist

Read this page and you should now be able to

CapabilityOutcome
Trace one question end-to-endKnow exactly where meaning and SQL were decided
Debug wrong output quicklyJump to the right stage/table without guesswork
Explain ownership clearlyJava orchestrates, LLM interprets/compiles, DB constrains
Justify final SQLTie each SQL clause to intent + mapping + guardrails
Lock this model

Java orchestrates. LLM interprets and compiles. DB semantic tables constrain and validate. Postgres executes. The answer comes from rows, not guesswork.