将 WebTerminal 改造成 Agent 可调用的 CLI 执行面,支持命令、文件传输与交互式调试。
原文标题:全是 Web 没 CLI 怎么行:一次把 StarAgent WebTerminal 改造成
原文作者:阿里云开发者
冷月清谈:
核心思路是让浏览器继续承担企业内部 SSO、授权、审计、角色选择等合规链路,而把真正执行命令、传输文件、捕获输出、交互调试的部分交给 CLI。这样 Agent 不需要操作 DOM,也不必依赖固定脚本套件,而是可以根据现场输出动态规划下一步。
文章强调 Skill 的定位不是“魔法 prompt”,而是工具说明书:它描述何时登录、何时执行、何时交互、哪些操作需要人工批准;真正稳定可复现的能力必须由 CLI 提供。
实践验收覆盖了 GPU hang 分析、WebTerminal 文件 API 传输、Emacs/eshell/gdb 下的 coredump 交互式调试。作者也总结了 Agent 工具建设的一些通用模式:先抽象执行面,再沉淀场景;授权与执行解耦;输出可保存、可解析、可复盘;交互式程序要保留状态;文件传输应协议化并校验。
怜星夜思:
2、文章里说不要把 GPU hang 做成固定 suite,而是让 Agent 动态判断。大家觉得固定脚本和 Agent 动态排障哪个更靠谱?
3、Skill 到底应该写多细?是把所有操作步骤都教给 Agent,还是只写原则和边界?
4、把浏览器登录态缓存下来给 CLI 复用,这种设计在安全和便利之间算不算一个合理折中?
原文内容
阿里妹导读
全是 Web,没有 CLI,怎么行?Agent 都会写代码了,远程排障还要人肉点网页、复制命令、盯滚动条,这画面多少有点“地铁老人看手机.jpg”。本文记录一次围绕 StarAgent/Drogo WebTerminal 的工具化实践:我们没有把 GPU hang、core dump 调试等场景固化成一个个“祖传脚本套件”,而是把 WebTerminal 抽象成稳定的 CLI 执行面,再用 Skill 描述操作方法。Agent 在任务中动态生成命令、读取结果、继续决策,最终完成远程 GPU hang 分析、文件上传下载、以及 Emacs + eshell + gdb 的交互式 coredump 调试验收。
插播:我对 Skill 的态度很朴素:Skill 不是法器,不是咒语,也不是“复制进去 Agent 就突然开悟”的玄学符纸。Skill 本质上就是说明书,是贴在工具箱盖子上的那张“先拧这个、再接那个、别把手伸进风扇里”的操作指南。真正能把活干成的,必须是 CLI:参数清楚、行为稳定、输出可解析、错误可复现、证据能落盘。 所以这套东西的核心不是“写一个很长的 Skill 让 Agent 背下来”,而是把能制度化的都制度化,把能流程化的都流程化,把以前靠老师傅手感、群里口口相传、网页上点点点的部分,全部压进 wt 这种可执行接口里。Skill 只负责告诉 Agent:什么时候该登录、什么时候该 run、什么时候该 interact、什么时候该停手问人。至于真正挥锤子的活, 必须交给 CLI。否则就是让 Agent 看着说明书徒手修发动机,场面很感人,结果很危险。(文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。)
WebTerminal 黑屏模式补充说明
号外号外,重大更新:
WebTerminal 终于可以像 SSH/SCP 一样用了
核心用法
$ ./bin/wt auth login --target-ip x.y.z.w
wt: waiting for browser login cookies; finish login in the opened browser
authenticated: True
user: default
source: browser
$ ./bin/wsh x.y.z.w
attached direct: x.y.z.w
$ ./bin/wsh x.y.z.w -- 'hostname; pwd'
hippo-033126067104.na175
/home/admin/hippo/worker/slave/drogo-share_worker-h20-na175.worker-h20-na175_11_33/main
$ ./bin/wcp /tmp/wcp-demo.txt x.y.z.w:/tmp/wcp-demo.txt --force
uploaded: /tmp/wcp-demo.txt -> /tmp/wcp-demo.txt
$ ./bin/wcp x.y.z.w:/tmp/wcp-demo.txt /tmp/wcp-demo.down.txt --force
downloaded: /tmp/wcp-demo.txt -> /tmp/wcp-demo.down.txt
这次补上的关键体验
一点遗憾
以下是 V1 内容
前言:先把仓库拍你脸上
背景:Agent 要的不是另一个网页按钮,它要手脚
-
目标 IP、操作步骤都必须参数化,框架和具体案例隔离。
-
不做固定 suite,Agent 应该像工程师一样动态发送命令。
-
WebTerminal 浏览器会话要持续存在,不能每次操作都重新登录。
-
上传下载要走 WebTerminal 后端 API 或协议,不能靠 DOM 自动化点弹窗。
-
调试要是真交互:Agent 可以一条条给 gdb / emacs / eshell 发命令,拿到 response 后继续判断,而不是“一把梭,听天命”。
先看效果:别先讲架构,先看能不能干活
bin/wt run --capture captures/gpu-hang/env.raw.log -- \
"hostname; date; uname -a; nvidia-smi -L || true; nvidia-smi || true"
bin/wt ls-files /home/admin
bin/wt download /home/admin/remote.log captures/remote.log
bin/wt upload ./local.txt /home/admin/local.txt
bin/wt interact \
--start "cd /tmp && gdb -q ./app core.wtdebug" \
--prompt-regex "\\(gdb\\)\\s*$" \
--host 127.0.0.1 \
--port 8765 \
--capture captures/debug/gdb.raw.log \
--summary-json captures/debug/gdb.summary.json
curl -s -X POST http://127.0.0.1:8765/command -d '{"send":"bt"}'
curl -s -X POST http://127.0.0.1:8765/command -d '{"send":"frame 0"}'
curl -s -X POST http://127.0.0.1:8765/command -d '{"send":"info locals"}'
curl -s -X POST http://127.0.0.1:8765/command -d '{"send":"print item.id"}'
1. 目标:把 WebTerminal 变成
Agent 友好的执行面
-
场景逻辑被写死后,Agent 只能“调用工具”,不能“分析现场”,智商被强行锁死。
-
每新增一个诊断路径,都要修改 CLI 代码。
-
远端状态复杂时,固定脚本很难处理分支,例如进程是否存在、gdb 是否可用、权限是否足够、core 文件是否生成成功。
-
安全边界不清晰,读操作、写操作、侵入式操作容易混在一起。
|
层次 |
职责 |
不做什么 |
|
WebTerminal 页面 |
登录、角色选择、审计、心跳、官方连接链路 |
不承载任务逻辑 |
|
|
会话复用、命令发送、输出捕获、文件 API、交互控制面 |
不内置具体排障 suite |
|
Skill |
描述操作方法、风险边界、推荐命令模板 |
不绑定某个 IP 或某个案例 |
|
Agent |
动态规划、执行、观察、复盘 |
不绕过授权链路 |
2. 会话设计:授权留在浏览器,执行交给 CLI
bin/wt session start --target-ip
bin/wt session status
-
授权、审计、心跳仍走官方页面链路。
-
CLI 不保存 SSO token,也不绕过登录流程。
-
目标 IP 是参数,不会写死在实现里。
-
多轮排障可以共享同一个远端 shell 状态。
{
"": {
"type": "data",
"data": "pwd\r"
}
}
3. 命令执行:不做 suite,做动态闭环
bin/wt run --capture captures/task/name.raw.log -- ""
printf '\n__WT_DONE___:%s\n' "$?"
-
*.raw.log:原始 ANSI 输出,适合保留完整现场。
-
*.plain:去 ANSI 后的文本,适合 Agent 解析。
-
*.snapshot.json:xterm buffer 快照,适合排查全屏程序或显示问题。
bin/wt run --capture captures/gpu-hang/env.raw.log -- \
"hostname; date; uname -a; id; pwd; which nvidia-smi || true; nvidia-smi -L || true; nvidia-smi || true"
bin/wt run --capture captures/gpu-hang/processes.raw.log -- \
"ps -eo pid,ppid,stat,etime,%cpu,%mem,wchan:32,cmd --sort=-%cpu | head -200; GPU_PIDS=\"$(nvidia-smi --query-compute-apps=pid --format=csv,noheader 2>/dev/null | sort -u | tr '\n' ' ')\"; echo GPU_PIDS=$GPU_PIDS"
bin/wt run --capture captures/gpu-hang/kernel.raw.log -- \
"dmesg -T | egrep -i 'nvrm|xid|gpu|cuda|uvm|pcie|ecc|oom|hung|reset' | tail -300 || true"
4. 文件传输:从 DOM 自动化改成 API 调用
-
DOM 结构容易变化。
-
文件选择器和下载行为依赖浏览器设置。
-
很难做完整校验。
-
失败时只能看到 UI 结果,不容易拿到协议级错误。报错一句“上传失败”,人也失败了。
-
openFileSystem
-
listFiles
-
getDownloadFileHead
-
downloadFile
-
uploadFile
-
heartbeat
bin/wt download /home/admin/remote.log captures/remote.log
bin/wt upload ./local.txt /home/admin/local.txt
5. 交互式调试:默认接口应该像普通 shell
-
bt 看到崩溃栈,才知道要进哪个 frame。
-
info locals 看到变量,才知道要 print 哪个字段。
-
gdb 缺符号、core 文件异常、路径不对,都需要临时调整。
-
对 emacs 这类全屏程序,需要发送 raw key,而不是 line command。否则你以为在控制 Emacs,Emacs 以为你在乱按键。
|
Endpoint |
用途 |
|
|
查看交互会话是否存活 |
|
|
查看完整步骤摘要 |
|
|
获取 xterm 屏幕快照 |
|
|
发送一行命令,按 prompt regex 等待结果 |
|
|
发送 raw keys,适合 emacs/vim/TUI |
|
|
读取当前缓冲输出 |
|
|
退出远端交互程序并关闭本地 server |
curl -s -X POST http://127.0.0.1:8765/command \
-d '{"send":"print item.id"}'
{
"ok": true,
"result": {
"name": "command",
"send": "print item.id",
"matched": true,
"timed_out": false,
"plain_output": "(gdb) print item.id\r\n$1 = 42\r\n(gdb) "
}
}
6. 验收案例:在 Emacs 里写 crash.c,
再用 eshell + gdb 定位 core
-
wt interact启动远端emacs -nw -Q。
-
/send发送C-x C-f /tmp/wt-emacs-crash.c。
-
/send插入 C 源码并C-x C-s保存。
-
/send执行M-x eshell。
-
在 eshell 里编译并运行程序,触发 segmentation fault。
-
生成core.wtdebug。
-
在 eshell 里启动gdb -q ./wt-emacs-crash core.wtdebug。
-
分别发送bt、frame 0、info locals、print item.id、print item.name。
#include
typedef struct {
int id;
const char *name;
} Item;
static int crash(int n) {
Item item = {42, "emacs-eshell-core"};
int *ptr = 0;
printf("about to crash: %s %d %d\n", item.name, item.id, n);
return *ptr + item.id + n;
}
int main(int argc, char **argv) {
int input = argc > 1 ? 7 : 3;
return crash(input);
}
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000401168 in crash (n=7) at /tmp/wt-emacs-crash.c:12
12 return *ptr + item.id + n;
#0 crash (n=7) at /tmp/wt-emacs-crash.c:12
#1 main (argc=2, argv=...) at /tmp/wt-emacs-crash.c:17
item = {id = 42, name = 0x402004 "emacs-eshell-core"}
ptr = 0x0
print item.id -> 42
print item.name -> "emacs-eshell-core"
7. GPU hang 分析:场景逻辑留给 Agent
-
机器:hippo-xyzw
-
Kernel:5.10.134-010.ali5000.al8.x86_64
-
Driver:580.82.07
-
CUDA:13.0
-
GPU:8 x NVIDIA H20
-
采集时 GPU compute processes 为空。
-
采集时 8 张卡利用率均为 0%,显存占用约为基础占用。
-
当前没有看到 active GPU hang。
-
反复出现 NVRM: refcntRequestReference_IMPL: Failed to enter state 1 ... status: 0x00000056。
-
NVSwitch 曾出现 SXid 22013 非致命链路中断。
-
5 月 8 日有一次 Xid 43 ,进程名为 python。
-
另有一次看起来不直接相关的 memcg OOM。
8. Skill 的角色:
把经验写成操作方法,而不是写死代码
-
如何启动或复用 session。
-
如何确认用户已经登录并进入 WebTerminal。
-
什么时候用 run ,什么时候用 attach ,什么时候用 interact 。
-
文件上传下载必须走 API,不能操作 DOM。
-
侵入式命令需要用户批准。
-
GPU hang 分析的建议命令,但不把它变成固定 suite。
-
coredump demo 的推荐构造方式和清理方式。
9. 几个设计取舍
9.1 为什么不直接连 SSH
9.2 为什么不把 GPU hang 做成内置命令
9.3 为什么交互控制面用 HTTP
9.4 为什么保留 interact-script
-
wt interact:默认 live server,用于动态调试。
-
wt interact-script:固定脚本,用于已知步骤。
10. 可以复用的工程模式
结语
-
WebTerminal 继续负责官方授权和连接链路。
-
wt CLI 负责把远程 shell、文件传输、交互式程序变成可调用能力。
-
Skill 负责把排障经验写成可执行方法,让 Agent 根据现场动态闭环。
招聘:欢迎底层系统同学跳进 AI 推理这口锅
-
大模型推理系统工程:面向 LLM 推理链路做系统设计、稳定性、吞吐、延迟和工程化。
-
AI 高性能计算:面向 GPU/异构计算、通信、调度、算子和推理性能做深度优化。
-
AI 性能研发:把模型服务从“能跑”推进到“跑得快、跑得稳、跑得省”。
-
多模态推理引擎:面向文本、视觉、语音等多模态推理场景做系统和性能建设。
附录 A:当前 CLI 能力速览
wt session 管理持久 WebTerminal 浏览器会话
wt status 查看当前终端状态
wt run 执行一条 shell 命令并捕获输出
wt attach 本地 raw TTY 直接接入 WebTerminal
wt interact 启动 live HTTP 交互控制面
wt interact-script 执行固定 expect 风格交互脚本
wt snapshot 获取 xterm buffer 快照
wt ls-files 通过 WebTerminal 文件 API 列目录
wt download 通过 WebTerminal 文件 API 下载文件
wt upload 通过 WebTerminal 文件 API 上传文件
wt direct-info 输出脱敏后的直连协议材料,便于实验





