A full engineering account of LinkedIn's internal Text-to-SQL chatbot: knowledge-graph backbone plus a Researcher Agent for fixing hallucinations, achieving 53% expert-rated correctness and 300+ weekly active users on a data lake with millions of tables.
Spider/BIRD execution accuracy has climbed from 54% to over 90%, but those numbers collapse the moment you move to a real enterprise data lake. LinkedIn set out to build a SQL assistant any employee at the company could use — and this paper is the full engineering write-up of that journey.
90%+
SOTA execution accuracy as of Nov 2023 — looks essentially solved.
76%
Best score as of Apr 2025. Sits between usable and unusable.
31%
Apr 2025 SOTA is only 31%. Ground truth queries are over 100 lines on tables with 1000+ columns. The realistic enterprise benchmark.
Even Uber's internal QueryGPT only reports roughly 50% overlap on ground-truth tables on their own eval set. In short, slapping a fine-tuned LLM on top of a schema is not enough.
The data lake contains millions of tables, with popular tables reaching 100+ columns. Tables get deprecated regularly and many overlap in content — the model must first pick the right table to do anything useful.
"Latest click-through rate" means something completely different to a notifications team vs a search team. The model must integrate user / product-area context to interpret correctly.
The company has its own acronyms and terms invisible to any public corpus — they must be mined from wikis, code repos, and historical queries.
Users don't only want SQL — they want the chatbot to find tables, explain queries, and debug. "Text-to-SQL" is only one part of the chat experience.
The paper's three contributions: ① a knowledge graph that fuses schemas, code repos, query logs, wikis, jargon, and crowdsourced domain knowledge, with ICA to auto-cluster tables into product areas; ② a Query Writer Agent with multi-stage retrieval + ranking, plus a Researcher Agent that dynamically retrieves new tables during fix-up to resolve hallucinations; ③ a Multi-Agent UI that routes intents — query writing / data finding / query fixing / Q&A — to keep follow-ups smooth.
"To our knowledge, this paper is the first detailed presentation of an enterprise Text-to-SQL solution."
Bottom-up: Knowledge Graph (semantic foundation) → Query Writer Agent (the SQL-generating core agent) → Multi-Agent Chat UI (user interface and intent routing). Data flow between the three layers is shown below.
Each layer in the diagram is expanded in the sections that follow. Three keywords to anchor on: the knowledge graph provides semantics, the Query Writer Agent turns semantics into SQL, and the multi-agent UI handles everything that isn't strictly T2S.
The central node of the knowledge graph is the Table: from a table you can find its columns, common joins, example queries, domain-knowledge records, and the user groups with read permission. The other organizing node is the Product Area, which ties tables to teams.
| Node | Attributes |
|---|---|
| Table | Database Name, Table Name, Human Description, AI Description, Usage Popularity, Table Cluster, Tags, Certification Status, Deprecation Status |
| Column | Database Name, Table Name, Column Name, Human Description, AI Description, Usage Popularity, Top Values, Data Type, Column Type (metric/dimension/attribute), Is Partition Key |
Key design choices: Certification Status flags governance-approved high-quality tables; Column Type distinguishes metrics, dimensions, and attributes so the LLM knows what a column is. When no human description exists, Glean Chat API auto-generates an AI description.
Source: DataHub. Embeddings cover table name + description + tags. Supports EBR plus lookup by name or product area. Refreshed weekly.
Parses EXPLAIN plans (JSON) from successful Trino queries to aggregate popularity and common joins. Refreshed weekly.
A list of relevant datasets per user (see §04 ICA clustering). Refreshed weekly.
Human-authored queries from code repos and wikis. Wiki descriptions are embedded directly; code repo queries get auto-descriptions via gpt-35-turbo before embedding. Filters: creation date, execution count, filename, and whether the user has certified the query.
User-submitted product background, data explanations, and personal preferences, gathered in the chatbot UI. Refreshed instantly (a user submission takes effect immediately).
Source: company wiki. Stored as {jargon → explanation}; pulled at query time via string matching and appended to the LLM prompt.
Key distributed-design choice: different indexes have different refresh cadences — domain knowledge is instant while others are weekly — so user-contributed annotations pay off immediately. This is the "user contributes → system improves → user contributes more" flywheel.
Millions of tables cannot be fed to an LLM. LinkedIn takes a user-table access matrix from three months of query history and runs Independent Component Analysis (ICA) for soft clustering, mapping each user and product area to its most relevant table subset.
Drop tables with too few total accesses or unique users — e.g. intermediate tables produced by data pipelines that no one queries directly.
Standardize across the user dimension (mean=0, std=1) so that a few heavy users don't dominate.
Use sklearn.decomposition.FastICA with N_comp = 200 components. Each component corresponds to one access pattern — typically a particular product team's working habits.
For each component, take the top T_c = 20 tables by absolute score. A single table can belong to multiple clusters — soft clustering is the key.
For each user, sum their access counts per component and take the top components. For product areas, vote across the clusters of representative employees in the team email group, breaking ties by cluster access count.
K-means is hard clustering — a table can only go to one cluster, but in reality a member table might be used by growth, ads, and search at once as a "shared table". ICA's soft clustering lets shared tables naturally show up in multiple clusters, and when a team disbands or a table is deprecated, simply rerunning the weekly job re-assigns everything automatically.
Throughput: the whole clustering pipeline has a P90 runtime of 15 minutes. Rerunning weekly is not a system bottleneck.
function GetCandidateTables(user, product_areas):
user_clusters = GetUserGroupClusters(user)
product_email_groups = GetEmailGroups(product_areas)
representative_users = GetEmployees(product_email_groups)
product_area_clusters = GetUserGroupClusters(representative_users)
clusters = merge(user_clusters, product_area_clusters)
inferred_tables = GetExtendedTables(clusters)
explicit_tables = GetExplicitTables(product_areas)
return merge(inferred_tables, explicit_tables)
At the start of every chat session, this function flattens all clusters corresponding to the user + selected product areas and adds in manually-curated explicit tables — defining the search scope for the subsequent EBR. Long-tail tables outside this set are dynamically pulled in via in-chat follow-up.
Implemented in langchain. Inputs: question, user name, list of product areas. Output: a dict containing the SQL, an explanation, the tables/columns used, and assumptions for the user to verify.
Goal: high recall. First the candidate-table list from §04 bounds the search space, then we pull from three sources:
The three combined produce K_ret = 20 tables, then we fetch all their columns, plus the product area's domain knowledge and jargon entries.
An LLM trims 20 tables down to K_rnk = 7. The Table Ranker LLM scores each table 1–10 with explanations, using:
A notable callout from the authors: feeding the table schema to the ranker actually hurt recall and increased latency, so schemas are omitted here.
The Column Ranker then selects columns from the top 7 tables into two tiers: relevant and potentially relevant. Including the second tier improves recall. Each table is rendered as a CREATE TABLE statement with columns ordered by usage popularity.
The selected tables + columns + relevance scores and explanations + examples + domain knowledge + jargon all get packed into the prompt. The Query Writer LLM (gpt-4o) returns:
{
"assumptions": [...], # for the user to verify
"query": "SELECT ...",
"explanation": "...",
"tables": [...],
"columns": [...]
}
The query validation loop runs at most twice, handling two error categories:
Validated via Trino EXPLAIN VALIDATE. The error message is fed straight back to a fixer LLM.
A separate custom hallucination validator catches all non-existent tables/columns in one pass (Trino EXPLAIN only returns one error at a time). This kind of error usually means the context lacked the right table, so a new round of retrieval is needed — Researcher Agent's cue.
The Researcher is a self-reflecting agent built specifically for hallucination resolution. It has tools to search tables, fetch table schemas, and fetch metadata. For instance, it can search for the table most similar to a hallucinated one.
Speed-tuning detail: the Researcher itself uses the faster gpt-4o-mini for search, but its self-reflection step uses the stronger gpt-4o. Output is "updated context + recommendation on what data to use", which is then passed to the query fixer LLM to rewrite the query.
20
tables kept after retrieval
7
tables passed to writer after ranking
≤ 2
max two fix-up rounds
The biggest lesson the authors learned post-launch: users don't want Text-to-SQL — they want a general data assistant that can write queries, find tables, debug bugs, and answer any data question. That's why the system evolved into a multi-agent structure.
The core agent — the full pipeline from §05.
Runs only the retrieve + rank stages of Query Writer, returning 7 suggested tables with metadata.
Dedicated to debugging query execution failures (permissions, syntax, schema).
All unsupported long-tail intents. Architecturally similar to Researcher Agent, with tools for schema lookup, wiki search, and query validation.
The Q&A agent has the widest scope, so the authors use three speed-ups: ① evaluate question difficulty and skip self-reflection on simple ones; ② pre-fetch table metadata to avoid repeated tool calls; ③ both LLMs use gpt-4o-mini.
The chatbot lives in the sidebar of the company's SQL editor — users never switch tools. A "Fix with AI" button appears automatically whenever a query execution fails.
Query output includes inline-commented SQL, validation results, an explanation, tables used, related reference queries, and assumptions to verify. Table output shows description, popularity, common joins, certification status, with checkboxes for users to pick which tables to use.
Suggested follow-ups appear above the chat box — users can keep the conversation moving without typing.
The UI lets users add product areas, add domain knowledge, and certify example queries — all written straight into the knowledge graph, spinning the weekly flywheel.
Speed is critical. Multi-agent + state maintenance + intent classifier all stack latency. The production full model averages 60 seconds per reply — not fast, but acceptable for complex enterprise queries.
The authors built an internal benchmark: 133 questions × 10 product areas × 167 ground-truth tables, with 60% of questions allowing multiple correct answers (multiple ground truths).
Table recall and column recall — did the bot find the right tables and columns? For multi-ground-truth questions, use the ground truth with the highest overlap.
Overall score (1–5), compilation success rate, valid tables & columns rate. Both human eval and LLM-as-judge (gpt-4o) are used.
Number of LLM calls, EBR queries, DB queries — proxies for system complexity. Full model averages 60 seconds per question.
| Score | Definition |
|---|---|
| 1 | Completely wrong; does not answer the question at all. |
| 2 | Right tables but 90% of columns are wrong; does not answer the question. |
| 3 | Right tables and most of the right columns, but has gaps requiring substantial effort or domain knowledge to fix; doesn't answer the question. |
| 4 | Right tables and almost all right columns; minor issues a non-expert can fix (e.g. wrong date filter). Answers the question but may miss trivial details. |
| 5 | Answers the question perfectly and completely. |
Models: example embeddings use E5-large-v2, table/column embeddings use text-embedding-ada-002, Researcher LLM uses gpt-4o-mini-2024-07-18, other LLMs use gpt-4o-2024-05-13, temperature = 0, single run.
| Config | Description | Tab Recall | Col Recall | Score 4+ | Compile OK | Valid T&C | LLM | EBR | DB |
|---|---|---|---|---|---|---|---|---|---|
| Full | All components | 78% | 56% | 48% | 96% | 99% | 4.6 | 3.0 | 9.4 |
| A.5 | Full w/o popularity or joins | 77% | 53% | 42% | 95% | 98% | 4.8 | 3.0 | 8.4 |
| A.4 | A.5 w/o domain knowledge or jargon | 76% | 52% | 49% | 96% | 99% | 4.7 | 3.0 | 8.5 |
| A.3 | A.4 w/o example queries | 60% | 38% | 24% | 98% | 100% | 4.6 | 1.0 | 7.0 |
| A.2 | A.3 w/o table or column attributes | 56% | 30% | 11% | 93% | 99% | 5.0 | 1.0 | 7.5 |
| A.1 | A.2 w/o table clusters (schemas only) | 45% | 24% | 9% | 88% | 99% | 5.1 | 1.0 | 7.1 |
| B.3 | Full w/o researcher agent | 75% | 53% | 47% | 95% | 98% | 4.3 | 3.0 | 9.5 |
| B.2 | B.3 w/o query fixer | 76% | 55% | 47% | 76% | 85% | 4.0 | 3.0 | 8.4 |
| B.1 | B.2 w/o rankers (EBR + writer only) | 67% | 50% | 46% | 66% | 77% | 2.0 | 3.0 | 7.1 |
| C.4 | (A.4, B.3) combination | 76% | 52% | 46% | 97% | 98% | 4.3 | 3.0 | 8.6 |
| C.3 | (A.3, B.2) combination | 60% | 37% | 20% | 77% | 87% | 4.0 | 1.0 | 6.1 |
| C.2 | (A.2, B.1) combination | 49% | 27% | 17% | 68% | 83% | 2.0 | 1.0 | 5.0 |
| C.1 | (A.1, B.1) combination | 37% | 23% | 16% | 67% | 81% | 1.9 | 1.0 | 3.9 |
Score 4+ climbs from A.1's 9% to Full's 48%, with most of the lift from example queries (A.3→A.4: +25 pp), table clusters, and table/column attributes. Semantic understanding can only come from the KG.
Compilation success rises from B.1's 66% to Full's 96%, valid T&C from 77% to 99%, largely from the query fixer and context rankers. But the score gain is small — modeling components can't fix semantic understanding.
A.5 (with domain knowledge) achieves Score 4+ = 42%; A.4 (without) achieves 49%. The authors suspect "irrelevant domain knowledge records" cause interference.
C.4 reaches Score 4+ = 46% (only 2 pp below Full) with fewer components (A.4 KG + B.3 modeling), and uses 4.3 LLM calls vs 4.6 and 8.6 DB queries vs 9.4 — cheaper with almost no quality loss.
The chatbot has been live since July 2024. Below are the real usage numbers at the time of writing (April 2025).
300+
weekly active users
100+
chat sessions per month
20%
this-week actives who return next week
33%
of sessions end with code in the SQL editor
Domain experts from each of the 10 product areas rated the production version, returning ratings for 124 of 133 questions:
53%
experts judged "correct" or "minor fix"
77%
"helpful for identifying tables and columns"
24%
filter condition wrong; incorrect join only 4%.
"Very good" or "Excellent": 39% — "very good, requires only minor modifications" or "excellent, queries are correct".
"Passes" or better: 95% — "at least requires some modifications" but usable.
This section is the most valuable part of the paper. The authors tried three mainstream academic techniques, and all three failed in the LinkedIn setting. Free lessons for anyone building enterprise T2S.
The academic recipe is to generate multiple queries and pick the most self-consistent (e.g. CHASE-SQL, CHESS). But in an enterprise setting:
A workaround (generating up to 3 ways to write the query as a kind of CoT) did not improve recall. The authors' conclusion: self-consistency's effectiveness comes from input shuffling AND actual execution — neither can be skipped.
Following DIN-SQL — use a planner LLM to break the question into subtasks solved iteratively. Result:
Even when they constrained the planner to "minimize the number of tasks" with few-shot examples, it still failed. The hypothesis: gpt-4o is strong enough on its own that task decomposition only constrains its solution space — smaller models may need it, but gpt-4o doesn't.
Use the planner's subtasks as query strings for retrieval (a form of query expansion). The result: no improvement in EBR table recall. The authors speculate that a prompt explicitly designed for query expansion might work, but the subtask format isn't quite right.
Free lessons for anyone building enterprise T2S: academic SOTA tricks (multi-path generation, self-consistency, task decomposition) often don't transfer to production systems — not because the tricks are wrong, but because (1) you can't execute queries, (2) you can't make users wait 5 minutes, (3) your base model may already be stronger than the academic-setup model. Investing in the KG and retrieval usually pays off more than model-side tricks.
The authors claim this is the first publicly available, fully detailed enterprise Text-to-SQL paper. Required reading for any team building an internal SQL chatbot.
9% → 49%
schemas only → Full KG
37% → 78%
C.1 → Full
23% → 1%
schema hallucination rate
34% → 4%
SQL compile failure rate
① The eval set is only 133 questions, all written and scored by the same domain experts — sample size is small and selection bias is real, so it's not directly comparable to Spider/BIRD.
② Production WAU of 300+ is only ~2% of LinkedIn's ~14k headcount. The authors don't discuss why broader adoption hasn't happened yet — likely the 60-second latency and 53% correctness are still adoption barriers.
③ All experiments are single runs at temperature 0, so they're reproducible but offer no variance estimate for the J metric.
④ The negative results sit in the appendix, but for practitioners they may be more valuable than the positive results.