Tool Dispatcher / Router
The model has read your tool schemas and replied with a tool call: a parsed object like {"name": "add", "arguments": {"a": 4, "b": 5}}. Now your program has to actually run the right function. That is the job of a dispatcher (or router): look up the named tool, check the arguments are exactly what the function expects, invoke it, and return the result. This is the line where an LLM's words become a real side effect in your system, so it is also where you must be strict.
In a real loop it sits right after parsing the model's reply:
call = parse_tool_call(model_reply) # {"name": ..., "arguments": {...}}
result = dispatch(call, TOOL_REGISTRY) # runs the matching Python function
# feed result back to the model as the tool's observationYou are building dispatch(call, registry), where registry maps tool names to Python functions. It must:
- Read
call["name"]andcall["arguments"](default arguments to{}). - Reject an unknown tool. If the name is not in the registry, raise a
ValueError-> never silently do nothing, and never run a tool the model hallucinated. - Validate the arguments. Use
inspect.signatureto get the function's parameter names and confirm the provided argument keys match exactly -> a missing argument or an unexpected extra one must raise. - Invoke and return. Call the function with
func(**arguments)and return its result.
import inspect
expected = set(inspect.signature(func).parameters)
if set(arguments) != expected:
raise ValueError("bad arguments")
return func(**arguments)Why so strict on arguments? A tool call that runs with the wrong arguments either crashes deep inside your function or, worse, does the wrong thing quietly. Failing loudly at the boundary is the whole point. Build it so two different tools (say a calculator and a lookup) each return their own result, an unknown tool raises, and both a missing and an extra argument raise.
Write dispatch(call, registry) where call is {"name": ..., "arguments": {...}} and registry maps names to functions. Raise on an unknown tool name. Use inspect.signature to confirm every required parameter is present and there are no unexpected extras (a parameter with a default is optional, so omitting it is fine), then call func(**arguments) and return the result. Two distinct tools must each return their own result.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.