AIAI EngineerFeb 22, 2025· 25:18

Tool Calling Is Not Just Plumbing for AI Agents — Roy Derks

Roy Derks argues that tool calling is the most critical yet overlooked component of AI agents, far more than mere 'plumbing.' He contrasts traditional tool calling—where developers manually manage callbacks, retries, and errors within the agent loop—with embedded tool calling, a black-box approach used by frameworks like LangChain’s createReactAgent. Derks advocates for separation of concerns via the Model Context Protocol (MCP) from Anthropic, which splits tool logic into MCP servers communicating with clients, and via standalone tool platforms such as IBM’s wxflows, Composio, and Toolhouse that let teams build tools once and reuse them across LangChain, CrewAI, or AutoGen. He also introduces dynamic tools, where an agent generates queries on the fly—e.g., using GraphQL or SQL schemas—instead of defining hundreds of static tools, noting that LLMs like Claude handle GraphQL well but may hallucinate on deeply nested schemas. The episode emphasizes that 'an agent is only as good as its tools' and provides practical guidance on designing tool descriptions (which act like system prompts) and output schemas to enable type-safe, chainable tool calls.

  1. 0:00Intro
  2. 1:49Agent Tools
  3. 3:22Application Layer
  4. 4:05Tool Calling Recap
  5. 5:58Tool Definition
  6. 8:34Traditional Calling
  7. 11:19Embedded Calling
  8. 13:43Separation
  9. 14:43MCP
  10. 16:20Tool Platforms
  11. 20:44Dynamic Tools
  12. 24:57Outro

Powered by PodHood

Transcript

Intro0:00

Roy Derks0:04

Tool calling is not just plumbing for AI agents. In this talk, I'm going to show you why tool calling is more important than some people think, and how you can use tool calling with your agentic frameworks. We'll be looking at some of the techniques for tool calling, such as regular tool calling or embedded tool calling, how this works with agent frameworks, and also some other considerations, like do you need a separate tool platform or can you look at different types of tools rather than the tools we see today.

If you think about plumbing, some people say you should do your own plumbing, some other people say you should always hire a professional. I hope at the end of this talk you'll be feeling like, "I can build my own tools, I know how to create tools separate from my agentic frameworks, and bring them in," and thereby get a lot of flexibility, like changing agentic frameworks or whatsoever.

If you think about agents in general, I feel we spend a lot of time on improving the agents, but we don't seem to spend a lot of time on building the tools that are reusable, robust, and can be put into different frameworks.

I feel it's changing slightly. There are tons of tool platforms popping up, there are more libraries to build tools, and I also feel the pressure is sort of off the agents. People know agents can do certain things, and now they're all trying to improve the tools these agents have.

So my name is Roy. I always worked for startups or founded my own startups. A few years ago I ended up at IBM after an acquisition. I've been doing tons of talks on GraphQL and web development, and also React, so you can find some of my books or previous talks on the internet.

Also, feel free to connect with me on social media in case you want to know more.

Agent Tools1:49

Roy Derks1:49

As I mentioned in the beginning, everyone is talking about agents, but not so many people are talking about the tools these agents need. If you look at a typical agent loop, there's always a user asking a question or sending a prompt.

There's the agent itself, which needs large language models, which needs a bit of memory, and then, of course, there are tools.

But the way that people are talking about these tools: everyone is talking about the agents, what agent framework should I use. They're probably using the tools that are provided by the agent framework, or they're writing the tools directly inside of the agent framework by extending some of the functions they have or interfaces they have to create tools.

But why are people not really talking about the tools? I always feel like every time I'm building an agent, the first thing that breaks is the tools. Either the large language model is not able to call the tool correctly, the large language model uses the wrong tool, maybe something inside my tool breaks because I didn't set up something properly.

The agent feels like a closed circuit where the tools are more dynamic. So at the end of this talk, I hope you feel like the agent is only as good as their tools. Frameworks do so much for you, but they don't do that much for you in terms of building the tools.

Someone once said, "A man is only as good as their tools." So let's make that: the agent is only as good as their tools. Make sure you have tools that are reusable and robust, and you can bring these into any other agent framework.

The LLMs advanced a lot over the last few years, and that's why I also feel the application layer, especially the part where you build your tools, deserves more attention. If you look at some of the things people are saying on the internet, it's actually saying, like, the wrappers around the GPTs, or wrappers around models, wrappers around the chat interfaces, they're way more— they provide way more options for improvement later on.

