Files
auto_control/doc/AI_TASK_GEN.md
T
butubb 104964aa53 feat: 动作经验库(agent_action)——成功步骤蒸馏命名动作(带元素定位/禁坐标)+ 执行前召回注入
- 新表 agent_action(name/app/aliases/params/steps/preconditions/hits/时间),
  独立于人工维护的 custom_action(2B 决策):AI 自学动作不污染手建动作
- 沉淀:任务成功后从**成功**工具轨迹(_ACTION_TOOLS: open_app/tap_text/tap_element/
  type_text/clipboard/swipe/press_key/wake/sleep)用模型蒸馏为命名动作;steps 用
  编辑器 schema,**必须元素定位**(xpath/text/resourceId/description…),
  **显式剔除 click_xy 等坐标类**;on_tool 记录带 result 的结构化轨迹以判成败
- 兼容模型形状漂移:顶层 {action,params} 自动归一为 {name,steps};宽容 JSON 解析
  (围栏/尾逗号/中文引号/坏对象逐条抢救),实测模型常返回带语法错误的 JSON
- 召回:执行前按动作名/别名命中(或相似度≥0.34)取 top3,注入 system prompt
  「可复用动作」段(含元素定位),模型可跳过重新探索;hits 回写
- 文档同步:ARCHITECTURE §3.6(agent_action 表)、API.md(🧠 动作经验 伪卡片 + 动作库
  说明)、AI_TASK_GEN P1(沉淀进展)
实测:跑「打开抖音,点搜索」→ 沉淀「打开抖音」;下一轮同指令命中并注入;日志
「命中可复用动作 1 个」「动作提炼: 轨迹 5 步, 成功可沉淀 1 步」「动作经验已保存 1 条」
2026-09-10 13:53:04 +08:00

15 KiB
Raw Blame History

AI 建任务(AI Task Generator)设计文档

分支:dev | 状态:设计稿(未实现) | 日期:2026-09-09 关联:AI 控制台(web/agent_api.py)、MCP 设备工具(mcp_server/)、任务/步骤编辑器(tasks/generic、static/admin/editor.js)

1. 背景与目标

平台已有两套能力,但互不相通:

  • AI 控制台:一句话 + 选设备 → 多模态 Agent(DeepSeek)通过 19 个 de_* 工具在手机上「边看边做」(截图看屏、de_ui_tree 拿元素树、de_tap_element/de_tap_text 语义点按),流式回放步骤。
  • 任务系统 + 步骤编辑器:generic_steps 任务 = 一棵可嵌套步骤树(open_app/click/swipe/loop/group/if_el…18 种节点),在编辑器里拖拽编排、单步试跑、定时调度。

目标:让非工程用户用一句自然语言需求(例:「创建一个每日养号刷视频的任务,每天 8:00-9:00 在 100.100.10.13 跑」)得到一条可直接调度、可继续在现有步骤编辑器里手改的任务。AI 先自己在设备上打开 App、看 UI 树、确认可点元素,再直接撰写编辑器的步骤 JSON。

产品体验(一页)

  1. 用户进入「AI 控制台 → 模式=AI 建任务」,选一台空闲设备,填需求 +(可选)任务名/调度/目标。
  2. AI 自探并流式回放(工具卡 + 截图,与现在一致):开 App → dump UI 树 → 确认要点的元素可命中 → 写步骤。
  3. 完成后平台返回任务草稿 draft,服务端 schema 校验后,**前端直接打开现有「新建任务 → 步骤编辑器」**预填。
  4. 用户核对/手改/单步试跑 → 保存 → 进任务列表,走原有调度器执行。

核心信任原则:AI 只“提案”,不直接建库、不直接执行最终任务;最终落库/执行都在用户确认后由现有机制完成。

2. 范围(P0 定稿,2026-09-09 与用户确认)

  • 入口:AI 控制台加「聊天 / AI 建任务」模式开关,复用会话/SSE/设备选择/停止/刷新恢复骨架。不新建顶级 Tab。
  • 产出方式:AI 直接撰写编辑器的步骤 JSON(非操作轨迹翻译)。自探信息只作上下文与审计;探索中的误点/多余截图不会混入任务。
  • 任务类型:P0 只产 generic_steps(通用步骤)。douyin_nurture 预设参数生成放 P1。
  • 定位原则:全部基于 UI 树:
    • 模型定位/点击一律走 de_ui_tree 拿到的元素(text/id/description/text_contains),多实例用 index,或后端 uiauto_helper 生成的 //*[@resource-id=..][k] XPath;
    • de_tap_element 确认能命中后才写进 click 步骤;
    • 默认不产 click_xy 坐标点击;UI 树给不了的元素记入 notes,交给人工/OCR 兜底;
    • 滑动用方向语义 swipe{direction},不用像素坐标。
  • 产出完整任务信封:{name, task_type:"generic_steps", target, schedule, retry, enabled, params:{max_duration, steps}}。

3. 现状与可复用点(实现依据)

  • 多模态 Agent 链路:web/agent_api.py(POST /api/agent/run 起后台线程、SSE delta/step/done/error、/stop、刷新恢复 GET /api/agent/run)→ mcp_agent/agent.py(OpenAI 兼容流式,工具经 fastmcp Client 拉 8033 的 19 个 de_*)→ mcp_server/mcp_server.py。
  • 前端 AI 控制台骨架:templates/admin/monitor.html #tab-agent + static/admin/agent.js(设备选择、sendAgentMsg、listenStream 渲染 agent-toolcard、实时画面跟随)。
  • 步骤权威 schema(前后端同构):tasks/generic/task.py STEP_TYPES(L44-83)/ DEFAULT_PARAMS(L86-103) 与 static/admin/editor.js STEP_LIB(L3-23)。
  • 元素抓取 → XPath:web/tasks_api.py /api/uiauto/elements(L224)→ core/uiauto_helper.get_elements(suggested.value 即编辑器可用的 XPath)。
  • 单步试跑:/api/steps/test(tasks_api.py L249)+ editor.js _testStep;tasks/generic/task.py test_step(L633)。
  • 任务/调度/目标:core/task_manager.py TaskJob(L121-199);POST /api/jobs(tasks_api.py L68)。
  • 设备占用语义:MCP 写工具 _ensure_device_free(mcp_server.py L60-78,running/connecting → device_busy);agent_api run 入口同样对 worker running/connecting 拒绝(409)。
  • 经验库自进化:agent_experience + bigram 检索注入 + 每日巡检(web/agent_api.py)——P1 沉淀模板的现成载体。

4. 架构与数据流

需求+设备(空闲) ──▶  Designer Agent(自探, 模式=designer)
                        │  de_open_app / de_ui_tree / de_screenshot / de_tap_element…
                        ▼
                平台工具 submit_task(draft)  ← 结束性调用
                        │  服务端 draft schema 校验(白名单+必填+深度≤5)
                        ▼
        前端: 打开 openTaskModal 步骤编辑器, 预填 draft.task
                        │  用户核对/手改/单步试跑(/api/steps/test)
                        ▼
                POST /api/jobs  → 任务列表(原调度器执行)
   (P1) draft+需求 沉淀 agent_experience, 相似需求注入参考

4.1 Designer Agent(新增模式,复用现有 Agent)

  • mcp_agent 增加 designer 系统提示词:角色=自动化任务设计师;行为约束见 §5.1。
  • 增加平台级工具(不属设备 de_*):
    • submit_task(draft):结束性工具,模型完成自探后提交草稿即停止,服务端立即校验。
  • 会话内同时记录结构化 trace(每轮 on_tool 的 {tool, args 精简, 屏号/证据}),用于:校验证据(每个 selector 来自哪次树)、审计、P2 回放。
  • POST /api/agent/run 增加 mode:"designer";done 事件负载携带 draft(校验通过)或 draft_error(校验失败+原因,让模型补一轮)。

4.2 draft 契约

{
  "summary": "每日8-9点刷抖音养号:开抖音→循环(看5~35s+上滑)+随机间隔",
  "task": {
    "name": "抖音每日养号",
    "task_type": "generic_steps",
    "target": {"mode":"serial","serial":"100.100.10.13:5555"}
            | {"mode":"group","group_name":"测试"} | {"mode":"all"},
    "schedule": {"mode":"once"} | {"mode":"cron","cron":"0 8 * * *"}
               | {"mode":"cron_stop","cron":"0 8 * * *","stop_cron":"0 9 * * *"},
    "retry": {"max_attempts":5,"delay":30},
    "enabled": true,
    "params": {
      "max_duration": 0,
      "steps": [
        {"type":"open_app","label":"打开抖音","params":{"package":"com.ss.android.ugc.aweme","wait_home":true}},
        {"type":"loop","params":{"loop_mode":"rounds","max_iterations":30,"children":[
           {"type":"wait","params":{"min":5,"max":35}},
           {"type":"swipe","params":{"direction":"up","duration_min":0.25,"duration_max":0.5}}
        ]}}
      ]
    }
  },
  "notes": ["评论按钮需先进入视频页才可见"],
  "evidence": [{"screen":"抖音首页","element":{"text":"关注","id":"..."},"xpath":"//*[@resource-id=\".../gvo\"]"}]
}
  • 步骤节点结构:{id?, type, label?, params};id 执行端忽略(编辑器重新生成),params 必填。
  • 必填字段语义(空值会被执行端静默跳过,校验器必须拦):
    • click / long_click / swipe_until / wait_el / if_el → params.selector_value
    • open_app / stop_app → params.package
    • 容器:loop / group → params.children(非空);if_el → params.then(else 可选)
    • swipe_until → direction + max_swipes;click_xy P0 不产(如允许则 x/y 0-100)
    • 节点公共可选 params.probability(0-100,缺省 100)
  • selector_type 允许值:xpath / description / text / resourceId / descriptionContains / className(if_el 可 ocr)。

