← chapter

Function calling

Chapter 6 · the model chooses, your code executes

The hour

The problem

Ask a model for 26.2 miles in kilometers.

It answers with confidence — and often the wrong number. Weights approximate arithmetic; they don't do it.

The division of labor

The model never runs anything.

  1. You declare convert with a JSON Schema
  2. The model replies with a function call, not text
  3. Your Python executes it
  4. The result goes back; the model writes the answer

The declaration is a prompt

TOOLS = [{
    "type": "function",
    "name": "convert",
    "description": "Convert a length between units exactly.",
    "parameters": {...},   # JSON Schema, enums included
}]

The model reads the description to decide when to call.

OpenAI: the round trip

response = client.responses.create(
    model="gpt-5.4-nano", input=QUESTION, tools=TOOLS)
call = next(i for i in response.output
            if i.type == "function_call")
result = convert(**json.loads(call.arguments))
final = client.responses.create(
    model="gpt-5.4-nano",
    previous_response_id=response.id,
    input=[{"type": "function_call_output",
            "call_id": call.call_id,
            "output": json.dumps({"result": result})}],
    tools=TOOLS)

Gemini: same trip, different spelling

response = client.models.generate_content(
    model="gemini-3.1-flash-lite",
    contents=QUESTION, config=CONFIG)
fc = response.function_calls[0]     # args already a dict
result = convert(**fc.args)
# replay: question + model's call turn + function_response

No previous_response_id — you reassemble the conversation.

Arguments are model output

Put it to work — three apps

Each one is a docker compose up web app.

Takeaway

The model chooses, your code executes — keep that line sharp. Next week: put a while around this loop and add more tools.