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