4.3 服务端新增

  • core/task_draft.py:
    • STEP_TYPES 白名单 + 每类必填/深度校验 validate_steps(steps, depth)(嵌套≤5);
    • validate_draft(draft):任务信封(name 非空、task_type==generic_steps、target mode ∈ {all,group,serial}(group 名存在)、schedule cron 合法、steps 校验);
    • 归一化:把 schedule 里「每天 8-9 点」这类由前端/向导填的值转成 cron/cron_stop。
  • web/taskgen_api.py(或并入 agent_api,推荐并入以最大化复用):
    • 入口检查:serial 必须、设备在池/在线、worker 非 running/connecting(409,与现有语义一致);
    • 起 designer 后台线程;SSE 事件在现有 delta/step/done/error 基础上,done 可带 draft。
  • 注意:现有 POST /api/jobs 对 params 盲存(只校验 name+task_type)。AI 通道在保存前必须过 validate_steps,避免「任务 done 但什么都没做」(执行器对未知 type/空 selector 静默跳过)。

4.4 前端

  • monitor.html AI 控制台加模式切换;建任务模式下输入栏旁有折叠「任务设置」(名称/调度时间/目标 serial·分组·全部/备注)。
  • agent.js:done 携带 draft 后:
    • generic_steps → 调 openTaskModal()(tasks.js)并把 draft.task 灌入步骤编辑器(step 卡片可视化、可拖改、单步试跑、保存);
    • 弹窗内对 notes(含“需人工复核/OCR 兜底”项)给出醒目提示。
  • 过程回放沿用现有 agent-toolcard 渲染;可标记当前为 designer 轮以便后续区分。

5. 约束与安全(红线)

5.1 Designer 自探规则(写入提示词)

  1. 先 de_open_app(package),再 de_ui_tree + de_screenshot 看每屏;点到关键状态后再 dump 下一屏。
  2. 每个将写入步骤的目标元素,先用 de_tap_element(by=text/id/desc…)+ 截图确认可命中,并记下证据。
  3. 不做破坏性动作:需“评论/发送”时只确认输入框/发送键存在,不真发;产物里这类步骤 probability 调低并在 notes 标注“请人工复核”。
  4. 探索步数上限(P0 建议 30 步),可被 /stop 打断;结束后尽力还原前台 App。
  5. 未命中的元素一律不进任务;拿不准的进 notes 而非硬编。

5.2 平台级约束

  • 自探/试跑只在用户选的空闲设备(busy → 409),杜绝与运行中任务在设备上物理打架。
  • AI 不直接建库;生成任务仍需用户点保存(POST /api/jobs 现有权限)。
  • 尽量不写死坐标;P0 默认禁 click_xy,产物以树元素定位为主。

6. 里程碑

  • P0(本设计主体):designer 模式 → 自探(UI 树定位)→ 直接撰写 generic_steps draft → 服务端 schema 校验 → 前端步骤编辑器预填确认保存。验收:一句话在真实设备上生成一条可调度的 generic_steps,步骤全部来自 UI 树且编辑器可打开。
  • P1:douyin_nurture 参数预设生成(照 default_params 结构);模板沉淀:把 draft+需求写入 agent_experience(新列存结构化 steps 或 JSON),相似需求注入参考;整链「演示试跑」(把 steps 在设备上以受控方式跑一遍并截图回报,需新增端点,复刻 device_busy 拒绝语义)。
    • 进展(2026-09-10):动作级沉淀已落地——agent_action 表 + 从成功步骤蒸馏"命名动作"(steps 用编辑器 schema、带元素定位、禁坐标)+ 执行前按名/别名召回注入(web/agent_api.py)。AI 建任务可直接把这些动作当作 generic_steps 的预制件复用。
  • P2:自定义动作支持(内联展开成 group,或新增 action_ref 节点 + 执行器/编辑器同步);多设备并行;成本与 token 控制。

