The problem: rethinking routing in multi-agent systems on Databricks
Databricks native supervisor agent pattern is a solid default for orchestrating multiple Genie spaces and toolsโ but it comes with a routing constraint worth examining. The supervisor relies heavily on user-provided instructions to decide which agent or Genie space a query should go to. That routing logic has to be authored, maintained, and gets re-evaluated on every single call, since the supervisor treats each incoming question independently before deciding where it goes.
This raises a natural question: do we need a fresh routing decision, with full context, on every single query?
The alternative we explored was building a custom LangGraph agent that consolidates all the Genie spaces and the Knowledge Assistant into one unified flow, rather than sitting a supervisor on top of them. The core idea: instead of routing purely on static instructions, generate a lightweight intent summary for the incoming question up front. That intent summary becomes the basis for routing to the correct Genie space or Knowledge Assistant tool for the remainder of that conversation thread, rather than re-deriving routing logic on every hop.
Where this gets more interesting is what the intent summary is routed against. Rather than hard-coding a static mapping of โthese keywords go to this Genie space,โ routing is grounded in Atlanโs semantic metadata layerโ the business glossary, asset descriptions, and lineage context Atlan already holds for each Genie spaceโs underlying tables. So the routing decision isnโt just โdoes this question sound like itโs about supply chainโโ โitโs checked against the actual, governed context of what each Genie space is scoped to know about. This makes routing more resilient as new Genie spaces get added, since the routing signal comes from Atlanโs catalog rather than a manually maintained instruction set that has to be updated every time.
The hypothesis: an upfront intent summary plus Atlan-grounded routing reduces redundant LLM calls in the routing path, which should show up directly in the per-run cost we track via MLflow later in this post.
To be clear, this isnโt a case against the supervisor agent pattern; itโs a legitimate, well-supported approach for many use cases. This post is about exploring a specific optimization for a specific shape of problem: many Genie spaces plus a Knowledge Assistant, high query volume, cost-per-run as a first-class concern, and Atlan metadata already in place to lean on.
Architecture overview
The stack: a LangGraph agent calling a Databricks-hosted foundation model through Databricks AI Gateway, Atlan connected via API key for both routing context and standalone metadata lookups, a Knowledge Assistant loaded with unstructured docs, one or more Genie spaces, and MLflow tracing wrapping the whole run for token and cost visibility.

At a high level:
- A user query comes in.
- The LangGraph agent (running a Databricks-hosted model via AI Gateway) reasons over the query and builds an intent summary.
- The intent summary is checked against Atlanโs semantic catalog to decide which Genie space or tool the query belongs to.
- The agent calls the right toolโ a Genie space, the Knowledge Assistant, or Atlan directly for a metadata/lineage question.
- Every LLM call along the way is traced through MLflow, which reports tokens and cost for the run.
- The final answer goes back to the user.
The agent design: a single ReAct node, not a multi-node graph
It would have been easy to over-engineer this as a LangGraph graph with separate nodes for intent extraction, routing, and tool execution. We deliberately kept it simpler: a single ReAct-style node that holds the whole loopโ โreason, decide on a tool call, observe the result, repeat until it has an answer.
The intent summary and the Atlan-grounded routing decision arenโt separate graph nodes with their own state transitionsโ โtheyโre part of the same reasoning step the ReAct agent already does before picking a tool. Practically, that means:
- The agentโs prompt is augmented with Atlanโs semantic metadata (glossary terms, asset descriptions, table-to-domain mapping) so that when it reasons about which tool should handle a question, itโs reasoning with governed context already in front of it, rather than routing rules bolted on as a separate step.
- Genie spaces and the Knowledge Assistant are exposed to the ReAct loop as tools, the same way any LangGraph tool-calling agent would see them. The โroutingโ is really the model picking the right tool given the metadata it has, rather than a distinct supervisor hop.
- The graph itself stays minimal: one reasoning node, a tool-execution edge, and a loop-back edge until the agent is done. Thatโs part of what keeps the token and cost profile lean compared to a multi-agent supervisor topology.
Worth naming honestly: a single ReAct node puts more weight on the system prompt and the quality of the metadata fed into it, since thereโs no separate routing stage to fall back on if the model reasons poorly. Thatโs a fair trade given the goal here, but not one to gloss over.

