Building an AI Financial Analyst — Part 5

The Builder, and Where I Let the Model Near the Code

Important

Disclaimer: The writing and musing of the author do not necessarily reflect the views of his employer.

If you have ever built the same thing twice and found yourself dreading a third time, this is what I did about it.

Having built this stack twice by hand, the third time I wrote something to do it for me. In this post I will go over what that tool does, and one design decision inside it that runs against where most of the industry currently is. The builder ships in the same repository, under agent-builder/.

github.com/BASoapbox/ACME-Corp-Select-AI-Agent-Project

What it does

It is a Python command-line tool. You answer a short interview covering what data, which tables, which documents, and what the agent's job is, and it generates the PL/SQL that builds the whole stack, shows it to you, and runs it.

That is the visible part. The parts that took longest are less glamorous and, I think, more useful:

Provisioning pre-flight. Before generating anything, it checks whether the environment can actually support an agent: is Resource Principal enabled, are the DBMS_CLOUD* grants in place, are the Oracle Machine Learning roles granted, does the Embedded Python Execution network ACL exist, are the source-table grants direct rather than through a role. Each failure prints the exact statement that fixes it. Almost every item on that list is something that cost me an afternoon at some point.

Comment management. Scan the tables, profile the column types and foreign keys, sample distinct values, draft table and column comments with the model, let a human review them, then emit COMMENT ON statements. As Part 2 argued, comments are the highest-leverage thing you can do for natural-language SQL quality, and writing them by hand for thirty columns is exactly the sort of task people skip.

Spec import. A project can be defined in a Word document or CSV rather than an interview, which means the definition of an agent becomes a reviewable artefact you can diff and version rather than a sequence of clicks.

The decision worth arguing about

Here is the part that matters beyond Oracle.

The model runs the interview. It is banned from writing the SQL.

The generator is deterministic. It takes a spec dictionary and emits PL/SQL with no model involvement at all. Object names, table lists and comment metadata are all owned by captured facts, not by anything generated. The system prompt says so outright:

ABSOLUTE RULE — NO SQL OR CODE GENERATION

This is the opposite of the default move in 2026, which is to let the model generate the code and check it afterwards. I went the other way for concrete reasons, all of which I had hit:

  • Models rename things. Ask for a tool called ACME_SQL_TOOL and get ACME_SQL_TOOL_V2, or a helpfully "corrected" profile name that no longer matches the agent's tools array.
  • Lists get dropped. An object_list with six tables comes back with four, and nothing errors, so the agent simply can't see two of your tables.
  • Output that must be executable arrives wrapped in markdown fences.
  • Long structured output gets truncated. Some fast models cut off mid-statement regardless of max_tokens, and a PL/SQL block truncated at 80% is not a syntax error you enjoy diagnosing.

None of these are model failures exactly. They are the model doing what it does, being helpful and approximate, applied to a task where approximate is the same as broken.

So the line I drew is this: fuzzy input from a human goes to the model; anything that becomes an executable artefact is generated deterministically. Interviewing someone about what their agent should do is genuinely hard to do with code and easy with a model. Turning a settled spec into CREATE_TOOL calls is genuinely easy with code and needlessly risky with a model.

There is a fallback path that calls the model if the deterministic generator is unavailable. It is a fallback, and it is instrumented as one. When it fires, the log says so, because output that came from a model is output you should read more carefully.

Spec as code

The second-order benefit took me a while to notice.

Because generation is deterministic, the generated PL/SQL is reproducible. The same spec produces the same script. Which means the script becomes a reviewable artefact: you can commit it, diff it between environments, and see exactly what changed when someone adjusts a routing instruction.

That is not available from a visual builder, which produces state rather than scripts, and it is not available from a model-generated script, which produces something slightly different every run.

One thing worth mentioning here, and it would be remiss of me not to: Oracle's own AskOracle APEX application now includes a visual agent builder, and it is a genuinely nice way to explore the framework interactively. This is certainly not the only way to approach the problem. The two solve different problems, though. One is a console for building an agent by hand; the other is provisioning and spec management for teams who want the definition in version control. If you want a chat interface, use AskOracle. This is the layer that gets you to the point where AskOracle has something to point at.

Would I do it again

Honestly, the interview is the least valuable part. If I rewrote it tomorrow I would keep the pre-flight checks and the comment management, and I would think harder about whether the conversational front end earns its complexity over a well-commented spec file.

But the deterministic generator I would keep exactly as is. Every time I have been tempted to let a model write the executable output, the failure mode has been the same: something that looks right, runs without error, and is quietly wrong in a way that surfaces three layers away.

Which, if you have read Part 4, is a familiar shape.

That is the series. The scripts, the builder, the sample knowledge base and a full implementation guide are all in the repository. If you build something similar and hit a wall somewhere I didn't, I would genuinely like to hear about it.

Enjoy!

Built on Oracle Autonomous Database 26ai · OCI Generative AI · OML4Py