By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
  • Home
  • Products
  • Agents
  • Capital
  • Commerce
Reading: Microsoft Agent Framework Tutorial: Build a Python Agent
Sign In
  • Join US
Font ResizerAa
  • Home
  • Products
  • Agents
Search
  • Home
  • Products
  • Agents
  • Capital
  • Commerce
Have an existing account? Sign In
Follow US
> Blog > Agent Infrastructure > Microsoft Agent Framework Tutorial: Build a Python Agent
Python developer building an AI agent with the Microsoft Agent Framework SDK in a code editor
Agent Infrastructure

Microsoft Agent Framework Tutorial: Build a Python Agent

Surya Koritala
Last updated: June 2, 2026 11:45 pm
By Surya Koritala
27 Min Read
Share
SHARE

An independent, end-to-end Python walkthrough: install agent-framework, build a real agent with a custom tool and Pydantic structured output, stream it async, and decide honestly whether to adopt MAF over the Semantic Kernel + AutoGen lineage it replaces.

Contents
  • What is the Microsoft Agent Framework, and why a Python tutorial?
  • How do I install agent-framework and get started?
  • How do I build an agent with a custom tool (ChatAgent tools tutorial)?
  • How do I get Pydantic structured output from a Microsoft Agent Framework agent?
  • How do I stream the agent response asynchronously?
  • Microsoft Agent Framework vs Semantic Kernel and AutoGen: what changed?
  • Is the Microsoft Agent Framework production ready, and when should you NOT use it?
    • Adopt MAF for multi-agent and enterprise builds; skip it for a single simple agent
        • Pros
        • Cons
  • Builder’s take
  • Frequently asked questions
    • How do I install the Microsoft Agent Framework for Python?
    • What is the difference between Agent and ChatAgent in MAF?
    • How do I add a custom tool to a Microsoft Agent Framework agent?
    • How do I get structured JSON output from the agent?
    • Is the Microsoft Agent Framework production ready?
    • Should I migrate from Semantic Kernel or AutoGen to MAF?
  • Primary sources

What is the Microsoft Agent Framework, and why a Python tutorial?

This Microsoft Agent Framework tutorial for Python builds a real agent from scratch: you will pip install agent-framework, create an Agent backed by an OpenAI or Azure OpenAI chat client, register a custom Python tool, return a validated Pydantic object as structured output, and stream the whole run asynchronously. Most pages that rank for this topic are either Microsoft’s happy-path docs or a .NET/C# walkthrough. This one is independent, end-to-end Python, and ends with an honest “should I adopt it” verdict.

Microsoft Agent Framework (MAF) reached version 1.0 GA in April 2026, unifying two previously separate Microsoft projects, Semantic Kernel and AutoGen, into a single open-source SDK for Python and .NET. Visual Studio Magazine and Microsoft’s own DevBlogs describe 1.0 as the production-ready, long-term-support milestone with stable APIs and native support for the Model Context Protocol (MCP) and Agent-to-Agent (A2A) interoperability.

The practical pitch: MAF combines AutoGen’s lightweight agent abstractions with Semantic Kernel’s enterprise features, session-based state, type safety, middleware, and telemetry, and adds a typed, graph-based workflow engine for multi-agent orchestration. If you have ever wired AutoGen and Semantic Kernel together by hand, MAF is the framework that stops you from doing that.

One housekeeping note before code: the brief and many early write-ups reference `pip install agent-framework –pre` and a `ChatAgent` class. That was correct during the 1.0 release-candidate window. As of the stable 1.7.0 release on PyPI (May 28, 2026), the package installs without `–pre`, and the public class you instantiate is simply `Agent`. This tutorial uses the current, stable surface and flags the older names where they still appear in the wild.

Python developer building an AI agent with the Microsoft Agent Framework SDK in a code editor
Image.

Python 3.10+, an OpenAI API key (or an Azure OpenAI deployment), and a virtual environment. MAF does not auto-load .env files, so you will call load_dotenv() yourself or export variables in your shell.

How do I install agent-framework and get started?

