Deploy a Microsoft Agent Framework (MAF) workflow as a managed online endpoint to an Azure ML workspace or an Azure AI Foundry hub-based project. Wraps any work
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-maf-online-endpoint-9df8c6c2fafa ,按照其中的说明把「maf-online-endpoint」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
This skill wraps a Microsoft Agent Framework (agent-framework) workflow into
a managed online endpoint using the standard scoring-script pattern
(init() / run()), following the patterns from the
azureml-examples managed endpoint samples.
The endpoint can be deployed to either:
| Deployment Target | Description |
|---|---|
| Azure Machine Learning workspace | Standalone AML workspace — user provides subscription, resource group, and workspace name |
| Azure AI Foundry hub-based project | An AI project living under a Foundry hub — the project name is the workspace name for az ml commands |
Both targets produce the same generated files (online-deployment/ directory)
and use the same az ml CLI / azure-ai-ml Python SDK. The difference is
in how the workspace is identified and RBAC scope.
The deployment creates all files in an online-deployment/ subdirectory under
the project root:
<project-root>/
workflow.py ← the MAF workflow
online-deployment/
score.py ← scoring script
conda.yml ← conda environment
endpoint.yml ← endpoint config
deployment.yml ← deployment template (${VAR} placeholders)
deploy.sh ← deploy script (Bash; see notes for Windows)
.gitignore ← ignores rendered YAML with secrets
score.py) — init() imports the workflow factory;
run() creates a fresh workflow instance per request to avoid concurrency errors.conda.yml) — Python 3.11 with agent-framework and
azureml-inference-server-http.endpoint.yml) — endpoint name and auth mode.deployment.yml) — template with ${VAR} placeholders
for environment variables, instance config, and request settings.deploy.sh) — renders the template, creates the endpoint
and deployment, runs a smoke test.Path resolution rule: AML CLI resolves
conda_file,code, andscoring_scriptpaths relative to the YAML file location, not the CWD. Since the YAML is insideonline-deployment/, useconda_file: conda.yml(same directory) andcode: ..(parent = project root).
When the user asks to deploy a MAF workflow as an online endpoint:
vscode_askQuestions:
vscode_askQuestions:
subscription, resource group, workspace/project name, and the workflow file
path.os.environ/os.getenv
calls to discover what the workflow needs (Step 0 §B).online-deployment/ subdirectory under the project root.az CLI commands
directly in PowerShell (the Bash deploy.sh won't work). On Linux/macOS,
use deploy.sh or run the commands directly..gitignore rendered YAML
files that contain secrets.The same variables apply to both deployment targets. For a Foundry hub-based
project, WORKSPACE_NAME is the AI project name (not the hub name).
| Variable | Description | Default |
|---|---|---|
SUBSCRIPTION_ID | Azure subscription | (required) |
RESOURCE_GROUP | Resource group containing the AML workspace or AI project | (required) |
WORKSPACE_NAME | AML workspace name or AI Foundry project name | (required) |
ENDPOINT_NAME | Name of the online endpoint | maf-endpoint |
DEPLOYMENT_NAME | Deployment name under the endpoint | blue |
INSTANCE_TYPE | VM SKU | Standard_DS3_v2 |
INSTANCE_COUNT | Number of instances | 1 |
REQUEST_TIMEOUT_MS | Request timeout in ms | 60000 |
Foundry project note: An AI Foundry hub-based project is backed by an AML workspace. All
az mlcommands and theMLClientSDK work the same way — just use the project name as--workspace-name. The endpoint scoring URI format is identical:https://<endpoint-name>.<region>.inference.ml.azure.com/score
Read the user's workflow file and inspect:
conda.yml.os.environ[...] / os.getenv(...) calls — determine environment
variables the deployment must inject.DefaultAzureCredential / ManagedIdentityCredential
means RBAC must be set up; an API key means a secret env var.| Pattern | Imports | Required env vars | Extra pip packages | RBAC role |
|---|---|---|---|---|
| Foundry LLM | FoundryChatClient, DefaultAzureCredential | FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL | agent-framework | Cognitive Services User |
| OpenAI API key | OpenAIChatClient | AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_API_KEY | agent-framework, agent-framework-openai | (none — uses API key) |
| RAG (AI Search) | AzureAISearchContextProvider | above + AZURE_AI_SEARCH_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, AZURE_AI_SEARCH_API_KEY | above + agent-framework-azure-ai-search | above (Search uses API key) |
| Function tools | plain Python functions | same as Foundry LLM | same as Foundry LLM | same as Foundry LLM |
Get endpoint managed identity principal ID:
az ml online-endpoint show --name <endpoint> --query identity.principal_id -o tsv
| Variable | Default | Description |
|---|---|---|
APPLICATIONINSIGHTS_CONNECTION_STRING | (empty) | Enables OpenTelemetry tracing |
Use the template at ./assets/score.py.
Key decisions:
AgentResponse is not JSON-serializable → extract .text before returning.project_root = Path(__file__).resolve().parents[1] — score.py is one
level deep (online-deployment/score.py), so parents[1] reaches the
project root. Adjust if your layout differs.asyncio.get_event_loop().run_until_complete() bridges the sync run() to
the async workflow."text", "question"). Adapt accordingly.init() imports the create_workflow factory from
workflow.py. Each run() call invokes the factory to get a fresh workflow
instance, avoiding RuntimeError: Workflow is already running on concurrent
requests.conda.ymlUse the template at ./assets/conda.yml.
Important:
agent-framework-azure-ai-search may not have published version ranges on
PyPI, which causes image build failures.agent-framework-openai but omit
agent-framework-azure-ai-search and azure-monitor-opentelemetry unless
needed.endpoint.ymlUse the template at ./assets/endpoint.yml.
deployment.yml (Template)Use the template at ./assets/deployment.yml.
Critical — path resolution:
AML CLI resolves all relative paths in the deployment YAML relative to the
YAML file's location, not the working directory. Since deployment files live
in online-deployment/:
environment:
conda_file: conda.yml # ← same dir as deployment.yml
code_configuration:
code: .. # ← parent dir = project root
scoring_script: online-deployment/score.py # ← relative to code root
Getting this wrong causes a double-nesting error like
online-deployment/online-deployment/conda.yml.
Other key settings:
request_timeout_ms: 60000 — LLM calls typically take 5–30 s; the AML
default of 5 s causes timeouts.conda_file (not pip_requirements) — the latter is not valid for
inline environment definitions.envsubst, use a restricted variable list so
$schema is not eaten.Security: The rendered YAML (deployment-rendered.yml) may contain API
keys in plaintext. A .gitignore file is generated automatically to exclude
it (see Step 4b).
.gitignoreAlways create online-deployment/.gitignore to prevent rendered YAML files
containing secrets from being committed:
deployment-rendered.yml
Use the template at ./assets/deploy.sh. Requires
envsubst (part of gettext).
On Windows, deploy.sh won't work (envsubst, mktemp, process substitution
are unavailable). Instead, run the steps directly in PowerShell:
# 1. Render deployment YAML (replace placeholders with actual values)
$content = Get-Content online-deployment/deployment.yml -Raw
$content = $content -replace '\$\{AZURE_OPENAI_ENDPOINT\}', $env:AZURE_OPENAI_ENDPOINT
# ... repeat for each placeholder ...
Set-Content -Path online-deployment/deployment-rendered.yml -Value $content
# 2. Create endpoint
az ml online-endpoint create `
--subscription $SUBSCRIPTION_ID `
--resource-group $RESOURCE_GROUP `
--workspace-name $WORKSPACE_NAME `
--file online-deployment/endpoint.yml
# 3. Create deployment (run from the project root directory!)
az ml online-deployment create `
--subscription $SUBSCRIPTION_ID `
--resource-group $RESOURCE_GROUP `
--workspace-name $WORKSPACE_NAME `
--file online-deployment/deployment-rendered.yml `
--all-traffic
# 4. Smoke test
Set-Content -Path online-deployment/request.json -Value '{"text": "Hello"}'
az ml online-endpoint invoke `
--subscription $SUBSCRIPTION_ID `
--resource-group $RESOURCE_GROUP `
--workspace-name $WORKSPACE_NAME `
--name <ENDPOINT_NAME> `
--request-file online-deployment/request.json
Important: Run the
az ml online-deployment createcommand from the project root directory, not from insideonline-deployment/. The CLI resolvescode: ..relative to the YAML file, but the CWD also matters for finding the YAML file itself.
After the endpoint is created, its system-assigned managed identity needs
the Cognitive Services User role on the Foundry resource.
az ml workspace show \
--name <project-name> \
--resource-group <rg> \
--query "associated_workspaces" -o table
# Get principal ID
PRINCIPAL_ID=$(az ml online-endpoint show \
--subscription "$SUBSCRIPTION_ID" \
--name <ENDPOINT_NAME> \
--resource-group "$RESOURCE_GROUP" \
--workspace-name "$WORKSPACE_NAME" \
--query identity.principal_id -o tsv)
# Assign role
az role assignment create \
--assignee-object-id "$PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Cognitive Services User" \
--scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>"
Why Cognitive Services User?
Azure AI Developer does not include Microsoft.CognitiveServices/accounts/AIServices/agents/write.Cognitive Services User has the wildcard Microsoft.CognitiveServices/*.See ./references/managed-identity.md for full details.
| Symptom | Cause | Fix |
|---|---|---|
No such file: .../online-deployment/online-deployment/conda.yml | Paths in deployment YAML resolved relative to YAML location, not CWD | Use conda_file: conda.yml and code: .. when YAML is in a subdirectory |
401 PermissionDenied | Missing RBAC | Assign Cognitive Services User on Foundry resource |
upstream request timeout | 5 s default too short | request_timeout_ms: 60000 |
AgentResponse is not JSON serializable | Returning raw workflow output | Extract .text from the response |
pip_requirements validation error | Invalid field for inline env | Use conda_file instead |
| Image build fails on version constraints | Package not on PyPI with that version | Remove version pins from conda.yml |
$schema missing after envsubst | Unrestricted envsubst eats $schema | Use restricted variable list |
FileNotFoundError: az (Windows subprocess) | az is a .cmd file on Windows | Use shell=True in subprocess.run |
envsubst not found (Windows) | envsubst is a Linux tool | Use PowerShell string replacement (see Step 5 Option B) |
| Deployment fails in Foundry project with network error | Hub managed network blocks outbound access | Check hub network settings; add outbound rules for required endpoints |
| Cannot create endpoint in Foundry project | Insufficient RBAC on the project | User needs Azure AI Developer role on the resource group |
See ./references/troubleshooting.md for extended diagnostics.