← Master Index
Vol. 15 Module 15.1 Lecture

Function Calling

Agent Fundamentals

How This Lesson Fits the Module & Volume

Tool calling is the capability model. Function calling is the dominant API contract used by OpenAI-compatible chat models: you send tools, the model may return tool_calls, you execute, then you send role: tool messages. This lecture is the practical wire format every AI engineer should be able to implement without a heavy framework.

Frameworks you met in Vol. 14—LangChain, CrewAI, PydanticAI—wrap this contract. Module 15.3 MCP tools will sit beside it as a discovery/transport layer, not a replacement for understanding the round-trip.

Learning Objectives

By the end of this lesson, students should be able to:

  • Describe the OpenAI-style round-trip: tools → tool_calls → tool results → final text.
  • Write JSON Schema parameters and parse arguments with json.loads.
  • Handle parallel tool calls and missing/invalid arguments.
  • Contrast native function calling with “please emit JSON” prompting.
  • Use tool_choice (auto / required / none / specific) deliberately.
  • Wire function calling into the upcoming agent loop.
Definition

Function calling is an API feature where the model is given JSON Schema tool definitions and may respond with one or more structured function invocations (name + arguments) instead of—or before—a natural-language answer. The host executes those functions and returns results as subsequent messages.

The Round-Trip

TurnWhoPayload
0Youmessages + tools schemas
1Modelmessage.tool_calls[] (id, name, arguments JSON string)
2YouFor each id: {"role":"tool","tool_call_id":...,"content":...}
3ModelFinal content or more tool_calls

Complete OpenAI-Style Example

import json from openai import OpenAI client = OpenAI() tools = [{ "type": "function", "function": { "name": "convert_c_to_f", "description": "Convert Celsius to Fahrenheit. Use for temperature unit conversion only.", "parameters": { "type": "object", "properties": { "celsius": {"type": "number", "description": "Temperature in Celsius"}, }, "required": ["celsius"], "additionalProperties": False, }, "strict": True, }, }] def convert_c_to_f(celsius: float) -> str: f = celsius * 9 / 5 + 32 return json.dumps({"celsius": celsius, "fahrenheit": round(f, 2)}) messages = [ {"role": "system", "content": "Use tools for arithmetic. Reply briefly."}, {"role": "user", "content": "What is 21°C in Fahrenheit?"}, ] completion = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, tool_choice="auto", # or "required", "none", {"type":"function","function":{"name":"convert_c_to_f"}} ) msg = completion.choices[0].message messages.append(msg) if msg.tool_calls: for call in msg.tool_calls: args = json.loads(call.function.arguments) if call.function.name == "convert_c_to_f": result = convert_c_to_f(**args) else: result = json.dumps({"error": "unknown_tool"}) messages.append({ "role": "tool", "tool_call_id": call.id, "content": result, }) final = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, tool_choice="none" ) print(final.choices[0].message.content) else: print(msg.content)

API Knobs Engineers Actually Use

tool_choice

  • auto — model decides
  • required — must call something
  • none — force a final answer
  • Named tool — force one function

Parallel calls

  • Multiple tool_calls in one turn
  • Independent lookups in parallel
  • Still one result per id

Strict schemas

  • additionalProperties: false
  • Pydantic / JSON Schema
  • Reject extra hallucinated keys

Strengths

  • Reliable structured invocations
  • Better than regexing chat JSON
  • Works across many providers
  • Fits thin custom loops

Tradeoffs

  • Arguments still can be wrong types
  • Must always match tool_call_id
  • Provider quirks / legacy functions API
  • Token cost of schemas every turn
Common Misconception

“Function calling is just prompting the model to print JSON.” Native tool_calls are a separate message channel with ids the API validates. Prompted JSON is easier to break, harder to parallelize, and easier to confuse with user-visible text. Use native calling when the provider supports it.

Knowledge Check

  1. Short Answer: What must you send back for each tool call? Answer: A role: tool message with the matching tool_call_id and result content.
  2. True/False: function.arguments arrives as a JSON string you must parse. Answer: True.
  3. Multiple Choice: tool_choice="none" means: (a) crash, (b) force a final natural-language answer, (c) train LoRA. Answer: (b).
  4. Short Answer: Why set additionalProperties: false? Answer: Reject extra hallucinated keys; stricter validation.
  5. True/False: You should use eval() to parse arguments. Answer: False—use json.loads.
  6. Multiple Choice: Parallel tool calls require: (a) one result per call id, (b) a single merged blob, (c) CSS. Answer: (a).
  7. Short Answer: How does this differ from tool calling as a concept? Answer: Function calling is the API/wire format; tool calling is the broader capability pattern.
  8. Short Answer: Name a Vol. 14 framework that wraps this contract. Answer: LangChain, CrewAI, or PydanticAI (any).
  9. Multiple Choice: Legacy OpenAI functions vs modern tools: (a) unrelated to models, (b) older vs current parameter shape, (c) CNN layers. Answer: (b).
  10. True/False: After tools return, the model may call tools again. Answer: True—that is why you need an agent loop.

Key Takeaways

  • Function calling is the structured round-trip: schemas, tool_calls, tool results, final text.
  • Parse JSON safely, match ids, validate types, fail closed on unknown names.
  • Use tool_choice to force, forbid, or allow calls; cap parallel work.
  • Prefer native calling over prompted JSON; frameworks wrap this same contract.
  • Next: the agent loop that repeats this round-trip until halt.
Trainer’s Guide

Whiteboard: Draw four boxes for the round-trip. Label where auth, logging, and HITL sit (host side, never in the model).

Lab: Add a second tool get_weather(city) and a user question that needs both tools in one turn (parallel) or two sequential turns.

Recap: Function calling is the wire format for tools. Continue with Agent Loop.