To get started, create a virtual environment and run pip install agent-framework, which pulls in all sub-packages; for OpenAI or Azure OpenAI you then import the client from agent_framework.openai and the Agent class from agent_framework. The umbrella package is the simplest path; if you want a smaller footprint you can install just agent-framework-core plus a specific integration package.

Set up your environment first. The pip install agent-framework getting started step is intentionally boring, which is the point: no compiler, no SDK download, just a Python dependency.

Now confirm the install works with a four-line agent. This is the smallest complete Microsoft Agent Framework Python example that actually calls a model and prints a response. Notice that `Agent.run()` is a coroutine, so the whole program lives inside `asyncio.run()`.

Swap OpenAIChatClient() for AzureOpenAIChatClient from agent_framework.azure, pass your deployment name and endpoint, and authenticate with AzureCliCredential() (run az login first) instead of an API key. The Agent code below is otherwise identical.

# 1) Set up and install
python -m venv .venv && source .venv/bin/activate
pip install agent-framework

# 2) Provide credentials (OpenAI shown; Azure OpenAI covered below)
export OPENAI_API_KEY="sk-..."
export OPENAI_CHAT_MODEL_ID="gpt-4o-mini"

# 3) hello_agent.py — smoke test the install
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient


async def main() -> None:
    agent = Agent(
        client=OpenAIChatClient(),  # reads OPENAI_API_KEY / OPENAI_CHAT_MODEL_ID
        name="HelloAgent",
        instructions="You are a concise assistant. Keep answers to one sentence.",
    )
    result = await agent.run("What is the capital of France?")
    print(result.text)


if __name__ == "__main__":
    asyncio.run(main())

How do I build an agent with a custom tool (ChatAgent tools tutorial)?

To build an agent with the Microsoft Agent Framework that calls your own code, write a plain typed Python function, describe its parameters with Annotated and Pydantic’s Field, and pass it in the agent’s tools list, MAF generates the JSON schema and handles the tool-call round trip for you. This is the single best ergonomic decision in the framework: your type hints are the schema, so there is no manual function-calling boilerplate.

Here is a complete agent with two custom tools, a fake weather lookup and a calculator. The weather function uses Annotated type hints to give the model a parameter description. The calculator uses the optional `@tool` decorator (renamed from the older `@ai_function`) when you want to override the name or description that the model sees.

When you call `agent.run()`, the agent decides whether to invoke a tool, MAF executes your Python function locally, feeds the result back to the model, and returns the final answer in `result.text`. You never write the tool-dispatch loop yourself. This is the agent framework ChatAgent tools tutorial pattern that the official docs spread across several pages, collapsed into one runnable file.

The calculator uses eval() for brevity. In any real agent, run tool code that touches a parser or shell inside a sandbox. See our companion tutorial on building an AI agent code-execution sandbox before you give an LLM-driven tool real power.

# tool_agent.py
import asyncio
from typing import Annotated

from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
from pydantic import Field


# A plain typed function becomes a tool automatically.
def get_weather(
    location: Annotated[str, Field(description="City and country, e.g. 'Amsterdam, NL'")],
) -> str:
    """Get the current weather for a given location."""
    # In production, call a real weather API here.
    return f"The weather in {location} is cloudy with a high of 15C."


# Use @tool when you want to control the name/description the model sees.
@tool(name="calculator", description="Evaluate a basic arithmetic expression.")
def calculate(
    expression: Annotated[str, Field(description="e.g. '15 * 1.08' or '120 / 4'")],
) -> str:
    allowed = set("0123456789+-*/(). ")
    if not set(expression) <= allowed:
        return "Refused: expression contains unsupported characters."
    return str(eval(expression, {"__builtins__": {}}))  # demo only; sandbox in prod


async def main() -> None:
    agent = Agent(
        client=OpenAIChatClient(),
        name="AssistantWithTools",
        instructions="You are a helpful assistant. Use the tools when relevant.",
        tools=[get_weather, calculate],
    )
    result = await agent.run(
        "What's the weather in Amsterdam, and what is 15 times 1.08?"
    )
    print(result.text)


if __name__ == "__main__":
    asyncio.run(main())

