
DeepSeek Harness 中的 429 限流重試次數增大與 RetryPolicy 配置陷阱1. 關于 DeepSeek HarnessDeepSeek Harness簡稱 dsh是 DeepSeek AI 開發的開源 Agent 運行時框架。采用 Cordis 插件架構一切皆插件支持 Web UI 和 CLI 兩種交互方式。當前處于開發者預覽階段迭代迅速。npx deepseek-ai/dsh web # 啟動 Web UI默認 http://127.0.0.1:30802. 問題生產環境遇到模型 API 限流導致的請求失敗RetryAfter: 1064ms Failure: 429 {message:rpm exhausted,type:quota_exceeded_error,code:8}DSH 默認DEFAULT_MAX_RETRIES 2定義于pi-ai/dist/utils/retry.js。對于高頻調用場景2 次重試在指數退避的初始階段即耗盡請求在 1-2 秒內失敗。3. 配置架構3.1 適配器路由settings.yaml中的agent-default-model決定了請求的適配器路由agent-default-model:provider:provider-amodel:model-xprovider字段作為路由 key決定請求發往哪個適配器provider 值適配器配置文件存在于llm-pi-ai.providers下llm-pi-aisettings.yamldeepseek-officialllm-deepseekcordis.patch.yml關鍵必須先確認模型走哪個適配器再改對應的配置文件。改錯文件不會生效。3.2 Provider 配置插槽llm-pi-ai適配器的 Provider 配置結構llm-pi-ai.providers.provider: - apiKeyEnv # 憑證環境變量名 - api # API 協議openai-completions / openai-chat - baseURL # 端點 - retryPolicy # 重試策略可選 - models[] # 模型聲明列表每個 provider 的配置是獨立命名空間retryPolicy只影響當前 provider 的請求。4. 配置 RetryPolicy4.1 配置項retryPolicy:mode:normal# 重試模式maxRetries:12# 最大重試次數默認 2retryableCodes:# 可重試的錯誤碼列表-RATE_LIMIT-SERVER-TIMEOUT-TRANSPORT-EMPTY_RESPONSEbackoff:initialDelayMs:5000# 初始退避延遲maxDelayMs:30000# 最大退避延遲指數退避上限4.2 參數語義mode: normal— 標準退避模式Retry-After響應頭優先級高于backoff計算值maxRetries— 重試次數的硬上限與retryableCodes共同構成重試判定backoff.initialDelayMs— 首次重試前的延遲基數backoff.maxDelayMs— 指數退避的上限超過此值的退避延遲會被截斷4.3 指數退避算法DSH 的退避實現采用 capped exponential backoffdelay min(initialDelayMs × 2^(attempt-1), maxDelayMs)對initialDelayMs5000, maxDelayMs30000AttemptDelayCumulative15,000ms5s210,000ms15s320,000ms35s430,000ms (capped)65s530,000ms95s630,000ms125s…30,000ms…1230,000ms~6min4.4 配置熱加載settings.yaml采用熱加載機制——DSH 在運行時通過文件系統 watch 檢測變更無需進程重啟修改后立即生效。5. 陷阱錯誤分類導致重試失效配置了maxRetries: 12之后遇到 429 限流仍然不重試直接報錯429: {message:Allocated quota exceeded, please increase your quota limit.,type:invalid_request_error,code:insufficient_quota}5.1 重試判定流程Request → Failure → classifyPiAiError(message) ← 錯誤分類 → isQuotaExceededError(message) ① 優先匹配 quota → /429|rate.?limit/i ② 其次匹配 429 → retryableCodes.includes(code) ← 重試判定 → true → recover() ← 指數退避后重試 → false → next() ← 直接終止拋出終態錯誤5.2 根因錯誤分類的優先級反轉classifyPiAiErrordsh-llm-pi-ai/lib/index.js的實現functionclassifyPiAiError(message){if(isQuotaExceededError(message))returnQUOTA_EXCEEDED_CODE;// priority 1if(/\b429\b|rate.?limit/i.test(message))returnRATE_LIMIT;// priority 2// ...}isQuotaExceededErrordsh-llm/lib/index.js的判定正則/\b(?:quota|usage[\s_-]limit)[\s_-](?:exceeded|exhausted|reached)\b/i當錯誤消息中出現quota_exceeded_error或quota exceeded等詞面時函數返回QUOTA_EXCEEDED_CODE QUOTA與 HTTP 狀態碼無關。match 發生在判定 429 之前。5.3 重試判定短路dsh-llm-retry/lib/index.js的recover方法if(!policy.retryableCodes.includes(failure.code))returnnext();retryableCodes默認值不包含QUOTA。因此即使maxRetries配置為 12一旦錯誤被歸類為 QUOTA重試判定在第一步就短路直接調用next()拋出終態錯誤。6. 解決方案在retryPolicy.retryableCodes中顯式聲明QUOTAretryPolicy:mode:normalmaxRetries:12retryableCodes:-RATE_LIMIT-SERVER-TIMEOUT-TRANSPORT-EMPTY_RESPONSE-QUOTA# 讓配額類429 也參與重試backoff:initialDelayMs:5000maxDelayMs:30000注意顯式聲明retryableCodes會覆蓋默認值因此需要將其他可重試錯誤碼一并列出。7. 設計缺陷與改進建議7.1 錯誤分類的優先級反轉QUOTA判定優先于RATE_LIMIT導致 429 限流被錯誤歸類為終態錯誤。合理的做法是將具體的 HTTP 狀態碼匹配429置于語義匹配quota之前或提供可配置的分類優先級。7.2retryableCodes默認值不完整QUOTA 碼在語義上屬于可重試的臨時錯誤應納入默認可重試列表。7.3providerRetryAfterMs的靜默丟棄當Retry-After響應頭值大于maxDelayMs時normal 模式直接調用next()放棄重試無日志、無告警。8. 調用鏈與代碼路徑層級組件職責配置宿主settings.yaml→llm-pi-ai.providers.provider.retryPolicy用戶配置入口Schema 驗證pi-ai/dist/types.d.ts→maxRetries?: number類型約束適配器dsh-llm-pi-ai/lib/index.js→classifyPiAiError錯誤分類錯誤分類dsh-llm/lib/index.js→isQuotaExceededErrorQUOTA 判定正則重試控制dsh-llm-retry/lib/index.js→recover重試判定 退避執行退避算法pi-ai/dist/utils/retry.js→DEFAULT_MAX_RETRIES 2默認值 指數退避計算9. 參考代碼位置node_modules/deepseek-ai/dsh-llm-pi-ai/lib/index.js—classifyPiAiErrornode_modules/deepseek-ai/dsh-llm/lib/index.js—isQuotaExceededError(±L298),QUOTA_EXCEEDED_CODE QUOTAnode_modules/deepseek-ai/dsh-llm-retry/lib/index.js—recover中的retryableCodes.includesnode_modules/earendil-works/pi-ai/dist/utils/retry.js—DEFAULT_MAX_RETRIES 2C:\Users\user\.dsh\settings.yaml— 用戶配置