diff --git a/backend/internal/service/openai_live.go b/backend/internal/service/openai_live.go index 9ec872ed3..92ba900b3 100644 --- a/backend/internal/service/openai_live.go +++ b/backend/internal/service/openai_live.go @@ -253,6 +253,7 @@ func (s *OpenAIGatewayService) createUpstreamLiveCall( ) (*LiveCallCreated, error) { token, _, err := s.GetAccessToken(ctx, account) if err != nil { + logLiveCreateStageFailure(ctx, account.ID, "access_token", err) return nil, err } body, err := json.Marshal(struct { @@ -272,6 +273,7 @@ func (s *OpenAIGatewayService) createUpstreamLiveCall( } authHeaders, err := s.buildOpenAIAuthenticationHeaders(ctx, account, token) if err != nil { + logLiveCreateStageFailure(ctx, account.ID, "authentication_headers", err) return nil, err } for key, values := range authHeaders { @@ -281,6 +283,7 @@ func (s *OpenAIGatewayService) createUpstreamLiveCall( } upstreamReq.Host = "chatgpt.com" if err := resolveAndSetOpenAIChatGPTAccountHeaders(ctx, s.accountRepo, upstreamReq.Header, account); err != nil { + logLiveCreateStageFailure(ctx, account.ID, "account_headers", err) return nil, err } upstreamReq.Header.Set("Content-Type", "application/json") @@ -289,6 +292,7 @@ func (s *OpenAIGatewayService) createUpstreamLiveCall( resp, err := s.httpUpstream.Do(upstreamReq, resolveAccountProxyURL(account), account.ID, account.Concurrency) if err != nil { + logLiveCreateStageFailure(ctx, account.ID, "upstream_transport", err) return nil, err } defer func() { _ = resp.Body.Close() }() @@ -318,6 +322,15 @@ func (s *OpenAIGatewayService) createUpstreamLiveCall( }, nil } +func logLiveCreateStageFailure(ctx context.Context, accountID int64, stage string, err error) { + logger.FromContext(ctx).Warn( + "OpenAI Live 创建阶段失败", + zap.Int64("account_id", accountID), + zap.String("stage", stage), + zap.String("error_type", fmt.Sprintf("%T", err)), + ) +} + func logLiveUpstreamFailure( ctx context.Context, accountID int64, @@ -376,6 +389,12 @@ func applyLiveUpstreamIdentityHeaders(headers http.Header) { headers.Set("OpenAI-Alpha", "quicksilver=v2") ensureCodexIdentityHeaders(headers) enforceCodexIdentityHeaders(headers) + if strings.TrimSpace(headers.Get("session-id")) == "" { + headers.Set("session-id", uuid.NewString()) + } + if strings.TrimSpace(headers.Get("thread-id")) == "" { + headers.Set("thread-id", uuid.NewString()) + } // Realtime/Live 不使用 Responses 的实验头。 headers.Del("OpenAI-Beta") } diff --git a/backend/internal/service/openai_live_test.go b/backend/internal/service/openai_live_test.go index 919233588..30845eb45 100644 --- a/backend/internal/service/openai_live_test.go +++ b/backend/internal/service/openai_live_test.go @@ -121,6 +121,8 @@ func TestCreateUpstreamLiveCallPreservesSession(t *testing.T) { require.Equal(t, "Bearer test-access-token", upstream.request.Header.Get("Authorization")) require.Equal(t, "acct_test", upstream.request.Header.Get("Chatgpt-Account-Id")) require.Equal(t, "quicksilver=v2", upstream.request.Header.Get("OpenAI-Alpha")) + require.NotEmpty(t, upstream.request.Header.Get("Session-Id")) + require.NotEmpty(t, upstream.request.Header.Get("Thread-Id")) require.Empty(t, upstream.request.Header.Get("OpenAI-Beta")) require.Equal(t, HTTPUpstreamProfileOpenAI, HTTPUpstreamProfileFromContext(upstream.request.Context())) require.True(t, HTTPUpstreamRedirectsDisabled(upstream.request.Context()))