Agent Control Plane in your database

exasol_nerd1 pts0 comments

Agent Control Plane: Build Multi-Agent Systems in the Database | Exasol

Skip to content

Watch our demo

Contact us

Watch our demo

Home » Blogs » Exasol’s Agent Control Plane

Database + Model = Agent Stack

Agents are non-deterministic. The same prompt against the same model can produce subtly different outputs run to run and across model versions. As teams move toward multi-agent fleets, that variance becomes an operational problem: how do you keep a fleet of agents consistent, auditable, and actually under control?

Deploying agents raises questions most teams don’t have good answers for: "Which prompt generated these results?" "What data did the agent interact with?" "What did it cost?" The answers are scattered across systems, if they’re accessible at all.

For true repeatability, agents in production can’t be free-form. They need controls: a versioned prompt the system actually used, a schema the model is required to match, an immutable record of every call, and a way to join all of that back to the row the agent wrote. At fleet scale, those controls have to be uniform across every agent, or the audit story collapses.

The best place to put those controls is where the data already lives.

Agents should be managed in the same place you manage the data they read and write.

The database that holds your output rows can equally hold the prompts that generated them, the schemas that constrained them, and the audit trail that connects it all.

In this post, we build an Agent Control Plane entirely on Exasol, using a multi-agent document parsing pipeline as proof. A complete agent fleet on infrastructure you already operate. A database and a model is the entire stack.

Agent Control Plane components

With Exasol’s Agent Control Plane, you develop, execute, and monitor agents in one place: your Exasol database. The key components:

agent_registry: Catalog of named agents with owners, status, and descriptions. Everything else (prompts, schemas, runs, calls) hangs off the agent.

agent_prompts: Every prompt that ever ran in production is retrievable, by agent and by version, append-only. A new version is a new INSERT; history is never overwritten.

agent_output_schemas: One JSON Schema per agent, stored as a row. Passed to the model as a tool definition at call time; the model can’t return a shape that doesn’t match.

agent_call_log: One row per LLM call, joinable to the prompt version, the schema, the run, and the data the agent produced. Cost and confidence are first-class columns.

agent_models: Model catalog with per-token pricing. Joined at log time to compute cost_usd, making FinOps a SQL query rather than a billing export.

Access control: Standard Exasol GRANT/REVOKE governs who can read prompts, author new versions, promote them to active, and inspect call logs.

Model credentials: AWS credentials for Bedrock sit in an Exasol CONNECTION object, not in code or environment variables. The same IAM policies your security team already wrote govern model access.

Orchestrator UDFs: Exasol User Defined Functions that fetch the active prompt and schema, call the model, validate the response, and write the audit row. A top-level orchestrator UDF chains agents into a multi-step run under a single trace ID.

The Use Case – Document Intelligence

A manufacturer receives supplier invoices as PDFs and needs to reconcile the costs against purchase orders in their ERP. Agents handle this kind of work well, provided their output is constrained and every call is auditable.

Extract. Read the PDF, return structured line items. This works well for an agent as long as the output is locked to a consistent, relational schema with enforced guardrails.

Match. For each invoice line, find the corresponding PO line. Descriptions won’t match verbatim, so this requires semantic reasoning that a SQL join can’t do on its own.

Flag. Compare invoice price and quantity against the PO, mark the variance. Once the data is clean and matched, this is a straightforward SQL expression.

Creating the Agents

Two agents handle this workflow: invoice_extractor and po_matcher. Both go into the agent registry:

INSERT INTO agent_registry (agent_name, description, owner, status) VALUES<br>('invoice_extractor', 'Reads supplier invoice PDF, returns structured line items.',<br>'[email protected]', 'active'),<br>('po_matcher', 'Matches invoice lines to PO lines via semantic match.',<br>'[email protected]', 'active');

Each one gets its own prompt and schema, scoped to its agent_id. The pattern is uniform: every agent in the registry has at least one active prompt row and one active schema row at any moment.

Creating the Prompts

Each agent gets its own prompt row. Author, model, and version are columns, not metadata buried somewhere else.

INSERT INTO agent_prompts (agent_id, prompt_text, model_id, version, status, created_by)<br>SELECT a.agent_id,<br>'You extract line items from supplier invoices via the submit_invoice_extraction tool.<br>Transcribe only what is...

agent model agents prompt control exasol

Related Articles