Skip to content
datarekha

Microsoft Agent Framework — overview

Microsoft Agent Framework is Microsoft's unified Python and .NET SDK for agents, tools, threads, and workflows. Learn its execution model, Azure strengths, production trade-offs, and when to choose it over LangGraph or ADK.

Written and reviewed by Last reviewed

12 min read Intermediate Agentic AI Lesson 38 of 78

What you'll learn

  • Why Microsoft unified AutoGen and Semantic Kernel into MAF
  • How ChatAgent, tools, threads, and workflows fit together
  • What agent.run does with and without a thread
  • How conversation history changes context size and cost
  • When MAF is the right choice over LangGraph or ADK

Before you start

It is 3 a.m. A customer asks your support bot, “Why did my Azure bill jump in March?” The bot checks the billing tool and gives a useful answer.

Then the customer asks, “What about February?”

The bot has forgotten the first question. It cannot tell what “what about” refers to, so it either asks the customer to repeat themselves or confidently compares the wrong things. Both outcomes are expensive ways to discover that a chat box is not the same thing as a conversation.

Now imagine the same product six months later: a billing agent, a policy agent, a human approval step for refunds, and an auditor workflow. Different teams built each piece with different Microsoft libraries, so authentication, tracing, history, and deployment conventions no longer line up.

That was the problem Microsoft Agent Framework, or MAF, was built to address. MAF is the agent-framework Python and .NET SDK for agents and multi-step agent systems. It unifies AutoGen, a research-oriented multi-agent library, and Semantic Kernel, an enterprise-oriented library for plugins and orchestration.

What MAF actually is

MAF has two related execution models:

  • A ChatAgent is a model-directed loop. The model receives instructions and messages, chooses whether to answer or call a tool, observes tool results, and continues until it produces a final response.
  • A workflow is an explicit graph. You define executors, connections, and sometimes routing conditions.

A billing question has an uncertain path: inspect the account, retrieve invoices, query usage, then explain the result. An invoice approval process has a known path: validate, check policy, ask for approval, then post it. The first suits an agent loop; the second suits a workflow.

Two execution models side by side: a single agent looping over tools, and a workflow graph of typed nodes.

Loop when the path is unknown. Graph when it is not.

The four building blocks are:

BlockPlain-English meaningWhat it controls
ChatAgentAn LLM with instructions and optional toolsHow one agent reasons and responds
ToolsFunctions the model can requestWhat the agent can do outside the model
ThreadsContainers for message historyWhat the agent can use as conversation context
WorkflowsGraphs of agents and other executorsHow several steps or agents coordinate

The model supplies probabilistic decisions. MAF supplies the machinery that turns those decisions into tool calls, executions, observations, and final answers.

That machinery is especially useful around Azure. AzureOpenAIChatClient is a first-class client, Entra ID credentials can replace API keys, and MAF fits Microsoft’s Foundry, Bot Service, Azure Functions, and OpenTelemetry ecosystem. Other model providers are supported; Azure is the reason many teams choose MAF over a neutral framework.

The smallest useful agent

You create a model client, give it to an agent with instructions, and run the agent.

# requires: pip install agent-framework==1.0.0 agent-framework-azure-ai==1.0.0 azure-identity==1.25.0
# Run after authenticating with Azure CLI: az login

from agent_framework import ChatAgent
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential

# 1. The model client. Entra ID supplies the credential.
chat_client = AzureOpenAIChatClient(
    credential=AzureCliCredential(),
    endpoint="https://my-foundry-resource.openai.azure.com",
    deployment_name="gpt-4.1",
)

# 2. The agent. It has instructions, but no tools yet.
agent = ChatAgent(
    chat_client=chat_client,
    name="data-explainer",
    instructions=(
        "You explain data engineering concepts in two sentences. "
        "Never use marketing language."
    ),
)

# 3. One request. .run() returns one completed response.
async def main():
    result = await agent.run("What is a window function in SQL?")
    print(result.messages[-1].text)

# In real code:
# import asyncio
# asyncio.run(main())

print("Shape only — real run needs Azure creds.")

The object relationships are:

  1. AzureOpenAIChatClient contacts the model.
  2. ChatAgent adds the name and instructions.
  3. agent.run() sends a request and returns the response.

deployment_name is your Azure deployment name, not necessarily the public model name. AzureCliCredential() uses an Azure CLI login for local development; a hosted service usually uses a managed identity or another Entra credential.

The call is stateless by default. The agent object exists in Python, but existence is not memory. Unless you pass conversation state, each call includes only its own input.

What happens during a run

For:

“Why did my March bill jump?”

a typical run is:

  1. MAF sends the instructions and user message to the model.
  2. The model requests a tool such as get_invoice(month="March").
  3. MAF validates and executes the tool.
  4. MAF sends the result back as a new message.
  5. The model requests another tool or writes the answer.
  6. MAF returns the completed result.

The model does not execute Python merely because it wrote a function name. MAF receives the structured request, runs the function, and feeds the result back. Your application can log the request, validate arguments, require approval, or reject it before a side effect occurs.

One agent.run() call can therefore contain several model turns. Trace the complete run and each tool call when investigating latency or cost.

Threads are history, not human memory

A thread is a conversation-history container. Passing it to later calls makes earlier messages available to the model.

thread = agent.get_new_thread()

await agent.run(
    "What is a window function?",
    thread=thread,
)

await agent.run(
    "Show me one in PySpark.",
    thread=thread,
)

The second call can resolve “one” because the thread contains the first question and answer. Without thread=thread, it is an independent request.

