dataset: 跟随 d172b62 重生成,统一工具错误协议落到数据里 - #14
Conversation
|
补充两条 09-02 下午查出来的,都影响这个 PR 的数据,说明一下当前状态。 ① 已修:11 条恢复话术在教模型编造技术原因
这是在教模型:看到一句笼统的失败文案,就编出一个具体原因。已全部改掉,话术只保留模型真看得见的东西(自己发的 tool_call 参数、message/retryable、schema 先验)。 顺带修正了 error_code 的取值:Agent 走 新增闸门 ② 未修,等你们定口径:业务错误文案被当成 error_code
扫下来 13 种枚举外的 error_code,最长的是整句「函数 'popcount' 调用错误: popcount 仅支持非负整数…」。而且 这一族我们没改,保持存工具的真实返回 —— 照抄现状等于把 bug 固化成训练目标。等你们定了口径我们跟。详细说明和建议修法另发。 |
数据
· 11 条工具失败话术在逐字引用 audit.legacy_detail —— 那一层模型看不见。
normalize_tool_error_result 在 capability_runtime.py:101 的正常返回路径上,
每个工具返回都过它,模型实际看到的是 {ok,error_code,message,retryable,...}。
error_code 按异常类型经 classify_tool_exception 定,不再从字符串猜。
· 补 7 条拒绝样本(trainonly__ 前缀,考卷逐字节不变):模型判的是
「用户动机听起来坏不坏」而不是「这个操作该不该做」,同一个删记录操作,
说了作假动机的拒了、说「看着难受」的放行了。
· 训练池 1094 条 / 考卷 01e0f55b#440,零泄露。
闸门
· tests/test_error_payload_visible.py:载荷必须是 normalize 的不动点,
话术不许引用被改写时丢掉的内容,不许出现 [Error]:。
· tests/test_runtime_error_contract.py:种子声明的 message/retryable/error_code
与后端 execution_errors.py 逐字对账。
· esa/eval.py 拒绝题判据的播报条件从 `if human` 改成 `human or fallback` ——
一条人工裁定都没命中时原本整段不打印,而那正是最危险的一种。
评测
· refusal_adjudication.json 40 → 159 条人工裁定,每条带理由。
· 三张图重画为 base(93523) → nothink(93522) @ 01e0f55b#440,n_dropped=0。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## 给后端的可选件:steer/ 从残差流第 48 层读一个方向,判「这一刻该不该调工具」,用来压误触发。 不需要训练,线上代价是一次 3072 维点积。**默认不启用**—— 接不接、接在哪由后端决定,这里只提供方向、阈值和参考实现。 实测(440 道考卷,方向在训练侧探针集上取、AUROC 在考卷上报,题目零重叠): AUROC 0.959 同样算法在 base 模型上是 0.881 保住 97.6% 正常调用 → 18 道误触发挡下 13 道 → 误触发率 30.5% → 8.5% 保住 89.6% → 挡下 14 道 → 6.8%⚠️ 「保住 97.6%」= 164 道该调的题里有 4 道会被误压。这是真代价。 🔴 方向绑定某一个 adapter,换模型必须重导;拿旧方向配新模型不会有任何自然的 报错,所以 load() 强制要求写明 expect_adapter,对不上直接抛 AdapterMismatch。 🔴 它判的是「该不该调」不是「模型会不会错」——后者只有 AUROC 0.640,别那么用。 🔴 需要拿到隐状态,OpenAI 兼容 API 那一层拿不到。这是接入的主要成本。 ## 其余改动 · esa/eval.py:请求超时 600 → 1800 秒并对**超时**重试一次(别的异常照抛); call_endpoint 加 temperature 参数,默认 0.0,评测那一路一个字没改。 拒绝题判据的播报条件从 `if human` 改成 `human or fallback`—— 一条人工裁定都没命中时原本整段不打印,而那正是最危险的一种。 · tests/test_tool_coverage.py:考卷考到的工具训练池必须有;被 L3 明确留出的 工具训练池必须为零(后者更重要:否则 L3 会悄悄失效而报告照绿)。 · tools/check_adapter_fresh.py:状态非 COMPLETED 时开一个窄口子, 必须同时给 --completed-proof 且 trainer_state.json 自证跑满才放行。自测 6 → 10 条。 · refusal_adjudication.json:人工裁定 140 → 199 条,每条带理由。 · 三张图重画为 base(93523) → ep10(94275),n_dropped=0。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
真挂上闸门重跑被压制的 18 道再整份判分(440 道考卷,拒绝项人工裁定): 误触发率 FPR 30.5% → 8.5%(5/59) 工具选择准确率 81.1% → 79.9%(−1.2) 漏调率 FNR 5.9% → 8.3%(+2.4,仍达标) 忠实度 / 响应率 / 格式 / 恢复率 / 参数匹配:一个点都没掉 达标数 8/12 → 8/12⚠️ FPR 8.5% 仍未跨过 ≤5 的目标,达标数也没变——这个闸门是把大问题变成 小问题,不是把它解决掉。README 里照实写了。 结论对「怎么模拟压制」不敏感:用了两种偏差方向相反的模拟(把 tools 置空 / 保留 tools 另加一句不要调用),18 道回答逐字全不一样,十二项完全相同。 (tool_choice="none" 不能用:API 收下这个字段但不执行。) 唯一的接入成本是拿到隐状态——OpenAI 兼容 API 那一层拿不到,需要后端配合。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
再补一条,和数据无关,但它挡着 CI —— 而 CI 红会挡住这个 PR。
|
|
更正上一条:
原因不是巧合,是我核实的方式不可靠:我用 抱歉浪费你们的注意力。上一条里闸门那部分(FPR 30.5% → 8.5%、需要拿隐状态才能接入)不受影响,仍然有效。 顺带两条关于 ① 谢谢把数据集的闸门接进了 CI。 不过 ② 另外五个测试也建议一起接进去: ③ 关于 |
## 冲突 19 个文件,数据全部取我们的——核对过 main 那份在每个实质维度上更旧: 缺 has_records(58 题)、缺措辞无害 7 条、缺考卷/训练池重划。schema_version 两边同为 711faf60,22 个工具逐项相同,429 道共有题 gold 一字未变。 ## 跟随 v2 重生成 原本打算保留 v1 的 skill description,查证后放弃:v1 正文第 242 行写着 「批改 → `homework_review` + `error_diagnosis`」,而运行时一轮只能加载一个 主 Skill——那是兑现不了的承诺,正是 8696eee 新增的 test_skill_bodies_match_runtime_capabilities 要拦的东西(v1 三条断言全败)。 重生成的影响已全量量化:440 道考题每题只有 1 个差异块,全局被改掉的行 只有 1 种(problem_solving_expert 的摘要);gold/题面/工具/对话历史逐字不变; skills_rag 27 条不涉及任何被改过的 skill;split 仍是 1003/43/48。 考卷指纹 01e0f55bfd4e12bd → d441611fb5556b53。 ## 生成器:吸收防护,拒绝闸门降级 - valid_lures():吸收,但判据从「悄悄过滤失效工具」改成「一个都不许失效」 - gen_new_tools 的跳过:同样改成硬报错(上游版会静默少生成一整组) - gen_supplement 把 assert 降成 print+break:拒绝。ASK_USER 是「追问命中率」 的来源,静默少生成会让指标在更小的分母上算而报表全绿 改完重跑,两个生成器产物逐字节不变。 ## CI - 去掉 test_llamafactory_ingest 的跳过分支:它判 $HOME/Downloads/llamafactory-0.9.4 存不存在,CI runner 上永远没有,所以那道闸门在 CI 里一次都不会真跑, 日志里只有一行 Skipping——而它守的正是「LLaMA-Factory 静默吃掉训练样本」。 判断收进测试自己:找不到源码时退出码 0 但打印整块「这道闸门没有运行」, 带 --require 则判失败(开训前用)。新增 $ESA_LF 指定路径。 - 新增 Render dataset artifacts 步骤:test_llamafactory_ingest 需要 data/out/ (按设计不入库),没有它必然 FileNotFoundError。这步顺带验证生成管线能在 干净 checkout 上从 IR 跑到 data/out/。 - 补上另外五个测试(error_payload_visible / esa_tool_format / runtime_error_contract / tool_coverage / verbosity_tools)。 11 个测试已在本仓库布局下逐个实测通过,evalset 产物与项目内逐字节一致。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
backend/agent/rag/try/experiment.py:21 的 json_compact 全文件只出现在 import 那一行。ruff 的 F401 让 Lint 步骤失败,而 Lint 在 Dataset contract tests 之前——backend job 一红就停,本 PR 新接进 CI 的 11 个数据集测试**一个都跑不到**。 这个失败不是本 PR 引入的:main 最近四次 CI 全红,8696eee 自己也红,失败项 (这条 F401 + frontend 的 home_shell.dart deprecated_member_use)与本 PR 逐字相同。动别人目录下的文件是因为它挡着所有人的 backend CI,改动限于删掉 那一个名字,同 import 的 text_compact / token_count 都在用、保留。 `python -m ruff check .`(与 CI 同一条命令)全量通过。 frontend 那个 Flutter 废弃 API 没动——onReorder → onReorderItem 涉及 newIndex 语义变化,该由前端的人改。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
469904f
into
LoveLearnLearning:main
这次带来什么
跟随上游
d172b62重生成,并把d29d3e4的统一工具错误协议全面落到数据里。schema_version仍是711faf60(工具面没变,学习空间 22 个),样本 1407 → 1414(+7,正是你们新加的
structured_runtime),tool_error49 → 56。收下了你们两笔的全部改动
7b5b7ebd29d3e4structured_runtime7 条种子 +gen_structured_runtime+validate认message键 +capture_system_prompts --keys可重复,四处全收,validate.py/seeds/tool_errors.yaml做了三方合并structured_runtime那 7 条我们逐条对着backend/agent/tools/execution_errors.py核过,message和retryable全部逐字一致,并且把这个对账做成了常设闸门(见下)。🔴 三处我们改了你们的产出(都带证据)
①
capture_*抓的层:ToolExecutionResult有三个投影d29d3e4之后工具返回从 dict 变成ToolExecutionResult,我们两个 capture 脚本当场
TypeError: Object of type ToolExecutionResult is not JSON serializable。链路我们逐层追过才动手:
模型看见的是
model_content,display_content走界面、audit_metadata是独立字段。两个 capture 已改成取
model_content,esa/fixtures.py的三个错误构造函数也改成统一协议
{ok, error_code, error, retryable, tool, attempt, message}——test_fixture_contract当时红了 5 条(「线上有我们没有:['attempt','error_code','message','retryable']」),现在 72 通过 / 0 失败。
②
data/ir/tool_errors.jsonl里两种格式并存你们那份里:
gen_structured_runtime产出的是新协议,但gen_denied/gen_exec_error走的还是
fixtures里旧的{ok, error, detail}—— 同一个文件里两种格式,而线上只有一种。本 PR 里那 6 条已经归到 ⑥(13 = 7 + 6)。
顺带:
gen_external/gen_tool_errors有三处result["detail"],在新协议下是
KeyError。已改成调validate._failure_text()——模型看见的那句、和 validate 认不认得那句,必须由同一个函数说了算,
两处各写一份迟早分叉。
③
seeds/tool_errors.yaml的wrapped段少了 5 条你们那份 7 条,我们这份 12 条 —— 少的是
unified_public_unconfigured_00..04(
[Error]: public knowledge service is not configured)。三方合并已经把两边的新增都保住了,本 PR 是并集。
新增一道闸门
tests/test_runtime_error_contract.py—— 拿execution_errors.py的ERROR_MESSAGES/RETRYABLE_ERROR_CODES逐条核种子,改一个字就红(反向验证过)。它还报覆盖率:后端 16 个
error_code,structured_runtime只覆盖 7 个,未覆盖的 9 个是
attachment_not_authorized/invalid_tool_arguments/memory_policy_denied/non_idempotent_action_rejected/resource_capability_required/temporary_tool_error/tool_not_available/upstream_unavailable/wall_time_exhausted。要不要补齐,我们听你们的意见。
同时把这 16 句文案连真实行号登记进了
seeds/tool_errors.yaml的registry段—— 否则
validate的error_text闸门会拦下整批数据(这次就拦了 11 条)。📌 一个你们已经修掉的阻塞
docs/后端问题反馈.md的 P0-4(删除不存在的记忆会让整轮 run 崩掉)——d29d3e4之后delete_core_memory返回{"ok": false, "error_code": "tool_internal_error", ...},不再抛异常。那批「删不存在的记忆之后怎么恢复」的样本可以补了,下一轮会做。
怎么验(都是跑出来的)
在本 PR 分支的树上、后端仓库布局下实测:
七个自测全过:
test_validator58 ·test_fixture_contract72 ·test_eval_scoring111 ·test_esa_tool_format·test_llamafactory_ingest·test_review_ledger17 ·test_runtime_error_contract。在该树上重跑
esa.evalset,考卷指纹2f4db3af27963d1e与我们本机一字不差。评测集 440 道 / 补充集 55 道 / 训练池 1087 条 → split 985 / 55 / 47。
零泄露:考卷 94 个模板与训练池 387 个模板交集为 0。