Function Calling Explained: How AI Models Trigger Real Actions in Your Application — Part 33 Function Calling enables large language models to generate structured requests that trigger real-world actions in applications, bridging the gap between conversational AI and task execution. The capability, explained in Part 33 of a generative AI tutorial series, allows models to request specific functions like database queries or API calls, with the application controlling execution and safety. The author illustrates the flow with an example where an AI assistant checks weather data and then books a cab based on the result. Three months into building AI applications, I hit a wall. My AI assistant could answer questions beautifully. It could summarize documents, explain concepts, draft responses, and hold intelligent conversations. But it couldn’t do anything. A user would ask: “Can you book me a meeting with the team for Thursday at 3 PM?” Learning Generative AI From Scratch: The Complete Roadmap 120+ Articles https://medium.com/codetodeploy/learning-generative-ai-from-scratch-the-complete-roadmap-120-articles-c3bff1f0aa10 The AI would respond: “Of course I’d be happy to help you schedule that meeting. You’ll want to open your calendar application and create a new event for Thursday at 3 PM…” It was giving instructions for how to do a task instead of actually doing it. Like asking a colleague to send an email and they respond by explaining how email works. The gap between talking about actions and performing actions is exactly what Function Calling solves. And understanding it properly — not just as a concept but as something you architect deliberately — changes what becomes possible in your AI applications. This is Part 33 of Learning Generative AI From Scratch. In Part 32 we covered Prompt Templates and Prompt Chaining — how to structure AI workflows. Now we’re going one step further: how AI models trigger actual functions in your application to perform real-world actions. Prompt Templates and Prompt Chaining: How to Build AI Workflows That Actually Scale — Part 32 https://sumanthpoola.medium.com/prompt-templates-and-prompt-chaining-how-to-build-ai-workflows-that-actually-scale-part-32-c20e381a4eba Function Calling is a capability that allows an LLM to request the execution of specific functions defined in your application — passing structured parameters, receiving structured results, and using those results to complete a task. The critical distinction from everything we’ve built so far: When Function Calling is available, the model doesn’t just generate text — it can generate structured requests for your application to execute real operations: database queries, API calls, file operations, calendar updates, email sends, payment processing — anything your application can do. The model decides what to call and with what parameters . Your application decides whether to execute it and how . That separation of concerns is the architectural foundation that makes Function Calling safe and powerful at the same time. Before writing any code, understanding the exact flow matters: User: "What's the weather in Bengaluru and book a cab if it's raining?"↓LLM receives message + available function definitions↓LLM decides: "I need weather data first"LLM generates structured function call request:{ "function": "getWeather", "parameters": { "city": "Bengaluru" }}↓Your application executes getWeather "Bengaluru" Returns: { "condition": "Heavy Rain", "temp": 22 }↓LLM receives result, decides: "It's raining — book cab"LLM generates second function call:{ "function": "bookCab", "parameters": { "pickup": "user location", "destination": "office", "type": "standard" }}↓Your application executes bookCab ... Returns: { "bookingId": "CAB-4829", "eta": "8 minutes" }↓LLM generates final natural language response:"It's raining heavily in Bengaluru 22°C . I've booked a cab for you — it arrives in 8 minutes.Booking reference: CAB-4829." Two things to notice: First — the LLM made two sequential decisions, each building on the previous result. It didn’t know it needed to book a cab until it knew the weather. Second — your application executed both functions. The LLM never directly called any API. It requested, your code executed, results flowed back. If you read Part 28 of this series, you might be wondering: isn’t this exactly what Tool Calling does? Yes — and no. Here’s the precise distinction: Function Calling is the underlying capability — the model generating structured requests for specific functions with typed parameters. It’s the mechanism. Tool Calling Part 28 is a higher-level abstraction — Spring AI’s @Tool annotation pattern that wraps Function Calling into a simpler developer experience. Think of it this way: In Part 28, we used @Tool annotations and let Spring AI handle the function registration, parameter parsing, and result injection automatically. In this article, we’re going one layer deeper — understanding how the raw Function Calling mechanism works, how to define function schemas explicitly, how to handle multi-step function execution, and how to build production-grade patterns that @Tool alone doesn't cover. Both matter. Understanding the engine helps you use the steering wheel better. The model knows which functions are available because you describe them in a structured schema — typically JSON Schema format — that gets included in the API request. @Configurationpublic class FunctionSchemaConfig { // Define function schemas as Spring AI FunctionCallback objects @Bean public FunctionCallback getWeatherFunction { return FunctionCallbackWrapper.builder new WeatherFunction .withName "getWeather" .withDescription "Get current weather conditions for a specific city. " + "Returns temperature in Celsius and weather condition. " + "Use this when the user asks about weather or before " + "making outdoor activity recommendations." .withInputType WeatherFunction.WeatherRequest.class .build ; } @Bean public FunctionCallback bookCabFunction { return FunctionCallbackWrapper.builder new CabBookingFunction .withName "bookCab" .withDescription "Book a cab/taxi for the user. " + "Use this when the user explicitly asks to book " + "transportation or when weather conditions suggest " + "they need a ride. Always confirm with user before booking." .withInputType CabBookingFunction.BookingRequest.class .build ; } @Bean public FunctionCallback sendEmailFunction { return FunctionCallbackWrapper.builder new EmailFunction .withName "sendEmail" .withDescription "Send an email on behalf of the user. " + "Use ONLY when the user explicitly requests sending an email. " + "Never send emails without explicit user instruction." .withInputType EmailFunction.EmailRequest.class .build ; }} Notice the descriptions are detailed and include when to use each function — not just what it does. This is critical. The model reads these descriptions to decide which function to call. Vague descriptions lead to wrong function selection. Each function is a Java class that implements the actual logic: // Weather function@Componentpublic class WeatherFunction implements Function