diff --git a/service/model_session_service.go b/service/model_session_service.go index b0c5fff..5de63a6 100644 --- a/service/model_session_service.go +++ b/service/model_session_service.go @@ -160,11 +160,14 @@ LOOP: g.Log().Warningf(ctx, "模型流式请求异常,第 %d 次重试(等待 %v): code=%s err=%v", attempt+1, wait, retryCode, err) select { case <-ctx.Done(): + recordSessionError(context.WithoutCancel(ctx), id, startTime, "调用取消: "+ctx.Err().Error()) return nil, ctx.Err() case <-time.After(wait): } goto LOOP } + // 非重试错误/重试耗尽:请求失败即返回,需把失败信息写入模型会话记录,避免留半截无错误信息记录 + recordSessionError(ctx, id, startTime, err.Error()) return nil, err } @@ -226,6 +229,7 @@ LOOP: g.Log().Warningf(ctx, "模型流式调用异常,第 %d 次重试(等待 %v): code=%s msg=%s", attempt+1, wait, streamErrCode, streamErrMsg) select { case <-ctx.Done(): + recordSessionError(context.WithoutCancel(ctx), id, startTime, "调用取消: "+ctx.Err().Error()) return nil, ctx.Err() case <-time.After(wait): } @@ -283,6 +287,8 @@ func (s *modelSessionService) CreateSessionStream(ctx context.Context, w http.Re // 获取上游流式 reader 并设置 SSE 响应头 streamReader, err := ModelHttpStreamRequest(ctx, w, modelInfo.BaseURL, modelInfo.RequestHeadMapping, modelInfo.HttpMethod, newRequestParams) if err != nil { + // 请求建立前失败:把错误写入模型会话记录,避免留半截无错误信息记录 + recordSessionError(ctx, id, startTime, err.Error()) return nil, err } @@ -441,6 +447,19 @@ func (s *modelSessionService) CreateSessionStream(ctx context.Context, w http.Re return docMsg, nil } +// recordSessionError 请求建立前失败(上游不可达/非 2xx 且非重试/重试耗尽/调用取消)时, +// 把错误与耗时写入模型会话记录,避免流式调用留半截无错误信息记录。 +// 仅写 ErrorMsg/DurationSeconds(OmitEmpty 不会影响已落库字段);ctx 已取消时须传 WithoutCancel(ctx)。 +func recordSessionError(ctx context.Context, id int64, startTime time.Time, errMsg string) { + if _, updateErr := dao.ModelSession.Update(ctx, &dto.UpdateModelSessionReq{ + Id: id, + DurationSeconds: int64(time.Since(startTime).Seconds()), + ErrorMsg: errMsg, + }); updateErr != nil { + g.Log().Errorf(ctx, "更新模型会话错误信息失败: %v", updateErr) + } +} + // isRetryableErrorCode 判定上游返回的错误码是否可重试:限流(429/limit_requests/limit_tokens/rate_limit_exceeded)与 5xx(500-503)。 // ModelHttpNormalRequest 不返回 HTTP status,只能按响应体 error.code 字符串判定。 func isRetryableErrorCode(code string) bool {