{"course":{"slug":"how-llms-work","title":"How a Language Model Actually Works","url":"https://addaly.com/learn/how-llms-work","level":"intermediate","track":"start"},"lesson":{"slug":"tools-and-function-calling","title":"Tool use, with the magic removed","url":"https://addaly.com/learn/how-llms-work/tools-and-function-calling","position":36,"of":78,"minutes":8,"answer":"A model does not call a function; it emits text describing a call, and your code decides whether to run it.","keyIdea":"A model does not call a function; it emits text describing a call, and your code decides whether to run it."},"body":{"format":"markdown","text":"## The loop, in full\n\nTool use sounds like the model reaching out into the world. It is not. Here is every step:\n\n1. You include descriptions of the available tools in the prompt: names, parameters, what each does. These are tokens like any other.\n2. The model generates text that, by a convention it was trained on, represents a call: a name and some arguments, usually as JSON.\n3. **Your code** parses that, decides whether to run it, runs it, and gets a result.\n4. You put the result back into the context as a new message.\n5. The model generates again, now with the result available.\n\nThe model emits a string. Everything that happens as a consequence is your program's doing. This is worth being blunt about, because the security implications in the rest of this module rest on it.\n\n## What \"trained on\" means here\n\nThe convention is learned. During fine-tuning, models are shown many examples of tool descriptions followed by well-formed calls, so they reliably produce the right shape. That reliability is behavioural, not structural, which is why constrained decoding, from module three, is worth applying to tool calls: it makes an invalid function name or a missing required parameter impossible rather than merely rare.\n\n## Where tool use actually fails\n\nNot usually in producing the call. In everything around it:\n\n- **Too many tools.** Beyond roughly a dozen, selection accuracy declines and the definitions themselves consume real context. If you have forty tools, group them, or use retrieval to select a relevant subset per request.\n- **Vague descriptions.** The description is the entire basis for choosing. \"Gets user data\" will be called for everything and nothing. Say what it returns, what it costs, and when *not* to use it: that last clause is the one people omit and it is frequently the most useful.\n- **Overlapping tools.** Two tools that could both plausibly answer a question produce inconsistent selection. Make the boundary explicit in both descriptions.\n- **Results that blow the budget.** A tool returning 30,000 tokens of JSON has just consumed the context window. Summarise, paginate or filter tool output before it goes back in.\n- **Errors reported as prose.** If your tool returns \"Error: connection refused\" as a plain string, the model will often apologise and try something unrelated. Return structured errors that say whether a retry is sensible.\n\n## The permission boundary is yours\n\nStep 3 is the one that matters. The model produces a request; your code decides. That decision point is where every safety property of a tool-using system lives:\n\n- **Read and write must be separated.** A search tool and a delete tool are not the same risk, and treating them identically because both are \"tools\" is how systems cause damage.\n- **Anything irreversible needs a human.** Sending a message, spending money, deleting data. The model can propose; a person confirms.\n- **Validate arguments against a schema** and against your own authorisation rules, every time, exactly as you would for input arriving from the internet, because in an important sense it is.\n\nThe reason this matters is the subject of the next lesson: text that arrives from outside can influence what the model emits, and the only reliable boundary is the one your code enforces.\n\n## Parallel calls and what they change\n\nMost current models can emit several tool calls at once: three searches rather than one, issued together. Your code runs them concurrently and returns all the results in one message. This is a genuine latency win, since the alternative is three full round trips through the model.\n\nIt also removes a safety property people did not realise they had. With sequential calls, the model sees each result before choosing the next action, so a failed lookup stops the chain. With parallel calls it has committed to all three before seeing any of them, which means arguments derived from a guess are not corrected mid-flight. Use parallelism for independent reads and keep anything dependent sequential.\n\n## The connection to agents\n\nAn agent is this loop, run repeatedly, with the model deciding when to stop. Nothing new is added. Everything above compounds: more steps mean more context, more chances to select the wrong tool, and more opportunity for one bad result to derail the rest.\n\nWhich suggests the design that works. Fewer tools, described precisely. Structured results, summarised. A step limit. Verification after each action rather than a hopeful check at the end. And an explicit human gate on anything you would not want done twice."},"check":{"question":"A model returns a tool call to `delete_records` with a customer id taken from a support email it was asked to summarise. What is the correct architectural response?","options":[{"text":"Instruct the model in the system prompt never to call destructive tools based on email content.","correct":false,"tempting":"Prompt-level guardrails do reduce the frequency of this behaviour, so it is a reasonable and common first mitigation."},{"text":"Use a more capable model that is less likely to misinterpret an email as an instruction.","correct":false,"tempting":"Stronger models are meaningfully more resistant to this, which makes capability an appealing lever."},{"text":"Enforce the boundary in the code that executes calls: destructive tools require authorisation and human confirmation, regardless of what the model emitted.","correct":true},{"text":"Filter incoming emails for instruction-like phrasing before they reach the model.","correct":false,"tempting":"Input filtering catches obvious cases and is worth having as one layer, though it is defeated by rephrasing."}]},"prev":{"slug":"chunking-decisions","title":"Chunking: the decision that quietly sets your ceiling","url":"https://addaly.com/learn/how-llms-work/chunking-decisions"},"next":{"slug":"the-system-prompt-is-just-tokens","title":"Why there is no boundary between instructions and data","url":"https://addaly.com/learn/how-llms-work/the-system-prompt-is-just-tokens"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Tool use, with the magic removed', in How a Language Model Actually Works. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/how-llms-work/tools-and-function-calling (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Tool use, with the magic removed","courseTitle":"How a Language Model Actually Works","module":{"index":4,"slug":"the-context-window","title":"What the model can see"},"answer":null,"keyIdea":"A model does not call a function; it emits text describing a call, and your code decides whether to run it.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-loop-in-full","runs":[{"text":"The loop, in full"}]},{"t":"p","runs":[{"text":"Tool use sounds like the model reaching out into the world. It is not. Here is every step:"}]},{"t":"ol","start":1,"items":[[{"text":"You include descriptions of the available tools in the prompt: names, parameters, what each does. These are tokens like any other."}],[{"text":"The model generates text that, by a convention it was trained on, represents a call: a name and some arguments, usually as JSON."}],[{"text":"Your code","b":true},{"text":" parses that, decides whether to run it, runs it, and gets a result."}],[{"text":"You put the result back into the context as a new message."}],[{"text":"The model generates again, now with the result available."}]]},{"t":"p","runs":[{"text":"The model emits a string. Everything that happens as a consequence is your program’s doing. This is worth being blunt about, because the security implications in the rest of this module rest on it."}]},{"t":"h2","id":"what-trained-on-means-here","runs":[{"text":"What “trained on” means here"}]},{"t":"p","runs":[{"text":"The convention is learned. During fine-tuning, models are shown many examples of tool descriptions followed by well-formed calls, so they reliably produce the right shape. That reliability is behavioural, not structural, which is why constrained decoding, from module three, is worth applying to tool calls: it makes an invalid function name or a missing required parameter impossible rather than merely rare."}]},{"t":"h2","id":"where-tool-use-actually-fails","runs":[{"text":"Where tool use actually fails"}]},{"t":"p","runs":[{"text":"Not usually in producing the call. In everything around it:"}]},{"t":"ul","items":[[{"text":"Too many tools.","b":true},{"text":" Beyond roughly a dozen, selection accuracy declines and the definitions themselves consume real context. If you have forty tools, group them, or use retrieval to select a relevant subset per request."}],[{"text":"Vague descriptions.","b":true},{"text":" The description is the entire basis for choosing. “Gets user data” will be called for everything and nothing. Say what it returns, what it costs, and when "},{"text":"not","i":true},{"text":" to use it: that last clause is the one people omit and it is frequently the most useful."}],[{"text":"Overlapping tools.","b":true},{"text":" Two tools that could both plausibly answer a question produce inconsistent selection. Make the boundary explicit in both descriptions."}],[{"text":"Results that blow the budget.","b":true},{"text":" A tool returning 30,000 tokens of JSON has just consumed the context window. Summarise, paginate or filter tool output before it goes back in."}],[{"text":"Errors reported as prose.","b":true},{"text":" If your tool returns “Error: connection refused” as a plain string, the model will often apologise and try something unrelated. Return structured errors that say whether a retry is sensible."}]]},{"t":"h2","id":"the-permission-boundary-is-yours","runs":[{"text":"The permission boundary is yours"}]},{"t":"p","runs":[{"text":"Step 3 is the one that matters. The model produces a request; your code decides. That decision point is where every safety property of a tool-using system lives:"}]},{"t":"ul","items":[[{"text":"Read and write must be separated.","b":true},{"text":" A search tool and a delete tool are not the same risk, and treating them identically because both are “tools” is how systems cause damage."}],[{"text":"Anything irreversible needs a human.","b":true},{"text":" Sending a message, spending money, deleting data. The model can propose; a person confirms."}],[{"text":"Validate arguments against a schema","b":true},{"text":" and against your own authorisation rules, every time, exactly as you would for input arriving from the internet, because in an important sense it is."}]]},{"t":"p","runs":[{"text":"The reason this matters is the subject of the next lesson: text that arrives from outside can influence what the model emits, and the only reliable boundary is the one your code enforces."}]},{"t":"h2","id":"parallel-calls-and-what-they-change","runs":[{"text":"Parallel calls and what they change"}]},{"t":"p","runs":[{"text":"Most current models can emit several tool calls at once: three searches rather than one, issued together. Your code runs them concurrently and returns all the results in one message. This is a genuine latency win, since the alternative is three full round trips through the model."}]},{"t":"p","runs":[{"text":"It also removes a safety property people did not realise they had. With sequential calls, the model sees each result before choosing the next action, so a failed lookup stops the chain. With parallel calls it has committed to all three before seeing any of them, which means arguments derived from a guess are not corrected mid-flight. Use parallelism for independent reads and keep anything dependent sequential."}]},{"t":"h2","id":"the-connection-to-agents","runs":[{"text":"The connection to agents"}]},{"t":"p","runs":[{"text":"An agent is this loop, run repeatedly, with the model deciding when to stop. Nothing new is added. Everything above compounds: more steps mean more context, more chances to select the wrong tool, and more opportunity for one bad result to derail the rest."}]},{"t":"p","runs":[{"text":"Which suggests the design that works. Fewer tools, described precisely. Structured results, summarised. A step limit. Verification after each action rather than a hopeful check at the end. And an explicit human gate on anything you would not want done twice."}]}],"check":{"question":[{"text":"A model returns a tool call to "},{"text":"delete_records","code":true},{"text":" with a customer id taken from a support email it was asked to summarise. What is the correct architectural response?"}],"options":[{"text":[{"text":"Instruct the model in the system prompt never to call destructive tools based on email content."}],"correct":false,"tempting":[{"text":"Prompt-level guardrails do reduce the frequency of this behaviour, so it is a reasonable and common first mitigation."}]},{"text":[{"text":"Use a more capable model that is less likely to misinterpret an email as an instruction."}],"correct":false,"tempting":[{"text":"Stronger models are meaningfully more resistant to this, which makes capability an appealing lever."}]},{"text":[{"text":"Enforce the boundary in the code that executes calls: destructive tools require authorisation and human confirmation, regardless of what the model emitted."}],"correct":true,"tempting":null},{"text":[{"text":"Filter incoming emails for instruction-like phrasing before they reach the model."}],"correct":false,"tempting":[{"text":"Input filtering catches obvious cases and is worth having as one layer, though it is defeated by rephrasing."}]}],"order":[1,3,0,2],"why":null},"prev":{"slug":"chunking-decisions","title":"Chunking: the decision that quietly sets your ceiling","minutes":8},"next":{"slug":"the-system-prompt-is-just-tokens","title":"Why there is no boundary between instructions and data","minutes":9}}}