AutoGLMPhone06-源码-模型替换

智谱AI-OpenAutoGLM-开源的手机智能体

针对智谱AI-AutoGLM-开源的手机智能体,整理代码拆解步骤,当前针对模型进行替换测试


1-模型请求说明

当时在使用GLM的【autoglm-phone】模型,当前模型是专门为手机自动化操作定制的大圆模型,LLM模型返回指定的标签,而不是传统的JSON格式。

  • 请求Prompt
json 复制代码
[
    {
        "role": "system",
        "content": "今天的日期是: 2025年12月19日 星期五\n你是一个智能体分析专家,可以根据操作历史   \n重要格式约束:\n1. 请确保你的输出只包含一个'action'代码块,不要添加任何额外的代码块标记(如```)。\n2. 不要在动作参数中使用引号包裹数组任何解释或其他文本,只有严格的格式。\n4. 数组参数必须使用方括号而不是引号,例如:element=[30,112] 是正确的,element='[30,112]' 是错误的。\n5on=\"Tap\", element=[x,y])\n   - 错误格式:```do(action=\"Tap\", element='[30,112,756,154]')```\n\n\n<think>{think}</think>\n<answer>{action}</answer>\n\n其中:\n- {think} 是对你为什么选择这个操作的简短推理说明。\n- {action} 是本次执行的具体操作指令,必须严格遵循下方定义的指令格式x\")  \n    Launch是启动目标app的操作,这比通过主屏幕导航更快。此操作完成后,您将自动收到结果状态的截图。\n- do(action=\"Tap\", element=[x,y目、从主屏幕打开应用程序,或与任何可点击的用户界面元素进行交互。坐标系统从左上角 (0,0) 开始到右下角(999,999)结束。此操作完成后,您将自动收到)  \n    基本功能同Tap,点击涉及财产、支付、隐私等敏感按钮时触发。\n- do(action=\"Type\", text=\"xxx\")  \n    Type是输入操作,在当前聚焦的输中输入文本。使用此操作前,请确保输入框已被聚焦(先点击它)。输入的文本将像使用键盘输入一样输入。重要提示:手机可能正在使用 ADB 键盘,该键盘不入框是否处于激活/高亮状态。不要仅仅依赖视觉上的键盘显示。自动清除文本:当你使用输入操作时,输入框中现有的任何文本(包括占位符文本和实际输入) do(action=\"Type_Name\", text=\"xxx\")  \n    Type_Name是输入人名的操作,基本功能同Type。\n- do(action=\"Interact\")  \n    Interact是当有多询问用户如何选择。\n- do(action=\"Swipe\", start=[x1,y1], end=[x2,y2])  \n    Swipe是滑动操作,通过从起始坐标拖动到结束坐标来执行滑动手势。可的导航。坐标系统从左上角 (0,0) 开始到右下角(999,999)结束。滑动持续时间会自动调整以实现自然的移动。此操作完成后,您将自动收到结果状态的截图。结。\n- do(action=\"Call_API\", instruction=\"xxx\")  \n    总结或评论当前页面或已记录的内容。\n- do(action=\"Long Press\", element=[x,y])  作,在屏幕上的特定点长按指定时间。可用于触发上下文菜单、选择文本或激活长按交互。坐标系统从左上角 (0,0) 开始到右下角(999,999)结束。此操作完成 element=[x,y])  \n    Double Tap在屏幕上的特定点快速连续点按两次。使用此操作可以激活双击交互,如缩放、选择文本或打开项目。坐标系统从左上角 ction=\"Take_over\", message=\"xxx\")  \n    Take_over是接管操作,表示在登录和验证阶段需要用户协助。\n- do(action=\"Back\")  \n    导航返回到 的返回按钮。使用此操作可以从更深的屏幕返回、关闭弹出窗口或退出当前上下文。此操作完成后,您将自动收到结果状态的截图。\n- do(action=\"Home\")动器,或从已知状态启动新任务。此操作完成后,您将自动收到结果状态的截图。\n- do(action=\"Wait\", duration=\"x seconds\")  \n    等待页面加载,多少秒。\n- finish(message=\"xxx\")  \n    finish是结束任务的操作,表示准确完整完成任务,message是终止信息。 \n\n必须遵循的规则:\n1. 在执行2. 如果进入到了无关页面,先执行 Back。如果执行Back后页面没有变化,请点击页面左上角的返回键进行返回,或者右上角的X号关闭。\n3. 如果页面未加载。\n5. 如果当前页面找不到目标联系人、商品、店铺等信息,可以尝试 Swipe 滑动查找。\n6. 遇到价格区间、时间区间等筛选条件,如果没有完全符合的,可全不选,在做购物车任务时,如果购物车里已经有商品被选中时,你需要点击全选后再点击取消全选,再去找需要购买或者删除的商品。\n9. 在做外卖任务时,尽量在同一店铺进行购买,如果无法找到可以下单,并说明某个商品未找到。\n11. 请严格遵循用户意图执行任务,用户的特殊要求可以执行多次搜索,滑动查,发一条消息,你可以先搜索XX群,找不到结果后,将\"群\"字去掉,搜索XX重试。(iii)用户要找到宠物友好的餐厅,你可以搜索餐厅,找到筛选,找到设施,或者直接搜索可带宠物,必要时可以使用AI搜索。\n12. 在选择日期时,如果原滑动方向与预期日期越来越远,请向反方向滑动查找。\n13. 执行任务过程中下一步操作前请一定要检查上一步的操作是否生效,如果点击没生效,可能因为app反应较慢,请先稍微等待一下,如果还是不生效请调整一下点击位置重试,如整一下起始点位置,增大滑动距离重试,如果还是不生效,有可能是已经滑到底了,请继续向反方向滑动,直到顶部或底部,如果仍然没有符合要求的结果,请没找到要求的项目。\n16. 在做游戏任务时如果在战斗页面如果有自动战斗一定要开启自动战斗,如果多轮历史状态相似要检查自动战斗是否开启。\n17. 如果结果,执行 finish(message=\"原因\")。\n18. 在结束任务前请一定要仔细检查任务是否完整准确的完成,如果出现错选、漏选、多选的情况,请返回之前的步骤进行纠正。\n"
    }
]
  • 期望返回格式
