What Are Tools? A Precise Walkthrough of LLM Tool Calling
This article walks through LLM tool calling using a simple write-file example. Tools are not magic: each tool is defined by a name, a description, and JSON Schema parameters, then injected into the system prompt. When the model decides to act, it returns only a tool-call message with an id and parameters; nothing actually happens until the developer intercepts that message, executes a matching function, and sends the result back under the same id. Errors are sent back too, so the LLM can adapt its next step. The post is aimed at engineers starting to build agents who want a precise mental model of the loop.
Giving the LLM tools is done via the system prompt. The system prompt is just another message in the message history which describes to the LLM what it's supposed to be doing, and in this case, what tools it can call.
给 LLM 提供工具,是通过系统提示词完成的。系统提示词不过是消息历史中的一条消息,用来向 LLM 说明它的任务,以及在这个场景下可以调用哪些工具。
For each tool, we're providing three things:
The name of the tool (e.g., writeFile)
A description of the tool (e.g., "Write a file to the file system")
The parameters it takes and their types (e.g., path and content)
These parameters are specified in JSON schema, so we can pass anything that JSON schema supports, like objects, arrays, and other complex types.
These tool definitions get injected into the system prompt, and any other information you've provided to the system prompt goes below it. There's nothing particularly fancy going on - it's just tool definitions inside the system prompt.
对每个工具,我们要提供三样东西:
工具名称(例如 writeFile)
工具描述(例如“把文件写入文件系统”)
工具接收的参数及其类型(例如 path 和 content)
这些参数用 JSON schema 来定义,因此 JSON schema 支持的任意内容都能传,比如对象、数组和其他复杂类型。
这些工具定义会被注入系统提示词,而你在系统提示词里提供的任何其他信息都放在它们下方。没什么特别玄妙的——只是把工具定义放进系统提示词而已。
The magic happens when we ask the LLM to choose a tool. We've got our system prompt saying "You have access to the following tools." Then we add a user message, which says, "Write a new file called .gitignore."
真正奇妙之处发生在请 LLM 选择工具的时候。我们的系统提示词里写着“你可以使用以下工具。”然后我们追加一条用户消息:“写一个名为 .gitignore 的新文件。”
We then receive back an assistant message with a tool call inside. This is just an instruction from the LLM indicating which tool to call. It has an id on it and also contains the required parameters.
In this example, it's writing an empty file to the path ".gitignore".
This tool call is just an instruction for which tool should be called. Nothing has happened yet - the assistant has just produced a message. That's it.
接着我们会收到一条助理(assistant)消息,里面含有一个工具调用。这不过是 LLM 给出的一条指令,指明该调用哪个工具。它带有一个 id,也包含所需的参数。
在这个例子中,它是在 “.gitignore” 这个路径上写一个空文件。
这条工具调用只是说明应该调用哪个工具的指令。目前什么都还没发生——助理只是生成了一条消息,仅此而已。
The tool then needs to be executed on our machine. The LLM has created this message, but we then need to actually execute the creation of the file on our machine.
This means that for every single tool in the system prompt, we're going to have functions in our code base that match up to those.
接着,工具需要在我们自己的机器上执行。LLM 只是创建了这条消息,但我们实际上要在机器上执行创建文件的操作。
这意味着,系统提示词中的每一个工具,都要在我们代码库里有一个与之对应的函数。
If the tool execution is successful, we're then going to send back a user message to the LLM. It's going to have the same id as the previous tool call, and we're going to send it a message saying what happened when we executed the tool.
This error handling is really important. If there are any errors when the tool is executed, we need to show that error message to the LLM so that it can do something differently.
So a tool result could be a success or it could be a failure.
如果工具执行成功,我们会回传一条用户消息给 LLM。这条消息会带着之前工具调用相同的 id,并在消息里说明执行工具时发生了什么。
这个错误处理非常重要。如果工具执行时出现任何错误,我们都要把错误消息展示给 LLM,这样它才能换个方案做事。
所以,工具的结果可能是成功,也可能是失败。
Let's go one more time through the entire flow:
We specify the tool in the system prompt: "You have access to the following tools..." passing it a bunch of JSON schema
We send a user message saying "Write a new file called .gitignore" (note that we don't have to specifically say "call this tool" - the LLM itself decides which tool to call)
The LLM produces a tool call message with all the right parameters
We see this tool call message and execute it on our machine
We send the result back with a message saying what happened
The LLM sees this entire history and responds with a summary
In this case, it said "Done. What should go in there?"
我们再把整个流程完整地走一遍:
在系统提示词中指定工具:“你可以使用以下工具……”并传入一堆 JSON schema
发送一条用户消息:“写一个名为 .gitignore 的新文件”(注意,我们不必明确说“调用这个工具”——由 LLM 自己决定调用哪一个)
LLM 生成一条工具调用消息,参数全都正确
我们看到这条工具调用消息,在自己的机器上执行它
我们发回一条消息,说明执行后发生了什么
LLM 看完这整段历史,给出一个总结
在这个例子里,它说的是:“完成。里面要写什么?”
That's what tools are - they're just ways of getting LLMs to produce certain types of messages which you can then intercept and execute on your machine, and give those results back to the LLM.
With this simple loop, you can build really, really powerful applications.
工具的本质就是这样——它们只是让 LLM 产出特定类型消息的方式;你可以截获这些消息、在自己的机器上执行,再把结果交还给 LLM。
借助这个简单的循环,你就能构建出真正、真正强大的应用。