Function & Tool Calling
The mechanism that turns a text generator into something that can actually take actions.
Intermediate
tools = [{"name": "get_weather", "parameters": {...}}]
response = call_model(messages, tools=tools)
if response.wants_tool_call:
result = run_actual_function(response.tool_call) # your code, not the model's
messages.append(response.tool_call)
messages.append({"role": "tool", "content": result})
response = call_model(messages, tools=tools) # call again with the result
# repeat until the model returns a normal text answer instead of another tool call
| Practice | Why |
|---|---|
| Write the tool description like documentation for a new engineer, not a code comment | The model has no other context about when to use the tool |
Keep parameter names unambiguous (city_name, not q) | Reduces malformed or wrong-field calls |
| Mark truly required fields as required in the schema | Constrained decoding will enforce it, avoiding a class of missing-argument errors |
| Keep the total number of exposed tools reasonable | Tool selection accuracy degrades as the list grows into the dozens |
The Model Context Protocol standardizes how tools/data sources are described and exposed to a model-calling client, so a tool server can be written once and used by any MCP-compatible client instead of every application hand-rolling its own tool-schema glue code. It's the same underlying function-calling loop above, with a standard wire protocol around discovery and invocation. Full coverage: MCP.