How do I get Pydantic structured output from a Microsoft Agent Framework agent?

To get structured output, define a Pydantic BaseModel and pass it as options={“response_format”: YourModel} to agent.run(); MAF instructs the model to conform to that schema, validates the response, and returns a typed instance on result.value. This is how you turn a chatty agent into a reliable component that other code can depend on, no regex parsing, no “please respond in JSON” prompt hacks.

Structured output composes cleanly with tools. The agent below first calls the weather tool, then returns a validated `WeatherReport` object. If parsing fails, `result.value` is falsy and you can fall back to `result.text`, which is the correct way to handle the model occasionally going off-schema.

One sharp edge worth internalizing: `response_format` lives in the `options` dict, not as a top-level keyword on `run()`. Early AutoGen and Semantic Kernel muscle memory will lead you to pass it positionally and get a confusing error. Put it in `options`, every time.

# structured_agent.py
import asyncio
from typing import Annotated

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from pydantic import BaseModel, Field


def get_weather(
    location: Annotated[str, Field(description="City and country")],
) -> str:
    """Get the current weather for a given location."""
    return f"The weather in {location} is cloudy with a high of 15C."


class WeatherReport(BaseModel):
    """Structured weather summary the rest of the app can rely on."""
    location: str
    condition: str
    high_celsius: int
    bring_umbrella: bool


async def main() -> None:
    agent = Agent(
        client=OpenAIChatClient(),
        name="WeatherReporter",
        instructions="Report weather as a structured object.",
        tools=[get_weather],
    )
    result = await agent.run(
        "What's the weather in Amsterdam?",
        options={"response_format": WeatherReport},
    )
    if report := result.value:           # parsed Pydantic instance
        print(report.location, report.high_celsius, report.bring_umbrella)
        print(type(report).__name__)     # -> WeatherReport
    else:
        print("Model went off-schema:", result.text)


if __name__ == "__main__":
    asyncio.run(main())

“Your type hints are the schema and your Pydantic model is the contract. That is the whole appeal of MAF in Python in one sentence.”

Field notes from building on MAF 1.7

How do I stream the agent response asynchronously?

To stream, call agent.run(…, stream=True), which returns a ResponseStream you iterate with async for to print tokens as they arrive; when you also requested structured output, call await stream.get_final_response() afterward to get the parsed .value. This is the async streaming pattern most early tutorials get subtly wrong, so it is worth seeing it correct.

The gotcha: while streaming, individual updates carry text chunks, but the structured `value` is only available after the stream completes. You cannot deserialize half a JSON object. So you iterate for the live feel, then call `get_final_response()` to obtain the validated object. If you do not need the live tokens at all, you can skip the loop entirely and call `get_final_response()` directly, it consumes the stream for you.

A second async streaming gotcha that bites people: every `run()` is a coroutine and every stream is an async iterator, so all of this must run under `asyncio.run()` or inside an existing event loop. Mixing synchronous code that blocks the loop (a `requests` call inside a tool, say) will stall token delivery. Keep tool I/O async or offload it.

# streaming_agent.py
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from pydantic import BaseModel


class CityFacts(BaseModel):
    city: str
    fun_fact: str


async def main() -> None:
    agent = Agent(
        client=OpenAIChatClient(),
        name="CityAgent",
        instructions="Describe cities briefly.",
    )

    stream = agent.run(
        "Tell me about Tokyo, Japan.",
        stream=True,
        options={"response_format": CityFacts},
    )

    # 1) Live token feed
    async for update in stream:
        if update.text:
            print(update.text, end="", flush=True)
    print()

    # 2) Validated object, only after the stream is done
    final = await stream.get_final_response()
    if facts := final.value:
        print(f"{facts.city}: {facts.fun_fact}")


if __name__ == "__main__":
    asyncio.run(main())
