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

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:

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/14-microsoft-agent-framework/code-samples/hotel_booking_workflow_sample.py).

Defining a Tool

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

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/14-microsoft-agent-framework/code-samples/hotel_booking_workflow_sample.py).

Conditional Routing Predicates

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

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.

Structured Plan Representation

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

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.

Parallel Agent Execution

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

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:

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 demonstrate environment-based configuration:

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) structures agents as resumable HTTP services:

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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →