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

19 KiB
Raw Blame History

智能办事助手:产品定义、架构与决策

这份文档回答"我们在做什么、为什么这样做、接下来做什么"。里程碑和实测数据见 PROGRESS.md。 每次做出新的设计决策,在「已定决策」追加一条并写日期;改变方向时改这里,不要只改对话。


1. 一句话定义

一个像 Codex 桌面端的办事 Agent:用户对着聊天框说一句"我要办某件事",助手识别业务、追问缺的资料、以对应角色登录学校的网页系统、自主找入口填表、在提交前逐项列出请用户确认,办完后记录结果,并把过程中学到的经验沉淀下来让下一次更快。

2. 目标用户与角色

角色 用什么 做什么
学校里的办事人(学生、辅导员、管理员) 桌面端 说需求、补资料、在关键节点确认。不参与知识审核
我们团队 后台管理(待做) 写出厂 YAML、审核各校沉淀的经验、看运行监控、维护密码本、交付

3. 产品原则

  1. 只在业务允许的域名内活动。
  2. 登录凭据来自密码本或用户手动,模型永远看不到明文(browser-use sensitive_data)。
  3. 任何正式提交前必须用户确认;用户取消就不提交。
  4. 不猜学校没有明说的规则,宁可停下来问。
  5. 全程可审计:每步截图、progress.md、run_logs。
  6. 经验先成草稿再生效,用户端无感,审核由我们或规则完成。

4. 架构

4.1 现状(2026-09-17)

Electron 桌面端(renderer 聊天 + 右侧状态/截图/时间线)
   │ IPC
Python FastAPI 后端(Electron 拉起并独占,端口 8788)
   ├─ nlu.py            意图识别 + 字段抽取(DeepSeek / 千问,一次调用,JSON)
   ├─ orchestrator.py   状态机、按业务路由、prompt 组装、暂停/续跑、沉淀触发
   ├─ browser/runner.py browser-use Agent,独立 Chrome,会话保活,每步截图
   ├─ learning.py       任务成功后生成 learned 草稿
   └─ db/database.py    psycopg 3,所有学校数据带 school_id
PostgreSQL 17(Docker,127.0.0.1:15433)
   knowledge / tasks / run_logs / system_accounts / learned_entries / skills / settings

桌面端直连 PostgreSQL,一台机器一所学校(.env 的 SCHOOL_ID)。

4.2 目标形态

桌面端(编排 + 浏览器,必须在本机)  ──HTTPS──▶  服务端 API  ◀──  后台管理(我们团队,跨学校)
                                                    │
                                              中心 MySQL(按 school_id 隔离)+ 向量库(手册)
  • 桌面端只保留必须在本机跑的部分:编排、browser-use、Chrome。知识、learned、账号、任务记录都走服务端接口。
  • 后台管理和桌面端用同一套接口。
  • 学校可以一校一库,也可以共库按 school_id 隔离,数据模型两种都支持。

5. 知识的三层