Troubleshooting: ImportError on agent_framework.openaiMake sure you installed the umbrella package (pip install agent-framework), not just agent-framework-core. The core package omits provider integrations. If you only want OpenAI, pip install agent-framework-core agent-framework-openai also works.
Troubleshooting: ‘response_format’ not respected / plain text returnedConfirm response_format is inside the options dict, that your model supports structured outputs (gpt-4o / gpt-4o-mini do), and that your Pydantic model has no unsupported field types. Primitives and bare lists are not supported as a top-level schema; wrap them in a BaseModel.
Troubleshooting: agent never calls my toolTighten the function docstring and the Annotated Field descriptions, the model uses them to decide. Make the instruction explicit (‘Use the tools when relevant’). If a tool needs runtime-only data, inject it via FunctionInvocationContext rather than as a model-visible parameter.
Troubleshooting: .env values not loadingMAF does not auto-load .env. Call load_dotenv() from python-dotenv at the top of your script, or export the variables in your shell before running.
Troubleshooting: RuntimeError about the event loopDo not call asyncio.run() twice or nest it. In notebooks, await the coroutine directly in a cell (Jupyter already runs a loop) instead of wrapping it in asyncio.run().

Microsoft Agent Framework vs Semantic Kernel and AutoGen: what changed?

Microsoft Agent Framework vs Semantic Kernel and AutoGen is not a competition, MAF is the successor that absorbs both: Semantic Kernel’s enterprise plumbing and AutoGen’s agent and orchestration ideas now live in one SDK, with Microsoft positioning MAF as the path forward for both. Understanding the lineage tells you exactly how much migration pain to expect.

From Semantic Kernel, the move is gentle. Microsoft’s migration guide frames it as mostly import-path and class-name changes, the `Kernel` plus plugin model maps onto the `Agent` plus tool model, and a typical 5-to-10-plugin app is roughly a 2-to-4-hour port. If you are on SK today, there is no fire drill; migrate when you next touch the code.

From AutoGen, the move is deeper because the programming model changes. AutoGen is conversation-centric: agents exchange messages on a chat thread. MAF’s multi-agent orchestration is a typed, directed graph, executors activate when their inputs are ready, and data flows along explicit edges, conceptually closer to LangGraph than to an AutoGen group chat. AutoGen’s `AssistantAgent` maps to MAF’s agent abstractions, `FunctionTool` becomes the `@tool` decorator, and event-driven teams become graph workflows. Budget real rethinking time, not just a find-and-replace.

The table below summarizes the practical migration shape so you can size the work before committing.

DimensionSemantic Kernel (legacy)AutoGen (legacy)Microsoft Agent Framework 1.0+
Core abstractionKernel + pluginsConversation-centric agentsAgent + tools, graph workflows
Multi-agent modelLimited / manualGroup chat on a threadTyped directed-graph workflow
Tool definitionKernelFunction pluginFunctionTool wrapperPlain typed function or @tool
Enterprise featuresStrong (state, telemetry)LighterInherits SK’s, unified
Migration effort~2-4 hrs (import paths)Higher (model changes)N/A (this is the target)
StatusSuperseded by MAFSuperseded by MAF1.0 GA, April 2026, LTS
Microsoft Agent Framework vs the Semantic Kernel + AutoGen lineage it replaces
Rule of thumb: Semantic Kernel users migrate on convenience; AutoGen users migrate on a plan. The friction is the conversation-to-graph mental shift, not the API.

Is the Microsoft Agent Framework production ready, and when should you NOT use it?

Adopt MAF for multi-agent and enterprise builds; skip it for a single simple agent

After building a tool-using, structured-output, streaming agent on MAF 1.7, the verdict is clear: the framework is production-ready where it counts and the developer ergonomics around tools and structured output are excellent. Choose it when you need unified telemetry, middleware, MCP/A2A, and graph-based multi-agent orchestration in one SDK, exactly the consolidation MAF was built to deliver. For a lone agent with a couple of tools, a lighter library is the faster path. Keep the experimental Functional Workflow API out of your critical launch path until it stabilizes.

Yes, the core of the Microsoft Agent Framework is production ready: version 1.0 GA (April 2026) commits to stable APIs and long-term support, and the agent runtime, tools, structured output, and the graph-based workflow engine are all stable, but the experimental Functional Workflow API is the one piece to keep out of a critical path. “Production ready” applies to the parts you used in this tutorial; it does not blanket-bless everything in the repo.

