Files
auto_control/doc/AI_CONSOLE.md
T
butubb 24d57d3b96 docs: doc/ 全量重整——按现状重写并建立文档索引;项目统一更名 auto_control
背景:文档长期落后于代码(Tab 数、任务类型、接口示例等多处与现状不符),
且信息分散重复。这次按当前代码状态逐篇重写,并建立统一的文档体系。

新增
- doc/README.md:文档总索引(文档地图 / 推荐阅读路径 / **文档维护约定**)
- doc/DATA_MODEL.md:数据模型(7 张模型表 + 5 张非模型表、迁移机制、app_meta 键、
  数据目录、备份覆盖清单与双向自检)
- doc/AI_CONSOLE.md:AI 控制台机制(会话与 SSE、经验库/动作库蒸馏与召回、巡检、
  Markdown 渲染、推理链、token 统计、故障排查)

重写(按现状,去掉过时与重复)
- README.md:7 个 Tab、18 种步骤、设备生命周期、调度/窗口语义、常见问题;修掉
  「6 个 Tab / 分组为顶级 Tab」等过时内容与损坏的目录树
- doc/ARCHITECTURE.md:补启动装配顺序(import 期副作用、A~G 七阶段)、线程与锁清单、
  设备状态机、调度全链路、前端结构与实时通道、设计决策、**已知缺陷与踩坑清单**、扩展点
- doc/API.md:按蓝图重建「接口总索引」(107 条路由含鉴权)+ 分域详细说明 +
  非 JSON 响应汇总 + 错误分支速查
- doc/TASK_DEV.md:18 种步骤全表(参数/默认值/语义)、容器与公共参数、
  选择器与 XPath 序号语义、抓取器建议规则、新增任务类型骨架
- doc/DEPLOY.md:容器入口 start.sh 三件事、发布流程与检查清单、备份覆盖红线、
  按现象分类的故障排查
- doc/DEVELOPMENT.md:流程/红线/本地开发/**测试与写测试的约定**/配置速查/文档同步
- doc/MCP.md:19 个工具的参数级清单、坐标空间、写门控三连、安全与审计
- doc/MCP_DESIGN.md、doc/AI_TASK_GEN.md:标注设计 vs 实现现状,补交叉链接
- doc/backlog/TODO.md:新增「已知缺陷」小节(含复现与影响)+ 已完成留档
- .env.example:按代码实际读取的键重写(补 USB/DISCOVERY/MCP/AGENT,删死配置)

其它
- 项目名统一 auto_control:README/文档/scripts/pack.py 产物名;代码内的
  doc 章节引用(templates/admin/monitor.html)同步更新
- 校验:16 篇文档 156 条相对链接全部可解析;文档中的关键数字与代码核对一致
  (19 个 MCP 工具 / 18 种步骤 / 12 张备份表 / 1 种任务类型)
2026-09-10 22:19:18 +08:00