Application Layer3:22

Roy Derks3:47

And I also feel that's where we can do a lot more: by writing software, by coming up with smart solutions, and doing things on top of the models. At some point, the models are going to— well, they are going to— become increasingly better, but at some point we need to have the application layer catch up as well.

So let's quickly recap tool calling so we make sure we're all on the same level here.

Tool Calling Recap4:05

Roy Derks4:11

For example, imagine you're asking a question to an agent, like, "How far does the moon orbit?" Express as the number of trips between Amsterdam and San Francisco. So half a year ago I moved from Amsterdam to San Francisco, so I was actually kind of interested in the answer to the question.

If you look it up on your favorite chat application, you will find the moon's orbit is about 44 round trips between Amsterdam and San Francisco. So sometimes the model might be able to come up with the answer itself, because there's training data, which includes the distance between the moon and the Earth, and then a distance between Amsterdam and San Francisco, and it's able to find the answer for you.

More probably, it's going to do a set of tool calls. So it's going to search for the distance between the Earth and the moon, it's going to search for the distance between those two airports, and then it's going to do some calculations.

Calculations: maybe it needs a tool, maybe it can do it on its own. This question is fairly simple, but maybe you can make it more complex by asking, "How long does it take me in number of days?" Or, "Is it quicker to have a moon orbit or do those 44 round trips?"

One trip is like 10 to 12 hours, you need to wait at the airport, you need to fly back every time. So you probably need a bit more than this simplified example.

Of course, you can come up with the answers for these by doing tool calling or looking at training data. If it's doing tool calling, it's most probably looking at external APIs. So it's going to do a web search, or it's going to go to some database with geographical data.

If you do the calculate, maybe it's using JavaScript functions or a Python function, or maybe it's going to an external API like WolframAlpha. All of this needs to be implemented, but how you define the tools matters a lot as well.

So before I'm going to show you implementation, let me tell you why defining the tools matters a lot. If you look at a typical tool definition, you have your tool name. I always advise to keep this simple. You have your tool description, and this, to me, almost feels like a system prompt for the large language model.

Tool Definition5:58

Roy Derks6:14

So your tool description typically doesn't just say, "Calculate something based on two incoming variables." If you look at some of the bigger tools, almost like agentic tools, you can see that the tool descriptions are fairly long. They're almost like system prompts.

Sometimes you see people duplicating system prompts, duplicating tool descriptions in system prompts. So there's a lot of things you can do there, but the tool description really is important. Then you have the input parameters, of course, because the model needs to know what is needed in order to call this tool.

And then something I really like, and I see this more and more in agentic frameworks, is the output schema has become an input variable as well. This will make you help— this will help you to make tools type-safe.

As I mentioned, I'm a big GraphQL guy, or at least I was before I started to work a lot with agents. If you don't have an output schema, how is the model going to know what data is being returned?

It's always a string, though, but if you're building a sequence of tool callings, if you're building more complex agents, you probably want an output schema so you can force structured outputs or you can chain tool calls. So the output schema, my feeling, is getting more and more important later on.

And then the tool call will look something like this. I believe this is LangChain. It could be CrewAI as well. So you would have your tool definition. Whenever the tool is being called, it needs the name, and then it needs the arguments.

Say you want to get the count of customers, you probably need to have a filter, like a country. Then the customer count will return a string, which includes customer. It might also be a string which is just JSON that you decode.

And this also works for other languages, like SQL. So I'm going to show you a bit about dynamic tools later on. So we've did some tests with GraphQL and SQL, and using those to create dynamic tools. So instead of getting the count of a customer, you could also give it access to a database, give it access to an API, and then have the model create the query, like query or GraphQL.

So let's also look at where the tool is being called from, because this is getting more important as well. As I mentioned, people are building their tools at the same place where they're building their agents, usually. So if you look at where the tool is being called from, you would have your agent loop, which has the model, which has the tools, which has perhaps some memory.

Traditional Calling8:34

Roy Derks8:34

Where do you implement the logic to define which tool is being called when?

