The Agent Loop & Tool Calling: overview
- Source
- From the RAG & Agents Engineering course
- By
- Sourav Banerjee
- Last updated
- 9 Nov 2026
A language model on its own can only write text. It cannot check whether a server is running or look up a policy. Tool calling closes that gap: you describe a few functions to the model, the model replies with a request to call one of them, your code runs the function, and the result goes back to the model as part of the conversation. An agent is a loop around that exchange, repeated until the model has what it needs to answer. This module covers how the loop works, how a tool is described to the model, what happens when a tool fails, how to score whether the model used its tools well, and when to let the provider run a tool for you.
The running example is a support agent for Larkspur Cloud, the fictional host from T5.1 to T5.3. It has two tools that run in your own code (client-side tools). search_handbook ranks the twelve handbook chunks from the T5.1 lab with TF-IDF and returns the best two. get_server_status looks up one of the customer's servers. The agent is tested on a small fixed set of questions with known right answers (a golden set). One comes from T5.1 (Can I export my data after I cancel my plan?). One needs both tools (Is my server web-1 running, and does a reboot change its IP address?): the model has to request two calls, your code has to run them, and both results have to come back before it can answer. Two fail on purpose: one asks about a server that does not exist, and in the other the model names a tool argument wrongly.
In short
- The loop has one rule. While the model's reply contains tool calls, run them, add the results to the conversation and call the model again. A reply with no tool calls is the answer. Because a confused model can keep calling tools indefinitely, the loop also needs a cap on the number of rounds and a fallback reply for when the cap is reached. Reaching the cap means the run stopped, not that the task was done.
- The model never sees your function's code. It sees only the tool's schema: a name, a description and a list of typed parameters. If a parameter has no declared type or description, the schema says nothing about it and the model has to guess what to send.
- Each tool call gets exactly one result message, linked to the call by an id, so the model knows which result answers which request. In the lab, the two-tool question ends with 5 messages in the conversation: the question, the model's reply requesting both calls, two results and the answer. A call that fails once and is retried ends with 6.
- A tool failure has to reach the model as a message it can read and react to. If the failure escapes as an exception instead, the whole run crashes. LangGraph's
ToolNodesettinghandle_tool_errorsdecides which failures become messages. Its default turns invalid arguments into messages but lets exceptions raised inside the tool through. In the lab,Trueanswers 4 of the 4 questions, the default answers 3 andFalseanswers 2. - Evaluate three things separately: did the model pick the right tool, did it send valid arguments, and did it write a correct answer from the results. For execution, run a tool in your own code when it touches customer data or anything you must check before it happens. A hosted tool, which the provider runs on its own servers, suits general-purpose work where you have nothing to enforce between the request and the result.
Mental model
- The customer asks how long a refund takes. State holds one HumanMessage.
- The model replies with a call to
search_handbook, but names the argumentqinstead ofquery. - The ToolNode validates the arguments and returns a ToolMessage with status error:
query: Field required. - The model reads the error and calls
search_handbookagain, this time withquery. - The tool returns
refund-timingat score 0.347, and the ToolMessage goes back to the model. - The reply has no tool calls, so the loop ends: six messages, two of them tool results.
The model never runs anything itself. It writes a structured request, and your code decides whether to run it, runs it, and writes the result into the conversation as a tool result message (a ToolMessage in LangChain). That division is where control sits. Your code can validate the arguments, refuse a call, redact the result or log it, and the model only learns what you send back. Every later agent in this course, from create_agent to a multi-agent graph, is this loop with more machinery around it.
Interactive lab
Where a tool error goes: open the file in a browser. It replays the support agent on the four golden questions under each handle_tool_errors setting. Pick Is my server web-9 up? first. The server lookup raises a ValueError because web-9 does not exist, and only True turns that exception into a message the model can answer from. Then pick How long does a refund take?, where the model names the search argument q instead of query. That is an invalid-argument error, which the default setting does catch: the model reads the error, retries with the right name and answers after one extra round trip, while False crashes. The table under the trace counts how many of the four questions each setting answers.
How it connects
- Before: T5.1 built the handbook index that
search_handbookwraps. T4.3 and T4.4 taught the LangGraph state, reducers and conditional edges that the 22.4 and 22.5 graphs use. T6.4 built the end-to-end retriever that this module's lab asks you to wrap as a tool. - Next: T7.2 packages this loop as a ReAct agent with LangChain's
create_agent. T7.3 to T8.3 add workflow patterns, planning and human approval around it. T9.1 to T9.4 put the retriever inside the loop (agentic RAG), and T12.1 to T12.3 reach tools over MCP, a protocol through which the model calls tools on a server you run.
Key Takeaways
- Write the loop's exit conditions first: a reply with no tool calls is the answer, and reaching the round cap means stop with a fallback, not success.
- Treat the tool schema as the interface. Give every argument a type and a description, because the model reads nothing else about your function.
- Every tool failure must come back as a tool result the model can read. Set
handle_tool_errorsdeliberately and test it with a tool that raises. - Run tools that touch customer data in your own code, where you can log, refuse and stub them. Hosted tools fit general-purpose capabilities where you have nothing to enforce.