fix(openai): 切组后剥离失配的 previous_response_id,修复跨组会话鉴权失败

用户从公开组切回订阅组后,客户端沿用旧 Responses 会话 ID,订阅组调度到
不拥有该会话链的账号,上游因会话链鉴权不匹配返回“鉴权失败,请检查 API Key”。

两处修复:
- openai_ws_state_store: 本地热缓存 responseToAccount 改为按 {groupID}:{responseID}
  命名空间,与 Redis 层 sticky_session:{groupID}:... 一致,避免单实例下跨组命中
  其他分组遗留的本地绑定,确保 StickyPreviousHit 信号可信。
- openai_gateway_handler: 转发前若 previous_response_id 未在当前分组命中粘连账号
  (StickyPreviousHit=false),主动剥离并改用完整 input 重建上下文;带
  function_call_output 的工具续链保持原样(与 WS 重连恢复逻辑一致)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
bwlcandClaude Opus 4.8 committed 2026-06-06 16:54:56 +08:00
1 parent 635ad81cdc
commit 87dd5f5d72
3 files changed
+37 -4

No files matched your search

@@ -358,6 +358,17 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
if channelMapping.Mapped {
forwardBody = h.gatewayService.ReplaceModelInBody(body, channelMapping.MappedModel)
}
// 切组/会话失配防护:previous_response_id 未在当前分组命中粘连账号(StickyPreviousHit=false)
// 说明会话链不属于本次账号,携带它会触发上游会话链鉴权失败,故主动剥离改用完整 input 重建。
// 带 function_call_output 的工具续链无法重建,保持原样(与 WS 重连恢复一致)。
if previousResponseID != "" && !scheduleDecision.StickyPreviousHit &&
!service.ValidateFunctionCallOutputContextBytes(forwardBody).HasFunctionCallOutput {
forwardBody = service.RemovePreviousResponseIDFromBody(forwardBody)
reqLog.Debug("openai.previous_response_id_stripped_cross_group",
zap.Int64("account_id", account.ID),
zap.String("schedule_layer", scheduleDecision.Layer),
)
}
writerSizeBeforeForward := c.Writer.Size()
result, err := func() (*service.OpenAIForwardResult, error) {
defer func() {