The 1.0 sharp edges worth flagging. First, the Python Functional Workflow API, the `@workflow` and `@step` decorators that let you write workflows as plain async functions instead of graph executors, is still marked experimental in 1.0. It produces the same observable results as the stable graph API and is a nice on-ramp, but I would not anchor a launch to it yet; use the graph-based workflow API for anything load-bearing. Second, the async streaming behavior covered above (structured `value` only after `get_final_response()`, no nesting `asyncio.run()`) is a real source of bugs, treat it as a contract. Third, Python and .NET are both first-class, but specific provider integrations and hosted tools land at slightly different times across the two, so verify a given feature in the Python package rather than assuming parity from a .NET sample.

When should you NOT reach for MAF? If you need a single tool-using agent with type-safe outputs and nothing else, a lighter framework like Pydantic AI gets you there with less surface area (see our Pydantic AI review). If you are committed to LangGraph’s ecosystem for graph orchestration, MAF’s workflow engine is comparable but not a reason to switch on its own. MAF earns its weight when you want enterprise telemetry, middleware, session state, MCP/A2A interop, and multi-agent orchestration unified behind one SDK, which is precisely the gap that having Semantic Kernel and AutoGen as separate projects used to leave.

Pros
  • Stable 1.0 GA with long-term support and a single unified SDK
  • Best-in-class tools: plain typed functions become tools with zero schema boilerplate
  • Clean Pydantic structured output via options={‘response_format’: Model} -> result.value
  • Native MCP and A2A interop, plus inherited enterprise telemetry and middleware
  • Gentle migration from Semantic Kernel (mostly import paths)
Cons
  • Functional Workflow API (@workflow/@step) is still experimental in 1.0
  • Async streaming has non-obvious gotchas you must respect
  • Heavier than Pydantic AI for a single-agent use case
  • AutoGen migration requires a conversation-to-graph rethink, not a quick port
  • Python/.NET feature timing can differ; verify per package

Builder’s take

I build agent orchestration for a living at Cyntr, so I came to MAF asking one question: would I rip out my current stack to adopt it? Here is the honest read after shipping a Python agent on it.

  • The single-binary-of-SDKs promise is real: one import surface across chat clients, tools, structured output, and workflows beats juggling Semantic Kernel plus AutoGen plus glue code.
  • Tools are the best part. A plain typed Python function with an Annotated docstring just works as a tool with zero schema boilerplate, which is exactly how I wish every framework did it.
  • The graph-based workflow engine is stable and genuinely good, but the experimental Functional Workflow API is where I would not bet a production deadline yet.
  • If you are on Semantic Kernel, migrate when convenient (it is mostly import paths). If you are deep in AutoGen, budget real time, because the mental model changes from chat threads to a directed graph.
  • For a single tool-using agent, MAF is overkill versus Pydantic AI. MAF earns its weight when you need enterprise telemetry, middleware, and multi-agent orchestration in one place.

Frequently asked questions

How do I install the Microsoft Agent Framework for Python?

Create a virtual environment and run pip install agent-framework, which installs all sub-packages. For a smaller footprint, install agent-framework-core plus a specific integration such as agent-framework-openai. As of the stable 1.7.0 release (May 28, 2026) the –pre flag is no longer required; it was only needed during the 1.0 release-candidate window.

What is the difference between Agent and ChatAgent in MAF?

In the current stable Python SDK you instantiate Agent (from agent_framework) with a chat client, name, instructions, and tools. ChatAgent was the name used during the 1.0 release-candidate period and still appears in older posts; treat Agent as the canonical class for new code on 1.x.

How do I add a custom tool to a Microsoft Agent Framework agent?

Write a plain Python function with type hints, describe parameters using Annotated and Pydantic’s Field, and pass it in the agent’s tools list. MAF auto-generates the JSON schema from your signature and docstring. Use the @tool decorator (formerly @ai_function) only when you want to override the tool’s name or description.

How do I get structured JSON output from the agent?

