Agent Framework Azure AI Py
MicrosoftOfficialCreated by Microsoft
- Skill
- Tool integration
- Data and AI
- MIT
- Low risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The agent-framework-azure-ai SDK provides a Python interface for creating and managing persistent agents within the Azure AI Foundry ecosystem. It supports conversation thread management, streaming responses, and the integration of various tools including hosted code interpreters, file search, web search, and Model Context Protocol (MCP) servers. The framework emphasizes an async-first architecture and secure authentication via DefaultAzureCredential.
What it does
- Creates and manages persistent agents on Azure AI Foundry.
- Supports function-based tools and hosted tools like code interpreters and web search.
- Integrates MCP servers through both service-managed and client-managed patterns.
- Handles conversation persistence using thread management.
- Enables structured outputs using Pydantic models.
- Provides streaming support for agent responses.
When to use it
- When building AI agents that require persistent state across multiple conversation turns.
- When integrating external tools or MCP servers into an Azure-hosted agent.
- When requiring structured data responses from an agent using Pydantic.
- When implementing streaming interfaces for agent interactions.
Advantages
- Native support for Azure identity and authentication standards.
- Flexible tool integration including custom functions and MCP servers.
- Built-in support for conversation threading and state management.
- Strong typing for agent outputs via Pydantic integration.
Usage examples
- “How do I create a basic agent using the Azure AI Agents Provider?”
- The agent is initialized using the AzureAIAgentsProvider within an async context manager, allowing for the creation of an agent with custom instructions and execution of queries.
- “How can I add a weather function to my agent?”
- Define a Python function with type annotations and pass it directly to the tools parameter when creating the agent via the provider.
- “How do I maintain conversation context between turns?”
- Use the get_new_thread method to create a thread object, then pass this thread to the agent's run method for each subsequent turn.
- “How do I enforce a specific output format for my agent?”
- Define a Pydantic model and pass it to the response_format parameter during agent creation or at runtime to receive structured JSON responses.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/agent-framework-azure-ai-py/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip agent-framework-azure-ai-py.zip -d .agents/skills
Documentation by Microsoft
Agent Framework Azure Hosted Agents
Build persistent agents on Azure AI Foundry using the Microsoft Agent Framework Python SDK.
Architecture
User Query → AzureAIAgentsProvider → Azure AI Agent Service (Persistent)
↓
Agent.run() / Agent.run_stream()
↓
Tools: Functions | Hosted (Code/Search/Web) | MCP
↓
AgentThread (conversation persistence)Installation
# Full framework (recommended)
pip install agent-framework --pre
# Or Azure-specific package only
pip install agent-framework-azure-ai --preEnvironment Variables
export AZURE_AI_PROJECT_ENDPOINT="https://<project>.services.ai.azure.com/api/projects/<project-id>" # Required for all auth methods
export AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini" # Required for all auth methods
export BING_CONNECTION_ID="your-bing-connection-id" # For web search
export AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in productionAuthentication & Lifecycle
🔑 Two rules apply to every code sample below:
Prefer
DefaultAzureCredential. It works locally (Azure CLI / VS Code / Developer CLI) and in Azure (managed identity, workload identity) with no code change. Avoid connection strings, account/API keys — they bypass Entra audit and rotation.
Local dev:
DefaultAzureCredentialworks as-is.Production: set
AZURE_TOKEN_CREDENTIALS=prod(orAZURE_TOKEN_CREDENTIALS=<specific_credential>) to constrain the credential chain to production-safe credentials.Wrap every client in a context manager so HTTP transports, sockets, and token caches are released deterministically:
Sync:
with <Client>(...) as client:Async:
async with <Client>(...) as client:andasync with DefaultAzureCredential() as credential:(fromazure.identity.aio)Snippets may abbreviate this setup, but production code should always follow both rules.
from azure.identity.aio import AzureCliCredential, DefaultAzureCredential, ManagedIdentityCredential
# Development
credential = AzureCliCredential()
# Production
# Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
credential = DefaultAzureCredential(require_envvar=True)
# Or use a specific credential directly in production:
# See https://learn.microsoft.com/python/api/overview/azure/identity-readme?view=azure-python#credential-classes
# credential = ManagedIdentityCredential()Core Workflow
Basic Agent
import asyncio
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MyAgent",
instructions="You are a helpful assistant.",
)
result = await agent.run("Hello!")
print(result.text)
asyncio.run(main())Agent with Function Tools
from typing import Annotated
from pydantic import Field
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
def get_weather(
location: Annotated[str, Field(description="City name to get weather for")],
) -> str:
"""Get the current weather for a location."""
return f"Weather in {location}: 72°F, sunny"
def get_current_time() -> str:
"""Get the current UTC time."""
from datetime import datetime, timezone
return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="WeatherAgent",
instructions="You help with weather and time queries.",
tools=[get_weather, get_current_time], # Pass functions directly
)
result = await agent.run("What's the weather in Seattle?")
print(result.text)Agent with Hosted Tools
from agent_framework import (
HostedCodeInterpreterTool,
HostedFileSearchTool,
HostedWebSearchTool,
)
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MultiToolAgent",
instructions="You can execute code, search files, and search the web.",
tools=[
HostedCodeInterpreterTool(),
HostedWebSearchTool(name="Bing"),
],
)
result = await agent.run("Calculate the factorial of 20 in Python")
print(result.text)Streaming Responses
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="StreamingAgent",
instructions="You are a helpful assistant.",
)
print("Agent: ", end="", flush=True)
async for chunk in agent.run_stream("Tell me a short story"):
if chunk.text:
print(chunk.text, end="", flush=True)
print()Conversation Threads
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ChatAgent",
instructions="You are a helpful assistant.",
tools=[get_weather],
)
# Create thread for conversation persistence
thread = agent.get_new_thread()
# First turn
result1 = await agent.run("What's the weather in Seattle?", thread=thread)
print(f"Agent: {result1.text}")
# Second turn - context is maintained
result2 = await agent.run("What about Portland?", thread=thread)
print(f"Agent: {result2.text}")
# Save thread ID for later resumption
print(f"Conversation ID: {thread.conversation_id}")Structured Outputs
from pydantic import BaseModel, ConfigDict
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
class WeatherResponse(BaseModel):
model_config = ConfigDict(extra="forbid")
location: str
temperature: float
unit: str
conditions: str
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="StructuredAgent",
instructions="Provide weather information in structured format.",
response_format=WeatherResponse,
)
result = await agent.run("Weather in Seattle?")
weather = WeatherResponse.model_validate_json(result.text)
print(f"{weather.location}: {weather.temperature}°{weather.unit}")Provider Methods
| Method | Description |
|---|---|
create_agent() | Create new agent on Azure AI service |
get_agent(agent_id) | Retrieve existing agent by ID |
as_agent(sdk_agent) | Wrap SDK Agent object (no HTTP call) |
Hosted Tools Quick Reference
| Tool | Import | Purpose |
|---|---|---|
HostedCodeInterpreterTool | from agent_framework import HostedCodeInterpreterTool | Execute Python code |
HostedFileSearchTool | from agent_framework import HostedFileSearchTool | Search vector stores |
HostedWebSearchTool | from agent_framework import HostedWebSearchTool | Bing web search |
HostedMCPTool | from agent_framework import HostedMCPTool | Service-managed MCP |
MCPStreamableHTTPTool | from agent_framework import MCPStreamableHTTPTool | Client-managed MCP |
Complete Example
import asyncio
from typing import Annotated
from pydantic import BaseModel, Field
from agent_framework import (
HostedCodeInterpreterTool,
HostedWebSearchTool,
MCPStreamableHTTPTool,
)
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
def get_weather(
location: Annotated[str, Field(description="City name")],
) -> str:
"""Get weather for a location."""
return f"Weather in {location}: 72°F, sunny"
class AnalysisResult(BaseModel):
summary: str
key_findings: list[str]
confidence: float
async def main():
async with (
AzureCliCredential() as credential,
MCPStreamableHTTPTool(
name="Docs MCP",
url="https://learn.microsoft.com/api/mcp",
) as mcp_tool,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ResearchAssistant",
instructions="You are a research assistant with multiple capabilities.",
tools=[
get_weather,
HostedCodeInterpreterTool(),
HostedWebSearchTool(name="Bing"),
mcp_tool,
],
)
thread = agent.get_new_thread()
# Non-streaming
result = await agent.run(
"Search for Python best practices and summarize",
thread=thread,
)
print(f"Response: {result.text}")
# Streaming
print("\nStreaming: ", end="")
async for chunk in agent.run_stream("Continue with examples", thread=thread):
if chunk.text:
print(chunk.text, end="", flush=True)
print()
# Structured output
result = await agent.run(
"Analyze findings",
thread=thread,
response_format=AnalysisResult,
)
analysis = AnalysisResult.model_validate_json(result.text)
print(f"\nConfidence: {analysis.confidence}")
if __name__ == "__main__":
asyncio.run(main())Conventions
Always use async context managers:
async with provider:Pass functions directly to
tools=parameter (auto-converted to AIFunction)Use
Annotated[type, Field(description=...)]for function parametersUse
get_new_thread()for multi-turn conversationsPrefer
HostedMCPToolfor service-managed MCP,MCPStreamableHTTPToolfor client-managed
Best Practices
This SDK is async-first — use
async defhandlers andasync withthroughout.Always use context managers for clients and async credentials. Wrap every client in
with Client(...) as client:(sync) orasync with Client(...) as client:(async). For asyncDefaultAzureCredentialfromazure.identity.aio, also useasync with credential:so tokens and transports are cleaned up.
Reference Files
references/tools.md: Detailed hosted tool patterns
references/mcp.md: MCP integration (hosted + local)
references/threads.md: Thread and conversation management
references/advanced.md: OpenAPI, citations, structured outputs
Files
- ATTRIBUTION.mdAdded by AutoGineer992 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md12.0 KiB
- references/advanced.md13.0 KiB
- references/mcp.md7.6 KiB
- references/threads.md7.7 KiB
- references/tools.md7.3 KiB
references/threads.md
Thread Management Reference
Patterns for managing conversation state and multi-turn interactions.
Overview
AgentThread links agent execution to server-side conversation state, enabling:
Multi-turn conversations with context
Conversation persistence and resumption
Thread-based message history
Creating and Using Threads
Basic Multi-Turn Conversation
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ChatAgent",
instructions="You are a helpful assistant.",
)
# Create a new thread for the conversation
thread = agent.get_new_thread()
# First turn
result1 = await agent.run("My name is Alice", thread=thread)
print(f"Agent: {result1.text}")
# Second turn - agent remembers the name
result2 = await agent.run("What's my name?", thread=thread)
print(f"Agent: {result2.text}")
# Third turn - context continues
result3 = await agent.run("Tell me a joke about my name", thread=thread)
print(f"Agent: {result3.text}")Accessing Thread Information
thread = agent.get_new_thread()
# Run a conversation
await agent.run("Hello!", thread=thread)
# Access the conversation ID for persistence
print(f"Conversation ID: {thread.conversation_id}")
# Thread also tracks service-side thread ID (for Azure AI agents)
print(f"Service Thread ID: {thread.service_thread_id}")Conversation Persistence
Saving Thread ID
import json
async def save_conversation(thread, filepath: str):
"""Save thread ID for later resumption."""
data = {
"conversation_id": thread.conversation_id,
"service_thread_id": thread.service_thread_id,
}
with open(filepath, "w") as f:
json.dump(data, f)
# Usage
thread = agent.get_new_thread()
await agent.run("Start a conversation", thread=thread)
await save_conversation(thread, "conversation.json")Resuming Conversations
For Azure AI agents with persistent server-side threads, you can resume conversations:
import json
from agent_framework import AgentThread
async def load_and_resume(provider, agent_id: str, filepath: str):
"""Resume a previous conversation."""
with open(filepath) as f:
data = json.load(f)
# Get the existing agent
agent = await provider.get_agent(agent_id=agent_id)
# Create thread with existing service thread ID
thread = AgentThread(service_thread_id=data["service_thread_id"])
# Continue the conversation
result = await agent.run("Continue our conversation", thread=thread)
return resultThread with Streaming
Threads work the same way with streaming responses:
thread = agent.get_new_thread()
# First turn - streaming
print("Agent: ", end="", flush=True)
async for chunk in agent.run_stream("Tell me about Python", thread=thread):
if chunk.text:
print(chunk.text, end="", flush=True)
print()
# Second turn - non-streaming (context maintained)
result = await agent.run("What was that language again?", thread=thread)
print(f"Agent: {result.text}")
# Third turn - streaming again
print("Agent: ", end="", flush=True)
async for chunk in agent.run_stream("Give me a code example", thread=thread):
if chunk.text:
print(chunk.text, end="", flush=True)
print()Thread with Tools
Tools work seamlessly within threaded conversations:
from typing import Annotated
from pydantic import Field
def search_database(
query: Annotated[str, Field(description="Search query")]
) -> str:
"""Search the database for information."""
return f"Results for '{query}': Item A, Item B, Item C"
def get_item_details(
item_name: Annotated[str, Field(description="Name of the item")]
) -> str:
"""Get details for a specific item."""
return f"Details for {item_name}: Price $99, In Stock: Yes"
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="ShoppingAgent",
instructions="Help users find and learn about products.",
tools=[search_database, get_item_details],
)
thread = agent.get_new_thread()
# Turn 1: Search
result1 = await agent.run("Search for laptops", thread=thread)
print(f"Agent: {result1.text}")
# Turn 2: Follow-up (context aware)
result2 = await agent.run("Tell me more about Item A", thread=thread)
print(f"Agent: {result2.text}")
# Turn 3: Another follow-up
result3 = await agent.run("Is it available?", thread=thread)
print(f"Agent: {result3.text}")Multiple Parallel Conversations
Handle multiple users/conversations simultaneously:
async def handle_user_session(provider, user_id: str, messages: list[str]):
"""Handle a single user's conversation."""
agent = await provider.create_agent(
name=f"Agent-{user_id}",
instructions="You are a helpful assistant.",
)
# Each user gets their own thread
thread = agent.get_new_thread()
for message in messages:
result = await agent.run(message, thread=thread)
print(f"[{user_id}] User: {message}")
print(f"[{user_id}] Agent: {result.text}")
# Handle multiple users concurrently
import asyncio
async def main():
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
await asyncio.gather(
handle_user_session(provider, "user1", ["Hello", "What's 2+2?"]),
handle_user_session(provider, "user2", ["Hi there", "Tell me a joke"]),
handle_user_session(provider, "user3", ["Good morning", "Weather today?"]),
)Thread Best Practices
Do's
# ✅ Create a new thread for each logical conversation
thread = agent.get_new_thread()
# ✅ Pass the same thread to maintain context
await agent.run("Message 1", thread=thread)
await agent.run("Message 2", thread=thread)
# ✅ Save thread IDs for conversations that need resumption
conversation_id = thread.conversation_idDon'ts
# ❌ Don't create a new thread for each message (loses context)
for msg in messages:
thread = agent.get_new_thread() # Wrong!
await agent.run(msg, thread=thread)
# ❌ Don't share threads between different agents
agent1_thread = agent1.get_new_thread()
await agent2.run("Hello", thread=agent1_thread) # May cause issues
# ❌ Don't forget to pass the thread (single-turn only)
await agent.run("Message 1") # No thread - no context saved
await agent.run("Message 2") # Can't reference previous messageThread Lifecycle
1. agent.get_new_thread()
└── Creates new AgentThread object
└── Server-side thread created on first run
2. agent.run(..., thread=thread)
└── Message added to thread
└── Agent response added to thread
└── Context accumulated
3. (Optional) Save thread.conversation_id
└── For later resumption
4. (Optional) Resume with AgentThread(service_thread_id=...)
└── Continues existing conversationStateless vs Stateful Patterns
Stateless (No Thread)
Each call is independent:
# Good for one-shot queries
result = await agent.run("What is 2+2?")Stateful (With Thread)
Context persists across calls:
# Good for conversations
thread = agent.get_new_thread()
result1 = await agent.run("My favorite color is blue", thread=thread)
result2 = await agent.run("What's my favorite color?", thread=thread) # Knows it's blueRequirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key, Needs Python
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/skills · .github/plugins/azure-sdk-python/skills/agent-framework-azure-ai-py · commit 0696600
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Microsoft.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download agent-framework-azure-ai-py.zip