I think it was on a blog from Cloudflare where I saw them introducing their Workers API, and they mentioned, "We have traditional tool calling, and then we have another form of tool calling." I kind of liked that they put "traditional" in there because, I don't know, we've been doing this for like 2 years, maybe 3.

So it already feels like weird to call something traditional while time is moving so fast. So traditional tool calling is— and don't mind the chaos on this screen— you would have your client application, you would have your application which has the agent, where you have your— you define your tools, where you're doing your server-side logic.

So assume you have my question, like, "How far does the moon orbit?" Express as the number of trips between Amsterdam and San Francisco. If you would type this from your client app, which might be a chat interface, it goes to your agent or AI application.

It's going to put this in a prompt, it's going to send it over to the model together with some prompts. The model is going to tell the tool call. So somewhere between your client app and your server app, you're going to define tool calls.

So you're going to look at the incoming recommendation from the large language model. You're going to call those tools based on the tools you have defined in your server app or your agent. In here, you would have some callback function to call them, and then you give back the tool response to the model.

And at some point, the model is going to do this a couple of times because of the number of calls. Finally, you will have your answer, which you can display in your client app. So there's a lot of back and forth between the application where you implement the logic and the large language model, and then between your client app and the agent.

There's a lot of logic in there as well, because it's not a closed system. It's the agent, and then within the agent, you need to define tool calling logic. So this is what is called being traditional tool calling.

If you implement this in something like LangChain, it would look like this. You would define your tools, then you set the callback function for a tool. You can see we have our models here from IBM's Watson X system.

And then you set— you look at the answer. So you look at the return from the large language model, and there you're going to filter the tool call messages. So you need to explicitly look for a message that has theright role, and you need to make sure that whatever is in there is being parsed and it's being executed based on the callback function that you have.

And then you need to handle all sorts of things, like executing the tool calls, handling retries, handling errors, all these kind of things that you need when you're building any system. So this is how it all started. This is what agentic looked like 2 years ago, maybe 3.

If you look at what it looks like today for most frameworks, it's something people like to call embedded tool calling. So this is where the system is a closed system. You pass your tools, almost like a black box, and what comes out is the answer.

Embedded Calling11:19

Roy Derks11:34

If you look at this example again, you would have your agent. This time your client app will only ask a question like, "How far does the moon orbit?" It's going to go to your agent. Your agent is a closed system.

It has the tools, it's connecting with the large language model, it's connecting with the tools, it's doing the tool calls. Finally, you get the answer back, like, "The moon's orbit is about 44 round trips between Amsterdam and San Francisco."

So this is what's being called embedded tool calling, because it all is executing on theright side of this screen. The client app, or the application logic you write, doesn't include any of the tool calling logic. It's all being handled by the agent framework or wherever you have your agent running.

And the tools in there, they're all defined in the same agent as well, and this is all doing the logic. So it really is a black box. You're sending your question with a prompt in the tool, and what comes out is the answer.

There's no control over whatever is going on inside of it. If you look at LangChain again— so stick to the LangChain examples for now— you import all the different LangChain interfaces, you import your model, you connect to the model, you define your tools, you set a prompt, and then you pass it into this create React agent function.

This will take your tools, the model and the prompt, and then the agent executor is going to make sure it's executed. If you compare this to the previous screen, it's the same functionality, but this time it's all hidden within that create agent function.

So this is what people like to call embedded tool calling, because it really is a black box where tools come in and the answer comes out.

So I'd say this is easy to implement. If you're getting started building agents, you don't need to worry about errors, retries, any of that stuff. But you don't have any control over the tool calling process. You don't really know how the tools are being executed, you don't know how any of the decisions are being made, you don't really control any of the formatting other than that callback function you provide together with your tool definition, which of course has the description with a sort of system prompt for the agent to understand how to use the tool.

So as a longtime developer, I'm always looking for separation of concerns. I'm not saying you should build microservices or micro frontends, but I do want to keep some systems a little bit more separate. I started developing at one point in PHP, and then I developed tools like— well, tools, it's really a framework, like Laravel, and everything was sort of connected there.

Separation13:43

Roy Derks14:04

You had your sort of backend code, you had your frontend code, the frontend code had ways to render View. I believe it was View, or maybe it was even jQuery in the beginning. It was all a closed system, which I didn't really like.

So at some point, I started to attach my backends for my frontends. I used Laravel to build the APIs, and then I connected it to a frontend, like Angular or React, or maybe it was jQuery, I don't really remember.

So there's a lot of things you can do to separate concerns without making things too big. You don't need microservices or micro frontends per se. Some separation between different parts of your system is something I always like to prefer.

And you can keep it all in the same repository, instead of putting it in different big repositories. So MCP is one good step in this direction. So if you didn't hear about MCP yet, it's a protocol introduced by Anthropic and now being adopted by many more people in the industry as a way to separate the client side and the server side of building agentic applications.

MCP14:43

Roy Derks15:09

So MCP stands for Model Context Protocol, and this is where you have your host, which also has a client in there. So the host could be Cloud Desktop. It has a client in there that's able to connect to MCP servers.

And the servers— think of a server as a backend that has access to tools or assets, like data files. So the server is the only thing the host and the client see. It doesn't really see the tools per se, because the tools are made available through the server.

So think of the server as a small backend that is able to give you any results from tools. So I really like this separation of concern, because now there's a clear distinction between the front side of the house and the back side.

And the MCP server is where you handle the logic, you define your tools, you import your tools, and then the MCP host and client, they understand how to call these servers. So I wrote a small blog post on how you can get started building these MCP servers using TypeScript, so feel free to check that out.

The link is probably a bit long, so if you go to my website, you can find the blog section there. MCP is really exciting. I guess it's a good step in the direction of making tool calling really separate from the agentic framework.

There's much more you can do. There are also other considerations, and I hinted at this in the beginning. You can, for example, look at a standalone tool platform.

Tool Platforms16:20

Roy Derks16:31

And this is something that's getting more attention in the market. I think there are a couple of Y Combinator startups as well that are jumping into this space. So a standalone tool platform means that instead of having a closed agent loop where you define your tools inside of the agentic framework, you define them separately.

And then inside of your agentic framework, you can import those tools by writing an SDK or by doing an API call. Your tools are on remote servers. But the tool creation and the tool hosting or execution is really being done separately.

The only thing the agent does, it takes in the tool definition, it uses the LLM to decide what tool to call, and then it just passes this on to the tool platform where it's being executed. Tools might be chained there, tools might be abstracted away.

There's a lot of things you can do in such a platform. As I mentioned, as a developer, I really like to separate concerns. So tool platforms allow you to easily create tools out of APIs or databases. So typically, these platforms are made of two things.

You can call them a framework as well. I don't really mind. They consist of two things: they have a place to create the tool, and then they have a place to execute the tool. And the tool creation is usually done via code or via CLIs, and then the tool execution or the tool servicing is being done via SDKs that you connect to LangChain or CrewAI or whatever agentic framework you might be using.

In there, you can also do things like chaining tools, because sometimes you can see repetitive patterns in agents. If you want to get the number of customers in a certain country, maybe you need to do a tool call first to retrieve the country of the person asking the question, based on their IP or whatever.

And then you want to chain that to another tool call to get the actual customers out of your database or CRM system. So this chaining of tool calls is something you can do in these platforms or frameworks. And this is also where you can handle authorization and errors and these kind of things.

If you think about tool calling and authorization and authentication, you can easily imagine that you have different systems you're connecting. Let's say it's a CRM, or let's say it's a database. They require different sort of credentials. Where you set those credentials and how you pass them to these underlying systems, it could get messy quite fast.

And the question is, do you want to put all of this in your agentic framework, or do you want to separate it into your different systems? This separation also allows you to be flexible. So imagine you have a tool platform where you build your tools.

So building the tools usually is the thing that takes me the longest, for all the reasons I mentioned. If you want to take these tools and bring them into LangChain or LangGraph, if it's as easy to bring those into CrewAI or bring them into AutoGen, then it really becomes easier for you to switch those different frameworks.

Build your tools once and bring them into different agentic frameworks so you get all of this flexibility. As I mentioned, there are a couple of tool platforms in the market. I'm a bit biased here because at IBM I'm actually building one.

But there are other great ones as well, like Composio, Toolhouse, ArcadAI, which is run by a couple of people I met, and then Wildcard, which recently got into Y Combinator. If you look on theright, you can see what the servicing part of a tool platform might look like.

So I'm bringing in my model, in this case Watson X models from IBM. I'm then creating a LangGraph React agent. I'm bringing in my tool platform, which is called wxflows. You can see there is a specific SDK integration for LangChain.

