Skip to main content

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)

向导将执行以下操作:

  1. 嗅探 URL 路径 — 以 /anthropic 结尾的 URL 被识别为 Microsoft Foundry Claude 路由。
  2. 探测 GET <base>/models — 如果端点返回 OpenAI 风格的模型列表,Hermes 将切换至 chat_completions,并预填充返回的部署 ID 选择器。
  3. 探测 Anthropic Messages 格式 — 作为对不暴露 /models 但接受 Anthropic Messages 格式的端点的后备方案。
  4. 回退至手动输入 — 对于拒绝所有探测的私有/受控端点仍然有效;您可手动选择 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 不原生支持 callable auth_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 端设置

  1. 在 Azure 门户中打开您的 Foundry 资源 → 访问控制 (IAM)添加 → 添加角色分配
  2. 选择 Azure AI User 角色(若租户已重命名,请使用 Foundry User)。
  3. 将其分配给:
    • 您的用户账户,用于本地开发时使用 az login
    • 托管标识或工作负载标识,用于 Azure 托管计算(生产环境推荐)。
    • 托管代理服务中的代理身份,当 Hermes 运行在托管代理内时。
    • 服务主体,当工作负载标识不可用时用于 CI/CD 流水线。
  4. 等待约 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 特定的选项:

其余所有内容(租户、服务主体密钥、联合令牌文件、主权云授权机构、代理偏好)均由 azure-identity 直接从标准的 AZURE_* 环境变量读取 —— 详见下方的 凭据解析顺序。请按照微软 SDK 参考说明,在 ~/.hermes/.env 或部署环境中设置这些变量。

在 Entra 模式下,没有凭据会写入 ~/.hermes/.env —— azure-identity 会在进程内缓存令牌(并在可用时存储于操作系统密钥链 / ~/.IdentityService)。

凭据解析顺序

azure-identityDefaultAzureCredential 在每次令牌请求时按此链路查找,一旦获取到令牌即停止:

  1. 环境凭据AZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET(或 AZURE_CLIENT_CERTIFICATE_PATH / AZURE_FEDERATED_TOKEN_FILE)。
  2. 工作负载标识AZURE_FEDERATED_TOKEN_FILE(AKS 联合令牌 / OIDC)。
  3. 托管标识 — IMDS 端点(169.254.169.254)用于虚拟机;IDENTITY_ENDPOINT 用于 App Service / Functions / Container Apps。Foundry Agent Service 托管代理使用托管代理自身的代理身份。
  4. Visual Studio Code — Azure 账户扩展。
  5. Azure CLIaz login 会话。
  6. Azure Developer CLIazd auth login
  7. Azure PowerShellConnect-AzAccount
  8. 代理程序(仅限 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(系统分配托管标识):

  1. 在计算资源上启用系统分配的标识。
  2. 将标识授予 Azure AI User(或 Foundry User)权限至 Foundry 资源。
  3. 在 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_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRET

主权云(政府、中国区):

  • 导出 AZURE_AUTHORITY_HOST(例如 https://login.microsoftonline.us` for Azure Government, `https://login.partner.microsoftonline.cn 用于 Azure 中国)。azure-identity 会直接读取该值。

健康检查

hermes doctormodel.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`` 范围。

相关内容