Python: [BREAKING] Python: move Azure AI embeddings to Foundry (#5056)

* renamed AzureAIINferenceEmbeddings and lazy load azure-cosmos and env var rename

* updated coverage

* fix readme
This commit is contained in:
Eduard van Valkenburg
2026-04-02 13:26:35 +02:00
committed by GitHub
Unverified
parent 47d82911c0
commit 95fd5ec658
74 changed files with 403 additions and 978 deletions
@@ -61,8 +61,8 @@ Depending on the selected client, set the appropriate environment variables:
**For OpenAI clients:**
- `OPENAI_API_KEY`: Your OpenAI API key
- `OPENAI_CHAT_MODEL`: The OpenAI model for `openai_chat_completion`
- `OPENAI_RESPONSES_MODEL`: The OpenAI model for `openai_responses`
- `OPENAI_CHAT_COMPLETION_MODEL`: The OpenAI model for `openai_chat_completion`
- `OPENAI_CHAT_MODEL`: The OpenAI model for `openai_responses`
**For Anthropic client (`anthropic`):**
- `ANTHROPIC_API_KEY`: Your Anthropic API key
@@ -8,6 +8,7 @@ These samples demonstrate different approaches to managing conversation history
|------|-------------|
| [`suspend_resume_session.py`](suspend_resume_session.py) | Suspend and resume conversation sessions, comparing service-managed sessions (Azure AI Foundry) with in-memory sessions (OpenAI). |
| [`custom_history_provider.py`](custom_history_provider.py) | Implement a custom history provider by extending `BaseHistoryProvider`, enabling conversation persistence in your preferred storage backend. |
| [`cosmos_history_provider.py`](cosmos_history_provider.py) | Use Azure Cosmos DB as a history provider for durable conversation storage with `CosmosHistoryProvider`. |
| [`redis_history_provider.py`](redis_history_provider.py) | Use Redis as a history provider for persistent conversation history storage across sessions. |
## Prerequisites
@@ -21,6 +22,14 @@ These samples demonstrate different approaches to managing conversation history
**For `custom_history_provider.py`:**
- `OPENAI_API_KEY`: Your OpenAI API key
**For `cosmos_history_provider.py`:**
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
- `FOUNDRY_MODEL`: The Foundry model deployment name
- `AZURE_COSMOS_ENDPOINT`: Your Azure Cosmos DB account endpoint
- `AZURE_COSMOS_DATABASE_NAME`: The database that stores conversation history
- `AZURE_COSMOS_CONTAINER_NAME`: The container that stores conversation history
- Either `AZURE_COSMOS_KEY` or Azure CLI authentication (`az login`)
**For `redis_history_provider.py`:**
- `OPENAI_API_KEY`: Your OpenAI API key
- A running Redis server — default URL is `redis://localhost:6379`
@@ -0,0 +1,98 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import Agent
from agent_framework.azure import CosmosHistoryProvider
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file.
load_dotenv()
"""
This sample demonstrates CosmosHistoryProvider as an agent history provider.
Key components:
- FoundryChatClient configured with an Azure AI project endpoint
- CosmosHistoryProvider configured for Cosmos DB-backed message history
- Provider-configured container name with session_id as partition key
Environment variables:
FOUNDRY_PROJECT_ENDPOINT
FOUNDRY_MODEL
AZURE_COSMOS_ENDPOINT
AZURE_COSMOS_DATABASE_NAME
AZURE_COSMOS_CONTAINER_NAME
Optional:
AZURE_COSMOS_KEY
"""
async def main() -> None:
"""Run the Cosmos history provider sample with an Agent."""
project_endpoint = os.getenv("FOUNDRY_PROJECT_ENDPOINT")
model = os.getenv("FOUNDRY_MODEL")
cosmos_endpoint = os.getenv("AZURE_COSMOS_ENDPOINT")
cosmos_database_name = os.getenv("AZURE_COSMOS_DATABASE_NAME")
cosmos_container_name = os.getenv("AZURE_COSMOS_CONTAINER_NAME")
cosmos_key = os.getenv("AZURE_COSMOS_KEY")
if (
not project_endpoint
or not model
or not cosmos_endpoint
or not cosmos_database_name
or not cosmos_container_name
):
print(
"Please set FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL, "
"AZURE_COSMOS_ENDPOINT, AZURE_COSMOS_DATABASE_NAME, and AZURE_COSMOS_CONTAINER_NAME."
)
return
# 1. Create an Azure credential and a CosmosHistoryProvider for agent context
async with (
AzureCliCredential() as credential,
CosmosHistoryProvider(
endpoint=cosmos_endpoint,
database_name=cosmos_database_name,
container_name=cosmos_container_name,
credential=cosmos_key or credential,
) as history_provider,
# 2. Create an agent that uses Cosmos for persisted conversation history.
Agent(
client=FoundryChatClient(
project_endpoint=project_endpoint,
model=model,
credential=credential,
),
name="CosmosHistoryAgent",
instructions="You are a helpful assistant that remembers prior turns.",
context_providers=[history_provider],
default_options={"store": False},
) as agent,
):
# 3. Create a session (session_id is used as the partition key).
session = agent.create_session()
# 4. Run a multi-turn conversation; history is persisted by CosmosHistoryProvider.
response1 = await agent.run("My name is Ada and I enjoy distributed systems.", session=session)
print(f"Assistant: {response1.text}")
response2 = await agent.run("What do you remember about me?", session=session)
print(f"Assistant: {response2.text}")
print(f"Container: {history_provider.container_name}")
if __name__ == "__main__":
asyncio.run(main())
"""
Sample output:
Assistant: Nice to meet you, Ada! Distributed systems are a fascinating area.
Assistant: You told me your name is Ada and that you enjoy distributed systems.
Container: <AZURE_COSMOS_CONTAINER_NAME>
"""
+1 -1
View File
@@ -8,7 +8,7 @@ FOUNDRY_MODEL=gpt-4o
# Azure OpenAI workflow sample
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
AZURE_OPENAI_RESPONSES_MODEL=gpt-4o
AZURE_OPENAI_CHAT_MODEL=gpt-4o
# Optional fallback env name also supported by workflow_with_agents/workflow.py:
AZURE_OPENAI_MODEL=gpt-4o
# Optional if you need to override the default API version:
+2 -2
View File
@@ -94,7 +94,7 @@ workflow_name/
| Sample | What it demonstrates | Required keys / auth |
| ------ | -------------------- | -------------------- |
| [**workflow_declarative/**](workflow_declarative/) | A YAML-defined workflow loaded through `WorkflowFactory`, with nested age-based branching and no model client code. | None |
| [**workflow_with_agents/**](workflow_with_agents/) | A content review workflow that uses agents as executors and routes based on structured review output (`Writer -> Reviewer -> Editor/Publisher -> Summarizer`). | `AZURE_OPENAI_ENDPOINT`, plus `AZURE_OPENAI_RESPONSES_MODEL` or `AZURE_OPENAI_MODEL`; Azure CLI auth via `az login`; `AZURE_OPENAI_API_VERSION` is optional |
| [**workflow_with_agents/**](workflow_with_agents/) | A content review workflow that uses agents as executors and routes based on structured review output (`Writer -> Reviewer -> Editor/Publisher -> Summarizer`). | `AZURE_OPENAI_ENDPOINT`, plus `AZURE_OPENAI_CHAT_MODEL` or `AZURE_OPENAI_MODEL`; Azure CLI auth via `az login`; `AZURE_OPENAI_API_VERSION` is optional |
| [**workflow_spam/**](workflow_spam/) | A multi-step spam detection workflow with human-in-the-loop approval, branching for spam vs. legitimate messages, and a final reporting step. | None |
| [**workflow_fanout/**](workflow_fanout/) | A larger fan-out/fan-in data processing workflow with parallel validation, multiple transformations, QA, aggregation, and demo failure toggles. | None |
@@ -130,7 +130,7 @@ export FOUNDRY_MODEL="gpt-4o"
# Azure OpenAI workflow_with_agents sample
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
export AZURE_OPENAI_RESPONSES_MODEL="gpt-4o"
export AZURE_OPENAI_CHAT_MODEL="gpt-4o"
export AZURE_OPENAI_MODEL="gpt-4o"
az login
@@ -2,7 +2,7 @@
# This sample uses Azure CLI auth, so run `az login` before starting DevUI.
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
AZURE_OPENAI_RESPONSES_MODEL=gpt-4o
AZURE_OPENAI_CHAT_MODEL=gpt-4o
# Optional fallback env name also supported by the client:
# AZURE_OPENAI_MODEL=gpt-4o
# Optional if you need to override the default API version:
@@ -65,7 +65,7 @@ def is_approved(message: Any) -> bool:
# Create Azure OpenAI Responses chat client
client = OpenAIChatClient(
model=os.environ.get("AZURE_OPENAI_RESPONSES_MODEL") or os.environ.get("AZURE_OPENAI_MODEL"),
model=os.environ.get("AZURE_OPENAI_CHAT_MODEL") or os.environ.get("AZURE_OPENAI_MODEL"),
azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
api_version=os.environ.get("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
@@ -1,10 +1,10 @@
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "agent-framework-azure-ai",
# "agent-framework-foundry",
# ]
# ///
# Run with: uv run samples/02-agents/embeddings/azure_ai_inference_embeddings.py
# Run with: uv run samples/02-agents/embeddings/foundry_embeddings.py
# Copyright (c) Microsoft. All rights reserved.
@@ -12,28 +12,29 @@ import asyncio
import pathlib
from agent_framework import Content
from agent_framework.azure import AzureAIInferenceEmbeddingClient
from agent_framework.foundry import FoundryEmbeddingClient
from dotenv import load_dotenv
load_dotenv()
"""Azure AI Inference Image Embedding Example
"""Microsoft Foundry Image Embedding Example
This sample demonstrates how to generate image embeddings using the
Azure AI Inference embedding client with the Cohere-embed-v3-english model.
Foundry embedding client with the Cohere-embed-v3-english model.
Images are passed as ``Content`` objects created with ``Content.from_data()``.
Prerequisites:
Deploy an embedding model in Azure AI Inference that supports image inputs, such as Cohere-embed-v3-english.
Deploy an embedding model to a Foundry-hosted inference endpoint that supports image inputs,
such as Cohere-embed-v3-english.
The details page for that model, has a target URI and a Key, which should be set in environment variables or a .env
file as follows, the target URI should append the `/models` path:
- AZURE_AI_INFERENCE_ENDPOINT: Your Azure AI model inference endpoint URL, for instance:
- FOUNDRY_MODELS_ENDPOINT: Your Foundry models endpoint URL, for instance:
https://<apim-instance>.azure-api.net/<foundry-instance>/models
- AZURE_AI_INFERENCE_API_KEY: Your API key
- AZURE_AI_INFERENCE_EMBEDDING_MODEL: The text embedding model name
- FOUNDRY_MODELS_API_KEY: Your API key
- FOUNDRY_EMBEDDING_MODEL: The text embedding model name
(e.g. "text-embedding-3-small")
- AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL: The image embedding model name
- FOUNDRY_IMAGE_EMBEDDING_MODEL: The image embedding model name
(e.g. "Cohere-embed-v3-english")
"""
@@ -41,8 +42,8 @@ SAMPLE_IMAGE_PATH = pathlib.Path(__file__).parent.parent.parent / "shared" / "sa
async def main() -> None:
"""Generate image embeddings with Azure AI Inference."""
async with AzureAIInferenceEmbeddingClient() as client:
"""Generate image embeddings with Foundry."""
async with FoundryEmbeddingClient() as client:
# 1. Generate an image embedding.
image_bytes = SAMPLE_IMAGE_PATH.read_bytes()
image_content = Content.from_data(data=image_bytes, media_type="image/jpeg")
+1 -1
View File
@@ -17,7 +17,7 @@ The Model Context Protocol (MCP) is an open standard for connecting AI agents to
## Prerequisites
- `OPENAI_API_KEY` environment variable
- `OPENAI_RESPONSES_MODEL` environment variable
- `OPENAI_CHAT_MODEL` environment variable
Run `mcp_api_key_auth.py` with the MCP API key as the first command-line argument.
@@ -25,7 +25,7 @@ The new usage tracking sample uses `OpenAIChatClient`, so set the usual OpenAI r
```bash
export OPENAI_API_KEY="your-openai-api-key"
export OPENAI_RESPONSES_MODEL="gpt-4.1-mini"
export OPENAI_CHAT_MODEL="gpt-4.1-mini"
```
Then run:
@@ -40,8 +40,8 @@ ENABLE_SENSITIVE_DATA=true
# OpenAI specific variables
# ==========================
OPENAI_API_KEY="..."
OPENAI_RESPONSES_MODEL="gpt-4o-2024-08-06"
OPENAI_CHAT_MODEL="gpt-4o-2024-08-06"
OPENAI_CHAT_COMPLETION_MODEL="gpt-4o-2024-08-06"
# Azure AI Foundry specific variables
# ====================================
+3 -1
View File
@@ -115,7 +115,9 @@ Orchestration-focused samples (Sequential, Concurrent, Handoff, GroupChat, Magen
| Sample | File | Concepts |
| -------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| State with Agents | [state-management/state_with_agents.py](./state-management/state_with_agents.py) | Store in state once and later reuse across agents |
| Workflow Kwargs (Custom Context) | [state-management/workflow_kwargs.py](./state-management/workflow_kwargs.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools |
| Workflow Kwargs - Global Context | [state-management/workflow_kwargs_global.py](./state-management/workflow_kwargs_global.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools in all agents |
| Workflow Kwargs - Per Agent | [state-management/workflow_kwargs_per_agent.py](./state-management/workflow_kwargs_per_agent.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools in individual agents |
### visualization
@@ -1,6 +1,6 @@
# OpenAI Configuration
OPENAI_API_KEY=
OPENAI_CHAT_MODEL=
OPENAI_CHAT_COMPLETION_MODEL=
# Agent 365 Agentic Authentication Configuration
USE_ANONYMOUS_MODE=
@@ -21,7 +21,7 @@ export USE_ANONYMOUS_MODE=True # set to false if using auth
# OpenAI
export OPENAI_API_KEY="..."
export OPENAI_CHAT_MODEL="..."
export OPENAI_CHAT_COMPLETION_MODEL="..."
```
## Installing Dependencies
+8 -8
View File
@@ -92,10 +92,10 @@ variable.
| --- | --- | --- | --- |
| `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_API_KEY` | `sk-ant-api03-...` |
| `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_CHAT_MODEL` | `claude-sonnet-4-5-20250929` |
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_ENDPOINT` | `https://my-endpoint.inference.ai.azure.com` |
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_API_KEY` | `env-key` |
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_EMBEDDING_MODEL` | `text-embedding-3-small` |
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL` | `Cohere-embed-v3-english` |
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_MODELS_ENDPOINT` | `https://my-endpoint.inference.ai.azure.com` |
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_MODELS_API_KEY` | `env-key` |
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_EMBEDDING_MODEL` | `text-embedding-3-small` |
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_IMAGE_EMBEDDING_MODEL` | `Cohere-embed-v3-english` |
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_ENDPOINT` | `https://my-search.search.windows.net` |
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_API_KEY` | `search-key` |
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_INDEX_NAME` | `hotels-index` |
@@ -144,8 +144,8 @@ variable.
| `agent-framework-ollama` | `OllamaChatClient` | `OLLAMA_MODEL` | `llama3.1:8b` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_API_KEY` | `sk-proj-...` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_MODEL` | `gpt-4o-mini` |
| `agent-framework-openai` | `OpenAIChatClient` | `OPENAI_RESPONSES_MODEL` | `gpt-4.1-mini` |
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `OPENAI_CHAT_MODEL` | `gpt-4o` |
| `agent-framework-openai` | `OpenAIChatClient` | `OPENAI_CHAT_MODEL` | `gpt-4.1-mini` |
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `OPENAI_CHAT_COMPLETION_MODEL` | `gpt-4o` |
| `agent-framework-openai` | `OpenAIEmbeddingClient` | `OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_BASE_URL` | `https://api.openai.com/v1/` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_ORG_ID` | `org_123456789` |
@@ -154,8 +154,8 @@ variable.
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_API_VERSION` | `2024-10-21` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_BASE_URL` | `https://my-resource.openai.azure.com/openai/v1/` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_MODEL` | `gpt-4o` |
| `agent-framework-openai` | `OpenAIChatClient` | `AZURE_OPENAI_RESPONSES_MODEL` | `gpt-4.1` |
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `AZURE_OPENAI_CHAT_MODEL` | `gpt-4o-mini` |
| `agent-framework-openai` | `OpenAIChatClient` | `AZURE_OPENAI_CHAT_MODEL` | `gpt-4.1` |
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `AZURE_OPENAI_CHAT_COMPLETION_MODEL` | `gpt-4o-mini` |
| `agent-framework-openai` | `OpenAIEmbeddingClient` | `AZURE_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-large` |
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_RESOURCE_URL` | `https://cognitiveservices.azure.com/` |