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/advanced.md
Advanced Patterns Reference
Advanced patterns including structured outputs, OpenAPI tools, file handling, and more.
Structured Outputs with Pydantic
Basic Response Format
from pydantic import BaseModel, ConfigDict
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
class MovieRecommendation(BaseModel):
model_config = ConfigDict(extra="forbid") # Strict validation
title: str
year: int
genre: str
rating: float
summary: str
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="MovieAgent",
instructions="Recommend movies based on user preferences.",
response_format=MovieRecommendation, # Set at creation
)
result = await agent.run("Recommend a sci-fi movie")
movie = MovieRecommendation.model_validate_json(result.text)
print(f"{movie.title} ({movie.year}) - {movie.rating}/10")Complex Nested Structures
from pydantic import BaseModel, ConfigDict, Field
from typing import Optional
class Address(BaseModel):
model_config = ConfigDict(extra="forbid")
street: str
city: str
country: str
postal_code: Optional[str] = None
class Person(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str
age: int
email: str
address: Address
hobbies: list[str] = Field(default_factory=list)
class TeamResponse(BaseModel):
model_config = ConfigDict(extra="forbid")
team_name: str
members: list[Person]
total_members: int
agent = await provider.create_agent(
name="TeamGenerator",
instructions="Generate fictional team data.",
response_format=TeamResponse,
)
result = await agent.run("Create a team of 3 software developers")
team = TeamResponse.model_validate_json(result.text)
for member in team.members:
print(f"- {member.name}, {member.age}, {member.address.city}")Runtime Response Format Override
class QuickAnswer(BaseModel):
answer: str
confidence: float
class DetailedAnalysis(BaseModel):
summary: str
key_points: list[str]
recommendations: list[str]
sources: list[str]
# Agent created without default response format
agent = await provider.create_agent(
name="FlexibleAgent",
instructions="Provide information in the requested format.",
)
# Quick answer format
quick_result = await agent.run(
"What is Python?",
response_format=QuickAnswer,
)
# Detailed analysis format (same agent)
detailed_result = await agent.run(
"Analyze the benefits of microservices architecture",
response_format=DetailedAnalysis,
)OpenAPI Tools
Integrate external APIs using OpenAPI specifications.
Basic OpenAPI Integration
from agent_framework import OpenAPITool
from agent_framework.azure import AzureAIAgentsProvider
from azure.identity.aio import AzureCliCredential
# OpenAPI spec can be URL or inline dict
openapi_spec = {
"openapi": "3.0.0",
"info": {"title": "Weather API", "version": "1.0.0"},
"paths": {
"/weather/{city}": {
"get": {
"operationId": "getWeather",
"summary": "Get weather for a city",
"parameters": [
{
"name": "city",
"in": "path",
"required": True,
"schema": {"type": "string"}
}
],
"responses": {
"200": {
"description": "Weather data",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"temperature": {"type": "number"},
"conditions": {"type": "string"}
}
}
}
}
}
}
}
}
}
}
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
agent = await provider.create_agent(
name="WeatherAPIAgent",
instructions="Use the weather API to answer weather questions.",
tools=OpenAPITool(
name="WeatherAPI",
spec=openapi_spec,
base_url="https://api.weather.example.com",
),
)OpenAPI with Authentication
from agent_framework import OpenAPITool
openapi_tool = OpenAPITool(
name="SecureAPI",
spec="https://api.example.com/openapi.json",
base_url="https://api.example.com",
headers={
"Authorization": "Bearer your-api-key",
"X-API-Version": "2024-01",
},
)File Generation and Handling
Code Interpreter File Output
from agent_framework import HostedCodeInterpreterTool
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="DataAnalyst",
instructions="Analyze data and create visualizations.",
tools=HostedCodeInterpreterTool(),
)
result = await agent.run(
"Create a bar chart of sales data: Q1=100, Q2=150, Q3=120, Q4=200. Save as PNG."
)
# Check for generated files in the response
print(result.text)
# Files generated by code interpreter are typically referenced in the response
# and can be downloaded via the files APIWorking with File IDs
from azure.ai.agents.aio import AgentsClient
async with (
AzureCliCredential() as credential,
AgentsClient(endpoint=endpoint, credential=credential) as agents_client,
AzureAIAgentsProvider(agents_client=agents_client) as provider,
):
# Upload a file
from pathlib import Path
file = await agents_client.files.upload(
file_path=Path("data/sales.csv"),
purpose="agents"
)
print(f"Uploaded file ID: {file.id}")
# Use file with code interpreter
from agent_framework import HostedCodeInterpreterTool, HostedFileContent
agent = await provider.create_agent(
name="CSVAnalyst",
instructions="Analyze the provided CSV file.",
tools=HostedCodeInterpreterTool(
inputs=[HostedFileContent(file_id=file.id)]
),
)
result = await agent.run("Summarize the data in the uploaded file")Citations and Source Attribution
Enabling Citations
agent = await provider.create_agent(
name="ResearchAgent",
instructions="""Answer questions using the knowledge base.
IMPORTANT: Always cite your sources using this format:
【message_idx:search_idx†source_name】
Example: "Azure Functions supports Python【1:0†azure-docs】"
""",
tools=[
HostedFileSearchTool(inputs=[...]),
],
)Parsing Citations
import re
def parse_citations(text: str) -> list[dict]:
"""Extract citations from agent response."""
pattern = r'【(\d+):(\d+)†([^】]+)】'
citations = []
for match in re.finditer(pattern, text):
citations.append({
"message_idx": int(match.group(1)),
"search_idx": int(match.group(2)),
"source": match.group(3),
})
return citations
result = await agent.run("What is Azure Functions?")
citations = parse_citations(result.text)
for cite in citations:
print(f"Source: {cite['source']}")Provider Configuration Options
Custom Model and Endpoint
from agent_framework.azure import AzureAIAgentsProvider
provider = AzureAIAgentsProvider(
credential=credential,
project_endpoint="https://my-project.services.ai.azure.com/api/projects/my-project-id",
model_deployment_name="gpt-4o", # Override default model
)Using Existing AgentsClient
from azure.ai.agents.aio import AgentsClient
from agent_framework.azure import AzureAIAgentsProvider
# Create and configure client separately
agents_client = AgentsClient(
endpoint=endpoint,
credential=credential,
)
# Pass to provider
provider = AzureAIAgentsProvider(agents_client=agents_client)Agent Lifecycle Management
Retrieving Existing Agents
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
# Create agent and save ID
agent = await provider.create_agent(
name="PersistentAgent",
instructions="You remember everything.",
)
agent_id = agent.id # Save this
# Later: retrieve the same agent
same_agent = await provider.get_agent(agent_id=agent_id)Wrapping SDK Agents
from azure.ai.agents.aio import AgentsClient
async with (
AzureCliCredential() as credential,
AgentsClient(endpoint=endpoint, credential=credential) as agents_client,
AzureAIAgentsProvider(agents_client=agents_client) as provider,
):
# Get agent via SDK
sdk_agent = await agents_client.get_agent("agent-id")
# Wrap as ChatAgent (no HTTP call)
agent = provider.as_agent(sdk_agent)
# Now use with agent framework
result = await agent.run("Hello!")Error Handling Patterns
Graceful Degradation
from agent_framework import HostedWebSearchTool, HostedCodeInterpreterTool
async def run_with_fallback(agent, query: str, thread=None):
"""Run query with fallback on tool failures."""
try:
result = await agent.run(query, thread=thread)
return result.text
except Exception as e:
# Log the error
print(f"Tool execution error: {e}")
# Create fallback agent without tools
fallback_agent = await provider.create_agent(
name="FallbackAgent",
instructions="Answer based on your knowledge only.",
)
result = await fallback_agent.run(query)
return f"[Fallback response] {result.text}"Retry Logic
import asyncio
from typing import Optional
async def run_with_retry(
agent,
query: str,
thread=None,
max_retries: int = 3,
delay: float = 1.0,
) -> Optional[str]:
"""Run query with exponential backoff retry."""
for attempt in range(max_retries):
try:
result = await agent.run(query, thread=thread)
return result.text
except Exception as e:
if attempt == max_retries - 1:
raise
wait_time = delay * (2 ** attempt)
print(f"Attempt {attempt + 1} failed, retrying in {wait_time}s: {e}")
await asyncio.sleep(wait_time)
return NonePerformance Optimization
Connection Reuse
# ✅ Good: Reuse provider and client
async with (
AzureCliCredential() as credential,
AzureAIAgentsProvider(credential=credential) as provider,
):
# Create multiple agents with same provider
agent1 = await provider.create_agent(name="Agent1", instructions="...")
agent2 = await provider.create_agent(name="Agent2", instructions="...")
# Process multiple requests
for query in queries:
await agent1.run(query)
# ❌ Bad: Creating new provider for each request
for query in queries:
async with AzureAIAgentsProvider(credential=credential) as provider:
agent = await provider.create_agent(...)
await agent.run(query)Concurrent Requests
import asyncio
async def process_queries(provider, queries: list[str]) -> list[str]:
"""Process multiple queries concurrently."""
agent = await provider.create_agent(
name="BatchAgent",
instructions="Answer questions concisely.",
)
# Each query gets its own thread
async def process_one(query: str) -> str:
thread = agent.get_new_thread()
result = await agent.run(query, thread=thread)
return result.text
results = await asyncio.gather(*[process_one(q) for q in queries])
return resultsDebugging and Logging
Enable Verbose Logging
import logging
# Enable Azure SDK logging
logging.basicConfig(level=logging.DEBUG)
azure_logger = logging.getLogger("azure")
azure_logger.setLevel(logging.DEBUG)
# Enable agent framework logging
af_logger = logging.getLogger("agent_framework")
af_logger.setLevel(logging.DEBUG)Inspecting Tool Calls in Streaming
from agent_framework import AgentResponseUpdate
async for chunk in agent.run_stream("Calculate something"):
if isinstance(chunk, AgentResponseUpdate):
if chunk.tool_calls:
for tool_call in chunk.tool_calls:
print(f"[DEBUG] Tool: {tool_call.name}")
print(f"[DEBUG] Args: {tool_call.arguments}")
if chunk.text:
print(chunk.text, end="", flush=True)Requirements 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