diff --git a/docs/DEVLOG.md b/docs/DEVLOG.md index 094ef3f..5d397df 100644 --- a/docs/DEVLOG.md +++ b/docs/DEVLOG.md @@ -2266,7 +2266,7 @@ S 10-26 定:只在本机自用,D0 的建议全部采纳;D3~D5 推迟到对 - CI:新工作流 desktop.yml(windows-latest):打包 → 静默安装 → `--smoke` → 强杀壳查孤儿 → 静默卸载查数据目录。PR #81 head 393e1e0:desktop run 40295387628 绿(安装包 65.5 MB、打包 347 s、--smoke 启动 2027 ms / 退出 505 ms 退出码 0、强杀后无孤儿、卸载后数据保留),tests 40295387542、sidecar 40295387588 绿。 - 本地:Rust 只能 `cargo check --target x86_64-pc-windows-msvc`(沙箱 aarch64、没有 MSVC),真编译和安装冒烟以 CI 为准。 -## [70] 2026-10-27 · 阶段 6 收尾:嵌套 Job 实测 + 重估 · commit <待提交> +## [70] 2026-10-27 · 阶段 6 收尾:嵌套 Job 实测 + 重估 · commit 7085714(PR #82) [69] 回填为 cdabfcf(PR #81,S 10-27 同意合并;合并前 head cb9e840 的 tests 40426911618、sidecar 40426911472、desktop 40426911624 都绿)。 @@ -2289,3 +2289,12 @@ S 10-26 定:只在本机自用,D0 的建议全部采纳;D3~D5 推迟到对 - README「安装」第 3 步说明了这一点。 **没做:** 安装目录 `%LOCALAPPDATA%\DataChat`(Tauri currentUser 默认的 `$LOCALAPPDATA\${PRODUCTNAME}`)和数据目录 `%LOCALAPPDATA%\datachat` 在 NTFS 上不区分大小写,其实是同一个目录。目前不出错的原因是:卸载器只删它自己装的文件,最后执行的是非递归的 RMDir;勾选「删除应用数据」时整个目录都会被删,而这本来就是卸载。要把两者分开,得改安装目录(需要改 NSIS 模板或 productName),或者改数据目录(会和浏览器模式分家,需要迁移已有数据),两种都超出收尾的范围,所以推迟到 D3 更新之前,记在 phase6-desktop.md 里。desktop.yml 卸载检查 ③ 的 data_kept 结论仍然成立,因为它验证的正是「卸载不递归删除」。 + +## [71] 2026-10-27 · 阶段 7 方案 · commit <待提交> + +新文件 docs/roadmap/phase7-accuracy.md(P0 + E0~E4 + A1~A6)。要点: +- 先做评测,再做改进。闸门已经快满分(react 14/15 + 9/10,workflow 多表 10/10),而且已经被逐题分析过,不能再作为目标;M20 的目标改为定在新的留出集 H1 上:先测基线,再由 S 定 X。 +- H1 约 40 题(单表 18 / 多表 12 / 画图 5 / 陷阱 5),流程照搬闸门(先写题 → 独立脚本算答案 → 冻结 → 再跑模型)。S 出 ≥ 1/3 的盲题,Hark 只看汇总。 +- A4 DuckDB、A5 YAML 语义层是有条件做的(看 H1 的失败分布);A6 反馈沉淀推迟。 +- plan.md 阶段 7 的交付物和验收按上面改写。 +- 待 S 定:§1 的 5 条(模型 / 网关、每轮预算、出题分工、judge 模型、数据许可)。 diff --git a/docs/roadmap/phase7-accuracy.md b/docs/roadmap/phase7-accuracy.md new file mode 100644 index 0000000..f6c6b06 --- /dev/null +++ b/docs/roadmap/phase7-accuracy.md @@ -0,0 +1,99 @@ +# 阶段 7:准确率(方案,待 S 评审) + +来源:plan.md 阶段 7 的交付物与验收;M20(阶段 7 要有目标定义)、M21(DuckDB / 语义层在单表假设下收益有限);B05(答错不修)、B09(没有列画像)、B65(缺失哨兵、合计行);plan.md「外部审计待办」第 58 行;HANDOVER §196(需要新的留出集,闸门 25 题只作回归);M13 方案第 292 行(真正的图表评测留给阶段 7 的留出集)。 + +## 0. 为什么先做评测,再做改进 + +- **闸门已经快到顶了**。react 单表门槛 14/15(只许 s02 错),多表 9/10(只许 m10 错);workflow 多表 10/10(DEVLOG [25]/[28])。在这 25 题上最多还能涨 2 题,而且这 25 题已经被逐题分析过,再在上面调就是对着测试集调参(DEVLOG [11]、[13])。 +- **自造的 130 题不能当准确率用**(docs/eval/FROZEN.md 五条:n=1、网关缓存、自造、比较器放宽、题面会变)。 +- 所以 M20 的「具体目标」只能定在一套**新的留出集**上,而且要先测出基线再定目标。没有基线的目标就是拍脑袋。 + +结论:顺序是 **E(评测)→ 定目标 → A(改进)→ 留出集终测**。 + +## 1. 要 S 先定的(P0) + +| # | 问题 | 建议 | 理由 | +|---|---|---|---| +| 1 | 评测用哪个模型 / 网关 | 用 S 日常在 DataChat 里填的那个 Key 和模型,全阶段不换 | 目标定在这个模型上;中途换模型,前后的数字就没法比 | +| 2 | 每轮预算 | 留出集 40 题 × 2 个 Agent ≈ 80 次分析,按闸门 p95 约 2.9 万 token 估,每轮最多约 230 万 token | 按闸门 token 基线(ReAct p95 28,846)估算,S 按自己的价格核算 | +| 3 | 留出集谁出题 | Hark 出 ≥ 2/3,S 另出 ≥ 1/3 且不给 Hark 看题面,只交给脚本跑 | 只有 Hark 出题的话,改进的人知道考题;S 出的那部分是真正的盲测 | +| 4 | LLM-judge 用哪个模型 | 和评测模型**不同家族**;如果 S 没有第二家的 Key,就不做 judge(E4 整体推迟) | 同家族会偏向自己的答案(审计报告 P1) | +| 5 | 数据源许可 | 只用 CC BY / CC0 / 公有领域;NC 许可的(像 Olist)只能在 CI 里跑,不随产品分发 | 和闸门一样(docs/gate/README.md「许可边界」) | + +## 2. E 系列:评测基础设施(不改模型行为) + +### E0 留出集 H1(约 40 题) +- 组成:单表 18、多表 12、画图 5、陷阱 5(陷阱就是 E1 的题,放进同一个集)。 +- 数据:**闸门没用过的**外部数据,按闸门的办法做中文 GBK 脏化(只改呈现,不改数值)。候选:UCI Beijing Multi-Site Air Quality(CC BY 4.0,单表,时间序列)、UCI Bike Sharing(CC BY 4.0)、一套多表关系数据(许可证在 E0 PR 里逐个核对,不合格的换掉)。 +- 流程照搬闸门(gate-phase35.md):先写题 → 独立脚本在原始数据上算答案 → 冻结(questions_sha256 / answers.json)→ 才跑模型。**冻结以后不改题**;题出错就作废那一题,记进 DEVLOG,不在原题上改。 +- 脚本:复用 scripts/gate 的结构,新目录 scripts/holdout/,报告 docs/eval/holdout_<时间>_.json。人工字段和闸门一样(human_correct / failure_class / reason / guessing),另加 `first_error_step`(审计待办:判定时记下第一个出错的 step 序号)。 +- **使用纪律**:H1 只在三个时间点跑:基线、A 系列中途一次(可选)、终测。平时调参只用闸门 25、自造 130 和单测。S 那 1/3 的题,Hark 只看汇总分数和 failure_class 分布,不看题面和逐题输出。 +- CI:和 gate-oracle 一样跑 oracle 自检(标准答案在脏表上可解),不调模型。 + +### E1 陷阱题(5 题,并入 H1) +- 错误前提(问一个数据里不存在的类别或年份)、误导性口径(「平均」到底是按订单还是按客户)、本该拒答的问题。 +- 判对标准:指出前提不成立或口径有歧义,并且不编数字。`guessing=true` 一律判错。 + +### E2 过程验证器(离线,不调模型) +- 对模型生成的代码做 AST 分析:区分**读取的列**和**新建的列**,读取的列必须在 schema 里;`result = <字面量数字>` 这类硬编码答案单独标记。 +- 用途:判定时的辅助证据,写进报告的 `process` 字段,**不参与自动判对**。先在已有的 13 份闸门报告上回放,统计它和人工判定的一致率。 +- 落点:app/eval/process_check.py + 单测。 + +### E3 pass^k 报表 +- 问题:网关在 temperature 0 时会缓存,`--repeat` 的几次结果完全一样(FROZEN.md 第 2 条)。 +- 做法:第 i 次重复在 system 提示末尾加一行没有语义的 `run-id: ` 打破缓存,同时打乱题目顺序;报 pass@1 和 pass^k(k 次全对的题占比)。k 默认 3。 +- 先用 5 道题做实测:加 run-id 之后,k 次之间的答案或 token 数确实会不同,才算独立化成功;如果不行,就改用 temperature 0.3,并在报告里写明。 + +### E4 LLM-judge(依赖 §1 第 4 条) +- 只判**结论文字**是否和数值一致、有没有过度推断;数值对错仍然由比较器 + 人工判。 +- 上线条件:在闸门 25 题的人工标注上,judge 和人工的一致率 ≥ 90%(预登记),否则不用。 +- 防偏差:答案位置随机化、长度不作为评分依据。 + +### E 系列验收 +- H1 冻结(题和答案的 sha256 写进 DEVLOG),oracle 自检在 CI 通过。 +- 在 H1 上跑出两个 Agent 的**基线**(pass@1 + pass^3),由 S 人工判定。 +- 用基线定 A 系列的目标(§4),**目标写进本文件后才开始 A**。 + +## 3. A 系列:改进(按 H1 基线的失败分布排序) + +下面的顺序是按现有证据排的,H1 基线出来以后,按 failure_class 的分布重排一次。 + +| 步 | 内容 | 对应 | 什么时候做 | +|---|---|---|---| +| A1 | **列画像**:schema 摘要里加枚举值(前 N 个 + 频次)、数值范围、空值率、疑似缺失哨兵(「未登记」「-」「N/A」)、疑似合计行 | B09、B65(闸门 s02 / s04 / s12) | 先做,证据最多 | +| A2 | **结果合理性校验**:执行后做便宜的检查(结果为空、全是 NaN、占比之和远离 100%、数量级突变),不通过就让 Agent 再看一遍,最多一次 | B05 | A1 之后 | +| A3 | **枚举值召回**:问题里的词(「华东」「已取消」)和列的枚举值做模糊匹配,命中的放进提示 | plan.md 阶段 7 | 看 H1 里过滤类的错误多不多 | +| A4 | DuckDB 统一 CSV / Excel / SQL | plan.md 阶段 7、M21 | **有条件**:H1 多表题的失败里,join / 数据读取类占一半以上才做 | +| A5 | YAML 语义层(指标、口径、同义词,条目带生效时间,声明「资料不是指令」) | 审计待办 | **有条件**:H1 口径类错误多才做;否则推迟到阶段 7 之后 | +| A6 | 反馈沉淀(👍👎 / 失败轨迹 → 聚类 → 人工入册) | plan.md 阶段 7 | 推迟:自用阶段反馈量太小 | + +每一步的回归闸门(不变):pytest / vitest / e2e 全绿;闸门 25 按 m13r 无回归;自造 130 不比上一步差(同一 evalset 指纹)。 + +## 4. 目标(M20,基线后补) + +基线出来以前只定**形式**,不定数字: +- 主指标:H1 上 react 的 pass@1,单表、多表分开报;辅指标:pass^3、陷阱题判对数、S 盲测那部分的单独分数。 +- 目标的形式:「终测比基线高 X 个百分点,且 S 盲测部分不低于基线」。X 由 S 在看到基线以后定,写进本节,之后不改。 +- 终测:A 系列做完后跑一次 H1;没达标就如实写,不在 H1 上补调。 + +## 5. 顺序和工作量 + +| 步 | 内容 | PR | S 要做的 | +|---|---|---|---| +| P0 | 本方案 + §1 的 5 个决定 | 本 PR | 评审、定 §1 | +| E0+E1 | 留出集 H1 + 冻结 + oracle CI | 实现 PR 1 | 出 ≥ 1/3 的题(不给 Hark 看) | +| E2+E3 | 过程验证器、pass^k | 实现 PR 2(可以和 E0 并行) | — | +| 基线 | 两个 Agent 跑 H1,人工判定 | 报告 PR | 跑一轮(S 的 Key)、判定、定 §4 的 X | +| E4 | LLM-judge(如果 §1 第 4 条有第二家 Key) | 可选 | 提供 Key | +| A1~A3 | 列画像、合理性校验、枚举召回 | 每步一个 PR | 每步看一次闸门回归 | +| A4/A5 | 有条件 | 另定 | — | +| 终测 | H1 再跑一次 | 报告 PR | 跑一轮、判定 | + +日历时间估 2–4 周(plan.md 重估),主要花在 S 跑评测和判定上。 + +## 6. 不做 + +- 不在闸门 25 题上调提示词(DEVLOG [11]、[13])。 +- 不让 LLM-judge 决定数值对错。 +- 不为了涨 H1 分数改 H1 的题或比较器;比较器要改,只能新增规则并在全部历史报告上 `--rescore`,写明影响。 +- 训练 / 微调:不在本阶段。 diff --git a/docs/roadmap/plan.md b/docs/roadmap/plan.md index c7cd182..d0c2c34 100644 --- a/docs/roadmap/plan.md +++ b/docs/roadmap/plan.md @@ -19,7 +19,7 @@ | 4 后端 API | 1–2 周 | 第一步:API Key 进系统钥匙串(keyring);`analyze_stream()` 逐步产出事件,`analyze()` 包一层(M09)。FastAPI:数据集上传(一个数据集可含多个文件,M10)、会话、消息(SSE 流式推送每一步)、设置;SQLite + SQLAlchemy(表结构兼容 PG,预留 user_id);logging + trace id(会话 / 消息 id),runs.jsonl 换成数据库(M08 M14);接口返回 png + 图表数据(M13)。最后:PyInstaller sidecar + 沙箱 worker 在 Actions Windows runner 上的 spike(B35 / M06) | 用 curl 走完"上传 → 提问 → 流式结果 → 历史可查";重启后会话还在;spike 打出的 exe 能在干净 runner 上执行一次沙箱代码 | B18 B35 | | 5 前端 | 2–3 周 | 第一件事(M13,从阶段 4 顺延,含后端三步):图表库定为 ECharts;定 option 格式与白名单、写 builder `chart(kind, df, x=, y=, series=, title=)`;worker 产出 chart_option(与 result 脱钩,B44);接口加 chart_option;改绘图提示词并重跑闸门。之后:React + Vite + TS:数据集面板、对话流(展示计划、代码、执行步骤)、图表、可展开的代码、👍👎 反馈、Key 设置页,分步与验收见 docs/roadmap/phase5-frontend.md(F0–F5) | 不碰命令行就能完整用一遍 | — | | 6 桌面打包 | 1–2 周 | Tauri 2 外壳(前提见上:前端只走 HTTP)+ PyInstaller 后端 sidecar;Windows 安装包;自动更新;首次启动引导填 Key;依赖许可证审计;pyarrow 已随 Streamlit 一起去掉(DEVLOG [67]) | 在一台干净的 Windows 上一键安装,可用;对外分发前代码签名,显示已验证的发布者(2024 年起任何证书都不能让 SmartScreen 立刻不拦,见 phase6-desktop.md §6,M19);方案见 docs/roadmap/phase6-desktop.md;对外分发前满足 THREAT_MODEL.md 的 (b) 条件 | — | -| 7 准确率 | 2–4 周 | DuckDB 统一 CSV/Excel/SQL;YAML 语义模型(指标、口径、同义词);枚举值召回;结果合理性校验;反馈沉淀为已验证问答对 | 在阶段 3.5 闸门数据上给出具体目标(闸门结论后定,M20);自造集只作回归 | B05 B09 | +| 7 准确率 | 2–4 周 | 先做评测:留出集 H1(约 40 题,含陷阱和画图题)、过程验证器、pass^k;再做改进:列画像、结果合理性校验、枚举值召回;DuckDB / YAML 语义层视 H1 失败分布而定;反馈沉淀推迟。方案见 docs/roadmap/phase7-accuracy.md | 在留出集 H1 上:先测基线,再由 S 定目标「比基线高 X 个百分点」(M20);闸门 25 题和自造集只作回归(2026-10-27 改:闸门已接近满分,而且已经被逐题分析过) | B05 B09 | | 8 Web 上线(后续) | 另定 | PostgreSQL、登录、任务队列、Docker/E2B 沙箱、Langfuse、服务器部署与 ICP 备案 | 另定 | 多租户 | 阶段 1–7 原估合计约 10–15 周(一个人业余时间)。M18 认为实际可能 6–12 个月:**阶段 3.5 闸门结论出来后重估工期,必要时砍范围**。