跳到主要内容

Microsoft Foundry

Hermes Agent 的 azure-foundry 提供程序支持 Microsoft Foundry(前身为 Azure AI Foundry)和 Azure OpenAI。单个 Foundry 资源可以托管具有两种不同线路格式(wire formats)的模型:

  • 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 门户的“Keys and Endpoint”下获取),要么如果你计划使用 Microsoft Entra ID(微软推荐的无密钥路径),则需要拥有该 Foundry 资源上的 Azure AI User RBAC 角色。在微软的重命名推广期间,某些租户可能将该角色显示为 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 中,以便模型能够正确调整其上下文窗口的大小。

微软建议在生产环境的 Foundry 工作负载中使用基于 Microsoft Entra ID 的无密钥身份验证。Hermes 支持两种 API 接口的 Entra ID:

  • 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 原生的可调用 api_key= 契约 — SDK 会自动为每个请求生成一个新的 JWT。
  • Anthropic 风格使用带有由 agent.azure_identity_adapter.build_bearer_http_client 安装的请求事件钩子的 httpx.Client,因为 Anthropic SDK 原生不支持可调用 auth_token。该钩子会在每个出站请求中重写 Authorization: Bearer <fresh-jwt>。相同的微软 RBAC,相同的 Foundry 范围 — 唯一的区别在于 SDK 契约。

为什么使用 Entra ID?

  • 无需轮换或撤销长期有效的 API 密钥。
  • 基于 RBAC 的访问控制 — 在 Foundry 资源上授予或移除 Azure AI User,无需重写配置。
  • 访问和审计日志按受让人细分,而不是所有调用者共享一个静态密钥。
  • 通过托管身份,为 Azure VM、AKS Pod、App Service、Functions、Container Apps 和 Foundry Agent Service 提供统一的身份验证表面。
  • 适用于 CI/CD 管道的工作负载身份和服务主体流程。