7. 实现时需新增/改动文件(规划)

  • 改:mcp_agent/(designer 提示词与 submit_task 工具、结构化 trace)、web/agent_api.py(mode=designer、done 带 draft)、static/admin/agent.js + templates/admin/monitor.html(模式切换/任务设置/draft 预填)、doc/(本文档关联)。
  • 新:core/task_draft.py(schema+校验+归一化)、(可选)web/taskgen_api.py。
  • 不动:任务执行器、调度器、POST /api/jobs 主体(保持现有盲存,只在 AI 通道校验)。

8. 验收(P0 实现后自测)

  1. 目标设备空闲时:需求「每日 8-9 点刷抖音养号」→ 生成 generic_steps 任务,步骤为 open_app → loop(wait+swipe) 结构,调度 cron_stop 8-9 点。
  2. 打开编辑器中该任务:步骤卡片完整、可拖改、单步试跑命中;保存后任务列表出现且下次运行时间正确。
  3. 反例:模型产出含 click_xy 或未知 type / 空 selector → 服务端校验拦截并让模型补正;busy 设备入口 409。
  4. 探索全程可在前端回放(工具卡+截图),未发送真实评论/未污染设备状态。

9. 需要转成 MCP / 平台工具的能力(分层,2026-09-09 与用户确认)

背景问答结论:目前 MCP 只有设备层 19 个 de_*(控制 + 只读 de_list_tasks),平台 CRUD(任务增改/启停/立即运行、分组、设备池、自定义动作、APK、备份、用户)都还没 MCP 化。方向认同「先把工具链补完善」,但不做"把所有平台 CRUD 一次性搬成 MCP"的大而全——按消费方(AI 建任务 / 外部自动化)分层、按需补。新增 MCP 工具一律:进 doc/MCP.md 手册 + doc/MCP_DESIGN.md 规格 + 与 web 同源的权限/busy/审计 + 校验逻辑下沉到 core/ 共用(防双份漂移)。

9.1 现状盘点

  • MCP(mcp_server/mcp_server.py,19 个 de_*)= 设备控制 + 设备只读 + de_list_tasks(平台任务只读)。
  • 任务创建/修改/删除、toggle、立即运行、分组、设备池管理、自定义动作、APK、系统备份等 REST 路由只给前端用,未暴露 MCP。

9.2 P0 —— AI 建任务链路真正需要的「平台工具」(最小集)

只补两小类,其余设备操作全部复用现有 de_*:

  1. 只读清单(供自探确定 target/能不能做):
    • list_task_types / list_groups(target 选 group 用)/ list_pool(可调度设备,含 busy 状态)
    • (可与现有 de_list_devices 合并语义,避免重复)
  2. 校验 + 提交(结束性):
    • submit_task(draft) → 服务端用 共用 core/task_draft.validate_steps()/validate_draft() 校验,不直接落库,返回 draft 供前端打开步骤编辑器预填、人工确认后走 POST /api/jobs。

关键:P0 的 Agent 不暴露任务 CRUD 写权限(create/update/toggle/run),否则模型可绕过"AI 提案 → 人工确认"直接入库,破坏信任模型。

9.3 P1 —— 外部自动化 / 后续 Agent 的「写 MCP」(受权限约束,逐块加)

若目标延伸为"外部程序能像调 REST 一样操控平台",则按此清单逐个补(每加一个都做权限+busy+审计+校验下沉):

  • 任务:create_job / update_job / delete_job / toggle_job / run_job_now / query_jobs
  • 分组:list_groups / create_group / update_group / delete_group
  • 设备池:pool_list / pool_add / pool_remove / pool_toggle
  • 自定义动作 / APK 清单 等视使用再加
  • 只读清单优先搬;写类确认有真实消费方再做,避免空转。

9.4 分层与登记(红线)

  • 每新增/修改/删除一个 MCP 工具或平台配置:同步更新 doc/MCP.md(全清单)、doc/MCP_DESIGN.md(规格/层级),并在提交里体现——见全局「doc 同步红线」。
  • core/task_draft.py 是 web 校验与 MCP 校验的唯一来源,杜绝两套规则漂移。