Qwen Code 改进建议
April 5, 2026 · View on GitHub
核心洞察:当 CLI Agent 被配置为 CI/CD 自动化流水线的一环,或是作为后台 Daemon 代理运行夜间批处理任务(如全局重构、大规模安全审计)时,系统的容错性要求会发生质变。在交互模式下,如果大模型 API 宕机或遇到限流(429 Rate Limit),快速失败(Fail-fast)并让用户知晓是合理的;但在无人值守(Unattended)模式下,一次长达数小时的任务因为偶发的 529 过载而直接退出,将导致前功尽弃。Claude Code 针对此场景专门设计了“无限持久化重试模式(Persistent Retry)”;而 Qwen Code 目前所有模式均采用一刀切的固定次数重试,无法胜任严苛的自动化场景。
返回 改进建议总览
一、自动化场景下的网络雪崩与痛点
1. Qwen Code 的现状:短视的重试
在 packages/core/src/utils/retry.ts 中,Qwen Code 设定了全局统一的 maxAttempts: 7。
- 痛点:假设凌晨 2 点触发了 GitHub Actions 自动化重构任务。如果 3 点时大模型服务遭遇突发的大规模高峰拥堵,连续抛出 529 错误。Qwen Code 在尝试 7 次(可能总跨度只有一两分钟)后,就会抛出致命错误,彻底终结 CI 进程。早上 9 点开发者来上班时,看到的只是一个红色的 Pipeline 和只做了一半的损坏代码树。这违背了自动化流水线“最终一致性(Eventual Consistency)”的初衷。
2. Claude Code 的解决方案:无人值守持久化
Claude Code 在 services/api/withRetry.ts 中,通过检测 CLAUDE_CODE_UNATTENDED_RETRY 环境变量(或者检测自身是否在 --bg / CI 环境),会激活 isPersistentRetryEnabled() 分支。
机制一:无视 maxRetries 的无限等待
当抛出错误被 isTransientCapacityError(error) 判定为暂时性的容量错误(特指 HTTP 429 限流和 HTTP 529 服务过载)时:
const persistent = isPersistentRetryEnabled() && isTransientCapacityError(error);
if (attempt > maxRetries && !persistent) {
throw new CannotRetryError(error, retryContext);
}
// 如果 persistent 为 true,直接 bypass 掉 maxRetries 检查,进入下一轮 while 循环。
它会变成一只有耐心的“僵尸”,永远不主动退出任务,直到 API 恢复响应。
机制二:心跳与退避上限锁定
无限重试并不意味着无限地用请求去轰炸 API 服务器:
- 退避上限 (Cap):普通的指数退避可能很快就会涨到每次等待几十分钟。但在持久化模式下,它将单次重试的最长等待时间封顶为 5 分钟(
PERSISTENT_MAX_BACKOFF_MS)。 - 重置计数器 (Reset Cap):如果累计退避时间达到了 6 小时,它会将退避重置机制清零,防止跨天任务出现等待过长的问题。
- 心跳保活 (Heartbeat):在干等的漫长周期内(比如等了 20 分钟),它还会每隔 30 秒向外部的遥测系统(或 CI Runner 的控制台)打印或发送一个心跳探测:
Agent is waiting for API capacity...,防止 CI 系统因为长期没有stdout产出而强行把任务timeout杀掉。
二、Qwen Code 的改进路径 (P1 优先级)
为了使 Qwen Code 能够作为可信赖的基础设施接入企业的 DevOps 管道,必须引入环境感知的容错层。
阶段 1:环境探针与 CLI 参数
- 在
packages/core/src/core/config.ts中引入isUnattendedMode()探测逻辑(例如检查是否配置了--ci参数、或者环境变量CI=true)。 - 让该状态可被底层的
geminiChat.ts或retry.ts访问。
阶段 2:重写 Retry 循环
在现有的 retryWithBackoff 函数中,修改判定退出条件的逻辑:
// Qwen Code: 改进的重试退出判定
const isTransient = status === 429 || status === 529 || status === 500;
const persistentMode = isUnattendedMode() && isTransient;
if (attempt >= maxAttempts && !persistentMode) {
throw error;
}
阶段 3:加入 CI 友好的日志与退避盖帽
- 设置
maxDelayMs:如果启用持久化模式,将指数退避的delay强制Math.min(delay, 5 * 60 * 1000)。 - 在
delay()函数运行期间,如果时间大于 1 分钟,每隔 30 秒通过debugLogger或向stderr抛出一条低噪音日志,安抚 CI Runner。
三、改进收益评估
- 实现成本:极低。只需在原有的重试函数上增加环境判断分支即可。
- 直接收益:
- 解放生产力:让 Qwen Code 真正具备“彻夜批处理”的能力,成为不知疲倦的代码审计员。
- 应对拥堵利器:在国内各种“百模大战”引发 API 限流的大背景下,不至于因为一时的配额枯竭而丢失几十个并发运行的宝贵任务。