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

17 KiB
Raw Blame History

研究单 · TypeSafe Jev 能否接管生时校正的意图分类(2026-09-19)

  • 基线:origin/staging @ bdf027a0
  • 分支:codex/rectification-jev-intent-classifier-research-20260919worktree .worktrees/rectification-jev-intent-classifier-research-20260919
  • 性质:离线对照测量,不改线上行为、不改模型选择。 有结论才另立实现单。
  • 外部依赖:TypeSafe API key(产品负责人正在申请)。key 到手前本单只能做 §5 的 T0/T1(T0 造语料需要会话模型凭据,与 key 无关),其余写进 BLOCKED.md
  • 产品 2026-09-19 口径:真机样本必然不足,由 Agent 模拟校正流程造语料,token 消耗不设上限

1. 背景与问题

校正流里,用户每发一条自由文本,服务端先调一次「意图分类」再决定走哪条分支(frontend/src/lib/rectification-agentic/v9/turn-intent-classifier.tsclassifyRectificationTurnIntentPOST /api/rectification/agentmessage 分支调用它,见 frontend/src/app/api/rectification/agent/route.tsclassifyTurnIntentWithRetry 四个调用点)。分类输出是一个严格 schema:

字段 取值 含义
intent answer_current_focus / provide_new_evidence / stop_rectification / ask_about_result / unclear 用户这句话在干什么
answer_class yes / weak_yes / no / unsure / null 只在 answer_current_focus 时非空
has_new_dated_event true / false 同一句里是否还带了新的带时间经历

现状:这一步走会话选定的贵模型 + 结构化输出,失败重试一次后 fail-open 为 classifier_unavailable(BUG-721 修复后回「这边没接上」)。没有置信度,只有「分出来了 / 没分出来」两态。

