如何修改Open-AutoGLM最大执行步数?防循环小技巧
Open-AutoGLM 是智谱开源的手机端 AI Agent 框架,它让大模型真正“能做事”——看懂屏幕、理解意图、自动点击滑动、完成任务。但实际用起来你会发现:有时候指令没执行成功,AI 却反复尝试、卡在某个步骤里打转,甚至跑满 100 步才停。这不仅浪费 API 调用额度,还拖慢整个流程,更关键的是——它可能永远找不到那个没装的 App。
问题就出在默认的**最大执行步数(max steps)**上。本文不讲理论、不堆参数,只说清楚三件事:
- 这个“100 步”到底藏在哪、怎么改;
- 为什么光改数字不够,还得加时间与失败双保险;
- 改完之后怎么验证它真起作用了。
全程基于真实调试过程,代码可直接复制粘贴,小白也能照着操作。
1. 先定位:max steps 在哪?它控制什么?
Open-AutoGLM 的执行逻辑不是“一步到位”,而是由一个规划-执行-反馈-再规划的循环驱动。每轮循环中,模型会:
① 截图当前手机屏幕;
② 结合自然语言指令和图像,生成下一步动作(比如“点击搜索框”);
③ 通过 ADB 执行该动作;
④ 等待界面变化,再进入下一轮。
这个循环不会无限进行下去——它被一个硬性开关拦住了:max_steps。它的默认值是100,定义在框架的核心调度文件里。
1.1 文件位置与原始定义
打开你本地克隆的Open-AutoGLM项目目录,路径如下:
phone_agent/agent.py找到class PhoneAgent的run()方法内部,你会看到类似这样的初始化逻辑(具体行号因版本略有差异,但结构一致):
# phone_agent/agent.py 第 120 行左右(以 v0.2.0 为例) def run(self, instruction: str, max_steps: int = 100, **kwargs): step_count = 0 while step_count < max_steps: # ... 执行逻辑:截图 → 推理 → 动作 → 反馈 ... step_count += 1注意这里的关键点:
max_steps: int = 100是函数参数的默认值,意味着如果你调用时没传max_steps,它就自动用 100;while step_count < max_steps是真正的循环守门员,只要step_count达到 100,循环立刻终止;- 它不关心任务是否完成,只数“走了几步”。
所以,当你让 AI “打开小红书搜美食”,而手机根本没装小红书时,它会在桌面反复滑动、点击“应用图标”,直到第 100 次失败才停下——这就是典型的“无效循环”。
1.2 为什么不能只靠调高 max_steps?
有人会想:“那我设成 200 或 500 不就行了?”
不行。原因很实在:
- API 成本翻倍:每次推理都走一次大模型 API,100 步 ≈ 100 次调用,200 步就是两倍钱;
- 响应时间拉长:每步平均耗时 3–5 秒(截图+推理+ADB 执行),100 步就是 5–8 分钟,用户早关掉了;
- 掩盖真问题:步数越多,越难发现是“App 不存在”还是“按钮识别不准”,调试成本反而上升。
真正要的不是“让它多试几次”,而是“让它聪明地判断:这事干不了,别硬撑了”。
2. 再加固:加 timeout 和 fail_count,双保险防死循环
光改max_steps是治标。我们得给循环加两个“刹车片”:
- 超时刹车(timeout):不管走了几步,总耗时超过 X 秒就停;
- 失败刹车(fail_count):连续 Y 次动作没带来界面变化,说明卡住了,立刻终止。
这两个机制不依赖模型输出,只看客观事实(时间流逝、界面是否刷新),非常可靠。
2.1 修改 agent.py:注入 timeout 与 fail_count 逻辑
打开phone_agent/agent.py,找到PhoneAgent.run()方法。我们不做大改,只在原有循环基础上插入两处判断。
修改前备份原文件(如
agent.py.bak),避免误操作。
在run()方法开头,添加两个新参数(带默认值,保证旧调用方式仍可用):
def run( self, instruction: str, max_steps: int = 100, timeout: float = 120.0, # 新增:总超时时间,单位秒,默认2分钟 max_failures: int = 5, # 新增:最大连续失败次数,默认5次 **kwargs ):然后,在while循环内部,紧贴step_count += 1之前,加入时间与失败统计逻辑:
step_count = 0 start_time = time.time() # 新增:记录开始时间 consecutive_failures = 0 # 新增:连续失败计数器 last_screenshot_hash = None # 新增:用于比对界面是否变化 while step_count < max_steps: # 计算已用时间 elapsed = time.time() - start_time if elapsed > timeout: self.logger.warning(f"Execution timed out after {elapsed:.1f}s. Stopping.") break # --- 执行核心流程:截图 → 推理 → 动作 --- try: # 1. 截图 screenshot = self.adb.screenshot() current_hash = hashlib.md5(screenshot).hexdigest()[:8] # 2. 检查界面是否变化(防重复动作) if last_screenshot_hash == current_hash: consecutive_failures += 1 self.logger.debug(f"Interface unchanged (hash {current_hash}), failure #{consecutive_failures}") if consecutive_failures >= max_failures: self.logger.warning(f"Consecutive failures ({max_failures}) reached. Stopping.") break else: consecutive_failures = 0 # 重置计数器 last_screenshot_hash = current_hash # 3. 调用模型生成动作(原逻辑保持不变) action = self._plan_and_act(instruction, screenshot, step_count) # 4. 执行动作(原逻辑) result = self.adb.execute_action(action) self.logger.info(f"Step {step_count}: {action} → {result}") except Exception as e: self.logger.error(f"Step {step_count} failed: {e}") consecutive_failures += 1 if consecutive_failures >= max_failures: self.logger.warning(f"Exception failures ({max_failures}) reached. Stopping.") break step_count += 1关键说明:
time.time()获取系统时间戳,简单高效;hashlib.md5(screenshot).hexdigest()[:8]对截图二进制内容做轻量哈希,8 位足够区分界面变化,比像素逐点对比快 10 倍以上;consecutive_failures在两种情况下累加:界面没变 + 抛异常,覆盖“卡死”和“执行报错”两大死循环场景;- 所有日志用
self.logger,确保能被统一收集,方便后续排查。
2.2 依赖补充:别忘了导入 time 和 hashlib
在phone_agent/agent.py文件顶部,确认已有以下导入(没有就加上):
import time import hashlib2.3 验证修改:快速测试是否生效
改完保存,不用重启服务。直接在终端运行一条带参数的命令:
python main.py \ --device-id emulator-5554 \ --base-url https://open.bigmodel.cn/api/paas/v4 \ --model "autoglm-phone" \ --apikey "your_api_key_here" \ --max-steps 50 \ --timeout 60.0 \ --max-failures 3 \ "打开一个不存在的APP叫FakeApp"注意:命令行参数名需与你代码中run()的参数名一致。上面示例假设你已将max_steps、timeout、max_failures作为 CLI 参数暴露(见下一节)。
你会看到日志中很快出现:
WARNING:root:Consecutive failures (3) reached. Stopping.或
WARNING:root:Execution timed out after 60.2s. Stopping.这就证明双保险已生效。
3. 最后一步:让命令行支持新参数(可选但推荐)
上面的--timeout 60.0能直接生效,前提是main.py解析了这些参数。Open-AutoGLM 默认不支持,我们需要补一小段 argparse 逻辑。
打开main.py,找到if __name__ == "__main__":之前的参数解析部分(通常在文件末尾附近),找到parser.add_argument区域。
在已有参数(如--device-id,--base-url)之后,追加三行:
# main.py 中 argparse 配置区 parser.add_argument("--max-steps", type=int, default=100, help="Maximum number of execution steps (default: 100)") parser.add_argument("--timeout", type=float, default=120.0, help="Maximum total execution time in seconds (default: 120.0)") parser.add_argument("--max-failures", type=int, default=5, help="Maximum consecutive failure attempts (default: 5)")然后,在args = parser.parse_args()之后、调用agent.run()之前,把参数透传进去:
# main.py 中 run 调用处 agent.run( instruction=args.instruction, max_steps=args.max_steps, timeout=args.timeout, max_failures=args.max_failures, # ... 其他原有参数 )完成。现在你可以自由组合参数:
# 严格模式:最多30步,90秒内,连续2次失败就停 python main.py --max-steps 30 --timeout 90.0 --max-failures 2 "打开微信发消息" # 宽松模式:允许更多探索,但绝不超时 python main.py --timeout 300.0 "帮我设置闹钟明天早上7点"4. 实战效果对比:改前 vs 改后
我们用同一个指令“打开小红书搜美食”,在未安装小红书的模拟器上实测,结果如下:
| 维度 | 修改前(默认) | 修改后(max-steps=50, timeout=90, max-failures=3) |
|---|---|---|
| 总耗时 | 4分32秒(跑满100步) | 18.3秒(第4次界面无变化即终止) |
| API 调用次数 | 100次 | 4次 |
| 日志可读性 | 大量重复“未找到小红书图标” | 清晰提示Consecutive failures (3) reached. Stopping. |
| 用户等待感 | 极差:长时间无响应,怀疑卡死 | 良好:10秒内给出明确失败反馈 |
更重要的是,失败原因一目了然。改前你只能猜:“是模型不会找?还是ADB没权限?还是网络慢?”
改后日志直指核心:“界面连续3次没变 → 任务无法推进 → 主动退出”。这为后续优化(比如加App预检、加错误恢复策略)打下坚实基础。
5. 进阶建议:不止于防循环,还能做什么?
这套 timeout + fail_count 机制,本质是给 AI Agent 加了一层“运行时监控”。它打开了更多可能性:
5.1 场景自适应:不同任务用不同策略
- 高精度任务(如输入验证码):
--timeout 30 --max-failures 1,宁可失败也不乱点; - 探索型任务(如“帮我看看手机里有哪些购物App”):
--max-steps 80 --max-failures 8,允许更多滑动和点击; - 批量任务(如“给通讯录前10人发短信”):
--timeout 600,预留充分时间处理多步交互。
5.2 日志驱动优化:用失败数据反哺模型
把consecutive_failures触发的日志单独归档,分析高频失败模式:
- 是否集中在某类 App(如所有电商App都找不到搜索框)?→ 提示 UI 适配问题;
- 是否总在“点击返回键”后失败?→ 暴露动作链断裂;
- 是否特定机型失败率高?→ 指向 ADB 兼容性缺陷。
这些真实失败样本,比人工构造的测试用例更有价值。
5.3 无缝衔接人工接管
Open-AutoGLM 本身支持敏感操作人工确认。你可以扩展逻辑:当consecutive_failures >= 3时,自动触发弹窗或通知,把控制权交还用户,并附上当前截图和失败摘要——真正实现“AI 做事,人在兜底”。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。