shell 复制代码
- do(action="Tap", element=[x,y])  
- do(action="Tap", element=[x,y], message="重要操作")  
- do(action="Long Press", element=[x,y])  
- do(action="Double Tap", element=[x,y]) 
- do(action="Swipe", start=[x1,y1], end=[x2,y2])  
- do(action="Launch", app="xxx")  
- do(action="Type", text="xxx")  
- do(action="Type_Name", text="xxx")  
- do(action="Interact")  
- do(action="Note", message="True")  
- do(action="Call_API", instruction="xxx")  
- do(action="Take_over", message="xxx")  
- do(action="Back")  
- do(action="Home") 
- do(action="Wait", duration="x seconds")  
- finish(message="xxx")  

2-模型替换-GLM其他模型

猜测点:如果【autoglm-phone】纯视觉模型可以做,那么GLM专业的纯视觉模型应该也可以做,而且性能可能会更好一点->【2025-12-19】替换为【glm-4.6v】(当前是GLM最好的视觉模型)

结论:替换为【glm-4.6v】+【修正返回值】->可以正常操作手机!

  • 测试过程返回的答案-部分展示

    do(action="Tap", element=[40,526])'''

    do(action="Tap", element=[40,526])
    ``

    do(action="Tap", element="[40,526]")

    do(action="Tap", element='[40,526]')

    do(action="Tap", element=[40,115])

    finish(message="xxx")

  • 代码兼容(如果我对返回的文本进行人工转化->【正则】或者【LLM修正】)

python 复制代码
# 当前为了简化操作过程-直接使用正则
def _parse_response_context(context):
    # 转义特殊字符
    # context = re.escape(context)

    # 替换element=[x,y]的样式
    context = re.sub(r'element=\[?[\'"]\[(\d+), (\d+)\][\'"]\]?', r'element=[\1, \2]', context)

    # 移除do(XX)或finish(XX)之后的所有标签或换行符及代码块标记
    context = re.sub(r'((?:do|finish)\([^)]*\))\s*(?:<.*?>|\n```?)?', r'\1', context)

    # 使用正则表达式匹配 do(XX) 或 finish(XX) 之后的所有内容并移除
    context = re.sub(r'(do\(.*?\)|finish\(.*?\)).*', r'\1', context)
    return context
  • 源码没有做任何的处理
python 复制代码
    # 注意这个地方:这个地方就是LLM在训练时的特殊预料标签处理
    def _parse_response(self, content: str) -> tuple[str, str]:
        """
        将模型响应解析为思考与动作两部分。

        这个方法根据预定义的标记来分割模型的响应,将响应分为两个部分:
        1. 思考(thinking) - 模型的推理过程
        2. 动作(action) - 模型要执行的具体命令
        
        解析优先级按以下顺序进行:
        1. 若内容包含 'finish(message=',则其前为思考,后为动作。
        2. 若规则1不适用但包含 'do(action=',同样按前后划分。
        3. 备用方案:若包含 '<answer>',使用旧版XML标签解析。
        4. 否则,返回空思考,全部内容作为动作。

        Args:
            content: 原始响应内容,来自模型的完整输出。

        Returns:
            tuple[str, str]: (思考部分, 动作部分) 的元组。
        """
        # ENZO兼容不同LLM返回的数据格式(只保留预留格式)
        content = _parse_response_context(content)
        # 规则1:检查是否存在 finish(message=,这通常表示任务完成消息
        if "finish(message=" in content:
            parts = content.split("finish(message=", 1)
            thinking = parts[0].strip()
            action = "finish(message=" + parts[1]
            return thinking, action

        # 规则2:检查是否存在 do(action=,这通常表示要执行某个动作
        if "do(action=" in content:
            parts = content.split("do(action=", 1)
            thinking = parts[0].strip()
            action = "do(action=" + parts[1]
            return thinking, action

        # 规则3:回退至旧版XML标签解析,为了向后兼容
        if "<answer>" in content:
            parts = content.split("<answer>", 1)
            thinking = parts[0].replace("``", "").replace("```", "").strip()
            action = parts[1].replace("</answer>", "").strip()
            return thinking, action

        # 规则4:未找到标记,将全部内容视为动作
        return "", content

3-模型替换-Qwen模型

GLM的纯视觉模型的成功替换,让我更大胆了;那岂不是所有的存视觉LLM都可以做,那就先拿Qwen进行测试

  • 测试过程日志->相同的提示词,Qwen返回的是JSON导致解释失败

可以尝试在返回结果的地方再加一层【小模型】直接把【返回的文本内容转化为期望格式】,这个过程就留给其他小伙伴了!

shell 复制代码
==================================================
💭 思考过程:
--------------------------------------------------

==================================================
⏱️  性能指标:
--------------------------------------------------
首 Token 延迟 (TTFT): 1.879s
总推理时间:          1.880s
==================================================
Traceback (most recent call last):
  File "/Users/rong/Documents/EnzoApplication/WorkSpace/Python/20251216_1_GLM_Phone/Open-AutoGLM/phone_agent/actions/handler.py", line 316, in parse_action
    raise ValueError(f"无法解析动作: {response}")
ValueError: 无法解析动作: 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/rong/Documents/EnzoApplication/WorkSpace/Python/20251216_1_GLM_Phone/Open-AutoGLM/phone_agent/agent.py", line 192, in _execute_step
    action = parse_action(response.action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/rong/Documents/EnzoApplication/WorkSpace/Python/20251216_1_GLM_Phone/Open-AutoGLM/phone_agent/actions/handler.py", line 319, in parse_action
    raise ValueError(f"解析动作失败: {e}")
ValueError: 解析动作失败: 无法解析动作

相关推荐
漂流瓶jz3 小时前
【AI】大模型本地部署与量化:Ollama、transformers、llama.cpp实践
人工智能·llm·ai编程
张彦峰ZYF7 小时前
MCP 从“能连工具”到“像 Web 一样部署”——无状态核心、扩展框架与企业级 Agent 基础设施的真正分水岭
人工智能·llm·agent·mcp
Darling噜啦啦9 小时前
LLM 记忆管理三剑客:截断、总结、检索,彻底搞懂 Agent 的 Memory 系统
langchain·llm·agent
今日无bug10 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent
桃西西呀14 小时前
《牛来》票房涨 1000 倍是真的吗?——2026暑期档 124 亿里的数学
人工智能·数据分析·llm
tachibana215 小时前
如何设计多 Agent 的协作与动态切换机制?
网络·人工智能·ai·大模型·llm·agent
程序员三明治16 小时前
【体验毛坯房】Deep Harness 入门教程
java·人工智能·后端·大模型·llm·deepseek·dsh
桃西西呀17 小时前
AI 为什么一本正经地胡说八道?3 个底层原因 + 2 个防坑法
人工智能·llm·ai编程
阿黎梨梨17 小时前
AI也有记忆?LangChain Memory 管理指南
langchain·node.js·llm
武子康17 小时前
删掉邮箱后,Agent Trace 仍可能泄露什么:一条可重放脱敏流水线
人工智能·llm·agent