I'm connecting to the tool platform. So I build my tools in one place, and then I'm connecting to these tools from my agent framework. So I need an endpoint, an API key, but you can also run this locally and then just pull in the functions or interfaces that way.

You retrieve the tools, so you need to get the tools from one place. And whatever you pass to that agent, that black box, is still the tools, it's the model. But this time the tool execution is being done on that remote end.

So instead of passing in callback functions, you pass in a way for the model, or in this case the agent, to actually call these tools. So now you have separation of concerns. You have your tools in one place and the agent in the other.

You're still doing embedded tool calling, where the agent is making sure the tools are being called and are working as expected, it's calling subsequent tools. But the entire execution is now being put on the tool platform or framework.

Dynamic Tools20:44

Roy Derks20:57

So I really like this because now I've pulled the two pieces apart, and I can easily substitute LangGraph with something else. Or I can use different interfaces. Let's say LangGraph is going to create different ways to create those black box agents, just React, maybe also other patterns.

Or I can use their graph-based approach. It all works in the same way. I still have tools in one place and agents in another place.

And then I hinted at this in the beginning: what about dynamic tools? So I did some tests with running GraphQL or SQL with some of our clients, and one thing we really saw is you can spend a lot of time creating all your tools, but you also don't want to create a million tools.

Let's say you have a CRM. You don't want a different tool for each of the different components of the system. You can get your customers. You don't want to have customers based per country. You want to have customers based on, I don't know, whatever search filters you might have.

Next to customers, you also have orders, maybe in the CRM. You have contracts. You have employee details. Whatever you can have in a CRM or in a database. So let's say you have a database with product data or order data or payment data.

You don't want to create all these different tools. If you run some tests, if you put in like 10 tools, it's probably fine. If you're going to paste in 100 tools to the agent, it's going to get really confused.

So you're going to need routers and all these things on top of your tool definitions. But these tool platforms might be able to handle it. Maybe some agentic frameworks are able to handle it. But another option is looking at dynamic tools.

And I'm a big GraphQL guy, or I used to be mostly. Let's say you can also create a dynamic tool. This is where you create a tool that's able to connect to GraphQL schema. And then instead of passing in arguments that are sort of fixed, like filter, like get me the customers from Europe, and your filter would be Europe, instead of doing this, you pass in a GraphQL query.

Or you didn't really pass it in yourself. You have the large language model create this for you. So what you give to the model is you give the model a tool, and you say, "This is GraphQL. You need to generate valid GraphQL to do so."

Then you pass in the schema. So the GraphQL schema is usually kind of small, and it's easy to read for humans, and thereby easy to understand for large language models, which has your type definition, so it knows what's coming out.

And then it also has a list of all the available operations: get customers, or get orders, or get customers by whatever. We found out by testing this with models like Llama or OpenAI, OpenAI's models, but also Claude is really good at this.

It's really good at generating GraphQL, as long as you pass in the GraphQL schema and you don't do too complex things. So if you want to have your custom scholars in GraphQL, you want to get rid of those because it gets confused.

You don't want to nest data too deeply. So maybe nesting at one level deep is fine. Nesting like five levels deep is going to be really confusing. And this is kind of cool because most models actually understand how to use GraphQL.

They understand things like fragments. And I can probably spend like an hour talking about just building these kind of dynamic tools on GraphQL or SQL or the query languages. But it's a really easy way to bring in existing APIs and databases to your agent frameworks.

You have less implementation in the downstream implementation. So where you connect your tools, where you bring your tools to the framework, you don't need to define 20 different tools and duplicate your business logic. Instead, you can take the existing business logic and put it directly in here.

So this allows for more flexibility, but it also comes at a cost, because there are trade-offs. LLMs might hallucinate. Sometimes it could do GraphQL really good well, and then the other time it does really poorly and messes up all the different syntaxes.

So there are some trade-offs here, but I see a real future for building dynamic tools rather than the static tools that we see today.

So in short, as we're all building agents, let's make sure we don't forget the tools are as important as the agents we're building. So thank you for listening to my talk. If you're at the conference, I hope to see you.

Outro24:57

Roy Derks25:08

If you aren't and you're watching this live, make sure to follow me on social media and connect there. So thanks again, and I hope to see you later at some point.