How AI Agents Actually Work Under the Hood


The notion that LLMs “execute code” or “call APIs” is one of the most persistent misconceptions in AI engineering. Understanding what actually happens when you build an AI agent changes everything about how you architect these systems.

The Core Misconception

LLMs output text. That’s their only capability. When you see an AI agent “using tools” or “executing functions,” what’s really happening is far more interesting and gives you far more control than most frameworks let on.

Here’s the actual flow: your Python code sends a request to the LLM with a description of available tools. The LLM analyzes the input and responds with structured text, typically JSON, suggesting which tools to use and what parameters to pass. Your code receives this text, parses it, validates it, and then decides whether to actually execute those tool calls. The LLM never touches your APIs directly.

This distinction isn’t academic. It’s the difference between building AI agents that are safe and controllable versus hoping a black box doesn’t break things.

Breaking Down the Agentic Loop

The agentic loop that everyone references is surprisingly simple when you strip away the framework abstractions. It’s a for loop in Python where each iteration involves three steps.

First, you call the LLM with context about what the user wants and what tools are available. The LLM responds with its analysis and suggested tool calls formatted as structured data. Second, your Python code validates these suggestions by checking parameters, verifying permissions, and handling edge cases, then executes the appropriate functions. Third, you pass the tool results back to the LLM for synthesis and summary.

That’s it. No magic. No complex state machines. Just a conversation loop where the LLM suggests actions and your code controls execution.

Tool Calling Mechanics

When you implement tool calling, you define function signatures that the LLM can reference. These aren’t real function calls the LLM makes. They’re templates that tell the LLM what parameters you expect and in what format.

The LLM reads your tool definitions and outputs structured parameters that match those templates. Your code receives these parameters as JSON. You validate them with type checking, range validation, and permission checks before calling your actual functions. If validation fails, you control what happens next. If it succeeds, you execute the tool and capture the results.

This validation layer is where production systems diverge from demos. You can implement rate limiting per tool. You can check user permissions before executing sensitive operations. You can sanitize inputs, log decisions, and gracefully handle errors. None of this requires framework magic, just solid Python patterns.

Multiple Tools, One Response

One detail that surprises engineers: the LLM can suggest multiple tool calls in a single response. When processing a meeting transcript, it might simultaneously request creating a calendar invite, generating a decision record, and drafting an incident report.

Your code receives all these suggestions at once. You can execute them in parallel, sequentially, or selectively based on your business logic. You control the execution order and error handling. If one tool fails, you decide whether to retry, skip, or abort the entire operation.

This level of control is trivial in plain Python. You’re just iterating over a list of tool calls, validating each one, and executing what makes sense. When you add framework abstractions, this simple pattern becomes configuration hell.

The Phase Approach

Organizing your agent logic into phases makes everything clearer. Phase one is tool selection, where the LLM analyzes the input and determines what tools are relevant. Phase two is tool execution, where your Python code validates and runs those tools. Phase three is summary generation, where the LLM creates a coherent response based on tool results.

These phases give you inspection points. After phase one, you can review what tools the LLM wants to use before committing to execution. After phase two, you can verify tool outputs before asking the LLM to summarize. Each phase is independently testable and debuggable.

The video walks through a complete implementation of this pattern with a transcript processing application. You see exactly how tool calls flow from LLM suggestion to Python validation to actual execution. No frameworks obscuring the mechanics.

Why This Understanding Matters

When you understand that LLMs only output text, you stop thinking about “giving the LLM access” to systems and start thinking about parsing, validation, and controlled execution. This mental shift makes you better at designing secure AI integrations.

You realize that every tool call is an opportunity for validation. Every LLM response is just structured text that your code interprets. Every execution is under your explicit control. This isn’t the LLM “doing things”; it’s your code using the LLM as a natural language interface to your logic.

Frameworks hide this reality behind abstractions. They make it seem like the LLM has agency, like it’s making decisions and executing code. Understanding the actual mechanics, text output, JSON parsing, Python validation, controlled execution, makes you a better AI engineer.

See the complete implementation with working code examples that demonstrate the agentic loop, tool calling validation, and phase-based architecture.

Watch: Building AI Agents Without Frameworks

Want to dive deeper into production AI patterns with experienced engineers? Join our community for practical discussions on building reliable AI systems.

Zen van Riel - Senior AI Engineer

Zen van Riel - Senior AI Engineer

Senior AI Engineer & Teacher

As an expert in Artificial Intelligence, specializing in LLMs, I love to teach others AI engineering best practices. With real experience in the field working at big tech, I aim to teach you how to be successful with AI from concept to production. My blog posts are generated from my own video content on YouTube.

Blog last updated