Skip to content
Sponsor

Tool-calling agent

In Boltjar a tool is a small branch of nodes. The model sees a name and a description; when it calls the tool, the branch runs with the model’s arguments, and whatever reaches the end of the branch goes back to the model. This graph gives a local model two tools, the time on your computer and the weather in a city, and the model decides which one a question needs: asked “Do I need an umbrella in Paris this afternoon?”, it calls the weather tool for Paris and answers from what it returns.

Download the graph and save it in user/graphs/, or build it below. The graph is MIT-0: copy it and license what you build from it however you like.

The same chat as in Chat with Ollama: a Chat Input named Message (placeholder Do I need an umbrella in Paris this afternoon?), a Prompt, an LLM and a Chat node, wired the same way. The downloaded graph has no model picked: pick one that takes tools on the LLM, such as Gemma 4 12b (Ollama). Its tool sockets, and the wires from the two Tool nodes into them, show once that model is picked. Use this Prompt:

You are a helpful assistant. Call your tools for anything they know, such as the time or the weather, and answer only from what they return.
User: {message}

Both halves of that sentence matter with a small local model. Asked only to use its tools “when they help”, Gemma 4 12b sometimes answered the umbrella question without calling any tool, and “answer only from what they return” keeps it from adding a forecast the tool never gave.

Node Settings
Tool, named get_time name get_time, description Returns the current date and time on this computer.
Tool Args, named get_time args fields empty
Time, named Now format Monday 08 Jun, 02:30 PM
Template, named Time answer It is {now}.
From To
get_time call LLM + tool (it becomes tool0)
get_time trigger get_time args trigger
get_time call get_time args call
get_time args trigger Time answer trigger
Now out Time answer now
Time answer trigger get_time result_trigger
Time answer out get_time result

Right-clicking a Tool offers to add its Tool Args already wired, by trigger and call. When the model calls the tool, the Tool’s trigger fires the Tool Args, which fires the Template; the Template assembles its text, and its trigger into result_trigger tells the Tool the answer on result is ready. A data wire never fires a node, so the answer needs that trigger beside it. The {now} tag is named after the Now node, the way a dropped wire names a tag.

The get_time tool branch: get_time's trigger and call go into get_time args, which fires Time answer, Now feeds Time answer, and Time answer's trigger and out go back into get_time's result_trigger and result
  1. call: when the model calls get_time, the arguments leave here, and trigger above it fires the body. call also goes into the LLM’s tool socket, which shows once a model that takes tools is picked.
  2. get_time args starts the body and fires Time answer.
  3. The answer goes back into get_time’s result, with Time answer’s trigger into result_trigger. These wires close the loop, so they cross the wires that go out.
Node Settings
Tool, named get_weather name get_weather, description Returns the current weather for a city, in one line.
Tool Args, named City fields city
HTTP Request, named Weather API method GET, url https://wttr.in/{city}?format=%l:+%C,+%t,+precipitation+%p, response text
From To
get_weather call LLM + tool (it becomes tool1)
get_weather trigger City trigger
get_weather call City call
City trigger Weather API trigger
City city Weather API + tag (it becomes city)
Weather API trigger get_weather result_trigger
Weather API body get_weather result

Typing city in the Tool Args fields does two things: the node grows a city output, and the tool tells the model it takes a city argument. The Tool’s schema mode stays auto for that. A wire dropped on the HTTP Request’s + tag makes a tag named after the node it comes from, which is why this Tool Args is named City: its wire becomes the {city} in the url.

The get_weather tool branch: get_weather's trigger and call go into City, City fires Weather API and passes its city output into the Weather API's city socket, and the Weather API's trigger and body go back into get_weather's result_trigger and result
  1. The fields of City: city.
  2. The city output they grew, wired into the Weather API’s city socket.
  3. The URL uses it as {city}. The format asks wttr.in for one line: the place, the sky, the temperature and the rain, such as Paris: Overcast, +15°C, precipitation 0.0mm.
  4. The weather goes back into get_weather’s result, and the Weather API’s trigger into result_trigger says it is ready.

Press On and ask “Do I need an umbrella in Paris this afternoon?”. The model decides whether to call a tool; each call runs its branch, and the Tool node shows the arguments and the result. A reply can take up to six rounds of tool calls before the model has to answer.

The LLM, with Gemma 4 12b picked, and the Chat node showing the question Do I need an umbrella in Paris this afternoon? and the answer the model gave after calling its tools
  1. The answer, written from what get_weather returned for Paris: what wttr.in said when this figure was made.
  • The model only sees the Tool’s name and description, and the parameters. Write the description for the model: say what the tool returns and when to use it.
  • Tool calls work with Ollama, xAI, Anthropic, OpenAI and OpenAI-compatible models that take tools, as their manifest or their provider says. The LLM page lists the ones that ship with a manifest.
  • Two tools cannot share a name, and a tool needs one: the graph will not turn On otherwise.
  • If a branch never sends a result, the model gets an error for that call after two minutes.
  • A tool branch is a graph like any other: DB lookups, Read File, HTTP Request with a {{secret.NAME}} key. Keep in mind that the model chooses the arguments, so treat them as untrusted input (Security).