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_functiondecorator automatically registers the function in the agent's tool registry - Type annotations and
Annotateddocstrings 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
AgentExecutorRequestandAgentExecutorResponse - 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
AgentExecutorinstances or@executorfunctions - 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:
dependenciesfield enables topological sorting for execution order - Agent assignment: Clear separation of concerns by specialized sub-agents
- LLM generation: The coordinator agent can output
TravelPlandirectly viaresponse_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
AgentExecutorwith@ai_functiontools for basic LLM-agent interaction - Layer 2:
WorkflowBuilderwith 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →