👁 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,判断其是否与目标推理端点匹配。
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 |
AddOpenAIChatCompletion | Authorization: Bearer * | 面向 OpenAI 兼容端点 | 否,返回 401 |
AddAzureOpenAIChatCompletion | api-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 中也建议在文档中补充相关说明。
🔗 相关阅读(你可能还想看)
📄 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