AI Engineer Summit 2025
How to Build AI Agents that Actually Work
Read the talk
How to Build AI Agents That Actually Work
Rasgo’s enterprise data agents reveal why reliable tool use depends on selective retrieval, carefully designed interfaces, user permissions, and clear ownership of outcomes.
From a talk by Patrick Dougherty
Before you start: Familiarity with SQL tables, language-model tool calls, and basic API authentication will help you follow the examples.
What makes a rebuilt product an agent?
What has to change when a product is rebuilt around AI agents? Patrick Dougherty opens with that decision at Rasgo, where he was co-founder and CTO: two years before the talk, the team began taking apart its existing product and rebuilding it around agents. The first requirement is a precise definition of what the new system should do.
Dougherty’s working definition has three parts:
- Accept an objective, supplied by a human or another AI.
- Call at least one tool and receive its response.
- Decide autonomously how and when to use tools to accomplish the objective.
That last requirement separates an agent from a predefined prompt chain. If the application always runs one tool followed by another, the sequence is making the decisions. An agent must use what it learns to choose its next action.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Let the agent retrieve what it needs
The first design shift was to enable reasoning instead of relying on what the underlying model already knew. Rasgo moved context gathering into discrete retrieval calls that the agent could make while working. The practical distinction is upfront context injection versus retrieval on demand; retrieval through tools is still a form of retrieval-augmented generation.
The product searched and queried enterprise data warehouses. Giving the agent a large collection of tables and all their columns seemed like a straightforward way to prepare it to write SQL. In practice, Dougherty reports that the volume of schema information overwhelmed its selection process: it picked the wrong table or produced a query that would not execute.
The replacement was a small set of tools with distinct purposes:
- Search tables: Find candidate datasets relevant to the question.
- Get table detail: Inspect a candidate’s structure before using it.
- Profile a column: Investigate the data in a field rather than relying only on its name.
These are building blocks for an iterative investigation, not a mandatory three-step chain. Each result helps the agent decide what to inspect next and which columns belong in the query.
That investigation also needs a valid stopping condition: the required data may not exist. A useful agent can search, recognize that it lacks the evidence needed to answer, and report the gap so someone can act on it. Dougherty contrasts this with his observations of GPT-4o, which tended to attempt a query even when the available data did not support the requested calculation.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A plausible churn query can still answer the wrong question
The demonstration supplies GPT-4o with a simplified Salesforce schema: accounts, contacts, and opportunities, each with representative columns. The request is direct: “Write a query to see how many of my customers churned in the last month.” Before writing SQL, the model needs to establish whether those fields can actually identify a customer’s transition to a churned state.
GPT-4o proceeds to generate SQL. Its crucial assumption is that an account type other than customer indicates churn, and that this type would be updated when a customer left. The supplied schema does not establish that business rule. Counting accounts under that assumption can produce a plausible-looking answer without measuring churn at all. Automatically running the query would carry that unsupported interpretation into the analysis; the response does not push back on the missing evidence.
Dougherty then runs the same schema and question through o1. In this example, o1 concludes that the provided schema cannot establish whether an account has churned.
| Model in the demonstration | Response | Analytical consequence |
|---|---|---|
| GPT-4o | Assumes a non-customer account type represents churn | Generates SQL around an unsupported definition |
| o1 | Identifies insufficient schema information | Avoids presenting the calculation as supported |
This is a same-prompt demonstration, not a general model benchmark. Its useful lesson is about the agent’s objective: answer the business question correctly, which sometimes requires declining to generate a query until the missing data or definition is supplied.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The tool interface is part of the reasoning system
The Agent-Computer Interface, or ACI, is the contract between the agent and the code that performs its actions. It includes the syntax and structure of tool arguments, along with the content and format of the response. A tool can execute correctly while still returning information in a form the model handles poorly.
Rasgo found that apparently trivial interface changes could substantially affect agent behavior. One example involved the format of search results. With Markdown responses, GPT-4o sometimes reported that a column did not exist even though the tool result contained it. Dougherty reports customer tables with 500 or 1,000 columns and tool responses of roughly 30,000 tokens. The failure occurred in long results where finding the relevant field was itself a demanding part of the task.
After testing alternative formats, the team changed those responses from Markdown to JSON. Dougherty reports that this resolved the missing-column failure for GPT-4o in their tests. A compact illustrative table-detail response makes the interface decision concrete:
json
{
"table": "accounts",
"columns": [
{ "name": "account_id", "data_type": "VARCHAR" },
{ "name": "account_type", "data_type": "VARCHAR" }
]
}
Here, the example field names illustrate a structured response: each column is an explicit object with named attributes. Formatting preserves the metadata; it does not supply a missing business definition such as what constitutes churn.
The team later found XML preferable for Claude in its setup. The actionable conclusion is to test the tool’s input and output contract with the model and workload actually in use. Dougherty suggests that training data may explain these preferences, but the observations do not establish a universal rule that one model always needs JSON and another always needs XML.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Spend capability on the model choosing the next action
Think of the model as the agent’s brain: its mistakes become visible as bad decisions in the product. That does not require using the same expensive model for every operation. Cheaper models can handle subordinate prompts or work inside tools, while a more capable controller decides what to do next from the results accumulated so far. At the time of the talk, Dougherty favored Claude 3.5 Sonnet for that controller role because of its balance of speed, cost, and decision quality.
Failures can also reveal how to improve the interface. If an agent repeatedly ignores a tool’s JSON Schema and supplies an argument in a different format, inspect the pattern rather than treating every occurrence as an isolated mistake. The repeated shape may suggest a tool definition the model can use more reliably. Where the intended operation permits it, changing the interface to match that expectation can reduce friction. Dougherty interprets this as working with the model’s learned expectations; the malformed calls are the observable evidence, while the training-data explanation remains a hypothesis.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Avoid teaching a sequence at the expense of reconsideration
Fine-tuning did not pay off for Rasgo’s agent work. Dougherty describes cases where tuned models became more likely to repeat a particular sequence of tasks instead of stopping to ask whether the next action made sense. He interprets this as overfitting that reduced reasoning flexibility.
For this setting, his recommendation is to prioritize ACI iteration over fine-tuning the agent’s controller. The distinction is practical: making relevant evidence easier to retrieve and interpret supports a fresh decision at each step, whereas reinforcing a habitual sequence can undermine that flexibility. This is a conclusion from the team’s experience, not a general limit on what fine-tuning or other post-training methods can achieve.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Choose architecture around the user’s permissions
The deciding constraint was production authorization. A person querying Snowflake may have granular permissions over the underlying data. The agent acting for that person needs to operate under those same permissions, rather than gaining broader access simply because a service is making the query.
Rasgo needed an OAuth integration that carried the requesting user’s permissions through to the agent’s work. Its own code needed to manage authentication, service keys, and tokens. Dougherty reports that fitting this requirement into an approach like LangGraph was difficult to build and scale. That is an account of Rasgo’s integration constraints, not a claim that LangGraph cannot support authentication; LangGraph Platform has documented custom authentication and access control. The architectural question is whether the chosen framework lets the application retain the required control over identity and delegated access.
For prototypes, Dougherty sees value in abstractions that help validate an idea quickly. For production, he advises deciding the end requirements before becoming dependent on them. His reasoning is that basic single-agent or multi-agent orchestration does not necessarily require much code, while adapting that orchestration to a product’s security and operational requirements can be the harder work.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The product’s value surrounds the agent
That production work also changes where differentiation comes from. Dougherty is skeptical that keeping a system prompt secret creates much of a moat. He places more value in the surrounding product: how users interact with the agent, which systems it connects to, and which security protocols govern its work.
Those connections, permissions, and interaction patterns were the most time-consuming parts of turning the agent into a production product. In his view, they are also more defensible than the prompt itself—although he qualifies even that claim because the technology is changing so quickly.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Give a small team one owner of the outcome
About a year into the transition, as customers became comfortable with single agents, Rasgo introduced a multi-agent concept. The central design decision was a hierarchy: a manager agent owns the final outcome and delegates subtasks to workers with more specific instructions and tools. This distributes specialist context instead of placing every instruction and tool in the manager’s context, where the volume can overwhelm its decision-making.
Team size mattered too. Dougherty invokes the two-pizza rule for human teams as an analogy for keeping agent collaboration bounded. In Rasgo’s experience, roughly five to eight collaborating agents typically worked well. In systems he saw or prototyped with 25 or 50 agents, loops and paths the system failed to return from made completion less likely. These are practical observations, not a measured scaling law or a universal agent-count limit.
The manager’s instructions should emphasize accomplishing the overall objective rather than forcing every worker through a prescribed sequence. Dougherty describes this as incentivizing or rewarding the manager for the outcome, without specifying a reinforcement-learning implementation. The responsibility is concrete: delegate useful work, judge whether the returned output is valuable, and determine whether it can contribute to the broader result. Delegation does not transfer ownership of the final answer. The manager must keep evaluating what the team has actually accomplished.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
The AutoGPT project's current source repository and setup information.
A framework for organizing autonomous agents with specialized roles and collaborative tasks.
Further reading
Patrick Dougherty's earlier account of building Rasgo's data agents, including retrieval tools, interface design, and production lessons.
Research on how purpose-built computer interfaces affect an agent's ability to navigate repositories, edit code, and run tests.
The December 2024 introduction of custom authentication and resource authorization for Python LangGraph deployments.
Documentation explaining Snowflake OAuth and External OAuth options for authorized client access.
- DeepSeek-R1Paper
Research on developing reasoning capabilities through reinforcement learning, multistage training, and distillation.
Updates since the talk
Anthropic's later guidance on selecting context, structuring prompts, and designing tools for agents.
Read the complete timestamped transcript
- 0:01
Hi, I'm Patrick. I was the co-founder and CTO of Roscoe, and two years ago, we decided to rip apart our entire product and rebuild it around AI agents. These are some of the lessons we learned.
- 0:16
First of all, let's start out with a definition, since a lot of people use the term agent but don't necessarily mean, mean the same thing that I do. For my definition, I came up with there's three specific criteria that it has to have to be considered an AI agent.
- 0:31
Number one, the agent needs to be able to take directions. These can be human or AI-provided, uh, but it should be one specific objective or overarching goal.
- 0:44
Two, it has to have access to call at least one tool and get a response back.
- 0:50
And three, it should be able to autonomously reason how and when to use its tools to accomplish that objective. What that means is it can't be a predefined sequence of this tool will run and then this next tool will run in a prompt chained type of setup.
- 1:08
It has to use autonomous reasoning in order to be called an AI agent.
- 1:15
One of the biggest lessons we learned in building agents was the necessity to focus on enabling the agent to think rather than be limited by what the underlying model knows.
- 1:28
So a lot of our tool calls were focused on retrieval. Rather than trying to do RAG, where we inserted contents into the system prompt, um, to, to guide the agent's actions, instead, we focused on discrete tool calls that allowed it to perform retrieval and get the relevant context into its, its context window while it was working.
- 1:52
The, uh, product that we built was enabling a AI agent to search and query your enterprise data in your data warehouse for you. And so one of the, a, a great way to kind of illustrate the, um, limitations of focusing on knowledge over reasoning is when it comes to writing a SQL query, uh, given some data.
- 2:16
So what we found frequently was that if you gave the agent a, a whole bunch of tables and all of the columns in those tables, it would fail to reason correctly about which one to use.
- 2:28
It would get overwhelmed by the number of tokens in the prompt and either choose the wrong one or just write a terrible query that didn't execute in the first place.
- 2:38
That's where we went to these more discrete, um, more simple, uh, building blocks of tool calls, such as search tables, get table detail, uh, or profile a column. The agent is then tasked with using those iteratively to find the right columns for the right query.
- 3:01
Similarly, we saw this play out as reasoning models, uh, have become recently introduced as well. So when you focus on reasoning, you give a reasoning model the ability to first attempt to find the data needed to answer a particular question, but then if it doesn't find it, it should be able to tell you that it didn't find
- 3:23
it, and you can take some action with that knowledge. What we've seen with GPT-4o, uh, prior to reasoning models coming out is that regardless of the ability or the underlying data being present for it to be able to answer a question, it is going to attempt to write that query anyway.
- 3:43
Let's walk through an example of this. So in this prompt, I'm providing 4o with a table schema that, uh, is pretty standard from Salesforce. So there's a table for accounts, contacts, and opportunities.
- 3:59
And these aren't all the columns in each of those tables. I'm just oversimplifying for representative purposes. At the bottom, I've asked GPT-4o a question, "Write a query to see how many of my customers churned in the last month."
- 4:12
What you'll see from GPT-4o is it is very incentivized to write a query, give me back SQL. It's not really stopping to think about, uh, is this query even possible to write in the first place.
- 4:28
So it makes some, uh, some assumptions, and then it just starts writing SQL. Its definition is really bad for, uh, calculating churn. Um, it's essentially just looking in the account table and assuming that, uh, there's a different type of account that's not customer that would somehow be updated when a customer churned.
- 4:52
Um, so I think this is very likely to lead an analyst to a totally wrong answer if they were to take this query and automatically run it. Um, but what you see is that it's not pushing back in any way.
- 5:03
It doesn't stop to say, "I, I should think about this and, and consider if this is even possible."
- 5:10
Okay, now let's flip over and see the same prompt run on, uh, o1. So this prompt is the exact same up top. We're providing the same schema and the same question.
- 5:21
o1 reasoned through, uh, the, the various aspects of this question, and it accurately concluded that there is no way, given the schema provided, to calculate the, uh, status of churned on an account.
- 5:41
And so that conclusion kind of shows the difference of giving the model the freedom to think and encouraging it to think and reason versus just, um, forcing it essentially to, to come up with a SQL query.
- 5:56
So that's one of the key lessons that, that we learned in kind of building and, uh, deploying agents that were useful for enterprises.
- 6:06
As part of this, there was a huge need to iterate on what I would call the ACI. I believe this was a, um, this was a paper that was published that kind of coined this term, uh, Agent-Computer Interface.
- 6:18
And it's really referring to the exact syntax and structure of tool calls, both what goes into the tool call and then the content and format of the response from the, you know, API or, or Python code maybe that would handle and execute that tool call.
- 6:36
So what we learned is really small tweaks to the Agent-Computer Interface can have a massive impact on the accuracy and performance of your agent. And you will feel when you're making these tweaks like they are so trivial, it makes no sense that they would have any bearing on your agent's performance.
- 6:54
Um, however, I'm, I'm telling you that this is actually one of the best ways you can spend your time when you're trying to get your agent working consistently. A couple of specific examples.
- 7:05
So number one, one of the things that we found was that the format of the response, depending on the model, was consumed better or worse, likely correlating to the underlying training data potentially of the model.
- 7:21
So specifically when working with GPT-4o, we transitioned from responding with these search result payloads. Initially, they were formatted as Markdown, and we were seeing examples where the agent would look at that response that it got back from the tool call and tell us that a column did not exist when you could see the column within the, uh,
- 7:44
context, you know, passed back in the tool result. These were long context tool results oftentimes. Some of our customers had five hundred or a thousand column tables in their data warehouse.
- 7:54
So it was understandable if you're getting, you know, thirty thousand tokens back that there might be some challenges there. But we felt like to consistently be completely blind to it, um, there had to be a way to improve this.
- 8:07
So we tested different formats. We ultimately learned that just switching the formatting of the response from Markdown to JSON, having that semi-structured, uh, payload and response immediately solved this problem for, for GPT-4o.
- 8:21
However, we learned later on that for Claude, it was really important to provide XML back to the model, uh, and not Mark-- uh, not JSON. So again, depending on the model you're using and the specific, uh, function arguments and then responses that you're, you're providing from those tools, it can really impact your agent's performance.
- 8:46
Think of the model as your brain when you're building an agent. Uh, the model is performing the, the thinking capabilities, and if the model sucks, then your users aren't gonna be happy because they're going to see some of the obvious logical fallacies that the agent will make.
- 9:03
Um, so I think what's, what's critical there is even if some of your tasks need to run on a cheaper model, like some of your tool calls or, or some of the, uh, sub-prompts that, that might be triggered by your agent, it's really important that the actual model making the determination of which tool call to make next
- 9:22
based on what has happened up to that point is, uh, a generally intelligent model. Um, I would say Claude 3.5 Sonnet's still probably my favorite for this, even beyond the reasoning models, because it does a really, a really nice balance between speed, cost, and making a good decision, uh, based on what it's learned so far.
- 9:45
Another thing, we talked about GPT-4o over o1 and how 4o is, is incentivized to make an effort even if the task is impossible. One thing you can learn, though, by observing the failure modes of agents running with a certain model is oftentimes the way it hallucinates tells you what the model expects in a tool call, for instance.
- 10:08
So if you see it consistently ignoring your JSON Schema for a tool call and providing an argument in a different format, that should be an indicator to you that the agent is telling you how it thinks, how it thinks the tool call should be defined.
- 10:25
And if you can change it to match that expected format, you're going to generally improve agent performance because it's going to be closer to the training data and the instinct that the model has natively versus you trying to force it into doing something else.
- 10:45
Another lesson we learned was that fine-tuning models was a waste of time. Uh, I think this is generally accepted now, but there's still a little bit of work happening on building agents with fine-tuned models.
- 10:58
If you buy the premise that we're focusing on reasoning over inherent knowledge of the model, then it's logical to say that fine-tuning does not really improve reasoning. Actually, in our, uh, experience, it actually decreased reasoning in a lot of cases because it effectively overfit or over-tuned the model to do a specific sequence of tasks each time
- 11:23
rather than stopping and thinking, uh, if it, you know, was, was making the right decision. So I would really spend your time, uh, focusing on that ACI iteration rather than trying to build a fine-tuned model to run your agent on.
- 11:42
Another question that we got frequently from customers, users, and others was, uh, "Hey, what abstraction are you using? Which framework are you building on?" And for two reasons, we did not end up using an abstraction.
- 11:57
Number one was simple. When we started building this two years ago, none of the abstraction libraries like a LangGraph or a CrewAI were publicly available yet. So we didn't even have a choice really.
- 12:07
We were just kind of basing some of our research off of Auto-GPT at the time. But the second reason is that even as those frameworks started to become more popular, we continued to evaluate, uh, transferring some of our code to them.
- 12:20
The problem was there's huge blockers and considerations when you want to go to production with an, with an agent running on one of these frameworks. Uh, one of the key things for us as an example was the ability for an end user security credentials to cascade down to the agent they were talking to.
- 12:41
So think about, uh, if, if a human is trying to use an agent to query their Snowflake account, they may have very granular permissions within that Snowflake account of, of what they specifically are allowed to see, uh, in the underlying data.
- 12:56
We needed our agent to be able to run with that user's permissions using an OAuth integration, and that was something that made some-- uh, an approach like LangGraph extremely difficult to build and scale because we needed to, uh, essentially manage the authentication process and the underlying, um, service keys and tokens, uh, within our code base, not within
- 13:20
a third-party framework. So the lesson I think to take away from that is think about what your end goal is first before you get too dependent on one of these frameworks.
- 13:30
There is not too much code that you have to write to build an agent or even a multi-agent system. If you're in prototype mode, then sure, use an abstraction, speed yourself up, validate something as quickly as possible.
- 13:44
But if your goal at the end is production, you'll likely regret being too dependent on a third-party library.
- 13:55
One of the other philosophical conclusions we made is ultimately your agent's not your moat, meaning the
- 14:03
system prompts, a lot of people were really careful not to share those, uh, early on, you know, as, as people were building agents, acting like there was a lot of IP in there.
- 14:12
I don't believe that's true. I think what really is, uh, the most valuable thing you can do is the-- set up the ecosystem around your agent, including the user experience of how your user interacts with your agent, and then also the connections and the security protocols that your agent has to follow in doing its work.
- 14:32
That is the most time-consuming part of building a production quality agent into a product, and that is ultimately going to be your moat inasmuch as we can even have moats these days with how quickly this stuff is moving.
- 14:50
Last but not least, one of the key lessons that we learned more recently was about designing and executing on multi-agent systems. So about a year into our process of transitioning to an agent-based product, um, as our customers were getting comfortable with single agents, we introduced a multi-agent concept.
- 15:08
And these are some of the key lessons we learned when doing that that really stuck with us and I think have continued to be highly resonant when you're designing agents in a product.
- 15:19
Number one was the need to implement a manager agent within a hierarchy. The reason for that is that we found the, the manager agent would own the final outcome but could delegate subtasks to specific worker agents that would have more context in their instructions and more specific tool calls to accomplish those tasks.
- 15:42
Whereas if you gave all of that information to a single manager agent, it could become overwhelmed. It might, uh, make bad decisions, go down bad, bad paths.
- 15:52
Uh, we also learned that the, um, number of agents working together, there's almost a two pizza rule, kind of similar to how Jeff Bezos would design teams early on at Amazon, that applies here.
- 16:04
So we found that if you could limit yourself to about between five and eight agents working together, then that was typically a task that could be accomplished well by a, a multi-agent team.
- 16:17
I've seen and, and prototyped some systems where you might have twenty-five or fifty agents working together, and really what happens is you, you strongly decrease the likelihood that the actual outcome ever gets accomplished because you're likely to trigger infinite loops or go down paths that, uh, you don't return from.
- 16:38
Incentivization is the number one way to set these things up. So the goal should not be to force your worker agents through a discrete set of steps, but rather to incentivize your manager agent, meaning describe and, uh, quote-unquote reward it with, uh, accomplishing the overall objective and relying on it to manage the underlying worker
- 17:03
agents and make sure that they, uh, their output is valuable and that it can be used, um, within the context of achieving that broader outcome.
- 17:15
I wrote more about the, um, designing effective multi-agent teams on my blog at asteraap.com. Uh, this is the, the blog post. So I go into a little more detail about these principles and some other thoughts as well.
- 17:31
Thanks so much for your time and hope you enjoyed, uh, learning all of the mistakes that I've made the last couple years in designing agent systems and multi-agent systems.
- 17:41
I hope you can avoid them and that it saves you some time.