Files
Jyotisha/docs/tasks/TASK-rectification-jev-intent-classifier-research-fix-20260919.md
T

12 KiB
Raw Blame History

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.pydocs/**.gitignoreBLOCKED.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 passedquick 门 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.0CRITERION_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_sampleSTOP_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. 现行分类器对照:产品 2026-09-19 确认线上现行模型就是 DeepSeek Flash。原报告的对照模型身份因此成立,偏差只剩「抽 33%」;本单要求全量(红线 8),报告改标「= 线上会话模型」。

  4. 来源 B:产品 2026-09-19 授权,Claude 会话已从 staging 只读抽取并去重脱敏,文件 source_b.jsonl(157 条,不入仓)由产品转交执行方,放到 .cache/jev_intent/source_b.jsonl(已 gitignore)。抽取口径:agentic_rectification_turns.user_message 非空 697 行 → 剔除点选回显(A. … / 「先这样」)339 行 → 剔除前端建议芯片原文 76 行 → 按消息文本去重 → 157 条;每条带当轮焦点(按 asked_at ≤ turn.created_at 取最近一条,focus_stale 标记焦点已在本轮前 resolved 的 22 条)与可反推的 runtime_intent85 条:no 49 / weak_yes 18 / yes 13 / unsure 5)。gold 留空,执行方逐条人工标注。

    来源 B 实测分布(来源 C 生成的长度约束以此为准,取代原单兜底值):

    指标
    条数 / 层 157:采集 107、无焦点 33、点选 17
    字数 P25 / 中位 / P75 / 最长 12 / 21 / 28 / 172
    含标点比例 13%
    含语气词(吧/呢/啊/嗯/哦/额/emm)比例 4%
    含年份或月份比例 81%

    对照模板语料(中位 11 字、惜字如金 45%、方言前缀 24%):真人回复更长、几乎不用语气词、绝大多数直接报年月。生成提示的人设权重必须按此校正:「惜字如金」与「方言/网络语」两种人设合计不得超过 20%。

  5. 原报告结论「不可接」撤回改为「缺数据」docs/tasks/README.md 状态行同步改;不得保留「不可接」字样误导后续拍板。

5. 硬红线

原单 §4 五条全部继续生效,另加:

  1. jev_intent_corpus_build.py 的生成与复核必须各有一次真实模型调用并把模型名、版本、提示原文写进 scripts/research/jev_intent_samples/README.mdGENERATOR_NAME / REVIEWER_NAME 必须是模型标识,不得再出现 template / ruletests/test_jev_intent_research.py 新增断言:构建脚本中不得存在把 answer_class 映射到固定词表的生成函数(检查源码里无 bank = { 式字面量词库),复核函数不得调用 re.search 判标签。
  2. 来源 C 去重后唯一条数 ≥ 810(≥ 90%);单条重复不得超过 5 次;八种人设每种 ≥ 40 条(点选+采集合计),且「惜字如金」+「方言/网络语」合计 ≤ 20%;字数 P25 / 中位 / P75 落在来源 B 实测值 ±30% 内(即 P25 816、中位 1527、P75 20–36)。不满足即重跑,不得进 T2。
  3. 现行分类器(DeepSeek Flash,= 线上)对照不得再抽样:来源 B 与来源 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 三份写入 READMEassert_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

  • 文件已交付(§4 第 4 条)。执行方逐条人工标注全部 157 条 goldruntime_intent 只做参考列,不得直接抄为 gold。
  • 跑 Jev 两次 + 现行一次,做原单 T3 代表性检验:来源 B 与来源 C 同层准确率差 > 10pp → 结论降为「缺数据」并写明是哪一层。
  • 验收:README 来源 B 段填实际条数、三层分布、长度分布、标注耗时;BLOCKED 来源 B 条目划掉。

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. 来源 B 人工标注做不完 157 条:至少标满点选 17 + 采集 60 + 无焦点 20 = 97 条,其余标 unlabeled 不计入分母;不得用模型代标。

8. 开工前置命令

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 编号

本单不立 BUGdocs/BUG_HISTORY.md 当前最大号 BUG-969,若执行中发现现行分类器的确定性错误再从 BUG-970 起。