【GUI-Agent】阶跃星辰 GUI-MCP 解读---(6)---HITL(Human In The Loop)
·
摘要
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 流程图
流程图如下,该流程图展示了任务从启动到结束的完整流程:
- 任务启动后先判断会话 ID,新建 / 续领会话并初始化设备;
- 捕获截图→Agent 处理→生成动作,根据动作类型分 3 类处理(设备执行 / 人工介入 / 任务结束);
- 人工介入支持自动回复、手动回复、转交客户端等模式,最终回到 Agent 循环;
- 任务结束 / 达到最大步数时,记录包含会话、设备、任务状态的日志。

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 服务器指令设备执行对应动作;
- 等待指定延迟后,捕获设备新截图,进入下一轮循环。
- ✅ 若动作是INFO(需要人类介入):
阶段 3:任务终止
- ✅ 任务完成:Agent 服务器返回
COMPLETE动作,MCP 服务器向客户端返回「任务成功完成」结果; - ❌ 达到最大步数:MCP 服务器直接向客户端返回「步数超限」结果。

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"
# 第二步:用户提供回复后继续
更多推荐

所有评论(0)