Knowledge Assistant: the โhow do I even find thisโ tool
Genie spaces answer questions grounded in structured, tabular dataโ โbut a large share of real questions from users arenโt โwhatโs the number,โ theyโre โwhere do I even go to get the number.โ Thatโs the gap the Knowledge Assistant covers in this design.
Itโs populated with organizational knowledge that usually lives scattered across wikis, onboarding docs, and tribal memory:
- FAQs and process documentation for Databricks and adjacent systemsโ โhow workflows are triggered, what a given pipeline does, standard procedure for common requests.
- Access and schema guidanceโ โwhich workspace, catalog, or schema a user should be looking at for a given project, and how to request access to it.
- Project-level pointersโ โwhere the documentation, design docs, or SharePoint artifacts for a particular initiative actually live.
In the ReAct loop, this is a distinct tool the agent reaches for when the intent summary suggests a โwhere/howโ question rather than a โwhatโs the valueโ questionโ โwhere do I get access to the supply chain schemaโ routes to the Knowledge Assistant, while โwhat were last monthโs shipment delaysโ routes to a Genie space. The Atlan-grounded routing context helps make that distinction cleanly, since Atlanโs metadata already documents which catalog or schema owns which domain, reinforcing rather than duplicating what the Knowledge Assistant holds.
Atlan integration: two separate jobs
Once Atlan is wired in via an API key, it does two different things in this architecture, worth keeping distinct rather than treating โAtlan integrationโ as one monolithic capability.
1. Routing context, via Atlan AI Applications. Atlanโs AI Applications layer holds structured information about each Genie spaceโโโwhat domain it covers, which tables and schemas back it, what kind of questions itโs scoped to answer. This is the metadata the Atlan-grounded router queries against. Instead of the agent working from a static, hand-maintained list of โGenie space X handles supply chain, Genie space Y handles finance,โ it asks Atlan which Genie space fits the current intent summary. As more Genie spaces get added, this stays current without touching the agentโs routing logic.
2. Direct answers, for metadata and lineage questions. Separately, Atlan is exposed as its own tool for a different class of question entirelyโโโwhen a user isnโt trying to get data out of a Genie space, but wants to know about a table: where it lives, what it means, where it comes from, or what depends on it. For these, the agent calls Atlan directly to answer things like what a column means, where a tableโs data originates, or what breaks downstream if a table changesโโโlineage and metadata questions that neither a Genie space nor the Knowledge Assistant is built to answer well.
So in the ReAct loop, Atlan wears two hats: a routing input the agent consults before dispatching to a Genie space, and a standalone tool the agent calls directly when the question itself is about metadata or lineage rather than the underlying data.
Token cost tracking with MLflow: what we can measure, and what we canโt
Databricks-managed MLflow tracing gives per-run visibility into the LLM calls that actually happen inside the agent loop. Specifically, cost and token usage are tracked across three points in a single run:
- The user question as it enters the agent.
- The intent summary generation step.
- The final answer generation step.
Since these are all calls to a model served through the Databricks AI Gateway, MLflowโs tracing captures prompt tokens, completion tokens, and the resulting cost for each of these spans automatically, and rolls them up into a per-run total the user can see.
The gap: Genie cost isnโt visible through MLflow. Genie runs as a managed Databricks service, and from the agentโs point of view itโs effectively free till January 2027โโโthereโs no LLM call MLflow can trace on that leg, so a Genie-heavy runโs true compute cost doesnโt show up in the MLflow number at all. If a fuller cost picture is the goal, that has to come from a separate source: Databricksโ system tables log Genieโs underlying warehouse and compute consumption, and that data can be joined in afterward alongside the traced MLflow numbers.
Itโs worth being upfront about this rather than presenting the MLflow number as the full cost of a runโโitโs the full cost of the agentโs own reasoning, not of everything the agent triggers downstream.
Closing thoughts
None of this is a rejection of Databricksโ out-of-the-box supervisor patternโ โitโs a good default for a lot of teams. What we found useful was treating routing as a governance problem rather than a prompt-engineering problem: let Atlanโs already-maintained semantic catalog decide where a question goes, keep the agent itself as simple as a single ReAct loop, and be honest in the cost reporting about what MLflow can and canโt see.
If youโre running a similar setupโโโmany Genie spaces, a Knowledge Assistant, and Atlan already in your stackโโโthis pattern is worth trying before reaching for a full supervisor topology.
Have you tried something similar on your own Databricks + LangGraph stack? Would love to hear what routing approach worked for you.