How to Host Agents on Azure Functions with Stateful Execution in Agent Framework

Wrap your Agent Framework workflow in an AgentFunctionApp to deploy stateful AI agents on Azure Functions, using WorkflowContext.set_state() and get_state() to persist data across orchestration steps without bloating message payloads.

Hosting agents on Azure Functions with stateful execution in Agent Framework enables serverless, durable AI workflows that maintain context across multiple steps. By leveraging Durable Functions orchestration combined with the AgentFunctionApp bootstrap class in the microsoft/agent-framework repository, you can build scalable agent systems where large payloads like email bodies or documents persist in a SharedState dictionary rather than passing through every message.

Architecture of Stateful Agent Execution

The stateful execution model relies on three core components working together inside a Durable Functions orchestration.

AgentFunctionApp extends the Durable Functions DFAppBase class to automatically register HTTP endpoints, health checks, and activity triggers. When you wrap a Workflow inside this app, the framework handles serialization and deserialization of the orchestration state between function activations.

SharedState is a per-orchestration dictionary that survives across activity invocations. Unlike standard message passing where large payloads travel through every executor step, SharedState lives in-memory and is serialized only when the function scales or checkpoints.

WorkflowContext provides the interface to this state through set_state(key, value) and get_state(key) methods. In python/samples/04-hosting/azure_functions/09_workflow_shared_state/function_app.py, the store_email executor demonstrates this pattern by storing a UUID-keyed Email object and updating a CURRENT_EMAIL_ID_KEY reference for downstream steps to retrieve.

Prerequisites for Local Development

Before running stateful agents locally, ensure your environment includes:

  • Azure Functions Core Tools 4.x – Required to run func start and publish to Azure
  • Azurite storage emulator – Provides the durable task hub’s storage tables and blobs for local orchestration persistence
  • Azure AI Foundry project – Must have an OpenAI model deployed (referenced as gpt-4o or similar) for the FoundryChatClient
  • Azure CLI authentication – Run az login to enable AzureCliCredential for seamless authentication without embedded secrets
  • Python 3.9+ – With a virtual environment to isolate dependencies listed in requirements.txt

Implementation Steps

Follow these steps to run the stateful workflow sample locally.

  1. Clone and configure the repository

    git clone https://github.com/microsoft/agent-framework.git
    cd agent-framework/python/samples/04-hosting/azure_functions/09_workflow_shared_state
    python -m venv .venv
    source .venv/bin/activate  # On Windows: .venv\Scripts\activate
    
    pip install -r requirements.txt
  2. Configure local settings

    Create local.settings.json in the sample root with your Azure AI Foundry endpoint:

    {
      "Values": {
        "FOUNDRY_PROJECT_ENDPOINT": "https://<your-project>.services.ai.azure.com/api/projects/<your-project>",
        "FOUNDRY_MODEL": "gpt-4o"
      }
    }
  3. Start the storage emulator

    azurite --silent
  4. Launch the function host

    func start
  5. Trigger the workflow

    Send a test request to the HTTP endpoint created by AgentFunctionApp:

    curl -X POST http://localhost:7071/api/workflow/run \
         -H "Content-Type: application/json" \
         -d '"URGENT! You have won $1,000,000! Click here to claim!"'

    The orchestration will either return a spam warning or a drafted email response, depending on the detection agent’s analysis.

Code Example: Persisting State Across Executors

The core logic in function_app.py demonstrates how to keep large payloads out of message traffic. The store_email executor receives raw email text, generates a UUID, and persists the full content in SharedState while passing only the ID through the workflow.


# python/samples/04-hosting/azure_functions/09_workflow_shared_state/function_app.py

import os
from uuid import uuid4
from dataclasses import dataclass
from typing import Any

from agent_framework import (
    Agent, AgentExecutorRequest, AgentExecutorResponse,
    Message, Workflow, WorkflowBuilder, WorkflowContext, executor,
)
from agent_framework.foundry import FoundryChatClient
from agent_framework_azurefunctions import AgentFunctionApp
from azure.identity.aio import AzureCliCredential