层 内容 存在哪 谁维护 状态
出厂配置 系统入口、登录方式、业务定义(角色、必填项、步骤、规则) 编写格式是 knowledge/*.yaml,启动时灌入 knowledge 表,运行时读表 我们,来源是学校手册 + 调研;将来后台直接改表,文件只做导入导出 已有
经验 learned 入口路径、控件技巧、前置阻断、踩过的坑 learned_entries 表,draft → verified / rejected,带 school_id、类别、观察次数、来源任务;YAML 里的 learned 只是出厂基线 任务成功后自动生成草稿,按内容判重归并;控件技巧 / 入口路径类被 ≥2 个任务观察到自动生效,系统规则类由我们后台人审,用户不参与 已有;后台审核队列待做
参考资料 学校手册、通知、FAQ 向量库(可复用已有 Qdrant),按学校 / 系统打标 我们导入 待做

YAML 文件与数据库的关系:文件是给人读写的格式,表是运行时副本。现阶段文件是源头;后台做出来之后反过来,表是源头,文件用于交付。

有后台之后(2026-09-17 确认):业务定义在后台维护(表单编辑 / YAML 文本编辑 / 上传导入 / 手册生成草稿),带学校、版本、发布状态;桌面端启动时从服务端拉本校已发布的定义并本地缓存,不再随安装包带文件;仓库里只保留模板(自家学工系统出厂模板、常见第三方系统骨架),给新学校开户时从模板复制进库再改;导出仍产出 YAML,用于备份、迁移和把 A 校审核过的 learned 打包给 B 校。过渡期加一个"知识来源 = 文件 / 服务端"的配置,服务端模式下启动不再用文件覆盖库,只在该校一条业务都没有时用模板初始化一次。

有手册:模型读手册生成 YAML 业务草稿(结构化,价值最高);手册切块进向量库,给 Agent 一个 lookup_manual 工具按需查"字段是什么意思、有什么前提"。 没手册:上线前按角色做一次建图扫描(枚举菜单、页面、表单字段),生成业务草稿;使用中靠 learned 沉淀;交付前预热多跑几遍,把慢的阶段藏起来。

6. 执行模型

用户一句话
 → nlu 识别业务、抽字段(今天/明天换算成日期)
 → 缺必填项:对话追问(模型生成追问语),用户下一句再抽取合并
 → 角色准入:业务 role 与用户在该系统密码本账号的 role 不一致 → 直接告知办不了
 → 浏览器 profile 按 人 × 系统 × 角色;任务涉及各系统的凭据按域名分组进 sensitive_data(占位符带系统后缀),没有账号的系统按 YAML fallback(测试环境快捷登录 / 请用户手动)
 → 业务的全部启用步骤按顺序在同一个浏览器会话里执行,前一步产物注入下一步
 → 执行业务的启用步骤:prompt = 业务 + 目标 + 资料 + 登录方式 + 规则 + learned(YAML 基线 + 库里 verified)+ 步骤要求
 → Agent 需要用户时调 ask_user:以 is_done 结束本轮,浏览器保活,状态 paused;用户回答后 add_new_task 续跑同一 Agent
 → 遇到系统提示「必须先办另一件事」时调 report_blocker:按 YAML 声明的 resolution 处理。self = 问用户要不要顺带办,同意则同一会话切去办前置业务再回来;other_role / manual = 说明要找谁怎么办,用户说已处理就重试,说取消就进 blocked(可稍后继续)
 → 提交类步骤:填完 ask_user 逐项确认 → 确认后提交,保存 submitted_record / result_message → 状态 submitted
                                       → 取消则保存 cancelled → 状态 completed(不算提交)
 → 成功后 learning.draft_learned 生成草稿
 → submitted 任务按 next_check_at 由调度循环拉起只读回查步骤:approval_status 归类 → completed / rejected / 继续排期

判定规则:success_artifacts_any 覆盖 Agent 自评;submitted_artifacts_any 决定是否算提交;cancelled 优先。

7. 已定决策(按时间)

日期 决策 原因 / 备注
09-16 产品形态像 Codex 桌面端;一定是桌面端 浏览器和登录态在本机,隐私好
09-16 账号由我们按角色从库里取,自动登录 用户不该反复输密码;用 sensitive_data 防泄露
09-16 知识由我们维护交付学校;手册是来源 学校只管用
09-16 模型 Key 先放 .env,不做用户级 Key 阿里 / DeepSeek Key 由我们持有
09-16 学工系统是自家产品,先拿它练 快捷登录等便利只在自家系统有,注意别依赖
09-16 skill / learned 全校受益;数据层用 MySQL(Docker) 为中心化做准备
09-16 提交后跟踪要做,但排在链路走通之后 提交不等于办完
09-17 演示业务从留校申请换成辅导员查课日志填报 测试环境学生端没有留校申请模块
09-17 学校之间数据隔离(school_id) 不是每所学校都用我们的系统
09-17 用户端不出现采纳 / 忽略;审核靠自动晋升 + 我们后台 办事人不该做知识审核
09-17 后台管理和服务端层要做,但桌面端先夯实 顺序:真实提交 → 第二业务 → 后台
09-17 learned 判重按内容不按 key;自动晋升只对控件技巧 / 入口路径类,系统规则类必须人审 模型每次起的 key 不同;记错规则代价大
09-17 有后台后 YAML 只做模板和导入导出,表是源头,桌面端从服务端拉配置 见第 5 节
09-17 前置阻断做成标准机制:同角色能办的顺带办(同一会话切换目标再回来),别的角色 / 线下的说明处理方式后 blocked 等待 请假被返校核验拦住是真实样例
09-17 桌面端登录走学校统一身份认证;业务系统登录配方要支持「统一认证跳转」,允许域名含认证中心域名 用户 09-17 确认
09-17 密码本只服务未接统一认证的系统:学校配发账号由后台导入,个人账号才需要用户绑定。开发期手动维护密码本是权宜之计。「绑定账号界面」从演示版拿掉,换成登录配方支持 sso(登录态在 profile 里复用,缺时请用户完成一次) 用户 09-17 指出
09-17 前置阻断需要别的角色处理时,是另一个人在自己的端上用自己的账号办(如辅导员办「核实学生返校」),不是同一用户切角色;两端联动(协办请求 / 完成通知 / 自动续跑)走服务端,现阶段学生手动点「继续」 纠正此前「跨角色闭环」的说法
09-17 目标系统自身的问题(如测试数据、缺功能)不纠结、不绕过:如实报告并 blocked,等系统方处理。我们会面对各种系统,链路跑通优先 学生请假被后端规则拦住是首例
09-17 跨人联动(通知辅导员、协办请求、自动续跑)本阶段不做,归服务端层 用户 09-17 决定
09-17 对照同事 PenguinUniOS 后的四项决定:桌面端按其形态重做并连打包链一起对齐;数据库切 PostgreSQL 17;继续独立仓库;执行路线保持 browser-use run() + learned 用户 09-17 拍板,见 REFERENCE_PENGUINUNIOS.md
09-17 身份模型:一个人在一个系统里只有一个身份,跨系统身份可不同。密码本按「人 × 系统」存账号并记录该账号在该系统的角色;业务的 role 是准入条件而不是登录依据;跨系统任务用 browser-use 按域名分组的 sensitive_data,一个会话依次登录各系统 用户 09-17 指出;这是跨系统操作的前提
10-28 学校工程整体移入 browser_use/school-assistant/,与独立获客项目 browser_use/assistant/ 并列;各自保留独立 Git 仓库,外层只作工作区导航 用户要求分开两个项目,避免代码、配置和文档混在工作区根目录

8. 待做设计(按建议顺序)

  1. 真实提交验证(09-17 完成:两条查课日志真实提交成功,状态 submitted,日期校验无问题)。
  2. 第二个业务(09-17 完成:每周谈心谈话)。前置阻断机制(09-17 完成:report_blocker + self / other_role 两条路径 + blocked 状态)。学生请假在测试环境被「返校核验」拦住;09-17 以辅导员和系统管理员探索后确认界面上没有任何角色能解开(后端业务规则作用于历史未返校记录),需学工团队清测试数据或补功能。业务 counselor_return_verify 已建,等系统侧有入口再补填报步骤;学生请假填报步骤同样等待。
  3. 防重复提交(09-17 完成:两个填报步骤提交前先查已有记录,重复时 ask_user)。
  4. learned 自动晋升(09-17 完成:按内容判重,≥2 任务观察且为控件技巧 / 入口路径类自动生效,系统规则类人审;OPERATOR_MODE 控制草稿面板)。失败驱动的自动降级待做。
  5. 浏览器展开 / 收起:CDP 停靠 + 最小化 / 恢复(09-17 完成,暂停确认时自动展开);下一步验证 Electron WebContentsView + cdp_url 真正内嵌。
  6. 密码本升级(跨系统地基):本地部分 09-17 完成(role 列、角色准入、按系统分 profile、域名分组凭据)。目标形态是"用户登录桌面端 → 服务端按人返回他有账号的系统及角色、据此过滤可办业务、密码本条目清单(无密码)→ 任务开始时按需取该任务涉及系统的凭据,用完即丢并记审计"。密码本来源两条:学校配发账号由后台批量导入;个人账号由用户在桌面端「绑定账号」一次写入。当前阶段先做本地能做的部分:system_accounts 加 role 列;业务执行前做角色准入检查(当前用户在该系统的账号角色 ≠ 业务 role 就直接告知办不了);浏览器 profile 按「人 × 系统」而非「人 × 角色」;多系统凭据按域名分组装进 sensitive_data,占位符带系统后缀(x_username_lib / x_password_lib),登录说明按系统分段;每系统登录配方(表单 / 统一认证 / 扫码);生产环境放中心库并经服务端按任务取用、审计日志。
  7. 多步串行执行器(09-17 完成:步骤顺序执行、每步可声明系统、产物跨步传递、同一会话 keep_session、允许域名取并集;跨系统登录待第二个系统接入后实测)。
  8. 提交后跟踪(09-17 完成:YAML tracking、调度循环、track-now / track-stop、状态 rejected、桌面端提示;真实任务实测两次回查)。后续:回查时静默运行。
  9. 手册导入 / 建图扫描:手册 → YAML 草稿;手册 → 向量库 + lookup_manual 工具;无手册时按角色扫描菜单和表单生成草稿。
  10. 后台管理 + 服务端层(审核队列部分 09-17 完成,见 PROGRESS D17):已做——server/(FastAPI,独立库 school_assistant_hub)+ console/(React 审核台),各校桌面端带凭证上报草稿、中心按内容跨校合并、智能预审(规则层 + 模型层)、人工采纳 / 驳回 / 改写、按「仅来源学校 / 所有学校」发布、桌面端按版本号增量拉回并落成本地 verified / rejected;backend/hub_sync.py 全后台异步,没配 HUB_URL 就是单机模式。智能采纳(09-17,PROGRESS D18):类别硬门槛只放行控件技巧 / 入口路径,证据够硬或模型背书两条路,模型建议改写则留人,自动驳回可复活,先干跑再执行。待做——运行监控(成功率 / 步数 / 时长趋势、失败截图)、知识与密码本管理、按学校分组推送、后台多人账号;桌面端统一身份认证登录、按人过滤业务、按需取凭据;跨人协办:一个人的任务被别的角色的前置事项拦住时,向对应角色发协办请求,对方办完后通知并自动续跑。
  11. UI 往 Codex 形态靠(09-17 完成:三栏布局、任务列表与回放、确认 / 阻断 / 结果卡片、我来接管)。后续:嵌入式浏览器面板。
  12. 登录配方支持统一认证:login.mode: sso | form | quick_login | manual;允许域名含认证中心;有登录态直接过,没有则请用户完成一次登录后复用 profile 登录态。测试环境无 SSO,先做配置与提示词,接真实学校再验。绑定账号界面推迟到真遇到非 SSO 的个人账号系统。
  13. 测试集(09-17 完成,见 PROGRESS D16):npm test 288 个用例 3.4 秒,覆盖 nlu 退路、状态判定、learned 规则与数据库生命周期、角色准入、凭据分组、阻断问句、执行结果判定、Key 兜底。@pytest.mark.db 的用例用一次性 pytest_xxx 学校隔离,PostgreSQL 不可达时自动跳过。写测试时挖出并修掉两个缺陷:关键词退路要求整段短语原样出现(模型不可用时真实说法全部误判为通用探索)、单字肯定词在句中任意位置命中(补充资料被当成同意先办前置事项)。
  14. 桌面端对齐同事的 PenguinUniOS 形态(09-17 完成,见 PROGRESS D13 / D14)(见 docs/REFERENCE_PENGUINUNIOS.md):已做——React/TS/Vite 渲染层、TS 主进程、WebContentsView 内嵌浏览器(browser-use 经 CDP 连 Electron 自带 Chromium,界面页走 app://ui 协议、主机名 ui 进白名单,不展示的视图停到窗口边缘外留 2px 在窗内而不能隐藏,否则截图挂死)、任务卡 / 确认卡 / 状态词汇对齐、Lucide 与其视觉规范、uv + PyInstaller + electron-builder 打包链(npm run package:win → release/win-unpacked,后端冻结成 exe 放 resources/backend,userData 放 .env / data / profiles)。待做——NSIS 安装器 / 图标 / 签名、Pydantic 契约生成 TS。已决:数据库已切 PostgreSQL(09-17 完成迁移);仓库独立;打包态只支持内嵌浏览器,不带 Chromium。

9. 实测基线

场景 配置 结果
学生端只读探索 无 learned,3 次 1 成功 2 自评失败(产物齐全),31 步 / 181 秒
学生端只读探索 修判定 + learned,2 次 2/2 成功,23 步 / 99 秒
辅导员查课日志填报到确认 首次 47 步 / 372 秒
辅导员查课日志填报到确认 控件技巧 + 每步 6 动作,干跑 2 次 2/2,18 步 / 158 秒
暂停续跑 强制先 ask_user 15 秒暂停,回答后 21 秒完成,同一会话
辅导员谈心谈话填报到确认 首次即带 learned,干跑 1 次 15 步 / 81 秒;一句话四个必填全抽出,无追问
辅导员谈心谈话填报到确认 第二次干跑 11 步 / 61 秒
查课日志真实提交 用户操作,2 次 均「填报成功」,状态 submitted
前置阻断 other_role(学生请假) 真实环境 25 秒识别拦截、标准化提问,取消后 blocked
前置阻断 self(模拟) 临时业务 切子目标并回到原目标完成,约 35 秒
两步串行(模拟,同系统) 临时业务 54 秒,一个会话,第二步使用第一步产物
提交后跟踪回查 真实提交的查课日志 立即回查 73 秒读到「未审批」+ 审批轨迹;调度自动回查 77 秒完成并排期

10. 目录与关键文件

学校项目根目录为 browser_use/school-assistant/(2026-10-28 从工作区根目录整体移入,含独立 Git 历史)。同级 browser_use/assistant/ 为独立 AI 获客项目。以下路径均相对学校项目根目录。

backend/nlu.py                  意图识别与字段抽取
backend/orchestrator/orchestrator.py  状态机、路由、prompt、暂停续跑、沉淀触发
backend/browser/runner.py       browser-use 执行器、会话保活、每步截图
backend/browser/tools.py        ask_user / save_artifact
backend/learning.py             learned 草稿生成
backend/security.py             密码本加解密(Fernet,ACCOUNT_ENC_KEY)
backend/db/schema.sql           MySQL 表结构(含 school_id)
backend/db/database.py          数据层与旧库迁移
knowledge/xuegong_demo.yaml     出厂业务定义 + 基线 learned
scripts/eval_run.py             评测(默认干跑)
electron/main.js                后端唯一所有者、旧后端接管
renderer/app.js                 三栏 UI:任务列表与回放、对话与卡片、状态 / 截图 / 时间线 / 沉淀草稿;无 Electron 时回退 fetch 便于自测
docs/PROGRESS.md                里程碑与实测