Microsoft Foundry
Hermes Agent 的 azure-foundry 提供商支持 Microsoft Foundry(前身为 Azure AI Foundry)和 Azure OpenAI。一个单一的 Foundry 资源可托管使用两种不同数据格式的模型:
- OpenAI 风格 — 在类似
https://<resource>.openai.azure.com/openai/v1的端点上使用POST /v1/chat/completions。适用于 GPT-4.x、GPT-5.x、Llama、Mistral 以及大多数开源权重模型。 - Anthropic 风格 — 在类似
https://<resource>.services.ai.azure.com/anthropic的端点上使用POST /v1/messages。当 Microsoft Foundry 通过 Anthropic Messages API 格式提供 Claude 模型时使用。
设置向导会探测您的端点,自动检测所使用的传输方式、可用的部署项,以及每个模型的上下文长度。
前提条件
- 一个包含至少一个部署项的 Microsoft Foundry 或 Azure OpenAI 资源
- 部署项的端点 URL
- 要么一个 API 密钥(来自 Azure Portal 中的“密钥和终结点”部分),要么在 Foundry 资源上拥有 Azure AI User RBAC 角色(如果您计划使用 Microsoft Entra ID,这是微软推荐的无密钥路径)。某些租户可能在微软重命名过程中显示为 Foundry User。
快速入门
hermes model
# → Select "Azure Foundry"
# → Enter your endpoint URL
# → Choose Authentication:
# 1. API key
# 2. Microsoft Entra ID (managed identity / workload identity / az login)
# → (Entra) Hermes probes DefaultAzureCredential; on success it never asks for a key
# → (API key) Enter your API key
# Hermes probes the endpoint and auto-detects transport + models
# → Pick a model from the list (or type a deployment name manually)
向导将执行以下操作:
- 嗅探 URL 路径 — 以
/anthropic结尾的 URL 被识别为 Microsoft Foundry Claude 路由。 - 探测
GET <base>/models— 如果端点返回 OpenAI 风格的模型列表,Hermes 将切换至chat_completions,并预填充返回的部署 ID 选择器。 - 探测 Anthropic Messages 格式 — 作为对不暴露
/models但接受 Anthropic Messages 格式的端点的后备方案。 - 回退至手动输入 — 对于拒绝所有探测的私有/受控端点仍然有效;您可手动选择 API 模式并输入部署名称。
所选模型的上下文长度通过 Hermes 的标准元数据链(models.dev、提供商元数据及硬编码家族回退)进行解析,并存储于 config.yaml,以便模型能正确调整自身的上下文窗口大小。
Microsoft Entra ID(无密钥,基于 RBAC)—— 推荐
微软建议对生产环境中的 Foundry 工作负载采用 无密钥身份验证与 Microsoft Entra ID。Hermes 支持 Entra ID 用于 两种 API 表面:
- OpenAI 风格(
api_mode: chat_completions/codex_responses)— GPT-4/5、Llama、Mistral、DeepSeek 等。 - Anthropic 风格(
api_mode: anthropic_messages)— 在 Microsoft Foundry 上运行的 Claude 模型。
Foundry 的 RBAC 是按资源粒度控制的(Azure AI User 同时授予两个表面;部分租户可能显示为 Foundry User),微软文档中对两者的推理范围(`https://ai.azure.com/.default``)描述一致。其底层实现如下:
- OpenAI 风格使用 OpenAI Python SDK 的原生 callable
api_key=合约 — SDK 会在每次请求时自动生成新的 JWT。 - Anthropic 风格使用一个
httpx.Client,该对象通过agent.azure_identity_adapter.build_bearer_http_client安装了请求事件钩子,因为 Anthropic SDK 不原生支持 callableauth_token。钩子会在每次出站请求时重写Authorization: Bearer <fresh-jwt>。相同的 Microsoft RBAC 和 Foundry 范围 — 唯一区别在于 SDK 合约。
为何使用 Entra ID?
- 无需轮换或撤销长期存在的 API 密钥。
- 基于 RBAC 的访问控制 — 可随时授予或移除
Azure AI User权限,无需修改配置。 - 访问和审计日志按分配者分段,而非所有调用者共享一个静态密钥。
- Azure VM、AKS Pod、App Service、Functions、Container Apps 以及 Foundry Agent Service 均可通过托管标识实现统一认证入口。
- 支持 CI/CD 流水线中的工作负载身份和服务主体流程。
一次性的 Azure 端设置
- 在 Azure 门户中打开您的 Foundry 资源 → 访问控制 (IAM) → 添加 → 添加角色分配。
- 选择 Azure AI User 角色(若租户已重命名,请使用 Foundry User)。
- 将其分配给:
- 您的用户账户,用于本地开发时使用
az login。 - 托管标识或工作负载标识,用于 Azure 托管计算(生产环境推荐)。
- 托管代理服务中的代理身份,当 Hermes 运行在托管代理内时。
- 服务主体,当工作负载标识不可用时用于 CI/CD 流水线。
- 您的用户账户,用于本地开发时使用
- 等待约 5 分钟,使角色生效。
Azure CLI 等效命令:
az role assignment create \
--assignee <principal-or-agent-identity-client-id> \
--role "Azure AI User" \
--scope <foundry-resource-id>
一次性的 Hermes 端设置
hermes model
# → Select "Azure Foundry"
# → Enter your endpoint URL
# → Authentication: 2 (Microsoft Entra ID)
# → (optional) user-assigned managed identity client ID
# → (optional) Azure tenant ID
# → Hermes probes DefaultAzureCredential() and reports which inner
# credential succeeded (e.g. AzureCliCredential, ManagedIdentityCredential)
向导会执行一次有限的预检探测(10 秒超时)。若失败,将提供“仍保存,稍后验证”的选项 —— 这对于尚未具备运行时凭据但将在运行时获得凭据的机器特别有用(例如为托管标识部署准备配置)。
azure-identity 会在首次使用时通过 Hermes 的懒加载安装路径自动安装。如需提前安装:
pip install azure-identity
写入 config.yaml 的配置
model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions
auth_mode: entra_id
default: gpt-4o
context_length: 128000
entra:
scope: https://ai.azure.com/.default # only when overriding the default
Hermes 仅在 config.yaml 中管理一个 Entra 特定的选项:
scope— OAuth 资源作用域。默认值为微软文档中记录的推理作用域(`https://ai.azure.com/.default``)。仅当您的资源部署到非标准受众时才需覆盖。
其余所有内容(租户、服务主体密钥、联合令牌文件、主权云授权机构、代理偏好)均由 azure-identity 直接从标准的 AZURE_* 环境变量读取 —— 详见下方的 凭据解析顺序。请按照微软 SDK 参考说明,在 ~/.hermes/.env 或部署环境中设置这些变量。
在 Entra 模式下,没有凭据会写入 ~/.hermes/.env —— azure-identity 会在进程内缓存令牌(并在可用时存储于操作系统密钥链 / ~/.IdentityService)。
凭据解析顺序
azure-identity 的 DefaultAzureCredential 在每次令牌请求时按此链路查找,一旦获取到令牌即停止:
- 环境凭据 —
AZURE_TENANT_ID+AZURE_CLIENT_ID+AZURE_CLIENT_SECRET(或AZURE_CLIENT_CERTIFICATE_PATH/AZURE_FEDERATED_TOKEN_FILE)。 - 工作负载标识 —
AZURE_FEDERATED_TOKEN_FILE(AKS 联合令牌 / OIDC)。 - 托管标识 — IMDS 端点(
169.254.169.254)用于虚拟机;IDENTITY_ENDPOINT用于 App Service / Functions / Container Apps。Foundry Agent Service 托管代理使用托管代理自身的代理身份。 - Visual Studio Code — Azure 账户扩展。
- Azure CLI —
az login会话。 - Azure Developer CLI —
azd auth login。 - Azure PowerShell —
Connect-AzAccount。 - 代理程序(仅限 Windows / WSL)— Web Account Manager。
交互式浏览器凭据默认被排除在非交互式 Hermes 运行之外;请改用 Azure CLI、Azure Developer CLI、托管标识、工作负载标识或服务主体凭据。
部署模式
本地开发:
az login
hermes model # pick Azure Foundry → Entra ID
hermes # uses your az login token
Azure VM / Functions / App Service / Container Apps(系统分配托管标识):
- 在计算资源上启用系统分配的标识。
- 将标识授予
Azure AI User(或Foundry User)权限至 Foundry 资源。 - 在 config.yaml 中设置
model.auth_mode: entra_id—— 无需额外环境变量。
Azure VM / Functions / App Service / Container Apps(用户分配托管标识):
- 将
AZURE_CLIENT_ID设置为用户分配标识的客户端 ID,以便DefaultAzureCredential正确选择。
Foundry Agent Service 托管代理:
- 创建托管代理,并将该代理的身份授予
Azure AI User(或Foundry User)权限至 Foundry 资源。Hermes 在托管代理内部使用ManagedIdentityCredential;角色分配应针对代理身份本身,而非父项目或您的用户。服务主体在 CI 中: - 在运行器环境变量中设置
AZURE_TENANT_ID、AZURE_CLIENT_ID、AZURE_CLIENT_SECRET。
主权云(政府、中国区):
- 导出
AZURE_AUTHORITY_HOST(例如https://login.microsoftonline.us` for Azure Government, `https://login.partner.microsoftonline.cn用于 Azure 中国)。azure-identity会直接读取该值。
健康检查
hermes doctor 在 model.auth_mode: entra_id 时对 DefaultAzureCredential 执行 10 秒探测,报告哪个内部凭证生效(环境变量是否存在、托管标识端点是否可达等)。
hermes auth 显示结构化状态块:
azure-foundry (Microsoft Entra ID): Endpoint: https://my-resource.openai.azure.com/openai/v1 Scope: https://ai.azure.com/.default Status: configured; live token probe is skipped here
限制
- Anthropic 风格端点使用 httpx 事件钩子。 Anthropic Python SDK 不原生支持可调用的
auth_token(≤ 0.86.0 版本)。Hermes 在自定义的httpx.Client上安装请求事件钩子,为每次出站请求生成新的 JWT 并重写Authorization: Bearer <jwt>。这在功能上等同于 OpenAI SDK 的原生Callable[[], str]合约,但增加了一层间接性。若未来 Anthropic SDK 增加对可调用认证的原生支持,Hermes 将自动切换。 - 批量任务与
multiprocessing.Pool。 Entra token 提供者是一个闭包,无法跨进程序列化。batch_runner.py会自动从工作器配置中移除该可调用对象,并让每个工作器进程从config.yaml重新构建自己的提供者——无需用户操作,但每个工作器启动时需多一次链路遍历。 auth.json中无 bearer JWT 持久化。 Hermes 不复制azure-identity内部的令牌缓存;冷启动时会在首次推理时重新遍历凭证链。
配置(写入 config.yaml)
运行向导后,你会看到类似如下内容:
```yaml
model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions # or "anthropic_messages"
default: gpt-5.4-mini # your deployment / model name
context_length: 400000 # auto-detected
以及在 ``~/.hermes/.env`` 中:
AZURE_FOUNDRY_API_KEY=<your-azure-key>
---
## OpenAI 风格端点(GPT、Llama 等)
Azure OpenAI 的 v1 GA 端点可兼容标准的 ``openai`` Python 客户端,仅需少量修改:
model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions
default: gpt-5.4
重要行为:
- **GPT-5.x、codex 和 o 系列模型自动路由至 Responses API。** Microsoft Foundry 将 GPT-5 / codex / o1 / o3 / o4 模型部署为仅支持 Responses API —— 调用 ``/chat/completions`` 会返回 ``400 "The requested operation is unsupported."``。Hermes 通过模型名称识别这些系列,并透明地将 ``api_mode`` 升级为 ``codex_responses``,即使 ``config.yaml`` 仍读取 ``api_mode: chat_completions`` 也无影响。GPT-4、GPT-4o、Llama、Mistral 等部署仍使用 ``/chat/completions``。
- **``max_completion_tokens`` 会自动使用。** Azure OpenAI(如同直接 OpenAI)对 gpt-4o、o 系列和 gpt-5.x 模型要求 ``max_completion_tokens``。Hermes 会根据端点自动发送正确的参数。
- **需要 ``api-version`` 的旧版端点。** 若你使用的是遗留基础 URL(如 ``https://<resource>.openai.azure.com/openai?api-version=2025-04-01-preview``),Hermes 会提取查询字符串,并通过 ``default_query`` 在每次请求中转发它(否则 OpenAI SDK 在拼接路径时会丢弃该部分)。
---
## Anthropic 风格端点(通过 Microsoft Foundry 使用 Claude)
对于 Claude 部署,请使用 Anthropic 风格路径:
model:
provider: azure-foundry
base_url: https://my-resource.services.ai.azure.com/anthropic
api_mode: anthropic_messages
default: claude-sonnet-4-6
重要行为:
- **``/v1`` 会被从基础 URL 中移除。** Anthropic SDK 会在每个请求 URL 后追加 ``/v1/messages``。Hermes 在将 URL 交给 SDK 前会移除尾部的 ``/v1``,以避免出现重复的 ``/v1`` 路径。
- **``api-version`` 通过 ``default_query`` 发送,而非附加到 URL。** Azure Anthropic 要求通过 ``api-version`` 查询字符串传递密钥。将其嵌入基础 URL 会导致路径格式错误,如 ``/anthropic?api-version=.../v1/messages``,并返回 404 错误。Hermes 通过 Anthropic SDK 的 ``default_query`` 传递 ``api-version=2025-04-15``。
- **OAuth 令牌刷新已禁用。** Azure 部署使用静态 API 密钥。针对 Anthropic Console 的 ``~/.claude/.credentials.json`` OAuth 刷新循环被明确跳过,以防止 Claude Code 的 OAuth 令牌在会话中途覆盖你的 Azure 密钥。
---
## 替代方案:``provider: anthropic`` + Azure 基础 URL
如果你已有 ``provider: anthropic`` 配置,仅想将其指向 Microsoft Foundry 用于 Claude,可完全跳过 ``azure-foundry`` 提供者:
model:
provider: anthropic
base_url: https://my-resource.services.ai.azure.com/anthropic
key_env: AZURE_ANTHROPIC_KEY
default: claude-sonnet-4-6
并将 ``AZURE_ANTHROPIC_KEY`` 设置在 ``~/.hermes/.env`` 中。Hermes 检测到 ``azure.com`` 出现在基础 URL 中后,会绕过 Claude Code OAuth 令牌链,直接使用 Azure 密钥进行 ``x-api-key`` 认证。
``key_env`` 是标准的 snake_case 字段名;``api_key_env``(以及驼峰命名的 ``keyEnv`` / ``apiKeyEnv``)作为别名接受。若同时设置了 ``key_env`` 与 ``AZURE_ANTHROPIC_KEY``/``ANTHROPIC_API_KEY``,则以 ``key_env`` 命名的环境变量为准。
---
## 模型发现
Azure **不提供纯 API 密钥端点** 来列出你已部署的模型。部署枚举需要 Azure Resource Manager 认证(``az cognitiveservices account deployment list``),使用 Azure AD 主体,而非推理 API 密钥。
Hermes 可实现的功能:
- Azure OpenAI v1 端点(``<resource>.openai.azure.com/openai/v1``)暴露 ``GET /models``,包含资源的**可用模型目录**。Hermes 使用此列表预填充模型选择器。
- Microsoft Foundry ``/anthropic`` 路由:通过 URL 路径检测,模型名称手动输入。
- 私有或防火墙内端点:手动输入,显示友好提示“无法探测”。
你始终可以直接输入部署名称——Hermes 不会基于返回列表进行验证。
---
## 环境变量
| 变量 | 用途 |
|------|------|
| ``AZURE_FOUNDRY_API_KEY`` | 用于 Microsoft Foundry / Azure OpenAI 的主 API 密钥(`api_key` 模式) |
| ``AZURE_FOUNDRY_BASE_URL`` | 端点 URL(通过 ``hermes model`` 设置;环境变量作为备用) |
| ``AZURE_ANTHROPIC_KEY`` | 由 ``provider: anthropic`` + Azure 基础 URL 使用(替代 ``ANTHROPIC_API_KEY``) |
| ``AZURE_TENANT_ID`` | Entra ID 租户,用于服务主体流程 |
| ``AZURE_CLIENT_ID`` | Entra ID 客户端 ID(服务主体、工作负载身份或用户分配的托管标识) |
| ``AZURE_CLIENT_SECRET`` | 服务主体密码 |
| ``AZURE_CLIENT_CERTIFICATE_PATH`` | 服务主体证书(替代密码) |
| ``AZURE_FEDERATED_TOKEN_FILE`` | 工作负载身份联合令牌路径(AKS) |
| ``AZURE_AUTHORITY_HOST`` | 主权云授权主机覆盖 |
| ``IDENTITY_ENDPOINT`` / ``MSI_ENDPOINT`` | App Service、Functions 和 Container Apps 的托管标识端点;VM 通常使用 IMDS |
Azure SDK 直接读取 ``AZURE_*`` 环境变量。Hermes 仅在输出 ``hermes doctor`` 时检查其存在性,其他情况下不主动解析。
---
## 故障排除
**gpt-5.x 部署返回 401 未授权。**
Azure 将 gpt-5.x 部署在 ``/chat/completions`` 上,而非 ``/responses``。当 URL 包含 ``openai.azure.com`` 时,Hermes 会自动处理,但如果看到带有 ``Invalid API key`` 响应体的 401 错误,请检查 ``api_mode`` 在你的 ``config.yaml`` 中是否为 ``chat_completions``。
**在 ``/v1/messages?api-version=.../v1/messages`` 上返回 404。**
这是早期 Azure Anthropic 配置中的 malformed-URL 问题。升级 Hermes —— 现在 ``api-version`` 参数通过 ``default_query`` 传递,而非嵌入基础 URL,因此 SDK 不会在路径拼接时破坏它。
**向导提示“自动检测不完整”。**
该端点拒绝了 ``/models`` 探测和 Anthropic Messages 探测。这对位于防火墙后或启用了 IP 白名单的私有端点是正常的。请回退至手动 API 模式选择,并直接输入部署名称——一切仍可正常工作,只是 Hermes 无法预填选择器。
**选错了传输方式。**
重新运行 ``hermes model``,向导将重新探测。如果探测仍选择错误模式,可直接编辑 ``config.yaml``:
model:
provider: azure-foundry
api_mode: anthropic_messages # or chat_completions
```Entra ID:切换至 auth_mode: entra_id 后出现“credential chain exhausted”或 401 Unauthorized 错误
- 运行
az login以刷新开发人员会话(缓存的令牌可能已过期)。 - 验证
Azure AI User(或Foundry User)的角色分配是否生效:请确认az role assignment list --assignee <user-or-identity-id>在您的 Foundry 资源上已正确列出。角色传播可能需要最多 5 分钟时间。 - 对于用户分配的托管标识,请再次确认
AZURE_CLIENT_ID与计算资源关联的标识一致。 - 运行
hermes doctor— Azure Entra 探针将报告令牌获取是否成功,并提供修复建议。
Entra ID:向导预检步骤卡住或超时
10 秒的预检为轻量级检查。可选择“仍保存并稍后验证”,部署到目标环境后运行 hermes doctor。常见原因包括无法访问令牌服务或本地登录状态过期——在 CI 中优先使用工作负载身份,使用服务主体时请设置 AZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET,本地开发时运行 az login。
使用 Entra ID 时 Anthropic 风格端点返回 401 错误
请确认相同的 Azure AI User(或 Foundry User)角色已在 Foundry 资源上分配(该角色同时覆盖 /openai/v1 和 /anthropic 路径)。如果向导阶段的 OpenAI 风格探针正常,但在运行时 claude-* 请求失败,最常见的原因是早期向导运行遗留的过期 model.entra.scope —— 请从 config.yaml 中删除 entra.scope 行,使运行时恢复默认 `https://ai.azure.com/.default`` 范围。
相关内容
- 环境变量
- 配置
- AWS Bedrock — 另一个主要云服务商集成
- Microsoft:为 Foundry 配置 Entra ID — 关键无密路径的上游文档