From 4a9fbe1205e9f0e532cb21aa929a8da0486be37c Mon Sep 17 00:00:00 2001 From: luobo Date: Fri, 14 Nov 2025 09:10:10 +0000 Subject: [PATCH] feat(setting): add EmptyResponseRetryEnabled toggle and empty-response retry flow --- .gitignore | 3 ++- controller/relay.go | 6 +++--- setting/model_setting/global.go | 7 +++++++ web/src/i18n/locales/en.json | 4 +++- web/src/i18n/locales/zh.json | 4 +++- .../pages/Setting/Model/SettingGlobalModel.js | 17 +++++++++++++++++ 6 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 4c26c7d6..6aca3a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ tiktoken_cache .aider* .history/ .kiro/ -.venv \ No newline at end of file +.venv +main \ No newline at end of file diff --git a/controller/relay.go b/controller/relay.go index d3290dcf..8373d974 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -128,7 +128,7 @@ func Relay(c *gin.Context) { if openaiErr == nil { // 检查是否实际写入了响应内容 responseWritten := c.GetBool("response_written") - if !responseWritten && model_setting.GetGlobalSettings().AutoRetryEnabled { + if !responseWritten && model_setting.ShouldTreatEmptyResponseAsError() { // 创建一个表示空回复的错误,以便触发重试 openaiErr = service.OpenAIErrorWrapperLocal( fmt.Errorf("empty response from upstream"), @@ -392,8 +392,8 @@ func shouldRetryWithAutoConfig(c *gin.Context, openaiErr *dto.OpenAIErrorWithSta return false } - // 对于空回复的情况,也应该重试 - if openaiErr.Error.Message == "" || strings.Contains(strings.ToLower(openaiErr.Error.Message), "empty") { + // 对于空回复的情况,根据配置决定是否重试 + if model_setting.ShouldTreatEmptyResponseAsError() && (openaiErr.Error.Message == "" || strings.Contains(strings.ToLower(openaiErr.Error.Message), "empty")) { return true } diff --git a/setting/model_setting/global.go b/setting/model_setting/global.go index e31fa1e3..12ac56c3 100644 --- a/setting/model_setting/global.go +++ b/setting/model_setting/global.go @@ -34,6 +34,7 @@ type GlobalSettings struct { AutoRetryCount int `json:"auto_retry_count"` AutoRetryForceChannelSwitch bool `json:"auto_retry_force_channel_switch"` AutoRetryStatusCodes string `json:"auto_retry_status_codes"` + EmptyResponseRetryEnabled bool `json:"empty_response_retry_enabled"` } // 默认配置 @@ -49,6 +50,7 @@ var defaultOpenaiSettings = GlobalSettings{ AutoRetryCount: 3, AutoRetryForceChannelSwitch: false, AutoRetryStatusCodes: "5xx,4xx", + EmptyResponseRetryEnabled: false, } // 全局实例 @@ -84,6 +86,11 @@ func ShouldForceChannelSwitch() bool { return globalSettings.AutoRetryEnabled && globalSettings.AutoRetryForceChannelSwitch } +// ShouldTreatEmptyResponseAsError 是否将空回复视为错误并触发重试 +func ShouldTreatEmptyResponseAsError() bool { + return globalSettings.AutoRetryEnabled && globalSettings.EmptyResponseRetryEnabled +} + // ShouldRetryForStatusCode 检查状态码是否应该重试 func ShouldRetryForStatusCode(statusCode int) bool { if !globalSettings.AutoRetryEnabled { diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 07a7d1a1..fc04b4cd 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1525,5 +1525,7 @@ "请先选择要设置标签的渠道!": "Please select the channel to set the tag first!", "标签不能为空!": "Tag cannot be empty!", "已为 {{count}} 个渠道设置标签!": "{{count}} channels have been set with tags!", - "已选择 {{count}} 个渠道": "{{count}} channels selected" + "已选择 {{count}} 个渠道": "{{count}} channels selected", + "空回复视为错误": "Treat empty responses as errors", + "空回复将触发自动重试与渠道切换": "Empty responses trigger automatic retry and channel switching" } \ No newline at end of file diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json index 65df58c1..42f571fb 100644 --- a/web/src/i18n/locales/zh.json +++ b/web/src/i18n/locales/zh.json @@ -86,5 +86,7 @@ "已完成": "已完成", "失败": "失败", "已取消": "已取消", - "刷新": "刷新" + "刷新": "刷新", + "空回复视为错误": "空回复视为错误", + "空回复将触发自动重试与渠道切换": "空回复将触发自动重试与渠道切换" } \ No newline at end of file diff --git a/web/src/pages/Setting/Model/SettingGlobalModel.js b/web/src/pages/Setting/Model/SettingGlobalModel.js index a43f7b8a..b92ffe65 100644 --- a/web/src/pages/Setting/Model/SettingGlobalModel.js +++ b/web/src/pages/Setting/Model/SettingGlobalModel.js @@ -44,6 +44,7 @@ export default function SettingGlobalModel(props) { 'global.auto_retry_count': 3, 'global.auto_retry_force_channel_switch': false, 'global.auto_retry_status_codes': '5xx,4xx', + 'global.empty_response_retry_enabled': false, 'general_setting.ping_interval_enabled': false, 'general_setting.ping_interval_seconds': 60, }); @@ -279,6 +280,22 @@ export default function SettingGlobalModel(props) { /> + + + + setInputs({ + ...inputs, + 'global.empty_response_retry_enabled': value, + }) + } + extraText={t('空回复将触发自动重试与渠道切换')} + disabled={!inputs['global.auto_retry_enabled']} + /> + +