EMAIL_STATE_PREFIX = "email:"
CURRENT_EMAIL_ID_KEY = "current_email_id"

@dataclass
class Email:
    """Object stored in SharedState to avoid passing large payloads."""
    email_id: str
    email_content: str

@executor(id="store_email")
async def store_email(email_text: str, ctx: WorkflowContext[AgentExecutorRequest]) -> None:
    """Persist raw email and kick off spam detection."""
    new_email = Email(email_id=str(uuid4()), email_content=email_text)
    
    # Store large payload in shared state

    ctx.set_state(f"{EMAIL_STATE_PREFIX}{new_email.email_id}", new_email)
    ctx.set_state(CURRENT_EMAIL_ID_KEY, new_email.email_id)

    # Pass only lightweight metadata to next step

    await ctx.send_message(
        AgentExecutorRequest(
            messages=[Message(role="user", contents=[new_email.email_content])],
            should_respond=True
        )
    )

Subsequent executors retrieve the original email using ctx.get_state(f"{EMAIL_STATE_PREFIX}{email_id}") without requiring the payload to transit through the Durable Functions message queue.

Deploying to Azure

To move from local development to production:

  1. Create a Function App using the Consumption plan or Premium plan (required for Durable Functions) in your target Azure region

  2. Configure application settings in the Azure portal or via CLI:

    • FOUNDRY_PROJECT_ENDPOINT
    • FOUNDRY_MODEL
    • TASKHUB_NAME (optional, for custom task hub isolation)
  3. Publish the code using Azure Functions Core Tools:

    func azure functionapp publish <APP_NAME>
  4. Configure authentication – Ensure the Function App’s managed identity has Reader role on your Azure AI Foundry project, or store service principal credentials in Azure Key Vault and reference them in the application settings.

Summary

  • AgentFunctionApp bootstraps Agent Framework workflows inside Durable Functions orchestrations, handling HTTP triggers and activity routing automatically.
  • SharedState provides durable, per-orchestration storage via WorkflowContext.set_state() and get_state(), keeping large payloads out of message queues.
  • The store_email pattern in function_app.py demonstrates production-ready state management: generate a UUID, persist the object, and pass only the reference ID.
  • Local development requires Azurite for durable task hub storage and AzureCliCredential for seamless Azure AI Foundry authentication.
  • Deployment relies on standard Azure Functions Core Tools with additional app settings for Foundry endpoints.

Frequently Asked Questions

What is SharedState and how does it differ from regular message payloads?

SharedState is an in-memory dictionary unique to each Durable Functions orchestration instance. Unlike message payloads, which pass through the Durable Functions message queue and have size limits and serialization overhead, SharedState persists arbitrary Python objects via WorkflowContext.set_state() and survives across activity invocations without leaving the execution context.

How does AgentFunctionApp differ from a standard Azure Functions app?

According to the microsoft/agent-framework source code, AgentFunctionApp inherits from DFAppBase (the Durable Functions base class) and extends it with Agent Framework-specific registration logic. It automatically wires HTTP endpoints to workflow runners, registers health checks, and injects the WorkflowContext into executor functions, whereas a standard Functions app requires manual trigger binding and state management.

What authentication method does the sample use for Azure AI Foundry?

The sample uses AzureCliCredential from the Azure Identity library, which picks up the authentication context from az login. This eliminates the need to store secrets in local.settings.json during development. In production, you should configure the Function App’s managed identity or reference service principal credentials from Azure Key Vault.

Can I test stateful workflows without deploying to Azure?

Yes. The repository includes support for local execution via the Azurite storage emulator, which provides the durable task hub’s tables and blobs required for stateful orchestration. Running func start with Azurite active allows full testing of set_state and get_state persistence before cloud deployment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →