Graph pipeline instead of one-shot SQL
Schema, generate, validate, fix, execute, error-retry, format, or a useful failure.
Case Study
A US manufacturer arrived with a chatbot that could not survive a second tool call. The work became a PydanticAI main agent, a SQL sub-agent, then an 8-step pydantic-graph — not a bigger prompt.
The first system was OpenAI function calling with tools that grew to thousands of lines because the loop after the first tool call was broken. The production system answers orders, inventory, and customers — thousands of queries a day — with schema-aware SQL that is SELECT or WITH only.
8 steps, 473+ columns across 15 views, and two retry stages are this manufacturer's published architecture, not STCC triage and not Synera's 2-hour node graph. New features take days, not months.
Schema, generate, validate, fix, execute, error-retry, format, or a useful failure.
The schema the SQL agent must not confuse — ProductCategory versus ProductCode.
Validation failures and execution failures each cap at two attempts. No infinite loop.
About the client
A large US manufacturing company making high-precision metal products. The company is not named here. The operations team needed natural-language answers from a MySQL database of customers, orders, products, and manufacturing data — and they arrived with a chatbot that already failed in production-shaped tests.
The challenge
The client had wired GPT to a handful of tools. After the first call, the loop did not hand tool definitions back to the model. “Find user XYZ and their latest order” could not be two steps. Developers compensated with sprawling tools: a get_user that also fetched the last ten orders whether anyone asked. Tools joined tables, aggregated, and returned piles of rows so the next call would never be needed. Functions ran to thousands of lines. Every query fetched data it did not need. A new field meant hunting the spaghetti. Error handling disappeared.
Three facts made a bigger monolith impossible. Realistic questions are sequential. The MySQL schema’s combinatorial queries cannot be enumerated as tools. Every schema change meant touching those giant functions again.
First a working agent that can call more than one tool. Then a graph inside the SQL tool, once production logs showed one-shot SQL failing on 473 columns.
The failure was not “GPT cannot do SQL.” It was a conversation loop that died after the first tool, plus tools that tried to anticipate every JOIN. The database had dozens of tables. Covering them as individual tools was not a plan.
A main agent with narrow tools for the common 80% — customer, order, contact — and a SQL sub-agent for the rest. Parallel tool calls. SELECT/WITH only. Schema fetched before SQL. Logfire from day one.
Months in, complex queries still confused ProductCategory with ProductCode. The SQL tool became a pydantic-graph: generate, validate, fix, execute, retry — max two each — then format or explain. Agent-as-tool: the main agent still just calls sql_query_subagent.
How it works
The main agent looks up customers, orders, and contacts. When the question is an edge case, it calls a SQL sub-agent — itself a PydanticAI agent — with enriched context, not the raw chat line. That sub-agent loads schema, writes SQL, and returns the statement plus rows. Nothing but SELECT or WITH is allowed.
Vstorm × undisclosed US manufacturer — hierarchical delegation, not peer agents negotiating
A query such as “open orders for Acme in the last 30 days” is a customer lookup in parallel with a SQL tool that already has the join_id. What used to need two user turns finishes in one. That held for months. Then production showed the atomic SQL step failing on questions like “open orders for ABC last quarter, copper category”: the JOIN was valid SQL and the wrong business join. The agent had no intermediate result to check.
The graph splits that work. The graph owns sequencing, state, errors, and parallel steps. The agent owns intent, SQL for this step, and language. create_execution_plan and sql_query_subagent are tools from the main agent’s point of view. This is hierarchical delegation, not a swarm of peers negotiating.
| Step | Node | What it does |
|---|---|---|
| 1 | Schema_lookup | Fetches the full schema for context |
| 2 | Generate_sql | LLM writes SQL from schema and intent |
| 3 | Validate_sql | Syntax, dangerous keywords (DROP, DELETE), prefixes, structure |
| 4 | Fix_sql | On validation fail, LLM sees the errors and regenerates (max 2) |
| 5 | Execute_sql | Runs the validated query |
| 6 | Error_retry | On execution fail (missing column), LLM corrects (max 2) |
| 7 | Format_results | Format; CSV + temporary link above 1,000 rows |
| 8 | Handle_max_retries | Useful error if retries are exhausted |
1. Main agent calls sql_query_subagent with a copper-category, last-quarter filter
2. Graph: schema → generate SQL → validate (pass) → execute
3. Execute fails: "ProductCategoy" is not a column
4. Error_retry: LLM sees the error, rewrites ProductCategory
5. Validate (retry) pass → execute (retry) pass → format, SQL included in the reply State is a typed SQLQueryState: query, schema, SQL as it is rewritten, validation errors, rows, retry count, CSV URLs. Logfire can inspect that state after any node. RAG over procedures, branded PDFs, CSV in Azure Blob, image search, and matplotlib charts are extra nodes on the same graph, not a second product.
Results
| Approach | When it fits |
|---|---|
| PydanticAI agent alone | One lookup, independent tools, obvious unchanging workflow, latency first |
| pydantic-graph | Lookup then filter then generate; parallel work; state across steps; isolation for tests |
The client started with a chatbot that could not complete a two-step question. They now run thousands of queries a day. Instant answers on orders, inventory, and customers. Features in days, not months. The architecture is not “always a graph.” It is a graph where a wrong JOIN is expensive, and a simple agent where it is not.
Meet directly with our founders and PhD AI engineers. We will walk through real implementations from 30+ agentic projects and the practical steps to integrate them into your workflows.