fix: 流式调用失败时写入模型会话错误信息

This commit is contained in:
2026-08-22 09:58:12 +08:00
parent cb9d04648c
commit 174eb7cf27
+19
View File
@@ -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/DurationSecondsOmitEmpty 不会影响已落库字段);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 {