Python: [Feature Branch] Structured Outputs and more examples for AzureAIClient (#1987)

* Small updates

* Added support for structured outputs

* Added code interpreter example

* More examples and fixes

* Added more examples and README

* Small fix

* Addressed PR feedback
This commit is contained in:
Dmytro Struk
2025-11-07 00:17:20 -08:00
committed by GitHub
Unverified
parent 915c749e41
commit 9423c1763c
17 changed files with 3915 additions and 3461 deletions
@@ -0,0 +1,71 @@
# Azure AI Agent Examples
This folder contains examples demonstrating different ways to create and use agents with the Azure AI client from the `agent_framework.azure` package.
## Examples
| File | Description |
|------|-------------|
| [`azure_ai_basic.py`](azure_ai_basic.py) | The simplest way to create an agent using `AzureAIClient`. Demonstrates both streaming and non-streaming responses with function tools. Shows automatic agent creation and basic weather functionality. |
| [`azure_ai_use_latest_version.py`](azure_ai_use_latest_version.py) | Demonstrates how to reuse the latest version of an existing agent instead of creating a new agent version on each instantiation using the `use_latest_version=True` parameter. |
| [`azure_ai_with_code_interpreter.py`](azure_ai_with_code_interpreter.py) | Shows how to use the `HostedCodeInterpreterTool` with Azure AI agents to write and execute Python code for mathematical problem solving and data analysis. |
| [`azure_ai_with_existing_agent.py`](azure_ai_with_existing_agent.py) | Shows how to work with a pre-existing agent by providing the agent name and version to the Azure AI client. Demonstrates agent reuse patterns for production scenarios. |
| [`azure_ai_with_existing_conversation.py`](azure_ai_with_existing_conversation.py) | Shows how to work with a pre-existing conversation by providing the conversation ID to continue existing chat sessions. |
| [`azure_ai_with_explicit_settings.py`](azure_ai_with_explicit_settings.py) | Shows how to create an agent with explicitly configured `AzureAIClient` settings, including project endpoint, model deployment, and credentials rather than relying on environment variable defaults. |
| [`azure_ai_with_response_format.py`](azure_ai_with_response_format.py) | Shows how to use structured outputs (response format) with Azure AI agents using Pydantic models to enforce specific response schemas. |
| [`azure_ai_with_thread.py`](azure_ai_with_thread.py) | Demonstrates thread management with Azure AI agents, including automatic thread creation for stateless conversations and explicit thread management for maintaining conversation context across multiple interactions. |
## Environment Variables
Before running the examples, you need to set up your environment variables. You can do this in one of two ways:
### Option 1: Using a .env file (Recommended)
1. Copy the `.env.example` file from the `python` directory to create a `.env` file:
```bash
cp ../../../../.env.example ../../../../.env
```
2. Edit the `.env` file and add your values:
```env
AZURE_AI_PROJECT_ENDPOINT="your-project-endpoint"
AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
```
### Option 2: Using environment variables directly
Set the environment variables in your shell:
```bash
export AZURE_AI_PROJECT_ENDPOINT="your-project-endpoint"
export AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
```
### Required Variables
- `AZURE_AI_PROJECT_ENDPOINT`: Your Azure AI project endpoint (required for all examples)
- `AZURE_AI_MODEL_DEPLOYMENT_NAME`: The name of your model deployment (required for all examples)
## Authentication
All examples use `AzureCliCredential` for authentication by default. Before running the examples:
1. Install the Azure CLI
2. Run `az login` to authenticate with your Azure account
3. Ensure you have appropriate permissions to the Azure AI project
Alternatively, you can replace `AzureCliCredential` with other authentication options like `DefaultAzureCredential` or environment-based credentials.
## Running the Examples
Each example can be run independently. Navigate to this directory and run any example:
```bash
python azure_ai_basic.py
python azure_ai_with_code_interpreter.py
# ... etc
```
The examples demonstrate various patterns for working with Azure AI agents, from basic usage to advanced scenarios like thread management and structured outputs.
@@ -11,7 +11,7 @@ from pydantic import Field
"""
Azure AI Agent Basic Example
This sample demonstrates basic usage of AzureAIAgentClient.
This sample demonstrates basic usage of AzureAIClient.
Shows both streaming and non-streaming responses with function tools.
"""
@@ -9,10 +9,11 @@ from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Azure AI Agent Basic Example
Azure AI Agent Latest Version Example
This sample demonstrates how to reuse the latest version of an existing agent instead of creating a new agent version on each instantiation.
The first call creates a new agent, while subsequent calls with `use_latest_version=True` reuse the latest agent version.
This sample demonstrates how to reuse the latest version of an existing agent
instead of creating a new agent version on each instantiation. The first call creates a new agent,
while subsequent calls with `use_latest_version=True` reuse the latest agent version.
"""
@@ -0,0 +1,46 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework import ChatResponse, HostedCodeInterpreterTool
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
from openai.types.responses.response import Response as OpenAIResponse
from openai.types.responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall
"""
Azure AI Agent Code Interpreter Example
This sample demonstrates using HostedCodeInterpreterTool with AzureAIClient
for Python code execution and mathematical problem solving.
"""
async def main() -> None:
"""Example showing how to use the HostedCodeInterpreterTool with AzureAIClient."""
async with (
AzureCliCredential() as credential,
AzureAIClient(async_credential=credential).create_agent(
instructions="You are a helpful assistant that can write and execute Python code to solve problems.",
tools=HostedCodeInterpreterTool(),
) as agent,
):
query = "Use code to get the factorial of 100?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Result: {result}\n")
if (
isinstance(result.raw_representation, ChatResponse)
and isinstance(result.raw_representation.raw_representation, OpenAIResponse)
and len(result.raw_representation.raw_representation.output) > 0
and isinstance(result.raw_representation.raw_representation.output[0], ResponseCodeInterpreterToolCall)
):
generated_code = result.raw_representation.raw_representation.output[0].code
print(f"Generated code:\n{generated_code}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,64 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIClient
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition
from azure.identity.aio import AzureCliCredential
"""
Azure AI Agent with Existing Agent Example
This sample demonstrates working with pre-existing Azure AI Agents by providing
agent name and version, showing agent reuse patterns for production scenarios.
"""
async def main() -> None:
# Create the client
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
azure_ai_agent = await project_client.agents.create_version(
agent_name="MyNewTestAgent",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
# Setting specific requirements to verify that this agent is used.
instructions="End each response with [END].",
),
)
chat_client = AzureAIClient(
project_client=project_client,
agent_name=azure_ai_agent.name,
# Property agent_version is required for existing agents.
# If this property is not configured, the client will try to create a new agent using
# provided agent_name.
# It's also possible to leave agent_version empty but set use_latest_version=True.
# This will pull latest available agent version and use that version for operations.
agent_version=azure_ai_agent.version,
)
try:
async with ChatAgent(
chat_client=chat_client,
) as agent:
query = "How are you?"
print(f"User: {query}")
result = await agent.run(query)
# Response that indicates that previously created agent was used:
# "I'm here and ready to help you! How can I assist you today? [END]"
print(f"Agent: {result}\n")
finally:
# Clean up the agent manually
await project_client.agents.delete_version(
agent_name=azure_ai_agent.name, agent_version=azure_ai_agent.version
)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,58 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIClient
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Azure AI Agent with Existing Conversation Example
This sample demonstrates working with pre-existing conversation
by providing conversation ID for reuse patterns.
"""
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
# Create the client
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
):
openai_client = await project_client.get_openai_client() # type: ignore
# Create a conversation that will persist
created_conversation = await openai_client.conversations.create()
try:
async with ChatAgent(
chat_client=AzureAIClient(project_client=project_client),
instructions="You are a helpful weather agent.",
tools=get_weather,
store=True,
) as agent:
thread = agent.get_new_thread(service_thread_id=created_conversation.id)
assert thread.is_initialized
result = await agent.run("What's the weather like in Tokyo?", thread=thread)
print(f"Result: {result}\n")
finally:
# Clean up the conversation manually
await openai_client.conversations.delete(conversation_id=created_conversation.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,53 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Azure AI Agent with Explicit Settings Example
This sample demonstrates creating Azure AI Agents with explicit configuration
settings rather than relying on environment variable defaults.
"""
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
ChatAgent(
chat_client=AzureAIClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model_deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
async_credential=credential,
agent_name="WeatherAgent",
),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent,
):
query = "What's the weather like in New York?"
print(f"User: {query}")
result = await agent.run("What's the weather like in New York?")
print(f"Agent: {result}\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,54 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
from pydantic import BaseModel, ConfigDict
"""
Azure AI Agent Response Format Example
This sample demonstrates basic usage of AzureAIClient with response format,
also known as structured outputs.
"""
class ReleaseBrief(BaseModel):
feature: str
benefit: str
launch_date: str
model_config = ConfigDict(extra="forbid")
async def main() -> None:
"""Example of using response_format property."""
# Since no Agent ID is provided, the agent will be automatically created.
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIClient(async_credential=credential).create_agent(
name="ProductMarketerAgent",
instructions="Return launch briefs as structured JSON.",
) as agent,
):
query = "Draft a launch brief for the Contoso Note app."
print(f"User: {query}")
result = await agent.run(
query,
# Specify type to use as response
response_format=ReleaseBrief,
)
if isinstance(result.value, ReleaseBrief):
release_brief = result.value
print("Agent:")
print(f"Feature: {release_brief.feature}")
print(f"Benefit: {release_brief.benefit}")
print(f"Launch date: {release_brief.launch_date}")
if __name__ == "__main__":
asyncio.run(main())
@@ -4,7 +4,6 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread
from agent_framework.azure import AzureAIClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
@@ -13,7 +12,7 @@ from pydantic import Field
Azure AI Agent with Thread Management Example
This sample demonstrates thread management with Azure AI Agent, showing
persistent conversation context and simplified response handling.
persistent conversation capabilities using service-managed threads as well as storing messages in-memory.
"""
@@ -131,7 +130,7 @@ async def example_with_existing_thread_id() -> None:
) as agent,
):
# Create a thread with the existing ID
thread = AgentThread(service_thread_id=existing_thread_id)
thread = agent.get_new_thread(service_thread_id=existing_thread_id)
query2 = "What was the last city I asked about?"
print(f"User: {query2}")
@@ -49,7 +49,7 @@ async def main() -> None:
break
# 1. Create Azure AI agent with the search tool
azure_ai_agent = await project_client.agents.create_agent(
azure_ai_agent = await agents_client.create_agent(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
name="HotelSearchAgent",
instructions=(
@@ -114,7 +114,7 @@ async def main() -> None:
finally:
# Clean up the agent manually
await project_client.agents.delete_agent(azure_ai_agent.id)
await agents_client.delete_agent(azure_ai_agent.id)
if __name__ == "__main__":
@@ -6,7 +6,6 @@ import os
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIAgentClient
from azure.ai.agents.aio import AgentsClient
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
"""
@@ -23,10 +22,9 @@ async def main() -> None:
# Create the client
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
):
azure_ai_agent = await project_client.agents.create_agent(
azure_ai_agent = await agents_client.create_agent(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
# Create remote agent with default instructions
# These instructions will persist on created agent for every run.
@@ -52,7 +50,7 @@ async def main() -> None:
print(f"Agent: {result}\n")
finally:
# Clean up the agent manually
await project_client.agents.delete_agent(azure_ai_agent.id)
await agents_client.delete_agent(azure_ai_agent.id)
if __name__ == "__main__":
@@ -33,12 +33,10 @@ async def main() -> None:
pdf_file_path = Path(__file__).parent.parent / "resources" / "employees.pdf"
print(f"Uploading file from: {pdf_file_path}")
file = await client.project_client.agents.files.upload_and_poll(
file_path=str(pdf_file_path), purpose="assistants"
)
file = await client.agents_client.files.upload_and_poll(file_path=str(pdf_file_path), purpose="assistants")
print(f"Uploaded file, file ID: {file.id}")
vector_store = await client.project_client.agents.vector_stores.create_and_poll(
vector_store = await client.agents_client.vector_stores.create_and_poll(
file_ids=[file.id], name="my_vectorstore"
)
print(f"Created vector store, vector store ID: {vector_store.id}")
@@ -66,9 +64,9 @@ async def main() -> None:
# 5. Cleanup: Delete the vector store and file
try:
if vector_store:
await client.project_client.agents.vector_stores.delete(vector_store.id)
await client.agents_client.vector_stores.delete(vector_store.id)
if file:
await client.project_client.agents.files.delete(file.id)
await client.agents_client.files.delete(file.id)
except Exception:
# Ignore cleanup errors to avoid masking issues
pass
@@ -79,9 +77,9 @@ async def main() -> None:
client = AzureAIAgentClient(async_credential=AzureCliCredential())
try:
if vector_store:
await client.project_client.agents.vector_stores.delete(vector_store.id)
await client.agents_client.vector_stores.delete(vector_store.id)
if file:
await client.project_client.agents.files.delete(file.id)
await client.agents_client.files.delete(file.id)
except Exception:
# Ignore cleanup errors to avoid masking issues
pass