A thread does not store facts in the model’s weights. It stores messages, which become input context on later calls. That has two consequences.

First, history increases context size. Consider:

CallNew user inputEarlier history includedInput sent to model
1200 tokens0200
2100 tokens500 tokens600
3120 tokens850 tokens970

Across three calls, the model receives 200 + 600 + 970 = 1,770 input tokens. Sending each question independently would use only 200 + 100 + 120 = 420 input tokens. Exact counts vary, but long threads can increase context, latency, and cost.

Second, a thread is not an authentication session.

For a prototype, agent.get_new_thread() creates an in-memory thread. It disappears when the process does, so production services should persist enough state to reconstruct or resume it in Cosmos DB, Redis, SQL, or another store.

Keep tenant and user identity separate from the conversation ID, authorize thread access, expire or summarize old history, encrypt sensitive messages, and define deletion policies. Avoid retaining tool results containing secrets longer than necessary.

Tools: the boundary between words and work

A tool is a callable operation exposed with a description and typed input schema. Type annotations describe arguments, and documentation helps describe the operation to the model.

def get_invoice(month: str, account_id: str) -> dict:
    """Return totals and line items for one billing month."""
    ...

MAF uses this information to create the tool schema and manages the tool-call loop. The model chooses when to request the tool, but your application owns execution.

Types are not authorization. The function must verify the authenticated caller’s account scope; otherwise a model can request another customer’s account_id.

Start with read-only tools. Refunds, database writes, emails, and infrastructure operations need authorization, validation, idempotency, audit logging, and sometimes human approval. Hosted capabilities such as code execution, file search, and web search also need explicit data and permission boundaries.

The next lesson covers MAF tools in depth.

Workflows: make the known path explicit

A workflow coordinates work that should not be left entirely to model judgment. Its nodes, often called executors, receive input, perform work, and emit output; edges connect each output to the next step.

A billing workflow might load invoices, classify the change, draft an explanation, audit its numbers, and route a refund recommendation for human approval. If the auditor must always run, encode that edge. “Remember to audit yourself” is a prompt suggestion; a graph edge is control flow.

Use an agent loop when the route is uncertain and a workflow when it is a business rule. Many systems use both: an agent researches within one node while a workflow controls the larger process.

MAF includes:

  • Sequential execution for fixed pipelines
  • Concurrent execution for independent work
  • Handoff for transferring control between specialists
  • Group chat for shared multi-agent discussion
  • Magentic-One for more general open-ended orchestration

Every additional agent adds model calls, context transfer, failure paths, and opportunities for contradictory conclusions. Start with one agent and workflow edges you can explain on a whiteboard.

Choosing MAF in practice

The deciding question is where your identity, models, deployment, and operators already live.

SituationSensible first choiceWhy
Azure OpenAI, Entra ID, Foundry, and Azure hosting are standardMAFLess authentication and deployment glue
A .NET team needs the same concepts as a Python teamMAFPython and .NET support
Stateful graphs with retries, checkpoints, and explicit branching dominateMAF or LangGraphCompare their workflow and persistence models
The stack is primarily GCP or provider-neutralADK, LangGraph, or OpenAI Agents SDKMAF’s Azure advantage is less valuable

MAF wins when Azure model access, Entra authentication, Foundry integration, .NET parity, and Microsoft hosting conventions remove work. It is weaker when your organization has no Azure footprint: you carry its concepts without receiving its strongest integrations. LangGraph may be preferable when durable graph state and recovery dominate; ADK may fit a deeply Google Cloud-based service.

API stability note

MAF reached GA in 2026, but convenience methods can still change. The shapes shown here—ChatAgent, AzureOpenAIChatClient, agent.run(), and get_new_thread()—represent the 1.x model described by this lesson. Before production rollout, confirm current signatures, persistence support, hosted-tool names, and provider requirements in the official documentation.

Quick check

Quick check

0/3
Q1What two earlier Microsoft projects does MAF consolidate?
Q2Why pass a thread to agent.run()?
Q3Transfer: a support service has a fixed five-step refund process, but one step may query several independent billing systems at the same time. What should control the overall design?

Next

The next lesson covers MAF tools: schemas, function execution, approval, MCP, and the safeguards that keep an agent from turning a plausible sentence into an expensive side effect.

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Practice this in an interview

All questions
What is an AI agent, and how does it differ from a single LLM call?

An AI agent is an application that lets an LLM choose and execute validated tools in a bounded loop, carrying observations and state forward until it reaches a goal or needs approval. A single LLM call produces one response or tool-call proposal and stops; it does not itself provide the loop, live-system access, memory, or side effects.

How do function/tool calling and LLM agents work at a high level?

Tool calling extends the LLM's output space to include structured function invocations. The model emits a JSON object naming a tool and its arguments; the runtime executes the tool and feeds the result back as a new message. An agent is a loop that repeats this cycle — observe, think, act — until the task is complete or a stopping condition is met.

What is tool use or function calling in LLMs, and how do you design good tools for an agent?

Tool use lets an LLM emit a structured request for an external function, which the application validates, authorizes, executes, and returns to the model. Reliable tools have clear descriptions, narrow scope, strict typed inputs, least-privilege access, idempotency, and useful structured errors.

What is the Model Context Protocol (MCP) and what problem does it solve?

MCP is an open protocol originally introduced by Anthropic that standardizes how an AI host discovers and uses tools, resources, and prompt templates exposed by separate servers. It solves bespoke integration sprawl by giving each server one common interface, while leaving model orchestration, permissions, and user approval to the host.

Related lessons

Explore further