assistant/docs/archive/README-school-2026-10-28.md

204 lines
14 KiB
Markdown
Raw Permalink 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.

# 智能办事助手(School Assistant)
跨系统智能办事助手 MVP:Electron 聊天 + Python 编排 + Browser Use 自主操作网页。
本项目位于 `browser_use/school-assistant/`,与同级的 AI 获客助手 `assistant/` 分开维护;以下命令均在本项目根目录执行。
产品形态类似 Codex 桌面端:左侧任务列表与历史(点开可回放过程),中间对话、任务卡与确认卡片,右侧是内嵌的浏览器面板——Agent 就在这个面板里操作学校系统,可以展开 / 收起,需要用户决定时停下来问,回答后在同一页面里继续,随时可以「我来接管」。
## 当前能力(D13,2026-09-17)
- 一句话发起任务:先识别业务并抽取字段(DeepSeek / 千问一次调用),缺资料时对话追问,再按业务角色登录执行
- Agent 自主登录、找入口、填表、提交前逐项确认(演示业务:辅导员每月查课日志填报;通用探索兜底)
- `ask_user` 暂停机制:不受 browser-use 步骤超时限制,浏览器会话保活,用户回答后续跑同一个 Agent
- 系统账号:`system_accounts` 表按学生 + 系统存加密密码,运行时通过 `sensitive_data` 自动填写,LLM 看不到明文
- 可观测:每步截图 `data/tasks/{id}/steps/`、进度 `progress.md`、精简执行历史存 `run_logs`
- 自动沉淀:任务成功后提炼经验草稿(带类别),按内容判重归并;控件技巧 / 入口路径类被多个任务观察到自动生效,系统规则类由团队在运维模式下采纳。用户端无感。YAML 只是出厂基线,`GET /learned/export` 可导出交付
- 运维模式:`.env` `OPERATOR_MODE=true` 才显示「沉淀草稿」面板,交付学校默认关闭
- 内嵌浏览器:每个任务一个 `WebContentsView` 挂在应用右侧面板里(独立登录态分区、域名白名单),browser-use 经 Electron 的 CDP 端口直接操作它;Agent 开始操作或停下来问你时自动展开,可随时收起;运行中可「我来接管」(Agent 模式下键盘输入会被拦住并提示先接管),操作完交还给 Agent 继续。单独跑后端(无 Electron)时退回独立 Chrome 停靠模式
- 提交后跟踪:已提交的任务定时回查审批状态,通过 / 驳回时在对话里提示,可「立即回查」或「停止回查」
- 前置阻断:系统提示「先办另一件事」时,同角色能办的问你要不要顺带办完再回来,需要别人处理的告诉你找谁,任务进入「被前置事项拦住」等你处理好再继续
- 多校隔离:所有学校数据带 `school_id`,实例用 `.env` 的 `SCHOOL_ID` 指定所属学校
- 评测脚本 `scripts/eval_run.py`:同一任务连跑 N 次统计成功率 / 步数 / 时长,默认干跑(到确认即取消)。查课日志填报实测到确认 18 步 / 158 秒
- Electron 是后端的唯一所有者:启动时自动关掉端口上残留的旧后端,退出时关掉自己的
## 环境要求
- **Node.js** 20.19+(Vite 8 / Electron 33 构建链)
- **Python** 3.11+
- **Docker Desktop**(运行 PostgreSQL 17)
- **DeepSeek 或千问 API Key**(默认 DeepSeek)
## 快速开始
### 0. 启动 PostgreSQL(Docker)
```powershell
cd D:\qiekj\browser_use\school-assistant
docker compose up -d
```
数据落在 `127.0.0.1:15433` 的 PostgreSQL 库 `school_assistant`,账号见 `docker-compose.yml`;后端启动时自动建表并同步 `knowledge/*.yaml`。2026-09-17 从 MySQL 切换而来,旧数据用 `scripts/migrate_mysql_to_pg.py` 迁移。`.env` 的 `SCHOOL_ID` 决定本实例属于哪所学校,学校之间数据互不可见。
### 1. 安装 Python 依赖
推荐用 uv(自动建 Python 3.12 的 `.venv`,按 `backend/requirements.lock` 精确同步,含打包用的 PyInstaller):
```powershell
cd D:\qiekj\browser_use\school-assistant
npm install
npm run backend:setup
```
没有 uv 也行:脚本会用系统 Python 的 pip 把 uv 装进项目的 `native/build/` 里,不碰系统环境。手工方式:`python -m venv .venv && .\.venv\Scripts\pip install -r backend\requirements.txt`。不需要 `playwright install`,浏览器就是 Electron 自带的 Chromium。
### 2. 配置 API Key
复制 `.env.example` 为 `.env`,填入:
```env
LLM_PROVIDER=deepseek
DEEPSEEK_API_KEY=sk-你的key
LLM_MODEL=deepseek-chat
LLM_BASE_URL=https://api.deepseek.com/v1
```
> 也可切换 `LLM_PROVIDER=qwen` 并使用 `qwen-vl-max`。
> 可选再配一把兜底 Key `DEEPSEEK_API_KEY_FALLBACK`(千问为 `DASHSCOPE_API_KEY_FALLBACK`):主 Key 返回 402 余额不足时,识别、沉淀和 Agent 执行中的下一次调用都自动切到兜底 Key,任务不中断;之后每 `LLM_PRIMARY_RETRY_HOURS`(默认 1)小时重试主 Key,充值后自动恢复。侧栏状态会显示「兜底 Key」。
### 3. 安装并启动 Electron
```powershell
npm install
npm start
```
`npm start` 先构建(esbuild 打主进程 / preload,Vite 打 React 渲染层,产物在 `dist/`),再启动 Electron;Electron 自己拉起 Python 后端(用 `.venv`),并在启动前关闭端口上残留的旧后端。发送任务后右侧**浏览器面板**自动展开,Agent 在里面操作;停下来提问时,点卡片按钮或直接在聊天框回答即可。只做类型检查用 `npm run check`。
### 4. 录入系统账号(可选)
密码本按「人 × 系统」存账号并记录该账号的角色;业务要求的角色和账号角色不一致时直接告知办不了。有账号时 Agent 自动登录(多系统时凭据按域名分组,模型看不到明文),没有则按 `knowledge/*.yaml` 里 `login.fallback_mode` 处理(测试环境用快捷登录按钮)。密码用 `.env` 的 `ACCOUNT_ENC_KEY` 加密存储:
```powershell
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8788/api/accounts -ContentType "application/json; charset=utf-8" -Body (@{ student_id = "default"; system_id = "xgxt"; role = "辅导员"; username = "工号"; password = "密码" } | ConvertTo-Json)
```
### 5. 跑测试
```powershell
npm test
```
288 个用例约 3.4 秒。其中 15 个要连本机 PostgreSQL(用一次性的测试学校隔离,跑完自动清理,不会碰到正式数据),数据库没起时自动跳过;`npm run test:fast` 直接跳过它们。覆盖意图识别与退路、状态判定、经验沉淀的判重与自动晋升、角色准入、凭据按域名分组、前置阻断问句、执行结果判定、模型 Key 兜底。
### 6. 评测成功率
```powershell
npm run eval -- --n 3 --supplement "课程是高等数学,授课教师是张老师"
```
默认干跑:走到「提交前确认」自动回复取消,不会真提交;加 `--submit` 才会确认提交。`--supplement` 是任务追问时自动补充的话。结果写入 `data/eval/*.jsonl`。
## 后台审核台(中心服务端)
桌面端办完事会自动沉淀经验草稿。草稿要不要生效,控件技巧和入口路径类被两个任务观察到就自动生效,系统规则类必须人审。人审就在这个后台做。
```powershell
npm run hub:build # 构建界面
npm run hub # 启动,打开 http://127.0.0.1:8801/
```
在「学校」页给每所学校生成一串上报凭证(只显示一次),写进那台机器的 `.env`:
```env
HUB_URL=http://中心地址:8801
HUB_TOKEN=生成的凭证
```
之后那台桌面端会在每次沉淀后自动上报,并定时(默认 15 分钟)拉回审核结果。没配这两项就是单机模式,本地照常沉淀和自动晋升。
审核台上每条草稿显示它被几所学校观察到过、累计观察多少次,可以采纳、驳回、改写后采纳,也可以批量处理。**跨校观察是最强的可信信号**:同一条知识被多所学校各自撞见,说明它不是某校特例。采纳时选发布范围:只回来源学校,还是推给所有学校。点「预审」会先让模型给建议和理由,建议只是建议,不会自动改状态。
驳回也会推回各校:本地可能已经自动晋升过一条错知识,中心驳回后桌面端会停止注入它。
### 智能采纳
队列一次几十条时,「智能采纳」页可以把能自动定的先处理掉。**只有控件技巧和入口路径可能被自动采纳,系统规则和其他类永远留给人**,因为一条错的规则会让 Agent 以后一直绕开正确操作。
自动采纳有两条路:跨校观察够或单校观察够(证据硬);或者证据薄但模型读过内容后明确说可复用(这种只发回来源学校)。模型如果建议改写,就不会自动采纳原文,留给人确认,理由里直接给出改写建议。
先点「先看会动哪些」干跑,列出每条的处置和理由,确认后再执行。自动处理过的条目标记来源为 auto,队列里勾「只看自动处理的」可复查,审错了点「退回待审」就会推回各校。
**自动驳回只是暂缓**:那条知识再被观察到会退回队列重新排队。只有人工驳回是终局。这样机器误判一次不会永久吃掉一条知识。
实测 43 条队列,配了模型 Key 的情况下自动处理掉 21 条(19 采纳、2 驳回,两条驳回都是带任务编号的一次性链接),剩 22 条全是按策略必须人审的。
## 打包(Windows)
```powershell
npm run package:win
```
依次执行:构建桌面端(esbuild + Vite → `dist/`)→ 用 `.venv` 的 PyInstaller 把后端冻结成 onedir(`native/release/school-assistant-backend/`,约 100 MB,脚本会跑一遍 `--selfcheck` 并在本机 PostgreSQL 可达时真起一次服务验收)→ electron-builder 产出 `release/win-unpacked/SchoolAssistant.exe`(整目录约 400 MB)。冻结后端放在 `resources/backend`,知识 YAML 放在 `resources/knowledge`。
运行安装包形态时,可写目录是 `%APPDATA%\school-assistant\`:首次启动会把 `.env` 模板复制过去,部署方在里面填模型 Key、PostgreSQL 连接、`SCHOOL_ID`、`ACCOUNT_ENC_KEY`;任务进度和登录态分别在其下的 `data/`、`profiles/`。目前只出免安装目录(`dir`),NSIS 安装器、图标、签名待做。
## 项目结构
```
school-assistant/
├── electron/ # Electron 主进程(TypeScript):窗口与 app:// 协议、WebContentsView 宿主、给后端的控制接口、后端进程管理、preload 桥
├── renderer/ # React + TypeScript + Vite 聊天界面(Sidebar / TopBar / Feed 卡片 / TaskCard / Composer / BrowserPanel / Settings)
├── dist/ # 构建产物(main.cjs、preload.cjs、renderer/、env.example),不入库
├── native/ # 打包中间产物:release/school-assistant-backend(PyInstaller onedir)、build/(smoke 结果、uv 引导),不入库
├── release/ # electron-builder 产出(win-unpacked/SchoolAssistant.exe),不入库
├── backend/ # FastAPI + 编排 + Browser Use(有 CDP_URL 时走内嵌模式,否则独立 Chrome);requirements.txt / requirements.lock
├── knowledge/ # 业务配置 YAML(系统、登录方式、步骤、规则、learned 沉淀)
├── data/ # 任务 progress.md、每步截图、评测结果(运行时生成)
├── docker-compose.yml # PostgreSQL 17(任务 / 知识 / learned / 密码本 / 设置)
├── profiles/ # 浏览器登录态(按 student_id 一份,登录一次长期有效)
├── server/ # 中心服务端(FastAPI):收各校草稿、审核队列、发布;独立库 school_assistant_hub
├── console/ # 后台审核台界面(React/TS/Vite),构建后由中心服务端直接伺候
├── shared/ # 桌面端与中心共用的规则(经验判重与归类)
├── tests/ # pytest 测试集(npm test);@pytest.mark.db 的用例需要 PostgreSQL
├── scripts/ # eval_run.py、打包与环境脚本
└── docs/PROGRESS.md # 开发里程碑进度
```
## 进度文档
- **开发进度**:`docs/PROGRESS.md`
- **任务进度**:每个任务自动写入 `data/tasks/{task_id}/progress.md`
桌面端右侧可预览并「打开 progress.md」。
## API 调试
后端 API 端口在 `.env` 的 `API_PORT`(默认 **8788**)。文档:http://127.0.0.1:8788/docs
```powershell
# 单独启动后端
python backend/main.py
```
## 演示业务与探索发现
**当前演示业务**:辅导员工作日志填报(查课)和每周谈心谈话记录,同一入口下两个业务,由意图识别路由。谈心谈话示例:「帮我记一条谈心谈话,今天和计科2301班的李思涵聊了学业压力,内容是……」。说一句「帮我填今天的查课日志,班级计科2301班,听课记录还好」,助手会追问课程名称和授课教师,然后以辅导员身份进入「辅导员工作日志 → 日志填报 → 每月查课要求 → 新建填报」填表,逐项列出后等你确认再点「提交填报」。业务定义和探索沉淀都在 `knowledge/xuegong_demo.yaml` 的 `businesses` 与 `learned` 段。
### 学生端探索发现(2026-09-16)
测试环境学生端**没有「留校申请」模块**。门户 8 个一级模块:学生管理、综合测评、评奖评优、违纪处分、资助管理、请销假、节假日离返校、辅导员评议。最接近的是「节假日离返校 → 我的报备」(默认在校,离校才需报备)。学生端可提交的申请表单是「请销假 → 发起请假」,建议作为填表里程碑的目标。这些已沉淀在 `knowledge/xuegong_demo.yaml` 的 `learned` 段,运行时注入为「已知信息」。
## 测试学工系统
默认业务:`knowledge/xuegong_demo.yaml`
入口:https://school.miaopinai.com:29800/xuegong/
在聊天框输入办事目标即可,例如:
> 帮我填今天的查课日志,班级计科2301班,听课记录还好
## 下一步
见 `docs/PROGRESS.md`