@autotest/agent
v0.0.23
Published
AutoTest Agent — AI 驱动的自动化测试执行代理,支持 HarmonyOS/Android/iOS
Downloads
1,751
Maintainers
Readme
@autotest/agent
基于 AI 的自动化测试执行代理核心包,通过多模态模型的视觉理解能力自主执行 HarmonyOS/Android/iOS 设备测试。
项目简介
AutoTest Agent 是一个智能化的移动设备自动化测试框架,支持 单层 Agent、双层 Agent 两种架构模式,能够理解自然语言指令,通过多模态模型自主执行测试操作、发现 Bug、分析失败根因并生成测试报告。
核心特性
- 多架构模式:
single(统一 Agent)、layered(Planner + Executor)两种模式可切换 - 多模态视觉理解:通过多模态模型观察屏幕截图、定位 UI 元素、判断操作结果
- 自然语言交互:中文描述测试步骤,自动转换为设备操作
- 多平台支持:HarmonyOS(纯 TS 直驱 HDC,35 个设备操作全覆盖)、Android、iOS
- MCP Server:42 个工具(35 设备操作 + 7 管理)通过 JSON-RPC 2.0 对外暴露
- Bug 自动发现与根因分析:执行中主动发现异常,
analyze命令基于报告生成根因分析与改进建议 - 录屏/雪碧图模式:动态场景(toast/加载动画/弹窗/倍速等瞬态效果)自动触发录屏(3 秒),抽取关键帧拼成雪碧图供多模态逐帧验证,避免单张截图漏判瞬态效果;报告内可"查看雪碧图"/"播放录屏"
- 坐标二次定位 + 文字元素点击:点击类工具支持
text参数按控件树文字定位元素中心;基于 dumpLayout 对裸坐标二次修正到最近可点击元素(coord snap),提升点击精度 - 自愈闭环(Loop):执行→归因→改写→重执行的多轮自愈,自动修复用例问题或补充知识,支持 5 种执行模式与死循环检测
- 多格式报告:执行报告生成 HTML / JSON,归因分析生成 JSON / HTML / Markdown 与批量汇总
- 批量执行:JSONL/JSON 批量用例执行,支持断点续跑、进度报告、分类汇总
- Skills 系统:加载技能步骤指导 Agent 执行复杂操作
- 知识库:按 App 维度管理领域知识(如华为商城 vmall)
- Debug 调试模式:任务执行后通过浏览器与 Agent 交互式复盘
目录结构
AutoTest-nodejs/
├── src/
│ ├── autotest-cli.ts # CLI 入口(run/list-devices/analyze/config)
│ ├── index.ts # 包导出
│ ├── api/ # AgentAPI 对外接口
│ │ ├── agent_api.ts
│ │ └── types.ts
│ ├── common/ # 公共模块
│ │ ├── config/ # 配置(config.yaml / manager.ts / types.ts)
│ │ ├── model/ # LLM 调用封装
│ │ ├── llm_cache/ # LLM 响应缓存
│ │ ├── dfx/ # 诊断/可观测性(LLM 流量记录)
│ │ ├── usage/ # Token 用量统计
│ │ ├── case_manager.ts # 用例管理
│ │ ├── collect_case.ts # 用例收集
│ │ ├── image_helper.ts # 图片处理
│ │ ├── image_cacher.ts # 图片缓存
│ │ ├── image_similarity.ts # 图片相似度
│ │ ├── logger.ts # 日志
│ │ ├── utils.ts # 工具函数
│ │ ├── path_utils.ts # 路径工具
│ │ ├── common_errors.ts # 结构化错误(AgentError)
│ │ ├── datetime.ts # 日期时间工具
│ │ ├── layout_parser.ts # dumpLayout 解析 + 坐标二次定位(coord snap)
│ │ └── result_parser.ts # 结果解析
│ ├── core/
│ │ ├── agent/ # Agent 实现
│ │ │ ├── single_agent/ # 单层 Agent
│ │ │ │ ├── agent.ts
│ │ │ │ ├── context_builder.ts # 上下文构建
│ │ │ │ ├── hooks.ts / hook_manager.ts
│ │ │ │ ├── image_utils.ts
│ │ │ │ ├── llm_helper.ts # LLM 调用辅助
│ │ │ │ ├── processors.ts # 消息/工具处理
│ │ │ │ ├── report_hook.ts # 报告 Hook
│ │ │ │ ├── scroll_search_agent.ts # 滚动搜索子 Agent
│ │ │ │ ├── subagent_manager.ts # 子 Agent 管理
│ │ │ │ └── tool_recorder_hook.ts
│ │ │ ├── layered_agent/ # 双层 Agent(Planner + Executor)
│ │ │ │ ├── decision.ts # Planner 决策
│ │ │ │ ├── agent_registry.ts # Agent 注册表
│ │ │ │ ├── ability_helper.ts # 能力辅助
│ │ │ │ └── execute_agent/ # Executor 执行
│ │ │ ├── report_analyzer_agent/ # 失败根因分析 Agent(agent / data_loader / trace_extract / design_tool / analysis_progress / report_markdown / report_html_template/ / prompts/)
│ │ │ ├── rewrite_agent/ # 报告改写 Agent(agent / guardrails / parse / mapping / result_writer / types / prompts)
│ │ │ ├── design_doc/ # 设计文档 Agent(design_doc.ts)
│ │ │ ├── utils/
│ │ │ └── types.ts
│ │ ├── device/ # 设备抽象层
│ │ │ ├── device_protocol.ts # 设备协议抽象
│ │ │ ├── index.ts # HDC 设备实现(封装 hdc/ 模块)
│ │ │ ├── types.ts
│ │ │ └── hdc/ # HDC 协议(device/input/screenshot/apps + capture_card_recorder / screen_recorder 录屏)
│ │ ├── mcp/ # MCP 适配器
│ │ │ ├── base_adapter.ts
│ │ │ ├── harmony_hdc_adapter.ts # HarmonyOS 适配器(纯 TS 直驱 hdc,35 设备操作)
│ │ │ ├── android_adapter.ts # Android 适配器
│ │ │ ├── ios_adapter.ts # iOS 适配器
│ │ │ ├── adapter_factory.ts # 适配器工厂
│ │ │ ├── mcp_tools.ts # 双层 Agent MCP 工具
│ │ │ └── local_tools.ts # 本地工具(wait / load_skill)
│ │ ├── prompt/ # 版本化提示词
│ │ │ ├── prompt_loader.ts
│ │ │ └── templates/ # single / hypium / planner / debug / fast_action / splitter 模板
│ │ ├── skill/ # Skills 系统(skill_manager.ts)
│ │ ├── memory/ # 记忆系统(memory_manager / compressed_session / context_compressor / reflector / tool_player / tool_recorder / session_factory)
│ │ └── preprocessor/ # 任务预处理
│ ├── data_types/ # 数据模型(action / agent / case / device / report / screen / task)
│ ├── reporter/ # 报告生成(generator.ts / batch_summary.ts / json_report.ts / html_template/ / types.ts)
│ ├── loop/ # 自愈闭环编排(执行→归因→改写→重执行,cli / orchestrator / result_writer / types)
│ ├── mcp-server/ # MCP server(42 工具:35 设备操作 + 7 管理)
│ │ ├── server.ts # JSON-RPC 2.0 HTTP 服务 + adapter 委托
│ │ └── types.ts # 工具枚举 + Zod schema + 描述
│ └── tools/ # 工具
│ ├── batch_runner.ts # 批量执行(发布为 autotest-batch 二进制)
│ ├── case_runner/ # 结构化用例执行(setup/process/teardown,发布为 autotest-case)
│ ├── config/ # 配置管理 CLI(init/get/set/list,发布为 autotest-config)
│ ├── gen_report.ts # 分析报告 HTML 生成(--prev/--truth/--dir/--output)+ resolveReportHref 用例查看链接解析
│ ├── gen_analysis_report.ts # 批量后分析报告 HTML(batch_runner import 调;--reports token;KPI/混淆矩阵/明细)
│ ├── prompt_compare/ # 多 Prompt 批量对比(发布为 autotest-prompt-compare)
│ ├── token_comparison/ # Token 用量对比
│ └── runner.mjs # caseTest/batchCaseTest 一键封装(自动 install/build)
├── types/
│ └── ai-stub.d.ts # ai/@ai-sdk/openai 类型桩(仅 .d.ts 生成时使用,避免 OOM)
├── tests/ # 单元测试(vitest,约 230 个用例 / 15 文件)
├── app_config.json # App bundle/ability 映射
├── tsconfig.json # 主 tsconfig(JS 编译,--noCheck)
├── tsconfig.emit.json # .d.ts 生成配置(用桩文件替换 ai 泛型)
└── package.json架构说明
架构模式选择
| 架构模式 | agent.mode | 说明 |
|----------|--------------|------|
| 单层 Agent | single(默认) | 统一 Agent 处理规划与执行,基于 AI SDK,效率高 |
| 双层 Agent | layered | Planner 决策 + Executor 执行,适合复杂任务拆解 |
单层 Agent 工作流程
用户任务 → SingleAgent → 多模态视觉理解 + 决策 → MCP 设备操作 → 报告生成
(AI SDK) (HDC/ADB/WDA) (HTML/MD/JSON)- SingleAgent:接收用户任务,分析屏幕状态,生成操作指令
- 多模态视觉理解:通过多模态模型理解截图,定位 UI 元素,判断操作结果
- 设备层:通过 MCP 适配器与设备通信,执行点击、滑动等操作
- 报告生成:记录执行过程,输出测试报告
双层 Agent 工作流程
用户任务 → Planner(decision) → 原子操作指令 → Executor(execute) → 设备操作
(HDC 设备)- Planner:分析当前状态,生成具体操作指令
- Executor:通过视觉识别定位 UI 元素,执行点击、滑动等操作
- 设备层:通过 HDC 协议与 HarmonyOS 设备通信
环境要求
系统要求
- 操作系统:Windows / Linux / macOS
- Node.js:推荐 22+ LTS(最低 18)
- 包管理器:pnpm(启用 workspaces)
HarmonyOS 设备驱动(纯 TS)
HarmonyOS 设备测试通过纯 TypeScript 的 HDC 适配器直接驱动
hdc命令。
HarmonyOS 适配器(src/core/mcp/harmony_hdc_adapter.ts)通过 hdc shell 执行 uitest uiInput(点击/滑动/输入)、snapshot_display(截图)、uitest dumpLayout(布局)、aa(应用启停)、bm(清数据)、power-shell(点亮/解锁)、uinput(多指手势)等原语,支持全部 35 个设备操作,进程内直接完成设备操作,无子进程、无 HTTP 服务。
Android/iOS 平台使用 @mobilenext/mobile-mcp(通过 npx 自动安装)。
设备要求
- HarmonyOS 设备:支持 HDC 协议的设备或模拟器
- HDC 工具:已安装并配置
hdc命令行工具(加入 PATH) - 网络连接:开发机与设备网络连通
快速开始
cd AutoTest-nodejs
npm install # 安装依赖
npm run build # 构建项目
npm run setup # 生成 config.yaml 配置文件(项目根目录)npm run setup 会在项目根目录创建 config.yaml(基于模板,含占位符),并提示需要修改的字段。编辑该文件填入你的配置:
model:
unified:
name: "qwen3.8-flash" # 模型名
api_key: "sk-xxx" # 你的 DashScope API Key
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
device:
device_sn: "LNG0223721000045" # hdc list targets 查看
config.yaml已加入.gitignore,不会被提交,可安全填入真实密钥。
也可用 autotest-config 命令行工具修改:
node dist/tools/config/config_tool.js set model.unified.api_key "sk-xxx"
node dist/tools/config/config_tool.js set model.unified.name "qwen3.8-flash"
node dist/tools/config/config_tool.js set device.device_sn "YOUR_DEVICE_SN"配置完成后即可运行测试:
node dist/autotest-cli.js run --task "打开设置应用,查看 WiFi 列表"配置说明
配置文件位于 src/common/config/config.yaml(构建后随包发布到 dist/common/config/config.yaml)。ConfigManager 按以下顺序分层加载并合并(后者覆盖前者):
- 包内默认
config.yaml - 包内
config.local.yaml(可选) - 当前工作目录(项目根目录)
config.yaml(可选,适合本地覆盖 API Key / 模型) - 当前工作目录
config.local.yaml(可选) - CLI
--config <path>指定的文件(最高优先级)
模型配置
推荐模型:
qwen3.8-flash(多模态,DashScope 兼容模式https://dashscope.aliyuncs.com/compatible-mode/v1)。实测在 100 条 verify 用例上准确率 84% / F1 0.887;双层模式下 execute/decision/verify 各槽位均可使用qwen3.8-flash,也可为 execute 单独配置专用 GUI 模型(如下方示例)。
model:
unified: # 单层模式使用
name: "qwen3.8-flash"
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key: "YOUR_API_KEY_HERE" # 必填
provider: "openai" # openai / azure
temperature: 0.1
top_p: 0.9
frequency_penalty: 0.5
max_tokens: 1024
timeout: 600
max_retries: 3
prompt_type: "v2.0" # 提示词版本
execute: # 双层模式 — 执行模型
name: "gui-plus-2026-02-26"
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key: "YOUR_API_KEY_HERE" # 必填
provider: "mai-ui"
max_steps: 3
decision: # 双层模式 — 决策模型
name: "qwen3.8-flash"
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key: "YOUR_API_KEY_HERE" # 必填
provider: "openai"
temperature: 0.0
top_p: 0.1
frequency_penalty: 1.0
verify: # 验证模型(可选,留空回退到 decision)
name: ""
base_url: ""
api_key: ""
provider: "openai"Agent 配置
agent:
unified: # 统一 Agent 配置(single/layered 共用)
mode: "single" # single / layered
max_steps: 50 # 最大执行步数
lang: "zh" # 语言
enable_preprocess: false # 任务预处理
stream_log: false # 流式输出模型回复
debug_mode: null # null / "memory" / "file"(预留,尚未实现)
parse_mode: "native" # 解析模式:custom(文本标签)/ native(SDK 函数调用)
tool_provider: "device" # 工具提供者:device / mcp
action_interval: 1.5 # 操作间隔(秒)
max_history_image: 3 # 历史截图保留数量
screenshot_max_pixels: 1500 # 截图最大像素
include_previous_screenshot: true # 是否包含上一步截图
previous_screenshot_compress_ratio: 0.7 # 上一步截图压缩比
max_history_actions: 10 # 历史操作保留数量
role: null # Agent 角色(控制提示词和工具过滤,如 planner)
session_type: "compressed" # 会话类型:sqlite / compressed(自动压缩历史)
prompt_name: "single_v2.0" # 提示词名称(全文件名,优先于 prompt_version)
prompt_version: "" # 提示词版本覆盖
max_loops: 0 # 自愈闭环:>0 启用(N 轮迭代),0 禁用
enable_cache: true # 启用 LLM 缓存
screenshot_on_tool_end: true # 工具执行后截图
verbose: false # 详细日志
json_output: false # JSON 输出
apirec: false # API 录制设备配置
device:
device_sn: null # 设备序列号(留空自动检测)
ip: "127.0.0.1" # 设备 IP
port: 8710 # HDC 端口
hdc_path: "hdc" # HDC 工具路径
reset_device: true # true=回主页+清后台, false=跳过, 列表=指定包名 force-stop
screen_always_on: true # 测试期间保持屏幕常亮
device_impl: "HDCDevice" # 设备实现:"HDCDevice"(默认)或 "HDCDeviceInner"
app_config: "" # app_config.json 路径(MCP bundle 映射,留空不使用)
operation_mode: "phone" # 操作模式:"phone"(默认)或 "pc"
keepalive_process_whitelist: [] # 清后台时保留的进程白名单(包名列表),这些进程不会被 force-stop
# keepalive_process_whitelist:
# - "com.hm.screenrecorder"
# - "com.hm.keeprunning"
skip_clear_process: false # true=每次用例执行前跳过清理后台进程(等价于 --skip-clear-process)进程清理与白名单
每次用例执行前,Agent 会调用 adapter.reset() 执行设备重置:回到主页 + 清理后台进程。通过以下配置控制行为:
reset_device: true(默认):回到主页,清理所有后台进程(白名单内除外)reset_device: false:完全跳过重置reset_device: ["pkg1", "pkg2"]:仅 force-stop 指定包名keepalive_process_whitelist:白名单内的进程不会被 force-stop(仅在reset_device: true模式下生效)skip_clear_process: true或 CLI--skip-clear-process:完全跳过adapter.reset(),不清理任何进程- CLI
--keepalive pkg1 pkg2:运行时设置白名单(别名--keepalive-process-whitelist),与keepalive_process_whitelist配置等价
白名单在
reset()执行时从 ConfigManager 动态读取,因此 CLI--keepalive和 config.yaml 中的keepalive_process_whitelist均能实时生效,无需关心 adapter 初始化顺序。
日志 / 输出 / 网络配置
log:
level: "INFO"
device_log_level: "info"
verbose: true
max_log_size: 10 # 单文件最大 MB
max_log_file_num: 5
enable_console_log: true
enable_file_log: true
output:
json_output: false
report_dir: null # 自定义报告目录
root_dir: "reports" # 报告根目录
report_name: "autotest_report"
embed_images: false
embed_max_pixels: 800
network:
timeout: 600
max_retries: 3
no_proxy: ""失败分析配置(analyze 命令)
analyze:
model_name: "" # 留空则回退到 decision
base_url: ""
api_key: ""
temperature: 0.1
max_tokens: 4096
timeout: 90
max_retries: 3
enable_multimodal: true
max_screenshot_pixels: 800
max_key_steps: 5
only_fail: true # 仅分析失败用例使用方法
以下命令均在
AutoTest-nodejs/目录下运行。
测试用例有三种运行方式,按场景选择:
| 方式 | 命令 | 适用场景 |
|------|------|---------|
| caseTest(推荐) | npm run caseTest -- <参数> | 日常单用例运行,自动增量构建 |
| batchCaseTest | npm run batchCaseTest <文件> | 批量执行 JSONL/JSON 用例 |
| 直接 CLI | node dist/autotest-cli.js run <参数> | 需手动 build,适合调试编译产物 |
方式一:caseTest(推荐)
caseTest 通过 runner.mjs 自动检测源码变更并增量构建,无需手动 npm run build,然后以 run 子命令调用 dist/autotest-cli.js:
cd AutoTest-nodejs
# 基本用法:-- 后传递 CLI 参数
npm run caseTest -- --task "打开设置应用,查看 WiFi 列表"
# 指定模式 / 平台
npm run caseTest -- --task "测试任务描述" --mode layered --platform harmony
# 从 JSON 用例文件加载(第 10 条用例)
npm run caseTest -- --case-file cases.json --case-index 10
# 指定配置文件
npm run caseTest -- --task "测试任务" --config /path/to/config.yaml
# 列出设备
npm run caseTest -- list-devices
# 查看配置
npm run caseTest -- config --show
# 分析失败任务
npm run caseTest -- analyze --task-id 20260714_145936_001 --case-idx 0使用示例
示例1:通知栏测试
npm run caseTest -- --task "动作:打开 com.example.saltplayerharmony -> 播放歌曲 -> 下拉通知栏观察歌曲显示 -> 切换歌曲 -> 再次下拉通知栏
预期结果:通知栏显示当前歌曲封面,与 App 内一致;切歌时通知内容自动更新"示例2:长按预览测试
npm run caseTest -- --task "测试步骤:
1、打开 com.example.webfifth8,点击【6.0.0.37】按钮,点击【SR20250224905259】按钮,
连续向上滑动找到黑色加粗字体的【地址】,长按【广州市白云区机场路1234号】,5 秒后点击右侧空白
2、长按【123 Queen's Road, London, UK】,5 秒后点击右侧空白
预期结果:
1、弹出预览项和【导航前往】【复制】【选择文本】菜单
2、不弹出预览项和菜单"示例3:指定模式 / 平台 / 配置文件
npm run caseTest -- \
--task "打开设置应用,查看 WiFi 列表" \
--mode layered \
--platform harmony \
--config /path/to/config.yaml示例4:从 JSON 用例文件加载
npm run caseTest -- --case-file cases.json --case-index 10示例5:列出设备 / 查看配置 / 分析失败
npm run caseTest -- list-devices
npm run caseTest -- config --show
npm run caseTest -- analyze --task-id 20260714_145936_001 --case-idx 0方式二:批量执行
通过 batchCaseTest 批量执行 JSONL/JSON 用例,具备断点续跑、进度报告、分类汇总能力。同样通过 runner.mjs 自动增量构建。
cd AutoTest-nodejs
# 位置参数:第 1 个 = 用例文件,第 2 个 = category(可选,默认 default)
npm run batchCaseTest cases.jsonl
npm run batchCaseTest cases.jsonl smoke
# 显式用 -- 标志(等价写法)
npm run batchCaseTest -- --testcases cases.jsonl --category smoke
# 跳过清理后台进程(保留上条用例的进程状态)
npm run batchCaseTest -- --testcases cases.jsonl --skip-clear-process
# 指定最大执行用例数
npm run batchCaseTest -- --testcases cases.jsonl --max-cases 5批量执行参数
| 参数 | 说明 |
|------|------|
| --testcases <path> | 用例文件路径(JSON/JSONL) |
| --category <name> | 用例分类名(默认 default,用于报告与回写) |
| --task-dir <dir> | 报告输出目录(默认 reports/<date>/<time>/) |
| --testset-root <dir> | 用例集根目录,用于回写 auto_result 到原始 JSON |
| --config <path> | 配置文件路径 |
| --mode <m> | Agent 模式:single / layered |
| --prompt-name <name> | 按名称加载提示词 |
| --max-cases <n> | 限制执行用例数量 |
| --skip-clear-process | 每条用例执行前跳过清理后台进程 |
作为已安装的 npm 包使用时,也可调用发布的 autotest-batch 二进制:
npx autotest-batch cases.jsonl
npx autotest-batch cases.jsonl smoke批量执行特性
- 支持断点续执行(自动跳过已完成用例)
- 支持指定起始索引
- 定期进度报告(每 10 例)
- 自动更新原始用例文件状态与分类报告
- 输出 JSONL/CSV 结果与汇总
- 单个用例超时 10 分钟
方式三:直接调用 CLI(需先构建)
cd AutoTest-nodejs
npm run build # 两步构建:tsc --noCheck 生成 JS + tsc -p tsconfig.emit.json 生成 .d.ts
node dist/autotest-cli.js run --task "打开设置应用,查看 WiFi 列表"CLI 命令参考
Usage: autotest <command> [options]
Commands:
run Run a test task
list-devices List connected devices
analyze Analyze a failed task
config Show or update configuration
--version Show version (alias: -v, version)
Run options:
--task <desc> Task description
--case-file <path> Path to a JSON case file (use with --case-index)
--case-index <n> 1-based case index in the file
--device <sn> Device serial number
--platform <p> Platform: harmony | android | ios
--mode <m> Agent mode: single | layered
--ip <addr> Device IP address
--port <num> Device port number
--task-name <name> Test case name
--case-num <num> Case number
--report-dir <dir> Report output directory
--prompt-version <v> Prompt version
--prompt-name <name> Load prompt by name (priority over --prompt-version)
--app-config <path> App→bundle mapping config file path
--config <path> Path to config.yaml (default: bundled config.yaml)
--loop Enable self-healing loop (execute→analyze→rewrite→re-execute), default 3 iterations
--max-loops <n> Max loop iterations (>=2 enables FULL_LOOP; 0 disables)
--analyze-after Auto-analyze after task execution (requires --task)
--analyze <dir> Analyze-only: attribute an existing report dir (alias: --analyze-dir)
--rewrite <dir> Rewrite-only: rewrite from an existing analysis (alias: --rewrite-dir)
--keepalive-process-whitelist <pkg1> <pkg2> ...
Keep these processes alive during device reset (alias: --keepalive)
e.g. --keepalive com.hm.screenrecorder com.hm.app
--skip-clear-process Skip clearing background processes before each test case
Analyze options:
--task-id <id> Task ID to analyze
--case-idx <n> Case index within the task自愈闭环(Loop)
Loop 是 AutoTest 的自愈闭环编排器,将"执行→归因→改写→重执行"串成多轮状态机,自动修复失败的测试任务。
工作原理
┌─────────────────────────────────────────────────────────────────┐
│ FULL_LOOP 单轮流程(Step 1→9) │
│ │
│ Step 1 执行(hybrid_agent_chat)→ report_dir │
│ Step 2 归因(ReportAnalyzerAgent)→ root_cause │
│ Step 3 PASS 判定 ──── PASS? → 终止 PASSED │
│ Step 4 UNREWRITEABLE 判定 ── 应用/环境/无问题? → 终止 │
│ Step 5 死循环检测 ──── 连续 2 轮相同根因? → 终止 DEAD_LOOP │
│ Step 6 改写(RewriteAgent)→ rewrite_action │
│ Step 7 知识注入 ──── ADD_KNOWLEDGE → args.task += 知识文本 │
│ Step 8 任务改写 ──── REWRITE_TASK → args.task = 改写后文本 │
│ Step 9 记录本轮 → 下一轮(回到 Step 1) │
│ │
│ 终止条件: PASSED / UNREWRITEABLE / MAX_LOOPS / DEAD_LOOP / ERROR │
└─────────────────────────────────────────────────────────────────┘5 种执行模式
| 模式 | 触发条件 | 跳步 | 说明 |
|------|----------|------|------|
| FULL_LOOP | --max-loops >= 2 或 --loop | Step 1→9 | 完整闭环,多轮迭代 |
| EXECUTE_ANALYZE | --analyze-after | Step 1→2 | 执行 + 归因,单轮 |
| EXECUTE_ONLY | 仅 --task(默认) | Step 1 | 仅执行,单轮 |
| ANALYZE_ONLY | --analyze <dir> | Step 2 | 仅归因(对已有报告) |
| REWRITE_ONLY | --rewrite <dir> | Step 6→9 | 仅改写(对已有分析结果) |
改写动作
RewriteAgent 根据根因分析输出决定改写策略:
| 动作 | 适用场景 | 行为 |
|------|----------|------|
| REWRITE_TASK | 用例问题 | 替换 args.task 为 LLM 改写后的完整文本 |
| ADD_KNOWLEDGE | Agent 问题 | 在 args.task 末尾追加知识文本 |
| BOTH | Agent 理解性问题 | 先替换 task,再追加知识 |
| NO_REWRITE | 不可改写 | 终止(UNREWRITEABLE) |
启动方式
CLI:
# 完整闭环(默认 3 轮)
npm run caseTest -- --task "打开设置" --loop
# 指定轮数
npm run caseTest -- --task "打开设置" --max-loops 5
# 执行 + 归因(单轮,不改写)
npm run caseTest -- --task "打开设置" --analyze-after
# 仅归因(对已有报告目录)
npm run caseTest -- --analyze reports/20260714_145936_001
# 仅改写(对已有分析结果)
npm run caseTest -- --rewrite reports/20260714_145936_001编程调用:
import { AutoTestAgent } from '@autotest/agent';
const agent = new AutoTestAgent({ apiKey, modelName, baseUrl });
// FULL_LOOP
await agent.runTask('打开设置', { maxLoops: 3 });
// EXECUTE_ANALYZE
await agent.runTask('打开设置', { analyzeAfter: true });
// REWRITE_ONLY
await agent.runTask('', { rewriteReportDir: 'reports/20260714_145936_001' });配置文件启用:
agent:
unified:
max_loops: 3 # >0 即启用闭环(N 轮迭代),0 禁用
max_loops是 loop 的唯一配置参数。>= 2进入 FULL_LOOP,1进入 EXECUTE_ONLY。CLI--max-loops优先于配置文件。
输出产物(仅 FULL_LOOP)
reports/<taskId>/
├── iter_1/ # 第 1 轮
│ ├── screenPath/ # 截图
│ ├── layout/ # 布局
│ ├── log/ # 日志
│ ├── <iter_1>.html # 执行报告(文件名 = 目录名脱敏)
│ └── analysis/ # 根因分析报告(json/html/md 三件)
├── iter_2/ # 第 2 轮(改写后重执行)
│ └── ...
├── loop_result.json # 闭环结果(各轮记录 + 终止原因 + task 演进)
└── loop_summary.html # 闭环汇总(Tab 切换各轮执行/分析报告)loop_result.json:序列化的LoopResult,含每轮IterationRecord(归因摘要、改写动作、改写后 task、知识文本)loop_summary.html:Tab 页面,Loop 汇总(终止原因 + 各轮概览表 + 任务演进时间线)+ iframe 内嵌各轮执行/分析报告
报告目录结构
reports/
└── <taskId>/ # 如 20260714_145936_001
├── <taskId>.html # HTML 报告(文件名 = 目录名脱敏)
├── <taskId>.json # JSON 数据(增量与终态同名渐进覆盖)
├── layout/ # 布局数据
├── log/ # 日志文件
├── screenPath/ # 截图目录
└── analysis/ # analyze 命令的根因分析报告(json/html/md 三件)报告内容
- 执行时间线:每一步操作与结果
- Bug 发现:异常与缺陷记录
- 截图记录:每步操作截图
- Token 消耗:模型 Token 统计
- 最终判定:测试通过 / 失败
- 根因分析(
analyze命令):失败原因、改进建议、关键截图、评分
Debug 调试模式
注意:此功能目前尚未实现。配置字段
agent.unified.debug_mode已在 schema 中预留(接受null/"memory"/"file"),但浏览器交互式复盘 Dashboard 尚未开发。配置该字段不会产生错误,也不会启用任何调试行为。
作为三方库集成
本包可作为 npm 依赖被其他工程集成,通过 AutoTestAgent 门面类创建实例并下发任务。
安装
npm install @autotest/agent
# 或
pnpm add @autotest/agent快速开始
import { AutoTestAgent } from '@autotest/agent';
const agent = new AutoTestAgent({
apiKey: 'sk-xxx',
modelName: 'qwen3.8-flash',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
deviceSn: 'LNG0223721000045', // 可选,留空自动检测
});
const result = await agent.runTask('打开设置应用,查看 WiFi 列表');
console.log(result.status); // 'completed' | 'failed'
console.log(result.tip); // 执行摘要
console.log(result.reportDir); // 报告目录路径配置参数
AutoTestAgent 构造函数接收 AutoTestAgentConfig:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| apiKey | string | 是 | LLM API Key(unified 模型使用) |
| modelName | string | 是 | 模型名称 |
| baseUrl | string | 是 | LLM API 地址 |
| provider | string | 否 | 模型提供商,默认 'openai' |
| executeModel | ModelSlotConfig | 否 | 双层模式 Execute 模型配置(apiKey/modelName/baseUrl/provider/temperature/topP/maxTokens);未设置时回退到 unified |
| decisionModel | ModelSlotConfig | 否 | 双层模式 Decision 模型配置;未设置时回退到 unified |
| deviceSn | string | 否 | 设备序列号,留空自动检测 |
| ip | string | 否 | 设备 IP,默认 127.0.0.1 |
| port | number | 否 | 设备端口,默认 8710 |
| platform | 'harmony' \| 'android' \| 'ios' | 否 | 指定平台,跳过自动检测 |
| agentMode | 'single' \| 'layered' | 否 | Agent 模式,默认 'single' |
| maxSteps | number | 否 | 最大执行步数,默认 100 |
| reportDir | string | 否 | 报告输出目录,默认 reports |
| enableCache | boolean | 否 | 启用 LLM 缓存,默认 true |
| configPath | string | 否 | 加载完整 YAML 配置文件路径 |
| configOverrides | Record<string, unknown> | 否 | 高级覆盖,结构同 AppConfig |
runTask 方法
const result = await agent.runTask(task: string, options?: RunTaskOptions);RunTaskOptions 可选参数(覆盖构造时的配置):
| 参数 | 类型 | 说明 |
|------|------|------|
| agentMode | AgentMode | 覆盖 Agent 模式 |
| platform | DevicePlatform | 覆盖平台 |
| deviceSn | string | 覆盖设备序列号 |
| ip / port | string / number | 覆盖设备地址 |
| reportDir | string | 覆盖报告目录 |
| taskName | string | 用例名称 |
| caseNum | string | 用例编号 |
| maxSteps | number | 覆盖最大步数 |
| skipClearProcess | boolean | 跳过清理后台进程(等价 --skip-clear-process) |
| configOverrides | Record<string, unknown> | 运行时配置覆盖 |
其他方法
// 查询任务结果
const result = await agent.getTaskResult(taskId);
// 分析失败根因
const analysis = await agent.analyzeFailure(taskId, caseIdx);
// 列出设备
const devices = await agent.listDevices();
// 停止正在运行的任务
agent.stopTask();
// 读取/更新配置
const config = agent.getConfig();
agent.updateConfig({ agent: { maxSteps: 50 } });使用完整 YAML 配置
如果需要配置双层 Agent(execute/decision 模型)、分析模型等高级选项,可通过 configPath 加载完整 YAML:
const agent = new AutoTestAgent({
apiKey: 'sk-xxx', // 覆盖 YAML 中的 api_key
modelName: 'qwen3.8-flash',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
configPath: '/path/to/config.yaml',
});日志显示
日志格式:<时间> - AutoTest - <级别> - <消息>。控制台默认输出 INFO+(INFO→stdout,WARNING/ERROR→stderr),runTask 时另落盘全量(DEBUG+)到报告目录 log/agent_<taskId>.log。各场景默认即可见 INFO+:
| 场景 | 日志去向 |
|------|----------|
| cmd / opencode 跑 node ... | stdout/stderr → 终端或被父进程捕获 |
| 脚本 spawn node | 管道,需同时读 child 的 stdout+stderr |
| 脚本内 new AutoTestAgent(...) | 当前进程 stdout;可用 addLogSink 接入自定义流 |
场景一:cmd / opencode 直接跑 CLI
无需额外配置,INFO+ 默认打印到控制台:
node dist/autotest-cli.js run --task "打开设置应用"场景二:脚本内 spawn 子进程
INFO 走 stdout、WARN/ERROR 走 stderr,需同时捕获两路才能拿到完整 INFO+:
import { spawn } from 'child_process';
const child = spawn('node', ['dist/autotest-cli.js', 'run', '--task', '打开设置'], {
stdio: ['ignore', 'pipe', 'pipe'],
});
child.stdout.on('data', (d) => process.stdout.write(`[out] ${d}`));
child.stderr.on('data', (d) => process.stderr.write(`[err] ${d}`));
child.on('exit', (code) => console.log('exit', code));场景三:进程内 new AutoTestAgent 接入自定义日志流
默认日志会进当前进程的 stdout。若要接入自己的日志系统(winston / pino / 远程上报等),用 addLogSink 订阅——回调按 INFO+ 阈值投递,返回取消订阅函数:
import { AutoTestAgent, addLogSink } from '@autotest/agent';
// 接入自定义日志流
const unsubscribe = addLogSink((level, message, formatted) => {
// level: 'INFO' | 'WARNING' | 'ERROR'(DEBUG 已被默认 INFO 阈值过滤)
myLogger.log({ level, message });
// 或转发完整带时间戳行:formatted
});
const agent = new AutoTestAgent({ apiKey, modelName, baseUrl });
await agent.runTask('打开设置应用,查看 WiFi 列表');
unsubscribe(); // 可选:停止订阅调整详细度
import { configureLogger } from '@autotest/agent';
configureLogger({ consoleLevel: 'DEBUG' }); // 控制台 + sink 同时放行 DEBUG
consoleLevel是控制台与 sink 的共同「详细度」旋钮;文件日志始终为DEBUG(落盘全量)。控制台写入已做 EPIPE 保护,消费方管道意外关闭不会导致 agent 崩溃。
脚本
在 AutoTest-nodejs/ 目录下:
cd AutoTest-nodejs
npm run build # 两步构建:tsc --noCheck 生成 JS + tsc -p tsconfig.emit.json 生成 .d.ts
npm run setup # 生成 config.yaml 配置文件(首次使用前执行)
npm run caseTest # 单用例运行(自动增量构建,推荐)
npm run batchCaseTest # 批量用例运行(自动增量构建)
npm test # 运行单元测试(vitest run)
npm run test:watch # 监听模式单元测试
npm run typecheck # 类型检查(tsc --noEmit)
autotest --version # 查看版本号构建说明:由于
aiSDK 的深层泛型类型会导致 tsc OOM,构建拆分为两步:
tsc --noCheck— 跳过类型检查,快速生成.js文件tsc -p tsconfig.emit.json— 使用types/ai-stub.d.ts桩文件替换ai/@ai-sdk/openai的复杂泛型类型,生成.d.ts类型声明copyfiles— 拷贝 yaml/md 资源文件
单元测试
单元测试位于 tests/,使用 vitest,共 205 个测试(13 个文件):
| 测试文件 | 覆盖模块 | 测试数 |
|---------|---------|-------|
| config-manager.test.ts | 配置加载/合并/Zod 校验 | 22 |
| agent-error.test.ts | 结构化错误/序列化/分类 | 22 |
| agent-api.test.ts | AgentAPI 接口/状态转换 | 24 |
| adapter.test.ts | 适配器/平台差异/工厂选择 | 19 |
| llm-caller.test.ts | LLM 调用封装/mock | 15 |
| report-generator.test.ts | 报告生成/HTML marker/标签剥离 | 11 |
| analyzer-parse.test.ts | 失败分析输出解析 | 10 |
| single-agent.test.ts | Agent 执行/截图注入/abort | 9 |
| key-steps-builder.test.ts | 关键步骤构建 | 9 |
| data-loader.test.ts | 数据加载 | 9 |
| hdc-adapter.test.ts | HarmonyHdcAdapter 35 设备操作全覆盖 | 42 |
| autotest-agent.test.ts | 门面类(mock adapter_factory,密闭) | 8 |
| logger.test.ts | 文件日志/格式 | 5 |
cd AutoTest-nodejs
npm test # 运行全部测试
npx vitest run tests/config-manager.test.ts # 运行单个文件开发扩展
自定义提示词
编辑提示词模板:src/core/prompt/templates/(single/ · hypium/ · planner/ · debug/ · fast_action/ · splitter/)。
添加新的 MCP 工具
- 在
src/core/mcp/mcp_tools.ts(双层)或local_tools.ts(本地)中添加 - 在
src/core/mcp/harmony_hdc_adapter.ts的callToolswitch 中添加设备操作 case - 在
src/mcp-server/types.ts中添加工具枚举 + Zod schema - 在
src/mcp-server/server.ts中注册到SCHEMA_MAP和DEVICE_TOOL_NAMES
自定义适配器
参考 src/core/mcp/harmony_hdc_adapter.ts,继承 base_adapter.ts 中的 MCPDeviceAdapter,并在 adapter_factory.ts 注册。
常见问题
Q1: 设备连接失败
- 确认 HDC 工具已安装并加入 PATH
- 运行
hdc list查看设备是否在线 - 检查
device.ip/device.port配置
Q2: 如何使用自定义模型?
在 config.yaml 修改对应模型的 base_url 和 api_key,支持所有 OpenAI 兼容 API。
Q3: 如何切换 Agent 架构模式?
- 修改
config.yaml的agent.mode - 或命令行
--mode single|layered
Q4: 如何查看测试报告?
查看 reports/<taskId>/<taskId>.html。
