第 8 章 dashboard:一站式工作台

本章目标:理解前端工作台如何把三个后端服务编排成"上传→生成→看结果→评估→治理"的一站式流水线。
学完你能回答:七个视图怎么分组?生成链为什么是前端驱动、关页为什么不断链了?批次和血缘怎么管理?
GB 级产物怎么按需查看?没有文档怎么对话式生成用例?

8.1 五组七视图:按使用者流程组织

dashboard 前端是 vanilla JS 单页应用、无构建工具链(内网部署零 node 依赖、改完刷新即生效——
刻意取舍,代价靠纪律补:IIFE + window 导出、固定加载序、发版 bump ?v=)。
信息架构按使用者流程分五组:

流程组 视图 干什么
① 录入 源文档 上传 docx/xlsx → 看转换进度 → 编辑保存 md
② 生成 生成监控 / 对话生成 全管线链编排(主入口)/ 引导式对话生成(8.5)
③ 审阅 工作台树 实体→要点→用例一棵树 + 评估问题红标 + 大产物按需展开(8.4)
④ 评估 评估报告 三段指标卡 + 看门狗扣分开关
⑤ 治理 样例库 / 日志 few-shot 录入治理 / 四服务日志只读浏览器

(历史注记:② 组原是"提问生成"视图,2026-09-16 渠道归一时退役,能力并入对话生成——
独立提问端点 /api/ask/* 一并下线,对话视图成为唯一的人口。)

后端 dashboard 是薄 BFF:数据面接口(项目/批次/归档/文件/日志/产物查询 /api/query/*)自己出,
任务面(转换/生成/评估的 POST)由浏览器拿 /config 里的服务地址直连三服务——
长任务不过代理,BFF 不承载超时风险。

8.2 生成链编排:前端驱动 + 服务端兜底

生成监控视图的"新建生成"触发的四阶段链(实体→要点→用例→评估),主驱动力是浏览器里的
TaskHub 单例
逐阶段驱动:

每运行 = 一个显式新批次(create_session)
循环 {
  解析输入(链批次 artifacts 优先,回退项目最新文件)
  → POST 对应服务(FormData 附 project_id/session_id)
  → 轮询任务状态(30min 探活窗、3 连错才判死)
  → 归档产物(/api/archive/{stage},登记批次血缘)
  → 推进下一阶段(链状态双登记:localStorage + 服务端 chains.json,刷新可续接)
}
链尾:综合分 <70 自动重评一次(cap 1)

为什么前端驱动? 服务端编排器要处理状态持久化/恢复/并发——而浏览器态 + localStorage
用几十行就够,且用户看得见每一步(顶部胶囊的"阶段间 + 阶段内"复合百分比就来自前端的
pillPct 纯函数订阅任务进度事件)。

代价与根治:链曾是纯浏览器态,关浏览器就断(服务端单任务照跑,但后续阶段无人续接)——
两次真实事故(孤儿链、用例完成后关页 4 小时停摆)之后,2026-09-20 上线服务端链推进
(openspec change chain-advance-server-side):

重跑 = 新批次:任何阶段的重跑都显式创建新批次、只跑该阶段、归档落新批次
(rerunOf 记源批次)——直接改写旧批次会污染血缘,这是评审钉死的裁决。

8.3 批次与血缘:AppStore 单一真相源

全前端唯一的状态源是 AppStore({project, batchId, files, sessions, tasks} 的发布/订阅单例):
切一次批次,顶栏/树/评估/监控全视图同步刷新——根治了 v3 时代"两个视图各读各的产物"的批次漂移病。

批次(session)是数据血缘的单位:每个 session 的 artifacts 记录五件套文件名
(source/entity/point/case/eval_summary)——任何一轮产物都能回溯"用的是哪份 md"。
产物选取双模:选了批次读批次快照(源文档视图进只读态——编辑旧 md 不会重新生成该批次产物,
这是快照的诚实语义);未选批次读项目最新。

批次展示名(2026-09-16 重设计,此前下拉里只有时间戳没法认):格式
{核心名}(重跑·{阶段})? · MM-DD HH:MM · 综合 NN%。核心名由服务端纯函数
derive_doc_label(modules/dashboard/src/session_manager.py)从源文件名剥层得出——
剥扩展名 → 剥尾部 _SRC/ENT_时间戳(≤2 轮)→ 剥行首连续【标签】→ 剥尾部 [方括号] 作者;
圆括号一律保留(副标题"(羁绊)"与作者"(丁加华)"同形不可辨,宁多勿删);剥空回落 None
宁可不显示也不错挂名。读路径 list_sessions 补计算字段 doc_name(不落盘,存量批次零回填
立即生效);前端消费单一出口 TaskHubCore.batchLabel(store.js)——monitor 历史行与
run-bar 下拉都用它,新增展示位禁止自行拼名。

8.4 产物按需查看:PNT/CAS 的 SQLite 双格式

问题的起源是量级:A3 批次 8863 用例的 JSON 有 1.26GB——前端把它整载进内存渲染树,
浏览器直接崩(2026-09-14 真实事故)。第一反应的方案是"JSON 旁边落分片索引 + 前端超 512MB
不预载只显示计数",对抗性评估后整体否决:双存储一致性税、只读服务扛懒生成内存峰值、
巨物 JSON 根因原封未动。终案 v2(openspec change artifact-view-on-demand,2026-09-16 生产):

换存储:PNT/CAS 产物落 SQLite 单文件库 <名>.db——nodes(seq,id,parent_key,name,kind,payload)
一张扁平表 + meta。为什么是 SQLite 而不是 MySQL/Neo4j/FAISS:产物是"结构化分页查询"访问模式
(不是语义检索也不是图遍历);单文件与既有产物同构(拷贝/归档/superseded 全复用);
嵌入式零运维。ENT/EVAL 保持 JSON——前者是结构层要整树载、后者是小文件,这是设计边界不是妥协。

查询面:dashboard 出四只读端点(mode=ro 打开,按文件缓存)——
/api/query/{projects|workspace}/{stage}/{file}/summary | items?parent= | item/{id} | export。
projects 族服务归档区;workspace 族是 2026-09-19 加的平行变体,服务未归档的对话生成产物
(8.5 的"查看树"就靠它)。旧 .json 打这些端点返回 422 提示迁移(不做运行时转换)。

前端懒加载:query_client.js 的 ArtifactQueryClient(summary 缓存 + items(parent) LRU64 +
item(id));tree.js 对 .db 产物先整载 ENT(结构层)、PNT/CAS 只取 summary 计数,展开时才
items(parent) 异步拉子节点(连点防重、失败可重试)。懒模式下树显示两级徽标——
实体行"要点 N"、要点行"用例 N"(用例按实体聚合不可得,两级各自准确)。
下载走 export 端点流式给 JSON(中文文件名按 RFC 5987 编码,直塞 latin-1 会 500)。

存量迁移:一次性工具 scripts/migrate_artifact_db.py(json→.db + 旧 JSON 旁置 _superseded/

8.5 对话式生成:不写文档也能生成用例

前面所有章节的入口都是"先有一份策划文档"。对话式生成(generator 侧 core/ask_chat.py
编排 + 前端 ask_chat_view.js,flag ASK_CHAT_MODE,2026-09-16 生产)回答另一个真实场景:
测试同学脑子里有个功能想法,还没有文档——用几轮对话把它变成实体、要点、用例。

入口是一道意图路由(core/ask_chat_router.py,三级):

tier1 规则(零 LLM):高置信关键词直接短路(问候/简单问询)
tier2 轻模型(GLM_INTENT_MODEL 单次调用):分类 + 槽位抽取 + 采集卡更新三合一
tier3 回退闲聊:LLM 异常/非法意图时宁可聊天不可误生成

五种意图(INTENTS 契约):generate(生成)/ refine(细化)/ locate(定位)/
diagnose(诊断)/ chat(闲聊)。没有文档时,一张引导式采集卡逐项收集
功能名/玩法描述/边界等槽位(readiness 满格才放行生成);有文档时可绑定项目走
locate-first——bge-m3 即刻检索候选实体 → 用户点选 → 只对选中实体跑裁剪链(crop)。

合成的实体要过确认门(flag ASK_CHAT_GATES,生产已开):树形级联勾选、
根节点锁定、每个实体带三桶来源徽标(点名=用户明确提到 / 骨架=玩法结构推出 /
补充=LLM 换词补的,最容易是幻觉)——用户逐个勾选确认后才会进入生成。
未勾选的记丢弃原因(审计),后续对话里同名功能再被提到会自然加回。

多轮差量(这是比"再跑一遍"精细得多的设计):

动作 kind 机制
"再补充 XX 功能" delta generation_scope_ids 差量——只对新实体生成,产物按实体并集合并
"细化第 #3 条要点" refine_pnt 要点寻址 resolve_point_ref(#N 规则解析零 LLM)+ PNT 合并替换器 merge_refine_pnt:按 source_entity_id 闭包"整子树剔除 + 整子树并入 + 兄弟零触碰"三不变量——新旧要点合并成一份,不会出现同实体两套要点挂树的歧义
"给第 #3 条要点补用例" refine_cas point_scope_ids 镜像 scope 模式:只跑该要点,新用例并集进 CAS
"改一下 XX" — 编辑类指令友好拒绝("暂不支持")——人工编辑生成结果的连锁不可控,是明确的二期边界

会话里每轮产物落批次卡(kind 标签:全量/裁剪/增量/细化/补用例 + 计数),聚合账本记录
累计产出;产物卡上三个动作:评估(镜像主链的 runEval 三件套)、查看树(复用工作台
树的装配管线,经 8.4 的 workspace 查询端点直读未归档 .db——归档后深链自动切 projects 路径,
两族不串)、下载 JSON(export 流式)。

归档规则化(2026-09-19):archiveProjectFor 纯函数——绑定了真实项目的会话归档进该项目
(血缘归位);未绑定的统一进「对话生成」固定类目,不再伪造"提问功能日期"假项目。

量级感(生产实测标定):合成卡 4min / 要点阶段 9-50min(随实体数)/ 用例 ~40min——
36 实体会话全链 37 分钟(对照:同规模走文档全链要按小时计)。慢的根源与主链相同
(LLM 调用趟数),治理手段也相同(task 化 + 轮询 + 退避)。会话落盘跨服务重启存活
(ask_chat_store 原子写 JSON),任务完成自动回贴卡片。


↙↙↙阅读原文可查看相关链接,并与作者交流