Dispatching tool calls (a tool registry)
Once you've detected a tool call, you have to dispatch it: look up the right Python function by name, call it with the model's arguments, and feed the result back. The clean way to do this is a function registry — a plain dict mapping tool names to the functions that implement them.
Two small pieces of Python carry the whole pattern:
- A dict of name → function. Functions are values in Python, so
{"get_weather": get_weather}stores the function itself;registry["get_weather"]gets it back to call. kwargs unpacking. The model gives you arguments as a dict,{"city": "London"}. Callingfn(args) spreads that dict into keyword arguments — exactlyfn(city="London"). The dict keys must match the function's parameter names.
This closes the tool-use loop: the model asks for a tool → you look it up and dispatch → you hand the result back to the model as another message → it carries on. Always guard the lookup: if the requested name isn't in the registry, raise a clear error instead of letting a KeyError escape — the model can hallucinate a tool that doesn't exist.
Syntax
# Registry = dict of tool name -> function. Dispatch with **kwargs.
registry = {"get_weather": get_weather, "add_numbers": add_numbers}
def dispatch(tool_name, tool_input, registry):
if tool_name not in registry:
raise ValueError(f"Unknown tool: {tool_name}")
fn = registry[tool_name]
return fn(**tool_input) # {"city": "London"} -> fn(city="London")Worked examples
Build a registry (functions are values)
def get_weather(city):
temps = {"London": 18, "Paris": 22}
return {"city": city, "temp_c": temps.get(city, 15)}
def add_numbers(a, b):
return {"result": a + b}
TOOLS = {"get_weather": get_weather, "add_numbers": add_numbers}
print(TOOLS["add_numbers"](2, 3)) # look up by name, then call
# Output:
# {'result': 5}Dispatch: look up + call with **kwargs, guard unknowns
def dispatch(tool_name, tool_input, registry):
if tool_name not in registry:
raise ValueError(f"Unknown tool: {tool_name}")
fn = registry[tool_name]
return fn(**tool_input)
print(dispatch("get_weather", {"city": "Paris"}, TOOLS))
print(dispatch("add_numbers", {"a": 5, "b": 7}, TOOLS))
try:
dispatch("fly", {}, TOOLS)
except ValueError as e:
print("raised:", e)
# Output:
# {'city': 'Paris', 'temp_c': 22}
# {'result': 12}
# raised: Unknown tool: flyThe tool-use loop: detect → dispatch → result message
def extract_tool_call(response):
tool = response["content"][0]
return (tool["name"], tool["input"])
def handle(response, registry):
name, args = extract_tool_call(response)
result = dispatch(name, args, registry)
# hand the result back to the model as a new message:
return {"role": "tool", "name": name, "content": result}
resp = {"content": [{"type": "tool_use", "name": "get_weather",
"input": {"city": "London"}}]}
print(handle(resp, TOOLS))
# Output:
# {'role': 'tool', 'name': 'get_weather', 'content': {'city': 'London', 'temp_c': 18}}Common mistakes & gotchas
Calling the function instead of storing it
In the registry write {"get_weather": get_weather} — the function *object*, no parentheses. {"get_weather": get_weather()} calls it immediately (and probably errors on missing args), storing the *return value* instead of the function. The parentheses come later, at dispatch time.
Argument keys must match parameter names
fn(**{"city": "London"}) works only because get_weather has a parameter named city. A mismatched key — {"town": "London"} — raises TypeError: unexpected keyword argument. The model's "input" keys and your function signatures have to line up.
Not guarding unknown tool names
Models hallucinate tools that were never registered. Without the if tool_name not in registry check you get a bare KeyError deep in dispatch. A clear ValueError(f"Unknown tool: {tool_name}") is both safer and far easier to debug.
Why it matters
The registry-and-dispatch pattern is the heart of every agent framework — strip the branding away and they're all a dict of tools plus `fn(**args)`. Understanding it in plain Python means you can build, debug and reason about agents without depending on any one library's magic.