diff --git a/service/model_task_start_service.go b/service/model_task_start_service.go index b7c26b4..1de9906 100644 --- a/service/model_task_start_service.go +++ b/service/model_task_start_service.go @@ -21,14 +21,23 @@ type modelTaskStartService struct{} // CreateTask 创建任务 func (s *modelTaskStartService) CreateTask(ctx context.Context, req *dto.CallModelTaskStartReq) (res *dto.ModelCallRes, err error) { startTime := time.Now() + attempt := 0 id := req.Id modelInfo := req.ModelInfo newRequestParams := req.RequestParams +LOOP: // 6) 模型请求 modelRespBody, err := httpclient.ModelHttpNormalRequest(ctx, modelInfo.BaseURL, modelInfo.RequestHeadMapping, modelInfo.HttpMethod, newRequestParams) if err != nil { + if attempt < modelCallMaxRetries && shouldRetryWithMemory(ctx, modelInfo, "", err.Error(), "") { + attempt++ + if waitErr := retryWait(ctx, attempt); waitErr != nil { + return nil, waitErr + } + goto LOOP + } return nil, fmt.Errorf("模型请求失败: %v", err) } if modelRespBody == nil { @@ -46,10 +55,18 @@ func (s *modelTaskStartService) CreateTask(ctx context.Context, req *dto.CallMod docMsg := new(dto.ModelCallRes) docMsg.TaskId = id // 按模型 ErrorMessageMapping 解析错误响应,无错误返回空串 - if _, docMsg.ErrorMsg, err = parseModelError(modelRespBody, modelInfo.ErrorMessageMapping); err != nil { + var errCode string + if errCode, docMsg.ErrorMsg, err = parseModelError(modelRespBody, modelInfo.ErrorMessageMapping); err != nil { return nil, fmt.Errorf("模型返回参数解析失败:%v", err) } if docMsg.ErrorMsg != "" { + if attempt < modelCallMaxRetries && shouldRetryWithMemory(ctx, modelInfo, errCode, docMsg.ErrorMsg, string(modelRespBody)) { + attempt++ + if waitErr := retryWait(ctx, attempt); waitErr != nil { + return nil, waitErr + } + goto LOOP + } updateModelReq.ErrorMsg = docMsg.ErrorMsg } if docMsg.ErrorMsg == "" { diff --git a/service/retry.go b/service/retry.go index d66d706..65dfc3b 100644 --- a/service/retry.go +++ b/service/retry.go @@ -25,16 +25,6 @@ func retryWait(ctx context.Context, attempt int) error { } } -// isRetryableErrorCode 判定上游返回的错误码是否可重试:限流(429/limit_requests/limit_tokens/rate_limit_exceeded)与 5xx(500-503)。 -// httpclient.ModelHttpNormalRequest 不返回 HTTP status,只能按响应体 error.code 字符串判定。 -func isRetryableErrorCode(code string) bool { - switch code { - case "429", "500", "501", "502", "503", "InvalidParameter", "limit_requests", "limit_tokens", "rate_limit_exceeded": - return true - } - return false -} - // firstText 取任意值首位文本:数组取首个元素,其余原样转字符串 func firstText(v any) string { if arr, ok := v.([]any); ok && len(arr) > 0 { diff --git a/service/session_stream.go b/service/session_stream.go index 3be7528..ae12c25 100644 --- a/service/session_stream.go +++ b/service/session_stream.go @@ -18,7 +18,7 @@ import ( ) // CreateSessionStreamOnce 流式调用上游模型 → 缓冲全量后一次返回(走 gf 框架正常返回)。 -// 与同步请求一致:上游返回可重试错误码(限流/5xx)时按指数退避重试(最多 modelCallMaxRetries 次)。 +// 与同步请求一致:上游返回错误时按 shouldRetryWithMemory 判定是否指数退避重试(最多 modelCallMaxRetries 次)。 func (s *modelSessionService) CreateSessionStreamOnce(ctx context.Context, req *dto.CallModelSessionReq) (docMsg *dto.ModelCallRes, err error) { startTime := time.Now() @@ -29,20 +29,22 @@ func (s *modelSessionService) CreateSessionStreamOnce(ctx context.Context, req * attempt := 0 LOOP: // 获取上游流式 reader(stream=false → w 不会被使用,传 nil)。 - // 非 2xx 状态/网络错误在此返回;错误含可重试错误码(限流/5xx)时按指数退避重试,与同步请求一致。 + // 非 2xx 状态/网络错误在此返回;按 shouldRetryWithMemory 判定是否指数退避重试,与同步请求一致。 streamReader, err := httpclient.ModelHttpStreamRequest(ctx, nil, modelInfo.BaseURL, modelInfo.RequestHeadMapping, modelInfo.HttpMethod, newRequestParams) if err != nil { - if retryCode := streamRetryCodeOfError(err); retryCode != "" && attempt < modelCallMaxRetries { - attempt++ - wait := time.Duration(1<= 0 { - codeStr := strings.TrimSpace(msg[idx+len("状态码异常: "):]) + if idx := strings.Index(e, "状态码异常: "); idx >= 0 { + codeStr := strings.TrimSpace(e[idx+len("状态码异常: "):]) if comma := strings.IndexByte(codeStr, ','); comma >= 0 { codeStr = codeStr[:comma] } - if isRetryableErrorCode(codeStr) { - return codeStr - } + return codeStr, "" } - return "" + return "", "" } diff --git a/service/session_sync.go b/service/session_sync.go index eabb093..721be3a 100644 --- a/service/session_sync.go +++ b/service/session_sync.go @@ -56,8 +56,7 @@ LOOP: return nil, fmt.Errorf("模型返回参数解析失败:%v", err) } if errCode != "" { - - if attempt < modelCallMaxRetries && isRetryableErrorCode(errCode) { + if attempt < modelCallMaxRetries && shouldRetryWithMemory(ctx, modelInfo, errCode, errMsg, string(modelRespBody)) { attempt++ wait := time.Duration(1<