Semantic routing, the metadata service, the business glossary, and few-shot example curation.
The routing layer determines which data source can best answer a user's question. It uses a combination of keyword matching, embedding similarity, and metadata lookup.
"Show PMPM by region" โ โโ Does a PBI measure named "PMPM" exist? โ โ YES โ Route to Power BI โ โโ Is the question about detail-level data? โ โ Route to Snowflake โ โโ Ambiguous? โ Check embedding similarity against known query patterns โ Route to highest-confidence match
Routing rules (in priority order):
| # | Rule | Routes To |
|---|---|---|
| 1 | Question references a known PBI measure | Power BI |
| 2 | Question asks for a report or dashboard | Power BI |
| 3 | Question asks for detail rows or raw data | Snowflake |
| 4 | Question matches a few-shot example | Per example |
| 5 | Fallback: embedding similarity | Highest match |
A central service that provides schema, measure, and relationship information from both data sources.
Tables, columns, measures, relationships, descriptions โ extracted via the PBI REST API or TMDL.
Databases, schemas, tables, columns, data types โ extracted from INFORMATION_SCHEMA.
Map PBI measures to Snowflake tables so the system knows which Snowflake tables back which PBI models.
Metadata refreshed on schedule (e.g., every 6 hours). Cached in-memory for sub-millisecond lookups.
The metadata service ensures prompts only include relevant context โ not the entire schema. For a question about "PMPM by region," the prompt includes only the PMPM measure, region dimension, and their relationship.
Domain-specific terms resolved to exact column/measure references before they reach the LLM:
| Business Term | Resolves To | Source |
|---|---|---|
PMPM | [Fact Claims].[PMPM] measure | Power BI |
member months | [Fact Eligibility].[Member Months] measure | Power BI |
LOB | [Dim LOB].[Line of Business] column | Both |
region | [Dim Region].[Region Name] column | Both |
denied claims | claims WHERE status = 'DENIED' | Snowflake |
high-cost claimant | claims WHERE amount > 50000 | Snowflake |
The glossary is maintained as a JSON file and can be updated by business users without code changes.
Curated questionโquery pairs injected into prompts. These dramatically improve LLM accuracy for domain-specific patterns:
// Example 1 Q: "What is the current PMPM by line of business?" A: EVALUATE SUMMARIZECOLUMNS( 'Dim LOB'[Line of Business], "PMPM", [PMPM] ) // Example 2 Q: "Show top 10 clients by total claims amount" A: EVALUATE TOPN( 10, SUMMARIZECOLUMNS( 'Dim Client'[Client Name], "Total Claims", [Total Claims Amount] ), [Total Claims Amount], DESC )
Best practices for few-shot examples:
Schema, measures, glossary. Refreshed every 6 hours or on demand. Stored in-memory. TTL-based eviction.
Recent query results keyed by normalized query string + user role. TTL: 15 minutes. Invalidated on data refresh.
Cache hits return in under 50ms. Cache misses fall through to the full pipeline.