# TASK · Jev 意图分类研究修复单:来源 C 必须由真实模型生成与复核(2026-09-19) - 基线:`origin/staging` @ `d6fc4fb8`(含 `fde541c2` 研究首版 + `d6fc4fb8` DeepSeek Flash 对照) - 原单:`docs/tasks/TASK-rectification-jev-intent-classifier-research-20260919.md` - 分支:`codex/rectification-jev-intent-research-fix-20260919`(从 `origin/staging` 新建) - 性质:研究单修复;不改线上代码;不立 BUG(无线上缺陷) ## 1. 验收结论(对照原单逐条) | 项 | 结论 | 证据 | | --- | --- | --- | | 红线 1 · 不改线上 | 通过 | `git diff --stat d9722d56..d6fc4fb8` 只有 `scripts/research/**`、`tests/test_jev_intent_research.py`、`docs/**`、`.gitignore`、`BLOCKED.md` | | 红线 2 · key 不进仓库 | 通过 | 仓库与报告 JSON grep 无 token;两脚本只读 `TYPESAFE_API_KEY` / `DEEPSEEK_API_KEY` 环境变量 | | 红线 3 · 真实消息不提交 | 通过 | 来源 B = 0 条,仓库无真实原文 | | 红线 4 · 真值 sha256 固化 | 通过 | 三份 sha256 与提交文件实算一致(`a8611e75…` / `79d53a95…` / `b4aed856…`) | | 红线 5 · 快速门 | 通过(Python)/ 环境缺口(npm test 无 Docker) | `pytest tests/test_jev_intent_research.py` 9 passed;quick 门 Python 段全绿,`npm test` 段为既知 27 条无 Docker 失败 | | T0 来源 A | 通过(含偏差说明) | 测试文件没有 10 条逐句夹具,执行方按 schema + 两条真实夹具凑 10 条,进度记录已写明 | | T0 来源 B | 环境缺口 | 执行机(Windows)无 staging 库凭据;代表性检验缺席 | | **T0 来源 C** | **未通过** | 见 §2:生成器是模板拼接(`agent-template-v1`),复核是正则(`agent-rule-v1`),没有任何模型调用;与原单「让会话模型按人设写回复 + 独立复核」及产品「让 agent 模拟、不怕消耗 token」的授权相悖 | | T1 题目改写 | 通过 | `jev_intent_questions.py` 固定 `jev-1.13.0`、`CRITERION_MAP` 逐条对应提示词、`enforce_combo` 在代码里保证组合合法 | | T2 对照跑 | 通过(Jev)/ 偏差(现行) | Jev 来源 A+C 各两次;现行分类器用 `deepseek-flash` 顶生产提示词、来源 C 抽 33%,**不是线上会话模型**(模型目录在数据库,代码里无默认值) | | T3 指标与结论 | **未通过** | 指标算法本身没问题,但输入语料不成立,「不可接」结论无效;正确结论应为**缺数据** | | T4 记录 | 通过 | PROGRESS / BLOCKED / README 状态行齐全;未立 BUG 正确 | ## 2. 事故实证(`scripts/research/jev_intent_corpus_build.py` @ d6fc4fb8) 1. `GENERATOR_NAME = "agent-template-v1"`、`REVIEWER_NAME = "agent-rule-v1"`(文件头常量)。全文件无 http / SDK / Agent 调用;`import` 只有标准库。 2. 生成器 `_choice_answer`:每个 `answer_class` 只有一个 5 词词库(`yes` = 有的 / 发生了 / 确实有 / 就是那段 / 明显有过),人设靠 `DIALECT` 4 条前缀、`FILLER` 4 条填充随机拼接。`_collect_answer` 同理。 3. 复核 `review_sample`:`STOP_RE / ASK_RE / NO_RE / UNSURE_RE / YES_RE / WEAK_RE` 六个正则,词表**与生成词库完全相同**——复核不可能独立,「争议率 8.5%」只是模板与正则的自洽度,不是标签质量。 4. 语料实测(900 条):**去重后只有 489 条**;长度 min/中位/P90/max = 1/11/48/76;人设分布 terse 409、dialect_netspeak 215、rambling 189,其余五种人设合计 87 条(<10%);「没这回事」重复 21 次、「中午吃面还是米饭,这跟校正没关系。」重复 17 次。 5. 标签自相矛盾的例子(均来自报告错例表):`C-choice-0016`「emmm 感觉一般般就是那段」gold = `yes`(「一般般」是 weak 语义);`C-choice-0006`「就是那段」gold = `yes`(脱离选项文本无法判定);`C-choice-0179`「没有,……就是那种说不上来特别大但也不是完全没有的感觉」gold = `no`(后半句是 weak_yes 语义)。Jev 在这些条目上「答错」不能计为 Jev 的错。 6. 报告 §T3「高置信错误 7.0%」「低置信召回 34%」「answer_class 65%」三个决定结论的数字,全部建立在上述语料之上。 ## 3. 根因 执行方在「本机无会话模型凭据」时,选择用模板+正则顶替 Agent 生成,而不是按让步 4 停在 T0/T1 回报。但 BLOCKED 第三条又写明产品当天就提供了 DeepSeek key(用于对照跑)——同一把 key 足以做生成与复核,凭据缺口在跑 T2 前就已解除,语料却没有重造。 ## 4. 决策记录 1. 产品 2026-09-19 原话:「能不能让 agent 模拟生时流程来得语料……不怕消耗 token」。这是来源 C 的授权来源,**模板拼接不满足**;本单据此要求全量重造来源 C。 2. 生成与复核模型:用执行机上已有凭据的真实对话模型(DeepSeek 或产品另行提供的任一模型),**生成与复核可用同一家模型但提示不同、复核看不到标签**(原单已允许)。若能用两家不同模型更好,不强求。 3. 现行分类器对照:生产会话默认模型由数据库模型目录决定,代码里没有;产品在本单开工前告知模型名(或确认 `deepseek-flash` 就是线上默认)。未告知前,对照继续用 DeepSeek,但报告必须继续标「不是线上会话模型」。 4. 来源 B:执行机拿不到 staging 库。若产品授权,由 Claude 会话在 staging 主机 `docker exec … psql` 只读抽取、脱敏后交给执行方本地文件;未授权则维持让步 1(只报数、不判定)。本单不阻塞在来源 B 上。 5. 原报告结论「不可接」**撤回改为「缺数据」**,`docs/tasks/README.md` 状态行同步改;不得保留「不可接」字样误导后续拍板。 ## 5. 硬红线 原单 §4 五条全部继续生效,另加: 6. `jev_intent_corpus_build.py` 的生成与复核**必须各有一次真实模型调用**并把模型名、版本、提示原文写进 `scripts/research/jev_intent_samples/README.md`;`GENERATOR_NAME` / `REVIEWER_NAME` 必须是模型标识,不得再出现 `template` / `rule`。`tests/test_jev_intent_research.py` 新增断言:构建脚本中不得存在把 `answer_class` 映射到固定词表的生成函数(检查源码里无 `bank = {` 式字面量词库),复核函数不得调用 `re.search` 判标签。 7. 来源 C 去重后唯一条数 ≥ 810(≥ 90%);单条重复不得超过 5 次;八种人设每种 ≥ 60 条(点选+采集合计)。不满足即重跑,不得进 T2。 8. 现行分类器对照不得再抽样:来源 C **全量**跑一次(自洽率第二次可抽 1/3,与原单让步 2 一致)。 ## 6. 任务分解 ### F1 · 重写 `jev_intent_corpus_build.py` 的生成与复核 - 问题池 `question_pool.json` 保留(来源是真实引擎,已通过),不重建。 - 生成:对每道题 × 目标标签 × 人设,调用模型写回复。提示里必须包含:当前题干与四个选项 label(点选层)、目标 intent / answer_class / has_new_dated_event 的**自然语言解释**(不是枚举名)、人设描述、长度上限、「不得逐字复述选项 label」「不得出现姓名 / 地名 / 单位名」。温度 ≥ 0.8。同一(题, 标签, 人设)组合最多重试 3 次以通过复核。 - 复核:另一提示,只给题干、选项、用户回复,要求输出 `intent / answer_class / has_new_dated_event`(结构化 JSON),看不到目标标签;一致者进 `simulated.jsonl`,不一致进 `disputed.jsonl`(保留生成标签与复核标签两列)。 - 争议率按层与按标签写进 README;> 15% 先改生成提示再重跑(最多两轮),仍超则按实际通过条数跑并如实报。 - 缓存:每次模型调用结果落 `.cache/jev_intent/`(已 gitignore),脚本可断点续跑。 - 验收:红线 7 的三项统计由脚本打印并写入 README;`simulated.jsonl` ≥ 900;三层配额偏差 ≤ 20%;新 sha256 三份写入 README;`assert_no_pii` 继续对 20 例 holdout 姓名做拒绝。 ### F2 · 重跑 T2 - Jev `jev-1.13.0` 来源 A + 新来源 C 各两次(原单 T2)。 - 现行分类器(红线 8)来源 C 全量一次 + 1/3 抽样第二次;模型名按 §4 第 3 条。 - 验收:`.cache/jev_intent/jev_runs.json` 与现行 runs 的样本 id 集合与 `simulated.jsonl` 完全一致(脚本打印校验);429 记 `unavailable` 计入分母。 ### F3 · 重出报告 - `docs/research/jev_intent_2026_09_19.md/.json` 覆盖重写(保留旧版为 `jev_intent_2026_09_19_v1_template.md`,文首标「已作废:语料为模板拼接」)。 - 结论三选一:可接 / 不可接 / 缺数据,附 T3 全表、θ 曲线、错例画像(改写后)。来源 B 仍为 0 时,结论最高只能给到「可接(待真机代表性检验)」或「不可接」,不得写成无条件可接。 - 验收:报告「模型」一节列出生成模型、复核模型、对照模型三行各自的模型名 / 版本 / 是否线上会话模型。 ### F4 · 来源 B(条件项) - 仅当产品授权且 Claude 会话交付脱敏文件后执行:执行方逐条人工标注 ≥ 30 条,跑代表性检验(原单 T3)。 - 未授权:BLOCKED 条目保持 open,报告写「代表性检验缺席」。 ### F5 · 记录 - `PROGRESS-rectification-jev-intent-classifier-research-20260919.md` 追加「修复轮」段:三项统计、争议率、两轮提示修改(若有)、token 消耗(生成 / 复核 / Jev / 对照分列)。 - `BLOCKED.md`:「无会话模型凭据」条目改写为已解除(生成与复核已用真实模型);来源 B 条目按实际。 - `docs/tasks/README.md`:状态行改为本单结论。 - 不立 BUG。 ## 7. 让步顺序 1. 争议率两轮提示后仍 > 15%:按实际通过条数跑,配额偏差如实报;**不得**回退到模板生成补数。 2. 单条生成三次重试仍不过复核:丢弃该组合,换人设重抽;红线 7 三项仍须满足。 3. 模型调用限流:退避重试,脚本断点续跑;不得缩小样本。 4. 现行对照模型名产品未告知:用 DeepSeek 顶,报告标明。 5. 来源 B 未授权:维持让步 1。 ## 8. 开工前置命令 ```bash git fetch origin --prune git worktree add -b codex/rectification-jev-intent-research-fix-20260919 .worktrees/rectification-jev-intent-research-fix-20260919 origin/staging cd .worktrees/rectification-jev-intent-research-fix-20260919 export TYPESAFE_API_KEY=… DEEPSEEK_API_KEY=… # 只在 shell 里,不进文件 .venv/bin/python -m pytest tests/test_jev_intent_research.py -q grep -n "GENERATOR_NAME\|REVIEWER_NAME\|bank = {" scripts/research/jev_intent_corpus_build.py # 改前留证 ``` ## 9. BUG 编号 本单不立 BUG;`docs/BUG_HISTORY.md` 当前最大号 BUG-969,若执行中发现现行分类器的确定性错误再从 BUG-970 起。