摘要

25年底,阶跃星辰升级发布了全新的AI Agent系列模型Step-GUI,包括云端模型Step-GUI、首个面向GUI Agent的MCP协议:GUI-MCP(Graphical User Interface - Model Context Protocol),这是首个专为图形用户界面自动化而设计的 MCP 实现,兼顾标准化与隐私保护。

因此,我们就来解读这个MCP协议,顺便看看端侧Agent的实现架构。本文是第六篇,主要是介绍Step-GUI的HITL,以及其他特殊之处。

因为是反推解读,而且时间有限,所以可能会有各种错误,还请大家不吝指出。

0x01 HITL

1.1 HITL的意义

Human-in-the-loop(简称HITL)是一种重新划分人类认知与机器能力边界、放大双方优势的系统设计理念。它的存在价值,可从三个核心维度展开:

  • 突破技术天花板。再强大的模型,认知边界也局限于训练数据覆盖的范围——在这个范围内,它能展现出稳定的“自信”;可一旦遭遇罕见场景、长尾问题或是对抗性样本,其判断的可靠性便会急剧下降。而HITL的设计巧思正在于此:当机器的置信度低于预设阈值时,会自动将决策权移交人类。这就像给系统装上了一张“安全网”,稳稳接住机器力所不及的漏洞。
  • 守住伦理与合规底线。算法的决策责任,永远无法转嫁到冰冷的硅片上。HITL特意保留了“人类确认”的关键环节,让整个算法决策链条中,始终存在一个可追溯、可追责的“自然人”主体,这是技术落地必须守住的伦理根基。
  • 优化经济成本结构。HITL不是“全程人工介入”,而是一种“稀疏化参与”——用极少的人类工时投入,换取系统安全性的大幅提升,其ROI远高于全人工操作或纯机器自主决策的方案。说到底,HITL就是用“人类注意力”撬动“系统鲁棒性”的最优杠杆。

因此,若要让人类有效掌控任务走向,落实HITL理念的核心在于两点:

  • 优化交互设计。通过合理的交互逻辑,让人类能够顺畅地参与到任务补充与推进的过程中,实现“需要时介入,介入时高效”。
  • 保障对话连续性。在人类介入任务的过程中,不得中断当前对话链路,应采用“挂起等待”的模式,确保人机协同的连贯性与信息完整性。

1.2 Step-GUI HITL

Step-GUI中,HITL 信息获取能力如下:

  • 上下文感知:

    • INFO 操作能够根据当前上下文提出具体问题;
    • auto_reply 函数利用当前截图和任务信息生成澄清问题;
  • 信息类型多样化:

    • 可以获取文本输入、确认信息、选择项等不同类型信息
    • 可以通过 value 字段传递具体问题内容
    • 支持多轮对话以获取复杂信息

0x02 MCP流程

2.1 流程图

流程图如下,该流程图展示了任务从启动到结束的完整流程

  1. 任务启动后先判断会话 ID,新建 / 续领会话并初始化设备;
  2. 捕获截图→Agent 处理→生成动作,根据动作类型分 3 类处理(设备执行 / 人工介入 / 任务结束);
  3. 人工介入支持自动回复、手动回复、转交客户端等模式,最终回到 Agent 循环;
  4. 任务结束 / 达到最大步数时,记录包含会话、设备、任务状态的日志。

hitl-1

2.2 时序图

时序图如下。该时序图清晰展示了「客户端 - MCP 服务器 - Agent 服务器 - 设备 - 人类」的协同交互流程,核心逻辑分为三阶段:

阶段 1:任务初始化
  • 客户端向 MCP 服务器发起「启动新任务」请求(携带任务信息、设备 ID);
  • MCP 服务器向 Agent 服务器申请会话 ID,Agent 服务器返回会话标识;
  • MCP 服务器指令设备重置环境(按 Home 键),并捕获设备初始截图。
阶段 2:Agent 动作循环(核心)

