# How the ai-agents-for-beginners Project Structures AI Agents: A Complete Guide

> Discover how ai-agents-for-beginners structures AI agents using a lesson-based architecture with MAF, AgentExecutor, @ai_function, WorkflowBuilder, and Pydantic models. Learn to build powerful AI.

- Repository: [Microsoft/ai-agents-for-beginners](https://github.com/microsoft/ai-agents-for-beginners)
- Tags: architecture
- Published: 2026-04-22

---

**The ai-agents-for-beginners repository structures AI agents through a progressive, lesson-based architecture using the Microsoft Agent Framework (MAF), combining `AgentExecutor` for LLM-backed agents, `@ai_function` decorators for tools, `WorkflowBuilder` for conditional routing, and Pydantic models for structured planning.**

The **ai-agents-for-beginners** project from Microsoft is an educational repository designed to teach AI agent engineering through incremental complexity. Rather than presenting a monolithic framework, it structures AI agents as composable building blocks that evolve from simple single-agent setups to sophisticated multi-agent workflows. This article examines exactly how the project structures AI agents, with direct references to source files and executable code patterns.

---

## Core Agent Architecture: The Microsoft Agent Framework (MAF)

The project structures all AI agents around the **Microsoft Agent Framework (MAF)**—a thin Python wrapper that unifies LLM interaction, tool registration, and workflow orchestration. Understanding how the ai-agents-for-beginners project structures AI agents requires understanding these five MAF primitives:

| Building Block | Purpose | Key Class/Decorator |
|--------------|---------|-------------------|
| **Agent definition** | Wrap LLM with instructions and tools | `AgentExecutor` |
| **Tool exposure** | Register Python functions as LLM-callable tools | `@ai_function` |
| **Workflow composition** | Build directed graphs of agents with conditional routing | `WorkflowBuilder` |
| **Custom post-processing** | Handle agent output (logging, UI, persistence) | `@executor` |
| **Structured planning** | Decompose tasks into typed sub-tasks | Pydantic `BaseModel` |

All samples import from the same namespace:

```python
from agent_framework import (
    AgentExecutor,
    AgentExecutorRequest,
    AgentExecutorResponse,
    ChatMessage,
    Role,
    WorkflowBuilder,
    WorkflowContext,
    ai_function,
    executor,
)

```

---

## Layer 1: Single LLM-Backed Agent with Tools

The simplest structure in the ai-agents-for-beginners project is a single `AgentExecutor` enhanced with `@ai_function` tools. This pattern appears in [[`hotel_booking_workflow_sample.py`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/hotel_booking_workflow_sample.py)](https://github.com/microsoft/ai-agents-for-beginners/blob/main/14-microsoft-agent-framework/code-samples/hotel_booking_workflow_sample.py).

### Defining a Tool

```python
from agent_framework import ai_function
from typing import Annotated
import json

@ai_function(description="Check hotel room availability for a destination city")
def hotel_booking(
    destination: Annotated[str, "The destination city to check for hotel rooms"]
) -> str:
    # Simulated availability logic

    has_rooms = check_inventory(destination)  # your implementation

    return json.dumps({"has_availability": has_rooms, "destination": destination})

```

Key structural points:
- The `@ai_function` decorator automatically registers the function in the agent's **tool registry**
- Type annotations and `Annotated` docstrings become the LLM's **function schema**
- Return values must be **JSON-serializable strings** for LLM consumption

### Wrapping in AgentExecutor

```python
from agent_framework import AgentExecutor
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient(model_id="gpt-4o")

availability_agent = AgentExecutor(
    client.create_agent(
        instructions="You are a hotel booking assistant. Check availability before proceeding.",
        tools=[hotel_booking],
        response_format=BookingCheckResult,  # Pydantic model for structured output

    ),
    id="availability_agent",
)

```

The `AgentExecutor` structure provides:
- **Consistent request/response interface** via `AgentExecutorRequest` and `AgentExecutorResponse`
- **Automatic tool dispatching** when the LLM emits tool calls
- **Structured output enforcement** through Pydantic `response_format`

---

## Layer 2: Conditional Workflows with WorkflowBuilder

The ai-agents-for-beginners project structures more complex AI agents as **directed acyclic graphs** using `WorkflowBuilder`. This allows conditional routing based on agent outputs. The full implementation appears in [[`hotel_booking_workflow_sample.py`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/hotel_booking_workflow_sample.py)](https://github.com/microsoft/ai-agents-for-beginners/blob/main/14-microsoft-agent-framework/code-samples/hotel_booking_workflow_sample.py).

### Conditional Routing Predicates

```python
import json
from agent_framework import AgentExecutorResponse

def has_availability_condition(msg: AgentExecutorResponse) -> bool:
    """Route to booking agent when rooms are available."""
    data = json.loads(msg.agent_run_response.text)
    return data.get("has_availability", False)

def no_availability_condition(msg: AgentExecutorResponse) -> bool:
    """Route to alternative suggestions when no rooms available."""
    return not has_availability_condition(msg)

```

### Building the Workflow Graph

```python
from agent_framework import WorkflowBuilder, executor, WorkflowContext

# Custom executor for final output

@executor(id="display_result")
async def display_result(response: AgentExecutorResponse, ctx: WorkflowContext[Never, str]) -> None:
    await ctx.yield_output(response.agent_run_response.text)

# Construct the workflow DAG

workflow = (
    WorkflowBuilder()
    .set_start_executor(availability_agent)  # Entry point

    .add_edge(availability_agent, booking_agent, condition=has_availability_condition)
    .add_edge(availability_agent, alternative_agent, condition=no_availability_condition)
    .add_edge(booking_agent, display_result)
    .add_edge(alternative_agent, display_result)
    .build()
)

```

Key structural characteristics:
- **Nodes** are `AgentExecutor` instances or `@executor` functions
- **Edges** define control flow; conditional edges use **predicate functions** that inspect `AgentExecutorResponse`
- **WorkflowContext** provides execution state and output streams
- The pattern supports **fan-out** (parallel agents) and **fan-in** (merging results)

---

## Layer 3: Planning and Task Decomposition

The ai-agents-for-beginners project structures **planning capabilities** through Pydantic models that represent hierarchical task decomposition. This pattern appears in [`07-python-agent-framework.ipynb`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/07-planning-design/code_samples/07-python-agent-framework.ipynb).

### Structured Plan Representation

```python
from pydantic import BaseModel
from typing import List

class TravelSubTask(BaseModel):
    task_id: int
    description: str
    assigned_agent: str  # "flight_agent", "hotel_agent", "activity_agent"

    priority: str  # "high", "medium", "low"

    dependencies: List[int] = []  # task_ids that must complete first

class TravelPlan(BaseModel):
    destination: str
    subtasks: List[TravelSubTask]

```

### Example Plan Instance

```python
plan = TravelPlan(
    destination="Tokyo",
    subtasks=[
        TravelSubTask(
            task_id=1,
            description="Search for flights to Tokyo",
            assigned_agent="flight_agent",
            priority="high"
        ),
        TravelSubTask(
            task_id=2,
            description="Book hotel in Tokyo",
            assigned_agent="hotel_agent",
            priority="high",
            dependencies=[1]  # wait for flight confirmation

        ),
        TravelSubTask(
            task_id=3,
            description="Recommend activities",
            assigned_agent="activity_agent",
            priority="medium",
            dependencies=[1, 2]
        ),
    ],
)

```

Structural significance:
- **Type safety**: Pydantic validates plan structure at runtime
- **Dependency DAG**: `dependencies` field enables topological sorting for execution order
- **Agent assignment**: Clear separation of concerns by specialized sub-agents
- **LLM generation**: The coordinator agent can output `TravelPlan` directly via `response_format=TravelPlan`

---

## Layer 4: Multi-Agent Coordination

The ai-agents-for-beginners project structures **multi-agent systems** by extending the workflow pattern to parallel execution and hand-off protocols. Implementation appears in [`08-multi-agent/code_samples/workflows-agent-framework/python/01.python-agent-framework-workflow-ghmodel-basic.ipynb`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/08-multi-agent/code_samples/workflows-agent-framework/python/01.python-agent-framework-workflow-ghmodel-basic.ipynb).

### Parallel Agent Execution

When agents have no inter-dependencies, `WorkflowBuilder` executes them in parallel:

```python
from agent_framework import WorkflowBuilder

# Define specialist agents

flight_agent = AgentExecutor(..., id="flight_finder")
hotel_agent = AgentExecutor(..., id="hotel_finder")
activity_agent = AgentExecutor(..., id="activity_finder")

# Parallel fan-out: all three run simultaneously

workflow = (
    WorkflowBuilder()
    .set_start_executor(coordinator_agent)
    .add_edge(coordinator_agent, flight_agent)
    .add_edge(coordinator_agent, hotel_agent)
    .add_edge(coordinator_agent, activity_agent)
    # Results merge at hand-off executor

    .add_edge(flight_agent, handoff_executor)
    .add_edge(hotel_agent, handoff_executor)
    .add_edge(activity_agent, handoff_executor)
    .build()
)

```

### Hand-Off Protocol

The **hand-off executor** receives multiple responses and decides final output:

```python
from agent_framework import executor, WorkflowContext, AgentExecutorResponse
from typing import Never

@executor(id="travel_handoff")
async def travel_handoff(
    response: AgentExecutorResponse,
    ctx: WorkflowContext[Never, str]
) -> None:
    # Access accumulated results from parallel branches

    accumulated = ctx.get_accumulated_results()
    
    # Synthesize final travel recommendation

    final_output = f"""
    Travel Plan Ready:
    ✈️ Flights: {accumulated.get('flight_finder', 'N/A')}
    🏨 Hotel: {accumulated.get('hotel_finder', 'N/A')}
    🎯 Activities: {accumulated.get('activity_finder', 'N/A')}
    """
    
    await ctx.yield_output(final_output)

```

Multi-agent structural principles:
- **Parallelization** reduces latency for independent subtasks
- **WorkflowContext** maintains state across agent boundaries
- **Hand-off executors** merge results and resolve conflicts
- **Agent specialization** improves accuracy through focused instructions

---

## Layer 5: Production Deployment and Agent Protocols

The ai-agents-for-beginners project structures **production-ready agents** through Azure AI Foundry integration and the Model Context Protocol (MCP) for cross-platform agent communication.

### Azure AI Foundry Integration

Production samples in [`10-ai-agents-production/code_samples/10-python-agent-framework.ipynb`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/10-ai-agents-production/code_samples/10-python-agent-framework.ipynb) demonstrate environment-based configuration:

```python
import os
from agent_framework.azure import AzureAIChatClient

# Azure AI Foundry endpoint

client = AzureAIChatClient.from_connection_string(
    os.getenv("AZURE_AI_FOUNDRY_CONNECTION_STRING"),
    model_id="gpt-4o",
)

# Or use GitHub Models (free tier)

github_client = OpenAIChatClient(
    base_url="https://models.inference.ai.azure.com",
    api_key=os.getenv("GITHUB_TOKEN"),
    model_id="gpt-4o",
)

```

### Model Context Protocol (MCP) Server

The MCP implementation in [[`11-agentic-protocols/code_samples/mcp-agents/server/server.py`](https://github.com/microsoft/ai-agents-for-beginners/blob/main/11-agentic-protocols/code_samples/mcp-agents/server/server.py)](https://github.com/microsoft/ai-agents-for-beginners/blob/main/11-agentic-protocols/code_samples/mcp-agents/server/server.py) structures agents as **resumable HTTP services**:

```python
from mcp.server import ResumableServer
from mcp.types import Tool, TextContent

class HotelBookingServer(ResumableServer):
    def __init__(self):
        super().__init__("hotel-booking-server")
        self.event_store = SimpleEventStore()  # For session resumption

    
    def register_tools(self):
        self.add_tool(
            Tool(
                name="check_availability",
                description="Check hotel availability",
                parameters={
                    "type": "object",
                    "properties": {
                        "destination": {"type": "string"},
                        "check_in": {"type": "string"},
                        "check_out": {"type": "string"}
                    },
                    "required": ["destination"]
                },
                handler=self._check_availability
            )
        )
    
    async def _check_availability(self, params: dict) -> list[TextContent]:
        # Long-running operation with progress streaming

        session_id = params.get("session_id")
        
        for progress in range(0, 101, 20):
            await self.emit_progress(session_id, progress, f"Checking {progress}% of inventory...")
            await asyncio.sleep(0.5)  # Simulated work

        
        result = await self._query_inventory(params["destination"])
        return [TextContent(type="text", text=json.dumps(result))]

```

Production structural features:
- **Environment-based model switching** (OpenAI, Azure, MiniMax, GitHub Models)
- **Session resumption** for long-running agent operations
- **Progress streaming** for real-time user feedback
- **Standardized tool schemas** via MCP for cross-platform interoperability

---

## Summary

The **ai-agents-for-beginners** project structures AI agents through a **five-layer progressive architecture**:

- **Layer 1**: Single `AgentExecutor` with `@ai_function` tools for basic LLM-agent interaction
- **Layer 2**: `WorkflowBuilder` with conditional edges for branching control flow
- **Layer 3**: Pydantic-based planning models for task decomposition and dependency management
- **Layer 4**: Parallel multi-agent coordination with hand-off protocols for team-based problem solving
- **Layer 5**: Production deployment via Azure AI Foundry and MCP resumable servers for scalable, interoperable services

Each layer builds upon the previous, with concrete implementations in progressive lessons from `01` through `14`. The consistent use of `AgentExecutor`, `@ai_function`, and `WorkflowBuilder` across all samples ensures conceptual transfer as complexity increases.

---

## Frequently Asked Questions

### What is the Microsoft Agent Framework (MAF) used in ai-agents-for-beginners?

The **Microsoft Agent Framework (MAF)** is a Python SDK that provides unified abstractions for building LLM-powered agents. It wraps multiple model providers (OpenAI, Azure AI, MiniMax, GitHub Models) through a consistent `AgentExecutor` interface, while providing decorators like `@ai_function` for tool registration and `WorkflowBuilder` for composing agent graphs. The framework is installed via `pip install agent-framework` and imported as `from agent_framework import ...`.

### How does ai-agents-for-beginners handle multi-agent coordination?

The repository structures multi-agent coordination through **parallel execution in workflow graphs** and **hand-off executors**. When agents have no dependencies, `WorkflowBuilder` executes them concurrently. A specialized `@executor` function then receives all parallel results via `ctx.get_accumulated_results()`, synthesizes the final output, and yields it through `ctx.yield_output()`. This pattern appears in `08-multi-agent` notebooks where flight, hotel, and activity agents run simultaneously.

### What is the difference between @ai_function and @executor in the project?

**`@ai_function`** registers a Python function as a **tool that the LLM can invoke** during its reasoning process. The LLM decides when to call it based on its description and parameters. **`@executor`** defines a **post-processing node in the workflow graph** that runs deterministically after an agent completes. Executors have access to `WorkflowContext` for state management and output emission, but they are not invoked by the LLM—they are wired explicitly via `WorkflowBuilder.add_edge()`.

### How does the project implement the planning design pattern?

The **planning pattern** is implemented through **Pydantic models that represent hierarchical task structures**. A `TravelPlan` contains `TravelSubTask` items, each specifying a task ID, description, assigned specialist agent, priority, and dependency list. The coordinator agent outputs a `TravelPlan` instance (enforced via `response_format=TravelPlan`), which is then topologically sorted and dispatched to the appropriate specialist agents. This structure appears in `07-planning-design/code_samples/07-python-agent-framework.ipynb`.