forked from Azure/azure-functions-durable-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Initial Docs for the Durable OpenAI Agents Integration #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
AnatoliB
merged 6 commits into
AnatoliB:durable-openai-agent
from
greenie-msft:durable-openai-agent
Sep 19, 2025
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4815015
Add initial docs
greenie-msft 9c1838e
Fix README
greenie-msft d33740e
Fix getting started doc
greenie-msft 013f272
Address PR feedback
greenie-msft 715d0a9
Fix title of docs
greenie-msft a1596b3
Address Docs PR feedback
greenie-msft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Durable OpenAI Agents | ||
|
||
Build production-ready AI agents with automatic state persistence and failure recovery. | ||
|
||
## Overview | ||
|
||
The Durable OpenAI Agents integration combines the familiar OpenAI Agents SDK with Azure Durable Functions to create reliable, stateful AI agents that can survive any failure and continue exactly where they stopped. | ||
|
||
## Key Benefits | ||
|
||
- **Enhanced Agent Resilience**: Built-in retry mechanisms for LLM calls and tool executions | ||
- **Multi-Agent Orchestration Reliability**: Individual agent failures don't crash entire workflows | ||
- **Built-in Observability**: Monitor agent progress through the Durable Task Scheduler dashboard | ||
- **Familiar Developer Experience**: Keep using the OpenAI Agents SDK with minimal code changes | ||
- **Distributed Compute and Scalability**: Agent workflows automatically scale across multiple compute instances | ||
|
||
## Documentation | ||
|
||
- [Getting Started](getting-started.md) - Setup and your first durable agent | ||
- [Reference](reference.md) - Complete reference documentation |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
# Getting Started with Durable OpenAI Agents | ||
|
||
Getting started guide for implementing stateful AI agents using Azure Durable Functions orchestration with automatic checkpointing and replay semantics. | ||
|
||
## Prerequisites | ||
|
||
- Python 3.10+ runtime environment | ||
- Azure Functions Core Tools v4.x (`npm install -g azure-functions-core-tools@4 --unsafe-perm true`) | ||
- Azure OpenAI service endpoint with model deployment | ||
- Docker (Optional for the Durable Task Scheduler Emulator) | ||
|
||
## Environment Setup | ||
|
||
### Create an Azure Functions App | ||
|
||
This framework is designed specifically for **Azure Functions applications**. You need to create a Python Functions app to use Durable OpenAI Agents. | ||
|
||
**For new users**: If you're new to Azure Functions, follow these guides to get started: | ||
- [Create your first Python function in Azure](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-python) | ||
- [Azure Functions Python developer guide](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-python) | ||
|
||
**For experienced Functions users**: Create a new Python Functions app or use an existing one. | ||
|
||
**Note**: The `samples-v2/openai_agents` directory contains a complete working example you can reference or use as a starting point. | ||
|
||
### Set Up Local Development Environment | ||
|
||
Create and activate a virtual environment to isolate dependencies: | ||
|
||
```bash | ||
# Create virtual environment | ||
python -m venv venv | ||
|
||
# Activate virtual environment | ||
# On macOS/Linux: | ||
source venv/bin/activate | ||
# On Windows: | ||
# venv\Scripts\activate | ||
``` | ||
|
||
### Install Dependencies | ||
|
||
Add the OpenAI Agents dependencies to your `requirements.txt`: | ||
|
||
``` | ||
azure-functions-durable | ||
azure-functions | ||
openai | ||
openai-agents | ||
azure-identity | ||
``` | ||
|
||
Then install them: | ||
|
||
```bash | ||
pip install -r requirements.txt | ||
``` | ||
|
||
### Configuring Durable Task Scheduler Backend | ||
|
||
**Durable Task Scheduler is the preferred backend** for this integration as it provides enhanced performance, better observability, and simplified local development. While not a hard requirement, it's strongly recommended for production workloads. | ||
|
||
There are two ways to configure the backend locally: | ||
|
||
#### Using the Emulator (Recommended) | ||
|
||
The emulator simulates a scheduler and taskhub in a Docker container, making it ideal for development and learning. | ||
|
||
1. **Pull the Docker Image for the Emulator:** | ||
```bash | ||
docker pull mcr.microsoft.com/dts/dts-emulator:latest | ||
``` | ||
|
||
2. **Run the Emulator:** | ||
```bash | ||
docker run --name dtsemulator -d -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest | ||
``` | ||
|
||
3. **Wait for container readiness** (approximately 10-15 seconds) | ||
|
||
4. **Verify emulator status:** | ||
```bash | ||
curl http://localhost:8080/health | ||
``` | ||
|
||
**Note**: The sample code automatically uses the default emulator settings (`endpoint: http://localhost:8080`, `taskhub: default`). No additional environment variables are required. | ||
|
||
#### Alternative: Azure Storage Backend | ||
|
||
If you prefer using Azure Storage as the backend (legacy approach): | ||
|
||
```bash | ||
# Uses local storage emulator - requires Azurite | ||
npm install -g azurite | ||
azurite --silent --location /tmp/azurite --debug /tmp/azurite/debug.log | ||
``` | ||
|
||
Update `local.settings.json`: | ||
```json | ||
{ | ||
"Values": { | ||
"AzureWebJobsStorage": "UseDevelopmentStorage=true" | ||
} | ||
} | ||
``` | ||
|
||
## Configuration | ||
|
||
1. **Install project dependencies:** | ||
|
||
```bash | ||
pip install -r requirements.txt | ||
``` | ||
|
||
2. **Configure service settings:** | ||
|
||
Update `local.settings.json` with your service configuration: | ||
|
||
```json | ||
{ | ||
"IsEncrypted": false, | ||
"Values": { | ||
"AzureWebJobsStorage": "UseDevelopmentStorage=true", | ||
"FUNCTIONS_WORKER_RUNTIME": "python", | ||
"AZURE_OPENAI_ENDPOINT": "https://<resource-name>.openai.azure.com/", | ||
"AZURE_OPENAI_DEPLOYMENT": "<deployment-name>", | ||
"AZURE_OPENAI_API_VERSION": "2024-10-01-preview", | ||
"DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "http://localhost:8080;Authentication=None;", | ||
"TASKHUB": "default" | ||
} | ||
} | ||
``` | ||
|
||
## Hello World Example | ||
|
||
Execute the included hello world sample. | ||
|
||
```python | ||
# basic/hello_world.py - Standard OpenAI Agent | ||
from agents import Agent, Runner | ||
|
||
def main(): | ||
agent = Agent( | ||
name="Assistant", | ||
instructions="You only respond in haikus.", | ||
) | ||
result = Runner.run_sync(agent, "Tell me about recursion in programming.") | ||
return result.final_output | ||
``` | ||
|
||
**Durable Transformation**: The `@app.durable_openai_agent_orchestrator` decorator in `function_app.py` wraps this agent execution within a Durable Functions orchestrator, providing agent state persisted at each LLM and tool interaction. | ||
|
||
## Execution and Monitoring | ||
|
||
1. **Start the Azure Functions host:** | ||
|
||
Navigate to the `samples-v2/openai_agents` directory and run: | ||
|
||
```bash | ||
func start --port 7071 | ||
``` | ||
|
||
2. **Initiate orchestration instance:** | ||
|
||
```bash | ||
curl -X POST http://localhost:7071/api/orchestrators/hello_world \ | ||
-H "Content-Type: application/json" | ||
``` | ||
|
||
Response contains orchestration instance metadata: | ||
|
||
```json | ||
{ | ||
"id": "f4b2c8d1e9a7...", | ||
"statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/f4b2c8d1e9a7...", | ||
"sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/f4b2c8d1e9a7.../raiseEvent/{eventName}", | ||
"terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/f4b2c8d1e9a7.../terminate", | ||
"purgeHistoryDeleteUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/f4b2c8d1e9a7..." | ||
} | ||
``` | ||
|
||
3. **Monitor execution via Durable Task Scheduler dashboard:** | ||
|
||
Navigate to `http://localhost:8082` for real-time orchestration monitoring: | ||
- Instance execution timeline with LLM call latencies | ||
- State transition logs and checkpoint data | ||
- Retry attempt tracking and failure analysis | ||
|
||
## Next Steps | ||
|
||
- Reference [Reference Documentation](reference.md) for complete technical details. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Reference Documentation | ||
|
||
Complete reference for Durable OpenAI Agents integration. | ||
|
||
## Durable Orchestration | ||
|
||
### @app.durable_openai_agent_orchestrator | ||
|
||
Primary decorator enabling durable execution for agent invocations. | ||
|
||
```python | ||
from azure.durable_functions.openai_agents import durable_openai_agent_orchestrator | ||
|
||
@app.orchestration_trigger(context_name="context") | ||
@app.durable_openai_agent_orchestrator | ||
def my_agent_orchestrator(context): | ||
# Agent implementation | ||
pass | ||
``` | ||
|
||
**Features**: | ||
- Automatic state persistence for agent conversations | ||
- Built-in retry mechanisms for LLM calls | ||
- Tool call durability and replay protection | ||
- Integration with Durable Functions monitoring using the Durable Task Scheduler | ||
|
||
**Constraints**: | ||
- Functions must be deterministic (identical outputs for identical inputs) | ||
- No non-deterministic operations: `datetime.now()`, `random`, `uuid.uuid4()` | ||
- See [Durable Functions Code Constraints](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-code-constraints?tabs=csharp) | ||
|
||
### @app.orchestration_trigger | ||
|
||
Azure Functions orchestration trigger decorator. Required with `@app.durable_openai_agent_orchestrator`. | ||
|
||
```python | ||
@app.orchestration_trigger(context_name="context") | ||
@app.durable_openai_agent_orchestrator | ||
def my_orchestrator(context): | ||
# ... | ||
``` | ||
|
||
## Agent Execution | ||
|
||
### Runner.run_sync() | ||
|
||
Runner for agents in durable orchestration context. | ||
|
||
```python | ||
from agents import Agent, Runner | ||
|
||
def my_orchestrator(context): | ||
agent = Agent(name="Assistant", instructions="Be helpful") | ||
result = Runner.run_sync(agent, "Hello world") | ||
return result.final_output | ||
``` | ||
|
||
**Parameters**: | ||
- `agent` (Agent): Agent instance to run | ||
- `messages` (str | list): Input message(s) | ||
|
||
**Returns**: Agent result object with `final_output` property | ||
|
||
## Tools | ||
|
||
### Durable Functions Activity Tools | ||
|
||
Durable Function Activities that execute as durable tool invocations. **This is the recommended approach for most use cases** as it provides the strongest correctness guarantees. - **When in doubt - this is the safe choice** | ||
|
||
```python | ||
# 1. Define activity function | ||
@app.activity_trigger(input_name="input_param") | ||
async def my_activity(input_param): | ||
# External API calls, database operations, etc. | ||
return result | ||
|
||
# 2. Use in orchestrator | ||
@app.orchestration_trigger(context_name="context") | ||
@app.durable_openai_agent_orchestrator | ||
def my_orchestrator(context): | ||
agent = Agent( | ||
tools=[context.create_activity_tool(my_activity)] | ||
) | ||
# ... | ||
``` | ||
|
||
**Components**: | ||
- `@app.activity_trigger(input_name="param")`: Decorator for activity functions | ||
- `context.create_activity_tool(activity_function)`: Creates tool from activity function | ||
|
||
**Best For**: External API calls, database operations, file I/O, expensive computations, non-deterministic operations | ||
|
||
### Open AI Function Tools | ||
|
||
Simple, deterministic tools that execute within the orchestration context. **Recommended only as a performance optimization when you're certain the tool meets all deterministic requirements.** | ||
|
||
```python | ||
from agents import function_tool | ||
|
||
@function_tool | ||
def calculate(expression: str) -> str: | ||
"""Calculate mathematical expressions.""" | ||
return str(eval(expression)) | ||
``` | ||
|
||
**Requirements**: | ||
- Must be deterministic (same input → same output) | ||
- Should be fast-executing | ||
- No external API calls (use activity tools instead) | ||
- Input/output must be JSON serializable | ||
|
||
**Best For**: Calculations, data transformations, validation logic, quick lookups | ||
|
||
### Current Limitations | ||
|
||
**MCP (Model Context Protocol)**: MCP tool support is not currently available. Use function tools or activity tools instead. | ||
|
||
## Constraints | ||
|
||
Orchestration functions must be deterministic and replay-safe: | ||
|
||
- **Deterministic**: Same input always produces same output | ||
- **Idempotent**: Safe to execute multiple times | ||
- **Side-effect free**: No external calls in orchestration logic | ||
|
||
```python | ||
# ✅ Good: Deterministic | ||
def good_orchestrator(context): | ||
input_data = context.get_input() | ||
agent = high_priority_agent if input_data.get("priority") == "high" else standard_agent | ||
return Runner.run_sync(agent, input_data["content"]) | ||
|
||
# ❌ Bad: Non-deterministic | ||
def bad_orchestrator(context): | ||
import random | ||
agent = agent_a if random.choice([True, False]) else agent_b # Non-deterministic! | ||
return Runner.run_sync(agent, context.get_input()) | ||
``` |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.