211 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI 控制台(AI_CONSOLE)
> 适用读者:使用 AI 控制台的人 + 改这部分代码的开发者。
> 相关文档:[API.md](API.md) §12(接口)、[MCP.md](MCP.md)(AI 用的工具层)、[AI_TASK_GEN.md](AI_TASK_GEN.md)("一句话建任务"的设计稿,尚未实现)。
---
## 1. 它是什么
「AI 控制台」是后台的一个顶级 Tab(仅管理员):选一台设备,用自然语言下指令,AI 通过 MCP 工具**看屏幕、点按、输入**,边做边把过程和结论流式显示出来。
```
你:「打开小红书搜索苏州好吃的饭店,把前 5 条列出来」
AI:de_list_devices → de_screenshot → de_tap_text("搜索") → de_type_text("苏州好吃的饭店")
→ de_screenshot → de_ui_tree → … → 汇总结论(Markdown 表格)
```
两个"自进化记忆"让它越用越顺:
| 记忆 | 存什么 | 怎么产生 | 怎么用 |
|------|--------|---------|--------|
| **🧠 经验库** | 任务级**操作配方**(这一步该怎么做) | 一轮任务成功后由模型蒸馏 | 相似任务开始时召回注入 system prompt |
| **🎬 动作库** | **命名动作**(可复用的动作单元,带元素定位) | 从**成功步骤**蒸馏,禁坐标 | 相似任务开始时召回注入,可直接复用定位 |
---
## 2. 使用
### 2.1 配置(首次必做)
右上角 **⚙ 配置**:
| 项 | 说明 |
|----|------|
| API Base | OpenAI 兼容地址(默认 `https://api.deepseek.com`) |
| 模型名 | 如 `deepseek-v4-flash-vision-exp`(需支持**视觉**,因为要看截图) |
| API Key | 只存数据库 `app_meta`,回显打码 |
| 默认设备 | 不选目标设备时用它 |
| 最大步数 | 1-200,默认 40(每轮模型调用算一步) |
> 配置存在数据库(`app_meta` 的 `agent_*` 键),**不在 `.env`**。`CLI(mcp_agent/cli.py)` 走的是环境变量 `AGENT_*`,两套互不影响。
### 2.2 跑一轮
1. 选 **🎯 目标设备**(AI **只操作你选定的设备**;有任务在跑的设备不可选)
2. 输入指令,Enter 发送
3. 右侧「📺 实时画面」自动跟随 AI 操作的设备(MJPEG)
4. 中途可「■ 停止」(下一个检查点生效,通常几秒内)
5. 刷新/换窗口:会话与运行状态都会自动恢复(见 §3.3)
### 2.3 会话管理
左侧会话列表 = 多轮对话(DeepSeek 风格):不同话题建不同会话,历史消息会作为上下文续上(最近 12 轮)。会话条目上显示 ID(前 8 位,点击复制),便于反馈问题时引用 `conv=<id>`。
---
## 3. 机制
### 3.1 执行链路
```
POST /api/agent/run web/agent_api.py 起后台线程(单实例:同时只允许一个)
│
├─ 经验召回 _find_experiences(prompt) ─┐
└─ 动作召回 _find_actions(prompt) ├─ 拼成 extra_context 注入 system prompt
┘
▼
mcp_agent.Agent.run_stream(prompt, serial, history, on_delta, on_tool, on_usage, …)
│ 循环(最多 max_steps 轮):
│ ① 流式调模型(OpenAI 兼容 /chat/completions)
│ ② 有 tool_calls → 执行 MCP 工具 → 结果回灌 → 继续
│ 截图工具的结果会转成 image_url 追加,模型"看得见"
│ ③ 无 tool_calls → 本轮即最终回答
▼
事件 → queue → SSE /api/agent/stream → 前端
```
- 一轮整体超时 **900 秒**;达到步数上限会让模型做一次收尾总结
- 工具调用由 MCP Server 执行(`:8033`),后者再调平台 HTTP 接口/直连设备
- **设备忙时拒绝**:目标设备正在跑任务 → `409`("AI 不与任务抢设备")
### 3.2 会话消息模型
`agent_conversation.messages`(JSON 数组):
```json
[{"role": "user", "content": "…"},
{"role": "assistant", "content": "最终回答(Markdown)",
"usage": {"prompt_tokens": 3480, "completion_tokens": 126, "total_tokens": 3606, "calls": 1},
"reasoning": "模型的推理链(最多保留 6000 字符)"}]
```
> `usage` / `reasoning` **只用于前端展示与回看**;回灌给模型的历史只取 `role` / `content`(不污染上下文预算)。
### 3.3 SSE 事件与刷新恢复
| event | payload | 前端行为 |
|-------|---------|---------|
| `delta` | `{"text","kind":"content"\|"reasoning"}` | 正文增量渲染 Markdown;推理增量进入可折叠「💭 思考过程」 |
| `step` | `{"tool","args","image"?}` | 追加工具卡片(含缩略截图,点击放大);伪卡片提示经验/动作命中与沉淀 |
| `usage` | `{"prompt_tokens","completion_tokens","total_tokens","calls"}` | 刷新单条消息脚注与顶栏「本会话累计」 |
| `done` | `{"answer","usage"}` | 最终答案 + 收尾 |
| `error` | `{"message"}` | 展示错误(MCP 不可达等已转成明确文案) |
**刷新/重连不丢进度**:服务端事件队列保留积压,页面重新订阅(`GET /api/agent/stream?run_id=`)后会补发 delta/step/usage/done;`EventSource.onerror` **刻意不结束运行**,靠自动重连续上。另外 `GET /api/agent/run` 提供状态快照(其他窗口/8s 轮询用)。
### 3.4 token 统计
- 请求带 `stream_options.include_usage`,服务端在**末尾 chunk** 返回 usage
- 按「每次模型调用」累加(多轮工具调用会累加多次);`calls` = 模型调用次数
- 个别网关不认该参数会直接 400/422 → **自动关掉并重试一次**,不影响主流程(只是没有 token 数字)
- 展示位置:单条消息脚注(`🪙 3,606 tokens(↑3,480 ↓126 · 1 次调用)`)+ 顶栏「🪙 本会话 3,606 tokens」
### 3.5 回答渲染
- **Markdown**:自研轻量渲染器(`static/admin/markdown.js`,**无 CDN 依赖**,生产在内网)
支持标题/段落/列表(含嵌套)/表格/代码块/引用/链接;**先 `esc()` 转义再套标记**,所以模型输出里的 HTML 只会显示为文本
- **推理链**:`<details>` 折叠块,流式时展开、正文开始时自动收起;手动点过后不再自动改;摘要显示字数
- **工具卡片**:每步 MCP 调用一行(工具名 + 参数 + 截图缩略)
---
## 4. 经验库
### 4.1 产生(蒸馏)
一轮任务**成功执行过工具**后,把「任务描述 + 工具序列」交给模型,提炼成一段**可复用的操作配方**(纯文本,不含具体坐标)。
健壮性设计(都是踩坑后加的):
| 措施 | 原因 |
|------|------|
| 蒸馏调用**关闭推理**(`thinking: {"type":"disabled"}`) | 推理模型会把 token 预算烧在 reasoning 上,导致 `content` 为空/被截断 → 经验被静默丢弃 |
| 纯文本问法 + 质量门槛 | 早期提示词里放了可照抄的占位示例,模型会把 `"1. …\n2. …"` 原样当配方存下来 |
| 截断容忍解析 | JSON 被截断时逐个对象抢救 |
| 失败有日志 | 不再静默 |
### 4.2 召回
相似任务开始时按 bigram 相似度检索(阈值 + 取前 2 条),拼进 system prompt,并在对话里推一张「🧠 经验记忆」卡片("命中 N 条同类历史经验,已注入参考")。命中会累加 `hits`。
### 4.3 巡检(质量治理)
- 每日 **03:47**(独立 APScheduler)自动跑一轮:把经验交给模型评审,输出「保留 / 建议删除」+ 评分 + 理由,写入 `experience_audit`
- 也可在面板里手动触发
- **删除永远需要人工确认**(巡检只打标 `pending`,面板上显示 ⚠ 建议删除 + 理由,人工点「确认删除」或「保留」)
- 「保留」会记 `action='kept'`,后续不再重复建议
### 4.4 面板
「🧠 经验库」按钮打开:列表(任务描述、配方摘要、引用次数、巡检建议)+ 删除/保留操作。
---
## 5. 动作库
### 5.1 与经验库的区别
| | 经验库 | 动作库 |
|---|--------|--------|
| 粒度 | 整个任务的操作套路(文字) | 单个可复用动作(结构化步骤) |
| 内容 | 自由文本配方 | 命名动作 + `steps`(编辑器 schema,**带元素定位**) |
| 用途 | 让 AI 知道"这类任务一般怎么做" | 让 AI 直接复用"打开抖音"这种动作,跳过重新探索 |
### 5.2 产生(蒸馏)
从本轮**成功**的步骤轨迹里提炼命名动作(如「打开抖音」)。硬约束:
- **禁坐标**:带 `click_xy` 的步骤不会被沉淀(坐标换个设备/分辨率就失效)
- 白名单步骤类型(18 种去掉 `click_xy`、`keep_screen`)
- 每类型有必填参数校验(如 `click` 必须有选择器)
- 输入/产出限量:最多 10 步输入、最多 3 个动作 × 4 步
- 保存时服务端**再校验一次**,含坐标的提交直接 400
### 5.3 召回与使用
相似任务时按动作名/别名匹配(子串或 bigram 相似度),注入「## 可复用动作」段,并推「🧠 动作经验」卡片。AI 被提示"优先按其中的元素定位操作;若与当前界面不符,再自行截图确认"。
### 5.4 面板
「🎬 动作库」:查看/编辑/删除/手动新建。编辑时直接改 `steps` JSON(有格式说明),保存走同一套校验。
---
## 6. 配置项(`app_meta`)
| key | 含义 | 默认 |
|-----|------|------|
| `agent_api_base` | 模型接口地址 | `https://api.deepseek.com` |
| `agent_model` | 模型名 | — |
| `agent_api_key` | API Key(**明文存库**) | — |
| `agent_default_serial` | 默认目标设备 | 空 |
| `agent_max_steps` | 最大步数(钳制 1-200) | 40 |
其它常量:单轮超时 900s、推理链落库上限 6000 字符、会话消息上限 60 条、历史上下文取最近 12 轮。
---
## 7. 故障排查
| 现象 | 原因 / 处理 |
|------|------------|
| 报「MCP server(8033) 不可达」 | MCP 没启动:容器由 `start.sh` 拉起;本机手动 `MCP_ALLOW_WRITE=1 python -m mcp_server.mcp_server` |
| 报模型 API **401** | API Key 无效/过期 → ⚙ 配置重填 |
| 报"请先选择目标设备" | 没选设备且没配默认设备 |
| 报"设备正在执行任务…"(409) | AI 不与任务抢设备:等任务结束,或去监控页停止该任务 |
| 没有 token 数字 | 该网关不支持 `stream_options.include_usage`(已自动降级,功能不受影响) |
| 经验/动作没沉淀 | 只有**成功执行过工具**才会蒸馏;看 `logs/web.log` 的「经验提炼 / 动作提炼」日志 |
| 推理链看不到 | 模型未返回 `reasoning_content`(非推理模型),或本轮没有推理输出 |
| 界面样式/脚本异常 | 强刷浏览器(Ctrl+Shift+R)——`markdown.js` 等前端文件有缓存 |