HOW-TO · RAG

How to Use OpenAI Function Calling with Tools

intermediate20 minBy Fredoline Eruo
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES

OpenAI API key or local model with tool support, Python 3.10+

What this does

Function calling lets the LLM request execution of external tools by outputting structured JSON. The application executes the tool and feeds the result back to the model for a final answer.

Steps

  • Define tool schemas. Each tool requires a JSON Schema description of its parameters.
import json
from openai import OpenAI

client = OpenAI(api_key="sk-...", base_url="http://localhost:11434/v1")  # Ollama also works

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get current weather for a city",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The city name"
                    }
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a math expression",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Math expression like '2+2'"
                    }
                },
                "required": ["expression"]
            }
        }
    }
]
  • Send a request with tools. The model may return a tool_calls response.
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What's 15*7 and the weather in Paris?"}],
    tools=tools,
    tool_choice="auto"
)

message = response.choices[0].message
print(message.tool_calls)
  • Execute tool calls and return results. Map function names to local implementations.
def get_weather(city: str) -> str:
    return f"Weather in {city}: 22°C, sunny"

def calculate(expression: str) -> str:
    return str(eval(expression))

if message.tool_calls:
    messages = [{"role": "user", "content": "What's 15*7 and the weather in Paris?"}]
    messages.append(message)

    for tc in message.tool_calls:
        func = globals()[tc.function.name]
        args = json.loads(tc.function.arguments)
        result = func(**args)
        messages.append({
            "role": "tool",
            "tool_call_id": tc.id,
            "content": result
        })

    # Send back to model for final answer
    final = client.chat.completions.create(model="gpt-4o-mini", messages=messages)
    print(final.choices[0].message.content)
  • Force a specific tool with tool_choice. Use {"type": "function", "function": {"name": "calculate"}} to force.

Verification

python -c "
from openai import OpenAI
c = OpenAI(api_key='sk-test', base_url='http://localhost:11434/v1')
r = c.chat.completions.create(model='llama3.2', messages=[{'role':'user','content':'say hi'}], tools=[{'type':'function','function':{'name':'test','parameters':{'type':'object','properties':{'x':{'type':'string'}},'required':['x']}}}])
print(r.choices[0].finish_reason)
# Expected: stop or tool_calls
"

Common failures

  • Tool choice ignored by local models. Some models don't respect tool_choice: "required". Fall back to parsing function calls from text.
  • JSON schema too complex. Deeply nested $ref or allOf schemas cause parsing failures. Use flat properties with type and description.
  • Missing tool_call_id. The tool response must include the exact id from the model's request. A mismatch causes the model to ignore the response.
  • Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
  • Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.

Related guides

  • How to Define JSON Schema for Tool Calling
  • How to Handle Function Call Errors and Retries