Semantic Kernel .NET 调 Azure AI Foundry 报 api-key 头未发送

👁 71 次阅读

Semantic Kernel 的 OpenAIChatCompletion 为何不发送 api-key 头?

问题来源:https://github.com/microsoft/semantic-kernel/issues/10455 该条目为 microsoft/semantic-kernel 仓库的 issue #10455,标签为 bug 与 .NET,创建于 2025-02-08,最后更新于 2026-07-29,状态仍为 open,评论 10 条(1 条为机器人或无效留言,已剔除,实质讨论 9 条),反应合计 1。

现象描述

使用 AddOpenAIChatCompletion 这个 Kernel 扩展方法注册 OpenAI 聊天客户端时,请求没有携带 api-key 头,而是发送了 Authorization: Bearer *。Azure AI Foundry 的部署要求使用 api-key 头,因此请求以 401 Unauthorized 失败。 复现步骤的注册代码如下:
services.AddOpenAIChatCompletion(
    modelId: modelId,
    serviceId: modelId,
    openAIClient: new OpenAIClient(
        credential: new ApiKeyCredential(
            apiKey
        ),
        options: new OpenAIClientOptions
        {
            Endpoint = new Uri(endpoint)
        }
    )
);
随后获取服务并发送请求:
var chatModel = _semanticKernel.GetRequiredService<IChatCompletionService>(chatModelInfo.ModelId);
var response = await chatModel.GetChatMessageContentAsync(
            chatHistory: _chatHistory,
            kernel: _Kernel);
预期行为是发送 api-key 头。报告者使用的环境为 C#、Semantic Kernel v1.3.6,模型为 Phi-3-small-8k-instruct,端点参数传入的是 https://<resource>.services.ai.azure.com/models。 报告者同时指出,虽然可以用自定义 HTTP client 手动补上正确的头来绕过,但作为微软官方支持的包,理应能与微软自家产品无缝集成。官方文档看起来暗示这种用法开箱即用,实际却不是。

背景原因

报告者补充了一次对照实验:改用 AddAzureOpenAIChatCompletion 时,确实发送了正确的 api-key 头,请求头中出现:
Semantic-Kernel-Version: 1.36.1.0
api-key: <API-KEY>
但该方式生成的 URL 与推理端点不一致:
https://<resource>.services.ai.azure.com/models/openai/deployments/Phi-3-small-8k-instruct/chat/completions?api-version=2024-10-01-preview
而 serverless 的 Phi-3-small-8k-instruct 部署使用实验性的扩展方法可以开箱即用:
(extension) IServiceCollection IServiceCollection.AddOpenAIChatCompletion(string modelId, Uri endpoint, [string? apiKey = null], [string? orgId = null], [string? serviceId = null]) (+ 2 overloads)
据 issue 讨论,serverless 部署期望的是 Authorization 头,这与 Azure AI Foundry 要求的 api-key 头形成了差异。 维护者 dmytrostruk 在 2025-02-09 回应,认可报告者关于「官方包应与微软产品无缝集成」的判断,并提出一个权衡:可以在 Semantic Kernel 层面提供修复,但即便这样做,直接使用 OpenAI SDK 的开发者仍然会遇到同样问题,因此也许在更底层修复更合适。 到了 2025-02-11,维护者进一步说明:考虑到这里用的是 OpenAIClient,实际上无法在 OpenAI .NET SDK 层面更新它,因为底层 SDK 不应感知 Azure AI Foundry 或任何其他 OpenAI 兼容的端点。这基本限定了修复位置——决策倾向于不在客户端 SDK 层做 Azure 特有逻辑。

排查或量化方法

识别该问题的关键量化信号是请求头与响应码的组合:
  • 请求头中是否出现 api-key;若只有 Authorization: Bearer,即命中本问题。
  • 响应是否为 401 Unauthorized。
  • 对照 AddAzureOpenAIChatCompletion 生成的实际 URL,判断其是否与目标推理端点匹配。
在 issue 讨论中,Semantic-Kernel-Version: 1.36.1.0 出现在使用 AddAzureOpenAIChatCompletion 的请求头里,可作为判断所用 SK 版本的一种参考信息。

完整解决方案(社区变通方案)

据 issue 讨论,官方尚未在框架层合入修复,当前可用的路径是换用面向 Azure AI Inference 的客户端与扩展方法。贡献者 jiangweifang 在 2025-02-24 给出如下写法:
var builder = Kernel.CreateBuilder();

var uri = new Uri(_azureOpenaiConfig.Endpoint);
AzureKeyCredential credential = new(_azureOpenaiConfig.API_KEY);
var client = new ChatCompletionsClient(uri, credential, new AzureAIInferenceClientOptions());
builder.AddAzureAIInferenceChatCompletion(_azureOpenaiConfig.DeploymentName, client);

_kernel = builder.Build();
_chatService = client.AsChatClient(_azureOpenaiConfig.DeploymentName).AsChatCompletionService();
qkalla 在 2025-07-18 给出了一段更完整的 Azure AI Foundry 与 SK 集成代码,结构一致:
var builder = Kernel.CreateBuilder();

var client = new ChatCompletionsClient(
    new Uri(_azureOpenaiConfig.Endpoint),
    new AzureKeyCredential(_azureOpenaiConfig.API_KEY),
    new AzureAIInferenceClientOptions()
);
builder.AddAzureAIInferenceChatCompletion(_azureOpenaiConfig.DeploymentName, client);
_kernel = builder.Build();

_chatService = client
    .AsChatClient(
需要注意的是,上述两段代码取自其他用户评论的完整代码,builder.Build() 与 AsChatClient(...).AsChatCompletionService() 的原样保留反映了评论中完整展示的两段调用链。这两段代码属于 issue 讨论中其他用户的经验分享,并非官方确认的修复,使用时需自行验证与当前 SK 版本的兼容性。

参数或对比表格

注册方式发送的头生成的 URL 特征是否适配 Azure AI Foundry
AddOpenAIChatCompletionAuthorization: Bearer *面向 OpenAI 兼容端点否,返回 401
AddAzureOpenAIChatCompletionapi-key: <API-KEY><endpoint>/openai/deployments/<model>/chat/completions?api-version=...URL 与推理端点不一致
实验性 AddOpenAIChatCompletion(modelId, endpoint, ...)Authorization面向 serverless 部署据 issue 讨论,serverless 部署可开箱即用

常见错误排查

  • 请求返回 401 Unauthorized 且抓包只看到 Authorization: Bearer:确认使用的是 AddOpenAIChatCompletion 而非 AddAzureOpenAIChatCompletion,前者据 issue 讨论不会发送 api-key。
  • 换用 AddAzureOpenAIChatCompletion 后 URL 变成带 openai/deployments/... 的形态:该形态与 https://<resource>.services.ai.azure.com/models 推理端点不匹配,需核对部署类型。
  • 目标是 serverless 部署却按 Azure AI Foundry 的 api-key 方式配置:据 issue 讨论,serverless 部署期望的是 Authorization 头,两者要求不同。
  • 直接使用 OpenAI SDK 的 OpenAIClient 并期望它发送 api-key:维护者已说明底层 OpenAI .NET SDK 不会感知 Azure AI Foundry,因此该期望无法在 SDK 层满足。
  • 想用自定义 HTTP client 补头:报告者提出过这一绕过方式,但官方文档层面并未给出统一指引,issue 中建议补充相关说明。

实践建议

据 issue 讨论,选择客户端时应先明确部署形态,而不是先写代码再排查头信息。维护者认为 OpenAIClient 应保持对具体模型部署无关,只要能对接兼容接口即可;报告者也认同 AzureOpenAI 客户端在 Azure 场景下更合适。因此可以形成两条实践原则:
  • 面向 Azure AI Foundry 的部署,优先考虑 AddAzureAIInferenceChatCompletion 配合 ChatCompletionsClient,并核对生成的 URL 是否与端点一致。
  • 面向 serverless 部署,据 issue 讨论可继续使用实验性 AddOpenAIChatCompletion(string modelId, Uri endpoint, ...) 重载,但该 API 带实验性质,版本升级时需重新验证。
  • 无论采用哪种方式,都应先抓取一次请求头与 URL 进行核对,再投入完整业务流程,避免把 401 误判为密钥错误。

FAQ

Q:为什么 AddOpenAIChatCompletion 不发送 api-key 头? A:据 issue 讨论,它基于 OpenAIClient,而 OpenAI .NET SDK 按设计不感知 Azure AI Foundry,因此只发送 Authorization: Bearer。维护者认为无法在 OpenAI .NET SDK 层面修正这一点。 Q:这个 issue 已经关闭了吗? A:没有。截至最后更新(2026-07-29),状态仍为 open,官方尚未合入修复方案。 Q:改用 AddAzureOpenAIChatCompletion 能解决问题吗? A:它确实会发送 api-key 头,但据报告者的实测,生成的是带 openai/deployments/... 的 URL,与 https://<resource>.services.ai.azure.com/models 推理端点不一致,因此不能直接视为等价替代。 Q:有没有可用的替代方案? A:据 issue 讨论,可使用 ChatCompletionsClient 配合 AddAzureAIInferenceChatCompletion,相关示例由 jiangweifang 与 qkalla 提供,需自行验证兼容性。 Q:为什么不能直接在项目里用自定义 HTTP client 补头? A:报告者提到这种方式可以作为变通手段,但也指出作为微软支持的包,应原生集成而无需用户自行补丁;issue 中也建议在文档中补充相关说明。

订阅 AI 百事知

每周精选 AI 工具评测、行业资讯与使用教程,第一时间送达。

🔗 相关阅读(你可能还想看)

📄 Outlook 节点创建草稿添加附件为何报 UnableToDeserializePostBody?
📄 Flowise 点击市场或聊天页为何整页白屏?
📄 如何解决 Azure AI Search 向量存储的 $filter 递归深度超限错误?
📄 如何解决 shadcn/ui Sidebar 与 Header 重叠的问题?
📄 Next.js 开发服务器为何会 JavaScript heap out of memory?
📄 Nuxt 偶发 Cannot read properties of undefined 报错是怎么回事
📄 如何解决「Visual Studio Code for ipad」相关的问题?
📄 如何在AutoGen中实现企业级代理治理的加密行动收据(AAR)?
📄 记忆内容未清洗直接注入系统提示词,如何防范间接提示注入?
crewAI LiteAgent 将记忆内容直接拼接到系统提示词,存在间接提示注入风险。社区提出分层防御方案,但 iss
🤖 想直接和 AI 对话?
免费体验 DeepSeek V4 等顶级模型,无需注册,随问随答
🎯 立即体验 AI 工具

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

🤖 嘟嘟客服
滚动至顶部
🤖 嘟嘟客服
🤖 嘟嘟客服
';i.value='';m.innerHTML+='
...
';fetch('/dify-chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({query:q,user:'w'+Date.now()})}).then(function(r){return r.json()}).then(function(d){var a=d.answer||'暂时无法回复';m.removeChild(m.lastChild);m.innerHTML+='
'+a+'
'}).catch(function(){m.removeChild(m.lastChild);m.innerHTML+='
网络异常
'})">发送