候选替代物:TypeSafe 的 jev-1.13(文档 https://docs.typesafe.ai/2026-09-17 版)。它不是生成模型,只回答 Choice / Score / Noul 三种题型,返回选项概率与校准过的置信度,输入 $0.042/Mtok、输出免费。题型与本分类器逐字段对口intent → Choiceanswer_class → Choicehas_new_dated_event → Noul。

2. 为什么不能直接接

三条来自官方文档、必须先用数据证伪或证实的风险:

  1. 中文准确率。 官方原文:"English is the primary training language... Other languages, including CJK scripts, are handled but not equally well; test on your own content before relying on Jev for a non-English workload." 我们的输入 100% 是中文口语(「那会儿没什么变化」「大概大二吧」「先不弄了」)。
  2. 字面理解。 官方短板表第 1 条:"answers the question you wrote, not the one you meant." 现行提示里大量「通常是…而不是…」「不要按 A/B/C/D 位置猜」这类意图性约束,搬到 Jev 上要改写成逐条字面条件。
  3. 结构不变量不保证。 官方明说同一问题问成 Noul 和 Choice 得数不可互比、P(是)+P(不是) 不等于 1。所以 intentanswer_class 两题的组合合法性(answer_current_focus 才允许非空 answer_class必须由代码强制,不能指望模型自洽。

另外:官方警告限流「动态调整、可能不经通知变化」。任何上线方案都必须有回退到现行模型的路径,这条不在本单量,但结论段必须写明。

3. 决策记录

  • 2026-09-15 产品决定「意图分类继续用会话选定的贵模型,不引入便宜快模型;后续不得以性能为由重提,要重提须先拿到新授权」(TASK-rectification-failure-attribution-20260915.md §4.6、§让步顺序)。
  • 2026-09-19 产品负责人主动提出评估 Jev,并授权本研究单。 这是新的授权来源,本单据此成立。但授权范围只到「离线测量」;是否上线、以何种方式上线(Jev 先判 + 低置信回退 / 双跑影子 / 不接)由本单结论后产品再拍板,本单不得直接改 classifyRectificationTurnIntent 的模型选择。
  • 本单只评估意图分类这一个位置。以下三处明确不在评估范围,执行方不得顺带试:证据抽取(rectification-record-evidence-batch 要生成摘要与原文定位,Jev 不生成文本)、候选分钟打分(Python 引擎算术,Jev 官方明说数值与日期是弱项)、旁白 / 交付卡 / 报告生成。

4. 硬红线

  1. 不得改线上行为。 turn-intent-classifier.tsroute.tsmastra/model.ts、模型目录一律不动;不得新增「工具模型」角色。研究代码全部放 scripts/research/docs/research/
  2. key 不进仓库、不进前端、不进日志。 只从环境变量 TYPESAFE_API_KEY 读;.env* 不得提交;进度记录与研究报告不得出现 key 片段。
  3. 真实用户消息不得提交。 从 staging 库抽的样本只存在 worktree 外的本地目录(或 .gitignore 覆盖的路径),报告里只出现聚合数字经过改写的示例(改写到无法对应任何真实会话;不含姓名、出生资料、地名、单位名)。违反即整单作废(AGENTS.md §8)。
  4. 不得为了让 Jev 看起来更准而改样本标签。 标注真值先于跑模型固定,跑完不得回头改;确有标注错误的,单独列一张「标注争议表」并说明双方判法,不得静默改。
  5. Python 改动跑 .venv/bin/python scripts/run_quality_gate.py --profile quick;既有缺口(test_shadbala_endpoint_returns_ranked_planet_strength 时区依赖、npm test 无 Docker 的 27 条)与基线逐条一致即可,不计入。
  6. 结论只允许三种:可接 / 不可接 / 缺数据,每一种都要落到 T3 的数字;不接受「感觉更准」「大体一致」。

5. 任务分解

T0 · 样本集(不需要 TypeSafe key;需要会话模型凭据)

产品 2026-09-19 已明确:真机样本肯定不够,用 Agent 模拟校正流程造语料,token 消耗不设上限。样本分三个来源,作用不同,不得混报:

来源 A · 既有合成样本(提交)。 frontend/tests/rectification-turn-intent-classifier.test.ts 里的 10 条用例(userMessage + 焦点 schema + 期望输出)直接转成样本。

来源 B · 真实会话样本(本地,不提交;作用是校准锚)。 从 staging 库 agentic_rectification_turnsuser_message 非空的行,连同当轮焦点(question_id 对应的 expected_answer_schema)与 case_status,输出到 worktree 外。有多少算多少,最少 30 条;它不是主测试集,而是用来检验来源 C 像不像真人(见 T3「代表性检验」)。同时记录真实消息的长度分布(字数的中位数 / P25 / P75)与标点 / 语气词比例,作为来源 C 的生成约束。来源 B 的真值由执行方逐条人工标注(条数少,不走模型复核),能从当轮后续动作反推现行模型当时的实际分类的(走了 applyRectificationChoiceanswer_current_focus + 对应 optionIdanswer_class;回了 classifierUnavailableReplyunavailable)另存一列。

来源 C · Agent 模拟语料(提交;主测试集,目标 ≥ 900 条)。 分三步,scripts/research/jev_intent_corpus_build.py

  1. 问题来自真实引擎,不手写。references/real_case_calibration/minute_rectification_holdout_v4.json 的 20 例公开 AA 案例,走 scripts/rectification/event_probes.pydiscriminating_event_probes 离线出点选题(题干 + 四个带 answer_classoptions),采集题用 frontend/src/lib/rectification-agentic/v9/ 里既有的采集题文案(七领域 + 定向补事),无焦点层用 focus: null。每例每层各取若干题,去重后作为「问题池」。

  2. 标签先定,再造回复。 对问题池里每道题,按下面的配额抽目标标签,再让会话模型(当前默认贵模型即可)以指定人设写一条中文回复,要求回复必须体现该标签、且不得出现选项原文(避免逐字匹配)。人设至少 8 种轮换:惜字如金(≤ 6 字)、口语啰嗦、先答后补一件事、先否定再补一件事、答非所问、不耐烦想停、追问结果、用方言/网络语。长度分布按来源 B 的中位数 / P25 / P75 约束(若来源 B 不足 30 条,用 P25 ≤ 6 字、中位 ≤ 15 字、P75 ≤ 40 字兜底)。

    目标条数 标签配额(大致)
    点选题 400 answer_current_focus 4 类 answer_class 各 15%(其中 1/4 带 has_new_dated_event=true)、provide_new_evidence 15%、stop 8%、ask_about_result 8%、unclear 9%
    采集题 400 no 25%、unsure 20%、yes/weak_yes 25%(其中 1/3 带新经历)、provide_new_evidence 12%、stop 6%、ask_about_result 6%、unclear 6%
    无焦点 100 provide_new_evidence 50%、stop 15%、ask_about_result 15%、unclear 20%
  3. 独立复核,只留双方一致的。 另起一次调用(不同提示、看不到目标标签)对每条回复重新标注;与目标标签一致的进入测试集,不一致的进「标注争议表」(提交,供人工看),不得用第三次调用投票硬拉回来。争议率 > 15% 说明生成提示有问题,先修生成提示再重跑,不得带病进入 T2。

    生成与复核的模型名、版本、提示原文、每类争议率写进报告。同一模型既生成又复核是允许的(提示不同、看不到标签即可),但要写明。

真值固化。 三个来源的标签在 T2 之前 sha256 固化并写进报告;跑完不得回头改(红线 4)。来源 C 的最终文件 scripts/research/jev_intent_samples/simulated.jsonl 提交;来源 B 路径进 .gitignore

验收:scripts/research/jev_intent_samples/ 下有 synthetic.jsonl(来源 A)、simulated.jsonl(来源 C,≥ 900 条且三层配额偏差 ≤ 20%)、disputed.jsonl(争议表)、README.md(来源 B 的抽取 SQL、长度分布、本地路径约定、三份 sha256)。合成回复里不得出现真实姓名、出生资料、地名、单位名(公开案例本身的姓名也不得进回复正文)。

T1 · 题目改写(不需要 key

把现行两段提示(点选题版 / 采集题版)改写成 Jev 的问题定义,落 scripts/research/jev_intent_questions.py

  • intentChoice,五个选项各带一句字面判据(不用「通常」「不要猜」这类词),并按官方建议保留 unclear 作兜底项。
  • answer_classChoice,选项集按当轮焦点动态生成(点选题只放该题实际存在的 answer_class;采集题固定 yes / weak_yes / no / unsure)。
  • has_new_dated_event:Noul,判据写成「这句话里是否出现了一件新的、带大概年或月的经历,且它不是对当前问题的直接回答」。
  • state 用对象:{"current_question": ..., "options": [...], "user_message": ..., "case_status": ...},与现行 agent.generate 的 JSON 输入同构,便于对照。
  • 三题同一请求并行(官方 fan-out 模式),每条样本一次调用。

组合合法性在代码里强制:intent != answer_current_focusanswer_classnull,不看模型。

验收:问题定义与官方 primitives/advanced 的 JSON 结构形式一致;文档化每一条判据与现行提示原句的对应关系(表格,一行一条),改写丢失的语义单列。

T2 · 对照跑(需要 key

scripts/research/jev_intent_probe.py:读样本 → 调 POST /v1/systemone(模型固定 jev-1.13.0不用 jev-latest 别名,理由是官方明说别名会移动)→ 记录每条的三题答案、各选项概率、confidenceusage.input_tokens、端到端毫秒数(本机到 api.typesafe.ai 的 wall clock,另记 SDK 报告的服务端耗时若有)→ 写 docs/research/jev_intent_2026_09_19.json(来源 B 的行只写聚合,不写原文)。

同一批样本用现行分类器(classifyRectificationTurnIntent,用会话默认模型)也跑一遍,走 frontend 里的 tsx 脚本或既有测试夹具,记同样的字段(现行模型没有置信度,记 null)。两边都跑 2 次,报自洽率(同一输入两次输出是否一致)。

T3 · 指标与报告

docs/research/jev_intent_2026_09_19.md,按焦点类型分层给出:

指标 定义 门槛(可接的必要条件)
intent 准确率 与 T0 真值一致的比例 来源 C 三层各 ≥ 现行模型准确率 − 3 个百分点;来源 B 单独报
answer_class 准确率 仅在真值 intent = answer_current_focus 的子集上算 同上
has_new_dated_event 准确率 全集 同上
高置信错误率 confidence ≥ 0.8 且答错的占全集比例 ≤ 3%(这是接了之后会直接写库的那部分)
低置信覆盖率 confidence < 0.5 的占比 报数,不设门槛;这是回退到贵模型的流量
低置信召回 答错样本里落在 confidence < 0.5 的比例 ≥ 60%(置信度是否真的能把错的挑出来)
no vs unsure 混淆 采集题里两者互判错的数量 单独列;这两者写库语义不同(declined / skipped
自洽率 两次跑同一样本输出一致的比例 报数,与现行模型并列
中位延迟 / P95 端到端毫秒 报数,与现行模型并列
每次调用输入 token 与折算成本 usage 报数

代表性检验(来源 B 对来源 C)。 同一模型在来源 B 与来源 C 上的 intent 准确率之差若 > 10 个百分点,判定模拟语料不代表真人,来源 C 上的门槛结论降级为「缺数据」,报告必须写明差在哪一类标签;不得只报来源 C 的数。

另加错例画像:Jev 错、现行对的样本按 §2 三条风险归类(中文口语 / 字面理解 / 其他),每类给 2–3 条改写后的示例。

结论段三选一,并附「若接,建议的接法」:只允许在 (a) Jev 先判、confidence < θ 回退现行模型,(b) 影子双跑只记日志不写库,(c) 不接 之间选,给出 θ 的推荐值与依据(从 T3 的置信度–准确率曲线上取,不得拍脑袋)。

T4 · 记录

  • docs/tasks/PROGRESS-rectification-jev-intent-classifier-research-20260919.md:样本数(分来源、分层)、真值 sha256、两边模型版本、跑的时间、指标表、偏离与原因。
  • BLOCKED.md:key 未到手期间挂一条「T2/T3 阻塞,替代证据 = T0/T1 产出」;到手后划掉。
  • 不写 docs/BUG_HISTORY.md(本单不是 Bug);若过程中发现现行分类器的确定性错误(同一输入稳定分错),另立 BUG 编号(当前最大 BUG-969,从 BUG-970 起),只记事实,不修。
  • docs/tasks/README.md 状态板加一行(生时校正段)。

6. 让步顺序

  1. 来源 B 不足 30 条:代表性检验降为「只报数、不判定」,报告标明;来源 C 照常跑。 1a. 来源 C 争议率修两轮提示仍 > 15%:按实际通过条数跑,配额偏差如实报,不得放宽复核标准。
  2. 现行模型对照跑时间超预算:来源 B 与来源 C 都必须至少跑一次,自洽率的第二次可以只跑来源 C 的 1/3 抽样。产品已明确 token 不设上限,不得以成本为由缩样本。
  3. Jev 限流(429):SDK 默认退避重试;仍失败的样本记 unavailable 计入分母,不得剔除。
  4. key 迟迟不到:T0/T1 完成后回报,状态板标「阻塞:等 key」,不得虚报 T2。

7. 开工前置命令

git fetch origin --prune
git worktree add -b codex/rectification-jev-intent-classifier-research-20260919 \
  .worktrees/rectification-jev-intent-classifier-research-20260919 origin/staging
cd .worktrees/rectification-jev-intent-classifier-research-20260919
git status -sb | head -1        # 确认分支
.venv/bin/python -m pip install typesafe-sdk   # 只装到 .venv,不改 requirements*.txt
export TYPESAFE_API_KEY=...      # 从产品负责人处拿,只放 shell 环境

本单不涉及引擎 / 镜像 / 发布,不要求跑 scripts/pre_work_check.py

8. 附:官方文档要点(2026-09-17 版,执行方不必再读一遍)

端点 POST https://api.typesafe.ai/v1/systemoneAuthorization: Bearer $TYPESAFE_API_KEY
模型 jev-1.13.0(别名 jev-latest / jev-preview 当前同指向;用版本号
价格 $42 / Btok 输入,输出免费
限流 250k tok/s、1200 req/min,动态调整
上下文 64k / 请求;state + 最长一题 ≤ 32k
输入 纯文本(字符串 / JSON 对象 / 数组)
返回 ChoicechoiceprobabilitiesconfidenceScorescorelegendprobabilitiesconfidenceNoulnoul01,无 confidence
SDK pip install typesafe-sdkTypeSafeClient().system_one(state=..., questions={...})
短板(官方列) 字面理解、算数与计数、日期比较、多跳间接、大而杂的 state、对抗性内容、指令与判据矛盾、结构不变量、不生成文本
语言 英语为主;CJK「可用但准确率更低,先在自己数据上测」
数据 不用客户请求训练;企业版有 ZDR