进入循环执行逻辑,直到任务结束 / 达到步数上限:

  • MCP 服务器将「会话 ID + 截图」传给 Agent 服务器,调用 automate_step 接口获取 Agent 动作;
  • 分支处理:
    • ✅ 若动作是INFO(需要人类介入):
      • MCP 服务器通知客户端「任务暂停,需人工回复」,并返回会话 ID;
      • 人类向客户端提供回复内容;
      • 客户端携带「会话 ID + 人工回复」请求 MCP 服务器续跑任务;
      • MCP 服务器将「截图 + 人工回复」传给 Agent 服务器,继续执行动作;
    • ❌ 若动作非INFO(如点击、输入等):
      • MCP 服务器指令设备执行对应动作;
      • 等待指定延迟后,捕获设备新截图,进入下一轮循环。
阶段 3:任务终止
  • ✅ 任务完成:Agent 服务器返回 COMPLETE 动作,MCP 服务器向客户端返回「任务成功完成」结果;
  • ❌ 达到最大步数:MCP 服务器直接向客户端返回「步数超限」结果。

hitl-2

2.3 MCP 工具区别

ask_agent_continue 和 ask_agent_start_new_task 的业务逻辑区别如下:

特性 ask_agent_start_new_task ask_agent_continue
环境重置 reset_environment = True reset_environment = False
会话状态 创建新会话 继续现有会话
目标 开始新任务 继续已有任务
设备状态 重置到初始状态 保持当前状态

2.3.1 详细业务逻辑对比

ask_agent_start_new_task

@mcp.tool
def ask_agent_start_new_task(
    # ...参数
):
    # 启动新任务,重置环境
    # 重置设备到初始状态(按 HOME 键)
    # 创建全新的会话
    # 适用于独立的、全新的任务
    reset_environment = True  # 重置环境
    return_log = execute_task(
        device_id=device_id,
        task=task,
        reset_environment=reset_environment,  # 重置环境
    )
    return return_log

ask_agent_continue

@mcp.tool
def ask_agent_continue(
    # ... 参数
):
    # 继续任务,不重置环境
    # 保持设备当前状态
    # 基于之前的上下文继续执行
    # 适用于需要连续性的任务
    reset_environment = False  # 不重置环境
    return_log = execute_task(
        device_id=device_id,
        task=task,
        reset_environment=reset_environment,  # 不重置环境
    )
    return return_log
2.3.2 使用场景对比

ask_agent_start_new_task 使用场景

graph TD
A[用户发起新任务] --> B[是否与之前任务相关?]
B --> |无关/新任务| C[使用 ask_agent_start_new_task]
C --> D[重置环境到初始状态]
D --> E[启动全新任务]

适用场景:

  • 完全独立的新任务
  • 不同 App 的任务(如:从淘宝切换到微信)
  • 需要干净环境的任务
  • 错误后的重新开始

ask_agent_continue 使用场景

graph TD
A[用户继续任务] --> B{是否与之前任务相关?}
B -->|相关/继续| C[使用 ask_agent_continue]
C --> D[保持当前环境状态]
D --> E[基于上下文继续任务]

适用场景:

  • 同一个任务的继续执行
  • 需要保持当前应用状态
  • Human-in-the-Loop 后的继续
  • 多步骤任务的后续步骤
2.3.3 业务逻辑实现差异
在 execute_task 中的处理
def execute_task(
# ...
 reset_environment: bool,  # 关键参数
# ...
):
 if reset_environment and session_id is None and task is not None:
     press_home_key(device_id, print_command=True)  # 重置设备
        
# session_id 为 None 时创建新会话

# session_id 存在时继续现有会话
在 gui_agent_loop 中的体现
def gui_agent_loop(
# ...
 reset_environment: bool = True,
 session_id: str = None,
# ...
):
 if reset_environment and session_id is None and task is not None:
     press_home_key(device_id, print_command=True)  # 重置环境
 if session_id is None:
    # 创建新会话
    session_id = agent_server.get_session({...})
 else:
    # 继续现有会话
    print(f"Continue Session ID: {session_id}")
Human-in-the-Loop 场景应用

任务中断后继续

# 第一步:开始任务,遇到INFO action
result = ask_agent_start_new_task(
    device_id=device_id,
    task="去淘宝帮我选一个生日礼物",
    # ...
)
# 返回:stop_reason="INFO_ACTION_NEEDS_REPLY", session_id="xxx"

# 第二步:用户提供回复后继续

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