一次性设置(Azure 端)

  1. 在 Azure 门户中,打开你的 Foundry 资源 → Access control (IAM)Add → Add role assignment
  2. 选择 Azure AI User 角色(如果你的租户已重命名角色,则选择 Foundry User)。
  3. 将其分配给:
    • 你的用户账户,用于通过 `az login进行本地开发。
    • 托管身份或工作负载身份,用于 Azure 托管的计算资源(生产环境推荐)。
    • Foundry Agent Service 托管代理的代理身份,当 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 的选项:

  • scope — OAuth 资源范围。默认为 Microsoft 文档中记录的推理范围(https://ai.azure.com/.default)。仅当你的资源是针对非标准受众配置时,才需要覆盖此值。

其他所有内容(租户、服务主体密钥、联合令牌文件、主权云权威机构、代理偏好)均由 azure-identity 直接从标准的 AZURE_* 环境变量中读取——请参阅下方的凭据解析顺序。请按照 Microsoft 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. 工作负载标识 (Workload Identity)AZURE_FEDERATED_TOKEN_FILE(AKS 联合令牌 / OIDC)。
  3. 托管标识 (Managed Identity) — 虚拟机的 IMDS 端点(169.254.169.254);App Service / Functions / Container Apps 的 IDENTITY_ENDPOINT。Foundry Agent Service 托管代理使用托管代理的代理标识。
  4. Visual Studio Code — Azure 账户扩展。
  5. Azure CLIaz login 会话。
  6. Azure Developer CLIazd auth login
  7. Azure PowerShellConnect-AzAccount
  8. 代理 (Broker)(仅限 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. 在 Foundry 资源上授予该标识 Azure AI User(或 Foundry User)角色。
  3. 在 config.yaml 中设置 model.auth_mode: entra_id — 无需环境变量。

Azure VM / Functions / App Service / Container Apps(用户分配的托管标识):

  • AZURE_CLIENT_ID 设置为用户分配标识的客户端 ID,以便 DefaultAzureCredential 选择正确的标识。

Foundry Agent Service 托管代理:

  • 创建托管代理,并在 Foundry 资源上授予该代理标识 Azure AI User(或 Foundry User)角色。Hermes 在托管代理内部使用 ManagedIdentityCredential;角色分配应属于代理标识,而不仅仅是父项目或你的用户。

AKS 工作负载标识(取代 AAD Pod Identity):

  • 使用工作负载标识客户端 ID 注解 Pod 的服务账户。
  • Pod 的联合令牌文件通过 AZURE_FEDERATED_TOKEN_FILE 自动检测。
  • model.auth_mode: entra_id 无需进一步配置更改即可工作。

CI 中的服务主体:

  • 在运行器环境中设置 AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRET

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

导出 AZURE_AUTHORITY_HOST(例如,Azure Government 为 https://login.microsoftonline.us,Azure China 为 https://login.partner.microsoftonline.cn)。azure-identity 会直接读取该变量。

健康检查

model.auth_mode: entra_id 时,hermes doctor 会对 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 令牌提供者是一个闭包,无法跨进程边界进行 pickle 序列化。batch_runner.py 会自动从工作器配置中删除该可调用对象,并让每个工作器进程从 config.yaml 重建其自己的提供者——无需用户操作,但每个工作器在启动时会执行一次链遍历。
  • auth.json 中不持久保存 bearer JWT。 Hermes 不会复制 azure-identity 的内部令牌缓存;冷启动时在首次推理时会遍历凭据链。

配置(写入 config.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 的 v1 之前版本的端点。 如果你拥有类似 https://<resource>.openai.azure.com/openai?api-version=2025-04-01-preview 的旧版基础 URL,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

重要行为:

  • 从基础 URL 中剥离 /v1 Anthropic SDK 会将 /v1/messages 附加到每个请求 URL 后面 —— 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
  • 使用 Bearer 认证而非 x-api-key Azure 的 Anthropic 兼容路由要求使用 Authorization: Bearer <key>,而不是 Anthropic 原生的 x-api-key 标头。Hermes 检测到基础 URL 中包含 azure.com 时,会将 API 密钥通过 SDK 的 auth_token 字段进行路由,以确保正确的标头到达上游。
  • 保留 1M 上下文窗口 Beta 标头。 Azure 仍然通过 anthropic-beta: context-1m-2025-08-07 标头对 1M token 的 Claude 上下文(Opus 4.6/4.7、Sonnet 4.6)进行 gating。Hermes 在 Azure 路径上保留该 Beta 标头(由于某些订阅会拒绝该标头,因此它在原生 Anthropic OAuth 请求中被剥离,但 Azure 需要它)。
  • 禁用 OAuth 令牌刷新。 Azure 部署使用静态 API 密钥。适用于 Anthropic Console 的 ~/.claude/.credentials.json OAuth 令牌刷新循环会针对 Azure 端点显式跳过,以防止 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

需在 ~/.hermes/.env 中设置 AZURE_ANTHROPIC_KEY。Hermes 检测到基础 URL 中包含 azure.com 时,会绕过 Claude Code OAuth 令牌链,直接使用 x-api-key 认证方式使用 Azure 密钥。

key_env 是规范的 snake_case 字段名称;api_key_env(以及 camelCase 形式的 keyEnv / apiKeyEnv)作为别名被接受。如果同时设置了 key_envAZURE_ANTHROPIC_KEY/ANTHROPIC_API_KEY,则以 key_env 命名的环境变量优先。

模型发现

Azure 暴露仅使用 API 密钥即可列出已部署模型的端点。枚举部署需要通过 Azure AD 主体进行 Azure Resource Manager 身份验证(az cognitiveservices account deployment list),而不是使用推理 API 密钥。

Hermes 可以执行的操作:

  • Azure OpenAI v1 端点(<resource>.openai.azure.com/openai/v1)暴露 GET /models,提供资源的可用模型目录。Hermes 使用此列表预填充模型选择器。
  • Microsoft Foundry /anthropic 路由:通过 URL 路径检测,手动输入模型名称。
  • 私有/防火墙后的端点:手动输入,并显示友好的“无法探测”消息。

你可以始终直接输入部署名称 —— Hermes 不会根据返回的列表进行验证。

环境变量

变量用途
AZURE_FOUNDRY_API_KEYMicrosoft Foundry / Azure OpenAI 的主要 API 密钥(api_key 模式)
AZURE_FOUNDRY_BASE_URL端点 URL(通过 hermes model 设置;环境变量用作回退)
AZURE_ANTHROPIC_KEYprovider: anthropic + Azure 基础 URL 使用(ANTHROPIC_API_KEY 的替代方案)
AZURE_TENANT_ID用于服务主体流程的 Entra ID 租户
AZURE_CLIENT_IDEntra ID 客户端 ID(服务主体、工作负载标识或用户分配的托管标识)
AZURE_CLIENT_SECRET服务主体密钥
AZURE_CLIENT_CERTIFICATE_PATH服务主体证书(密钥的替代方案)
AZURE_FEDERATED_TOKEN_FILE工作负载标识联合令牌路径(AKS)
AZURE_AUTHORITY_HOST主权云权威主机覆盖
IDENTITY_ENDPOINT / MSI_ENDPOINTApp Service、Functions 和 Container Apps 的托管标识端点;VM 通常改用 IMDS

Azure SDK 直接读取 AZURE_* 环境变量。Hermes 除了报告 hermes doctor 输出中存在哪些源之外,从不检查这些变量。

故障排除

gpt-5.x 部署出现 401 Unauthorized。 Azure 在 /chat/completions 上提供 gpt-5.x 服务,而不是 /responses。当 URL 包含 openai.azure.com 时,Hermes 会自动处理此问题,但如果你看到带有 Invalid API key 正文的 401 错误,请检查 config.yaml 中的 api_mode 是否为 chat_completions

/v1/messages?api-version=.../v1/messages 出现 404。 这是修复前 Azure Anthropic 设置中的 malformed-URL(URL 格式错误)bug。升级 Hermes — api-version 参数现在通过 default_query 传递,而不是硬编码到基础 URL 中,因此 SDK 在连接 URL 时不会破坏它。

向导显示“自动检测不完整。” 端点拒绝了 /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。 验证 Foundry 资源上是否分配了相同的 Azure AI User(或 Foundry User)角色(它涵盖 /openai/v1/anthropic 路径)。如果向导期间 OpenAI 风格探测成功,但 claude-* 请求在运行时失败,最常见的原因是早期向导运行留下的过时 model.entra.scope — 从 config.yaml 中删除 entra.scope 行,以便运行时回退到默认的 https://ai.azure.com/.default 范围。