Define a Pydantic BaseModel and pass it as options={‘response_format’: YourModel} to agent.run(). MAF instructs the model to conform to the schema, validates the result, and returns a typed instance on result.value. If parsing fails, result.value is falsy and you can fall back to result.text.

Is the Microsoft Agent Framework production ready?

Yes for its core. Version 1.0 reached GA in April 2026 with stable APIs and long-term support, and the agent runtime, tools, structured output, and graph-based workflow engine are stable. The exception is the Python Functional Workflow API (@workflow/@step decorators), which is still experimental in 1.0, so keep it out of load-bearing paths for now.

Should I migrate from Semantic Kernel or AutoGen to MAF?

From Semantic Kernel, migration is mostly import-path and class-name changes, roughly 2 to 4 hours for a typical 5-to-10-plugin app. From AutoGen it is harder because the model shifts from conversation-centric chat threads to a typed directed-graph workflow, so budget time to rethink orchestration, not just rename APIs.

Primary sources

  • Microsoft Agent Framework Version 1.0 — Microsoft DevBlogs
  • Microsoft Ships Production-Ready Agent Framework 1.0 for .NET and Python — Visual Studio Magazine
  • Step 1: Your First Agent — Microsoft Learn
  • Using function tools with an agent — Microsoft Learn
  • Producing Structured Outputs with agents — Microsoft Learn
  • AutoGen to Microsoft Agent Framework Migration Guide — Microsoft Learn
  • agent-framework on PyPI — Python Package Index
  • microsoft/agent-framework on GitHub — GitHub

Last updated: June 2, 2026. Related: Agent Infrastructure.

AI Agent Token Cost Per Task 2026: The Real Numbers
NVIDIA NeMo agent customization — the 5-stage pipeline mapped
AP2 Mandate Chain Python Tutorial: Intent to Cart to Pay
LLM Training Glossary 2026: 20 Terms Every Builder Should Know
Claude Agent SDK vs OpenAI Agents SDK vs Google ADK 2026
TAGGED:AI AgentsAutoGenAzure OpenAIMicrosoft Agent FrameworkPythonSemantic KernelTutorial
Share This Article
Facebook Email Copy Link Print
Leave a Comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

More Popular from Alatirok

Reference architecture diagram showing an AI agent calling a website's NLWeb /ask endpoint, which extracts Schema.org JSON-LD into a vector store and exposes an MCP server
Agent Infrastructure

What Is NLWeb? Microsoft’s Agentic Web Protocol Explained

By Surya Koritala
28 Min Read
What Is Cognition Devin? The Enterprise Guide for

What Is Cognition Devin? The Enterprise Guide for 2026

By Surya Koritala
An AI agent connected to a virtual credit card with a spending limit gauge, illustrating agentic commerce controls in 2026
Commerce

How to Give an AI Agent a Credit Card With a Spending Limit

By Surya Koritala
31 Min Read
Agent Infrastructure

Azure Agent Mesh Tutorial: Deploy a Federated Agent

This azure agent mesh tutorial is the first hands-on deploy: target the Mesh with Agent Framework…

By Surya Koritala
Capital

LLM Long-Context Pricing Surcharge 2026: The Cliff Mapped

Long-context pricing surcharge: The LLM long context pricing surcharge 2026 doubles your whole request the moment…

By Surya Koritala

What Is Claude Cowork? Architecture, Cost, and Limits

What is Claude Cowork? A technical, vendor-neutral guide to its sandbox architecture, real per-seat plus API…

By Surya Koritala
Commerce

Best AI Agent Marketplaces 2026: Where to Sell Agents

The best AI agent marketplaces 2026 ranked by audience, listing model, and revenue share — AgentExchange,…

By Surya Koritala

Best AI Coding CLI 2026: Claude Code vs Codex vs Antigravity

The best AI coding CLI 2026 comes down to Claude Code, Codex CLI, and Antigravity CLI.…

By Surya Koritala

what’s actually being built in AI agents, who’s building it, and why it matters. Independent. Opinionated.

Categories

  • Home
  • Products
  • Agents
  • Capital
  • Commerce

Quick Links

  • Home
  • Products
  • Agents

© Alatirok by Loomfeed. All Rights Reserved.

Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?