AI 控制台下新增子分栏「🧭 AI 建任务」:描述要做什么(例:建一个跑 2 小时的任务、自动刷
某 App、随机点赞),AI 用 de_* 工具自己在设备上探索(看屏/读元素树/点按验证),把走通的
路径写成一条任务草稿,经服务端校验后交人在步骤编辑器里核对/手改/试跑,保存才入库。
链路:POST /api/agent/run{mode:"designer", settings}
→ Agent 自探 → 本地工具 submit_task(draft)
→ core/task_draft 校验(失败把 errors 回灌模型让它改)
→ 只暂存(运行态 + app_meta.agent_task_draft,**不落库**)
→ SSE done{mode,draft,warnings} → 页面草稿预览 → openTaskModal(null, prefill) 预填
关键实现
- core/task_draft.py(新):把执行器的"静默跳过点"(未知 type/空 selector/空 children/
嵌套>5/节点>60/cron 非法/必填缺失)前移成显式 error——POST /api/jobs 对 params 是盲存的,
执行器又静默跳过错误步骤,没有这道闸门就是"任务建好了、跑起来什么都没做"。
归一化兜底任务名/target/schedule/retry/时长;页面填的设置以 overrides 优先于模型。
故意**不比执行器更严**:loop_mode 近义值归一(count→rounds)、缺 max_iterations 补默认 10
(执行器本来就默认)——实测卡太死会把一轮探索耗在改字段上。
有副作用的步骤(评论/发送/购买/删除…)只警告并把触发概率压到 30%(编辑器可改回)。
- mcp_agent/agent.py:双系统提示词(CHAT/DESIGNER)+ 平台级本地工具
(LOCAL_TOOL_SPECS,不进 MCP)+ 每工具调用上限 40 + designer 输出上限 8192 +
**json.loads 容错**(草稿被截断时给模型可读错误,而不是整轮失败)。
- web/agent_api.py:mode/settings 透传、submit_task 处理器(app_context 内校验+暂存)、
done 带 draft、GET /api/agent/task_draft{,+POST,/clear}(草稿走 app_meta,不新建表)。
- 前端:static/admin/taskgen.js + #agent-sub-taskgen 子面板(showSubTab 机制);
tasks.js 的 openTaskModal(jobId, prefill) + 信封归一化 + 唯一 draftKey;
agent.js 按 mode 门控(一个 run 只有一个事件队列,两个 EventSource 会互相瓜分事件)。
顺带修掉一个 chat 也踩的协议 bug:一轮里同时调 de_screenshot 与别的工具时,截图图像会被
插在两条 tool 消息之间 → 模型侧判"工具回应不足"直接 400。改为本轮 tool 消息发完再附图像,
_repair_tool_messages 也改成只数**连续**的 tool 消息。
真机实测(Redmi 22120RN86C,设置页):8 步探索(含 tap_text 验证)→ submit_task 一次通过 →
草稿 8 个顶层步骤(screen_on/open_app/wait_el/click/wait/key_event…)、max_duration 1800、
无 click_xy、3 条 evidence;页面恢复草稿 + 预填编辑器 + 提示块渲染均正常,无 JS 报错。
自测数据已清理(草稿已丢弃、未创建任何任务)。
文档:AI_TASK_GEN.md 状态改「P0 已实现」+ §10 实现记录(差异/护栏/未做项)、AI_CONSOLE.md
(子分栏、designer 分支、SSE done 负载、app_meta 键)、API.md、DATA_MODEL.md、ARCHITECTURE.md、
DEVELOPMENT.md(自测入口)、README.md 索引、backlog 勾掉 P0。
243 lines
20 KiB
Markdown
243 lines
20 KiB
Markdown
# AI 建任务(AI Task Generator)设计文档
|
||
|
||
> 状态:**P0 已实现**(2026-09-13)——§1~§9 是设计稿(与实现基本一致),
|
||
> **§10 是实现记录**:差异、落地细节、怎么自测,以 §10 为准。
|
||
> 现状请读:[AI_CONSOLE.md](AI_CONSOLE.md)(AI 控制台已实现的能力)、[TASK_DEV.md](TASK_DEV.md)(任务与步骤)、[MCP.md](MCP.md)(已实现的 19 个工具)。
|
||
> 关联代码:`web/agent_api.py`、`mcp_server/`、`mcp_agent/`、`tasks/generic/`、`static/admin/editor.js`。最后核对:2026-09-10。
|
||
|
||
## 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**(非操作轨迹翻译)。自探信息只作上下文与审计;探索中的误点/多余截图不会混入任务。
|
||
- **任务类型**:**只产 `generic_steps`**(通用步骤)——平台当前唯一的任务类型
|
||
(原 `douyin_nurture` 预设参数生成已随该类型删除,不再做)。
|
||
- **定位原则:全部基于 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 契约
|
||
```json
|
||
{
|
||
"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 树且编辑器可打开。(平台只剩 generic_steps 一种任务类型,与原规划一致)
|
||
- **P1**:模板沉淀:把 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 校验的**唯一来源**,杜绝两套规则漂移。
|
||
|
||
---
|
||
|
||
## 10. 实现记录(2026-09-13)
|
||
|
||
### 10.1 与设计稿的差异(以本节为准)
|
||
|
||
| 设计稿 | 实际实现 | 为什么 |
|
||
|---|---|---|
|
||
| 聊天页加「模式」开关 | AI 控制台下的**独立子分栏**「🧭 AI 建任务」 | 用户要求独立页面;探索回放 + 草稿预览需要自己的版面 |
|
||
| `submit_task` 作为平台工具(§9.2,未指定放哪层) | **Agent 本地工具**(`mcp_agent/agent.py` 的 `LOCAL_TOOL_SPECS`),**不进 MCP Server** | 放进 MCP 等于给外部客户端开"写任务"的口子,还要连带改 MCP.md/MCP_DESIGN.md 与审计;收益为零 |
|
||
| draft 经前端灌进步骤编辑器 | 同上,但草稿**先落 `app_meta`**(`agent_task_draft`,只留最近一份) | 刷新/重进页面能拿回来;**不新建表**,绕开备份覆盖红线(SUMMARY_TABLES / DEPLOY §3.5) |
|
||
| (未提) | designer 跑**不绑会话、不吃聊天历史**,且**不沉淀**经验/动作 | 探索轨迹里有试错与误点,沉淀会污染记忆库;"draft→经验"归到 P1 |
|
||
| —— | 校验失败把 `errors` **原样回灌模型**,最多重提 3 次(提示词约束) | 这是"AI 写坏任务"的唯一闸门:`POST /api/jobs` 对 params 盲存、执行器又静默跳过错误步骤 |
|
||
|
||
### 10.2 关键实现点
|
||
|
||
- **校验器**:`core/task_draft.py`。`validate_draft()` 逐条复刻执行器的"静默跳过点"
|
||
(未知 type / 空 selector / 空 children / 嵌套 >5 / 深度节点数 >60 / cron 非法 /
|
||
必填 params 缺失 / `click_xy` 直接拒)→ 返回可被模型读懂的 `errors` + 不拦的 `warnings`。
|
||
`normalize_draft` 负责兜底(任务名、target、schedule、retry、时长);页面上的任务设置
|
||
以 `overrides` 形式**优先**于模型给的。
|
||
- **提示词**:`mcp_agent/agent.py` 的 `DESIGNER_SYSTEM_PROMPT`(16 条规则:先看再动、
|
||
定位优先级、禁坐标、禁序号型 XPath、**副作用动作只核对不真点**、时长语义映射、
|
||
随机化三件套、规模上限、收尾方式)。
|
||
- **护栏**:单工具调用上限 40 次(`Agent.tool_call_limit`;总步数由 `max_steps` 兜底,
|
||
两个值都要**大于**正常重试次数,否则会把一轮探索截断在"改字段"上——实测踩过);输出上限 8192(designer);
|
||
`json.loads` 容错(草稿被截断时返回可读错误而不是整轮崩)。
|
||
- **前端**:`static/admin/taskgen.js` + `#agent-sub-taskgen`(子 Tab 机制见
|
||
`static/admin/base.js` 的 `showSubTab`)。草稿预览能直接点「在步骤编辑器中打开」→
|
||
`openTaskModal(null, prefill)` 预填(用唯一 draftKey,避开 localStorage 旧草稿覆盖)。
|
||
- **两个页面共用一个运行槽**:`GET /api/agent/run` 回 `mode`,两个前端各按 mode 决定
|
||
是否订阅 SSE(一个 run 只有一个事件队列,两个 EventSource 同时消费会互相瓜分事件)。
|
||
|
||
### 10.3 附带修掉的一个协议 bug
|
||
|
||
Chat 模式同样受益:一轮里若模型同时调了 `de_screenshot` 与别的工具,旧实现会把截图图像
|
||
作为一条 `user` 消息**插在两条 tool 消息之间**,模型侧判定"工具回应不足"直接 400
|
||
(`An assistant message with 'tool_calls' must be followed by tool messages…`)。
|
||
现改为:本轮 tool 消息发完后再附一条 user 图像消息;`_repair_tool_messages` 也改成
|
||
只数**连续**的 tool 消息。
|
||
|
||
### 10.4 还没做(P1 / 后续)
|
||
|
||
- 「探索完直接创建」接口(服务端复验后 `add_job`)——目前一律走人工确认。
|
||
- draft → `agent_experience` / `agent_action` 沉淀(模板重用)。
|
||
- MCP 侧补 `de_snapshot`(截图+元素树一次取齐,见 `doc/research/U2_ELEMENT_SELECTORS.md`)。
|
||
- 多设备并行探索、成本控制。
|
||
|
||
### 10.5 自测怎么跑
|
||
|
||
1. 纯逻辑:`core/task_draft` 的正反例(未知 type / 空 selector / `click_xy` / cron 少段 /
|
||
深度 6 / probability 越界 …),断言 `errors` 文案模型能读懂。
|
||
2. 真机:AI 控制台 →「AI 建任务」→ 选空闲设备 → 描述需求 → 看回放 → 核对草稿 →
|
||
「在步骤编辑器中打开」→ 单步试跑 → 保存。
|
||
3. 反例:需求里出现"自动评论并发送" → 草稿的这类步骤应是"只核对存在性"(`notes` 里提示
|
||
人工复核),**探索期审计日志里不应有对发送键的 `de_tap_*`**。
|
||
4. 自测产生的东西(草稿/自建任务)用后即删,别碰用户真实数据。
|