学-练-测-评一体化

SKILL教育学习
教育学习 未标注权限 许可证不明确
安装这个技能

把作业或试卷的作答照片变成一份发给家长的学情诊断报告(Word 版)。逐题识别题干与学生作答并按分值判分,图像模糊或作答…

一句话选型结论

按资料字段整理

学-练-测-评一体化是教育学习类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类教育学习 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_edbd5466/xue-lian-ce-ping
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

教育学习
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_edbd5466仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791713915
正文体量68.2 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
讲解知识点

按水平把知识点讲清楚。

出练习题

按章节生成练习与答案。

制定学习计划

按目标和时间排学习节奏。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在教育学习场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
学-练-测-评一体化当前 未标注权限 未标注 未标注 未标注 有
食谱创建课堂课程 未标注权限 GitHub 仓库 25.5 万 Codex、Claude、Cursor 有
语言学习 联网访问 ClawHub 市场 23.6 万 OpenClaw 有
learning 效率 只读 ClawHub 市场 19.2 万 OpenClaw 有
学习习惯 未标注权限 ClawHub 市场 10.2 万 OpenClaw 有
日语家教 只读 ClawHub 市场 8.2 万 OpenClaw 有

SKILL.md 全文

68.2 KB
模型实际读到的说明书原文,来自技能仓库

学-练-测-评一体化:作业/试卷拍照批改与学情诊断

把一份(或多份)作业/试卷的作答图像,变成一份家长看得懂、教师能讲评、学生能照做的诊断报告,
交付一份可编辑的 Word 文档。

本技能是 kcode-textbook-graph 的下游消费方:图谱写一次,诊断用很多次。
知识点对齐与前置溯源全部走真实图谱数据,不靠模型记忆。

> v1.1.0 的三条口径(改动最大,先记住):
> 1. 报告固定四段式「总体评价 / 优势 / 待提升项 / 建议」,全文 ≤ 1800 字;
> 2. 正文不出现内部编码,一律用中文能力项名称,确需溯源才在名称后加括号小字编号;
> 3. 只交付 DOCX(不再产 PDF),全篇去教学行话。
>
> v1.2.0 新增:性能(详见 §四之二)。核心是「先量再优化」——
> stage_timer.py 出耗时剖面,report_cache.py 三级指纹缓存,
> kcode_lookup.py 图谱编译缓存,slice_for_llm.py 数据裁剪。
> ⚠ 实测结论:本地脚本不是瓶颈(kmap 对齐 40 题仅 0.1–0.2 秒),
> 真正的大头是模型侧的识卷/归因/成稿与无头浏览器自检。
>
> v1.6.0 新增:家长版可视化三表(详见 §三之二,★ 先读那节的口径警告)。
> 四段正文之后追加「成绩与错题一览」区:成绩概览表 / 需要重点补的内容表 / 典型错题表。
> 三张表不计入 1800 字上限,四段正文一字未动。
> ⚠ 其中「薄弱内容」表只报失分分布,不报正确率——原因见 §三之二,这是数据边界不是偷懒。
> 全部缓存可用 --no-cache 关闭,关闭后行为与 v1.1.x 完全一致。
>
> v1.3.0 新增:模型侧并行与流式(详见 §四之三)。既然大头在模型侧,就动模型侧——
> parallel_units.py 把识卷/判分/解析/归因拆成题目级单元并发(实测 4 线程 3.9×),
> stream_report.py 把四段正文分成两批并发并先流式吐核心结论(首屏 2.06s → 0.60s),
> 叠加以 --layers 的分层交付(核心版四段齐全、先发;完整版随后补全)。
> ⚠ 两条红线:流式只推已经算出的确定性数字,先给结论再改比晚给伤害大;
> 核心版必须保持四段齐全,宁可返回占位文案也不许缺段。
>
> v1.4.0 新增:分档模型 + 自检门控(详见 §四之四)。前两阶段把「怎么跑得更快」做完了,
> 这一阶段动的是「哪些活根本不该花这个价」——
> model_tier.py 分档路由:识卷/判分走快档(规则性强,实测 50% 的分派可降档、
> 成本量级省 ~44%),解析/归因/成稿走强档;
> selfcheck_gate.py 自检门控:无头浏览器自检单项占 47–84%,但它检的是
> 生成逻辑而非本次产物,故按「渲染脚本源码哈希 + 浏览器版本」决定是否重跑
> (实测每轮省 2.47 秒 = 自检层的 67%)。
> ⚠ 两条红线:归因阶段永不降档(它是本技能的智力核心);
> 文本级自检不接受门控(它检本次产物且只要毫秒),门控只作用于无头浏览器那一层。


零、开工前必做三件事

  1. 核实教材版本(最贵的一课)。成都/四川尤其要命:
    物理=教科版(非人教版)、英语=外研版、高中数学=人教A版、小学数学=北师大版、
    初中数学=北师大版。版本错 → 知识顺序与编码锚点全悬空。
    不确定就问用户一句,比返工便宜。
  2. 确认学段与年级。学段决定归因用语(小学用「数感/量感/运算能力」,不用「数学抽象」)
    与图谱文件选型。另注意:初中物理自八年级起开设,别把物理解析挂到七年级作业上。
  3. 确认是否有参考答案。有答案 → 可判对错给分;无答案 → 该题一律标「待确认」,
    绝不用「看起来像错的」来推断(见 §二 红线)。

一、五阶段流水线

① 识卷   图像 → 逐题 {题干, 学生作答, 分值, 可辨度}
② 判分   对照参考答案按分值给分 → 每题得分 + 总分
③ 解析   每题双视角(命题者 / 做题者)
④ 归因   能力项定位 → 四类归因 + 认知层分析 + 前置溯源
⑤ 成稿   补缺优先级 → 四段式报告 → 导出 DOCX

① 识卷(★「不臆造」的落点)

逐题输出:题干要点 / 学生作答(可见痕迹) / 满分 / 可辨度。

可辨度三档 → 直接映射到题目的 status:

情形 status 处理
作答题清晰可辨 → 进入 ② 判分 正常判定
图像模糊 / 涂改覆盖 / 拍摄残缺 unreadable 标「待确认」,不给分不判错
无参考答案可核(主观题、涂卡区未下发答案) pending_answer 标「待确认」,不给分不判错

三条禁令:
- 不允许根据「看起来像错的」推断对错;
- 不允许补全学生没写的步骤来凑得分点;
- 不允许猜分值(分值不清就留 null,报告会显示「—」)。

题干摘录要点即可,不必逐字抄;但学生作答的痕迹要如实记(划掉重写、旁注、涂改位置常常
正是归因的关键证据)。

② 判分

  • 按题目分值给分,输出 score_full / score_got。
  • 解答题有步骤分 → 用 partial(部分得分),并写清丢的是哪一步。
  • 汇总:sum(score_got) / sum(score_full),得分率由脚本算,别手写。
  • ⚠️ 题面满分合计与卷面声明总分不一致时:若差额可被「未批改/待确认的题」解释,属正常;
    若题面合计超过声明总分 → 真错误,必须查。

③ 双视角解析(每题)

视角 写什么
命题者视角 考点是什么;陷阱埋在哪;命题意图(想区分哪种能力);干扰项怎么设计的
做题者视角 审题关键(哪个词决定了方向);解题步骤(可照做的分步流程);规范作答(评分点分布、格式、单位、结论句式)

写解析时对照图谱节点的错因参考与常见题型字段——若卷面痕迹吻合,归因可信度大幅提高,可直接引用;
若不符,说明是新错法,值得在报告中特别指出。

⚠ 双视角解析进数据与讲评稿,不进家长版报告正文(报告正文只有四段,见 §三)。教师需要讲评时,
从数据契约里取这一步的内容。

④ 归因(本技能的智力核心)

先做知识点定位,再做四类归因。

知识点定位(一律走脚本,不凭记忆写码):

# 列出全库索引
python scripts/kcode_lookup.py --list

# 单条检索(调试用,带出层级/难度/素养/典型错因/前置链)
python scripts/kcode_lookup.py --subject 物理 --stage 初中 --query "欧姆定律"

# 批量对齐:读诊断数据的 questions[].kc_hint,输出 kmap 段
python scripts/kcode_lookup.py --subject 物理 --stage 初中 --in 诊断.json --out kmap.json

# 校验报告里的编码是否都真实存在(⚠ 此模式不要同时传 --subject/--stage)
python scripts/kcode_lookup.py --subject 物理 --stage 初中 --verify 报告数据.json

⚠ 接入新图谱后必做两项断言(脚本不报错,但内容可能整片消失):
_pre/_next 非空(关系键名中英文混用会被静默丢弃)、unit_total > 0
(unit_scope 前缀须与节点键同形,否则覆盖率失真)。详见 §六 踩坑表。

未命中 ≠ 随便编一个码:进 missing[],报告正文不出现该项(家长不关心图谱有没有建全),
只在「依据边界」里说明哪几处没能对上图谱,并建议建校本题库标签与内部编码并行。
绝不为迁就一份卷子新增编码。

四类归因判据(完整版见 references/attribution-rules.md):

归因 卷面判据 补救形态
不会 留空/只抄题干/方向无关;同知识点卷内从未答对 补前置(回溯到能答对的层级重讲)
不熟 方向对、第一步对,中途错;有对有错;限时错不限时对 限时重复练
方法问题 用了不该用的方法;方法对但笨重超时 方法对比训练(同题两法)
规范/粗心 思路答案都对,但步骤跳跃被扣分、抄错数、结论缺比较对象、涂改覆盖 流程化习惯(草稿分区、结论模板)

冲突时取最先命中者:空白→不会 / 有对有错→不熟 / 方法与题不匹配→方法 / 会做但被扣→规范。

⚠️ 判据错了,后面全错:把「枚举漏数」判成「不会」,补救方案就会变成「重讲古典概型」,完全打偏。
另注意:答案本身正确但表述不完整 → 规范问题,不是计算错,不要误导学生去练计算。

认知层分析必写三段:surface(只陈述卷面可见事实)/ root(指向认知结构,不写「态度不端正」)/
pattern(是首次还是反复,引用跨题证据)。—— 这三段是内部推导,报告里只落成人话结论。

前置溯源:若失分能力项的前置项本身也是失分点 → 根因更上游,属「旧疾未清」而非「新知未学」。
这是家长版报告里必须讲清楚的一件事——「这次错的是 A,但根子在上学期的 B」比单说 A 有用得多。

⑤ 成稿与交付

  • 补缺优先级:按 命中次数 × 外溢影响数 排序,不用「感觉哪块弱」。图谱频度字段可参与加权,
    但不得在报告里标注年份/卷别/题号(本项目的铁律)。
  • 四段式成稿:严格按 §三 的结构与字数上限写,见那份契约。
  • 交付:只出 DOCX(做法见 §四)。

二、红线(违反即报告作废)

  1. 不臆造:作答复不可辨或参考答案缺失 → 标「待确认」,不计入对错统计,不写入待提升项,
    只在报告末尾的补件提示里说明。
  2. 不臆造编码:图谱没有的节点,进 missing[] 并说明,绝不新增编码迁就卷子。
  3. 数字一律脚本算:报告正文里所有数字(题数/得分/得分率/失分题数/涉及能力项数)由
    len()/求和算出后注入。手写常量必错——本项目实拍:手写「3 个主责节点」实算是 7 个。
  4. 归因必须可观察:证据只能是卷面可见事实,「他大概不懂」不算证据。
  5. 不改图谱:发现的缺边/缺节点写成建议,交回 kcode-textbook-graph 全链路重生成。
  6. 正文不出现内部编码:报告四段正文里不得出现编码;需要溯源时只在能力项名称后加括号小字。
    编码不得出现在任何标题或结论句里(见 §三 硬约束)。
  7. 只出 DOCX:不再生成 PDF,也不保留 PDF 相关的分支、参数或说明。

三、报告契约(四段式,固定不变)

这是本技能最重要的一张表。报告永远只有以下四段,顺序、用途、句数都不得改。

总字数上限:≤ 1800 字(含小标题,不含卷面信息条与末尾的补件提示)。
建议区间 1000–1500 字。超限时先砍「优势段」与「建议段」的铺陈句,绝不砍事实与动作。

段 用途(回答家长的什么问题) 句数 写法要求
总体评价 这次考得怎么样、整体是个什么状态 3–4 句 首句给结论(得分率 + 一句话定性),其后 1–2 句说清「强在哪、弱在哪」的总体分布,末句给出与上次/与标准的对比(无对比数据则省略,不编)。不出现任何编码。
优势 孩子哪里是真好,不是客套 2–4 句 每条必须有卷面依据(哪几题、什么表现);只写「确实做对了且不是蒙对的」,答对但步骤跳跃不完整的不算优势。没有可靠优势时改为一句实话(如「本次没有可以确认的稳定优势项」),不硬凑。
待提升项 具体差在哪、差成什么样、根子在哪 3–6 句,最多 3 个条目 每条固定三件事:① 用中文能力项名称说清是什么(不得用编码);② 卷面上具体是什么表现(错了几题、怎么错的,用可见事实);③ 归到四类原因里的一类,若根子在更早的前置知识,一并点明(「这次错的是 A,根子在上学期的 B」)。确需溯源时,在能力项名称后加括号小字编号,如「分数的加减运算(K2031)」——编号只出现在这里,不得进标题、不得进结论句。
建议 接下来这一两周具体做什么 3–5 句,最多 3 条 每条必须是可执行动作:做什么、做多少、什么时候做、怎么算做到了。按待提升项的优先级排序(先补根子、再补本次)。禁止出现「多加练习」「认真审题」「培养兴趣」这类没有落点的句子。

写作硬约束

  1. 去行话:不出现「学情诊断」「知识图谱」「认知结构」「元认知」「命题立意」「核心素养水平」
    「K 码」等教学/测评术语。等价说法:
    「知识图谱定位」→「对照课本」;「认知层分析」→「为什么错」;
    「前置溯源」→「根子在哪」;「补缺优先级」→「先补哪个」。
  2. 结论必须具体:「掌握不牢」是废话,「20 道计算题错了 5 道,都是小数点位置」才是结论。
  3. 数字口语化:写「19 道题错了 6 道」,不写「失分率 31.6%」;比例只在总体评价段出现一次。
  4. 称呼一致:面向家长 → 用「孩子」;面向学生 → 用「你」。同一份报告不混用。
  5. 不评态度:不写「粗心大意」「不认真」「态度不端正」这类评价,只写行为与可改的流程
    (如「抄数时抄错了符号,建议草稿本上分区抄写」)。
  6. 不承诺分数:不写「照这样做能提高 10 分」。
  7. 待确认题:只在报告末尾的补件提示里一句话交代,不占四段正文的篇幅。

报告骨架(固定)

标题(含卷面信息条:科目 / 年级 / 卷面 / 日期)
总体评价          ← 3–4 句
优势              ← 2–4 句
待提升项          ← 3–6 句 / ≤3 条
建议              ← 3–5 句 / ≤3 条
———(以下不属于四段正文,字数不计入上限)———
补件提示(有未判定题目时才出现)
依据边界声明(固定一句:依哪份课本目录、哪部分未作判定)

空白兜底(每一段都必须自解释)

任何一段写不出来时,不允许留空标题。改为一句如实说明 + 补什么就能有,例:

  • 优势段:本次 19 道题中 13 道未作判定,没有可以确认的稳定优势项;补齐参考答案后可重出本报告。
  • 待提升项:本次全部题目因缺少参考答案未作判定,暂时无法指出具体差在哪;补齐后本节会自动生成。

三之二、家长版可视化三表(v1.6.0)

四段正文之后追加一个 Heading 1「成绩与错题一览」,下挂三个 Heading 2 小节。
三张表不计入 1800 字上限,四段正文一字未改。

小节 表头 数据来源
1. 本次成绩概览 项目 / 本次情况 / 说明 derive() 的 sum_got、sum_full、rate、mastery、n_err、n_todo
2. 需要重点补的内容 考查内容 / 涉及题号 / 失分情况 / 常见错法 kmap.hits(role=主)聚合 + 节点 err 字段
3. 典型错题 题号 / 考查内容 / 当时怎么做的 / 问题出在哪 questions[](ERR_STATUS)join kmap.hits 与 diagnosis.attributions

★ 口径警告:为什么第 2 张表不报正确率(2026-10-06 实测定案)

kcode_lookup.py --in 只为失分题建立「题 → 能力项」映射,答对的题不产生 hit。
即 kmap.hits 天然是失分侧数据(main_nodes = 失分相关节点,unit_covered 6/40)。

⇒ 若照常写 正确率 = 做对题数 / 已判定题数,分母里只会出现失分题,每一行都算出 0%,
六块内容全部显示「明显薄弱」。家长会读成「六块内容全都完全没掌握」——这是彻头彻尾的误导。

实测:sample-junior-physics.json 有 8 题,其中 q1 correct 无任何 hit,
7 条 hit 全部落在 q2–q6 的失分题上。

故本表只报它确实知道的事:哪些内容出了问题、各牵连几道题、对应什么常见错法。
真实正确率需「全卷每道题都做图谱映射」,属上游 kcode_lookup 的能力边界,
在此如实说明,不以估算数字填充(符合 §二 红线 1「不臆造」)。

自检断言(make_docx.py --verify,家长版分支)

VISUAL_PARENT = "成绩与错题一览"
VISUAL_SECTIONS = ("1. 本次成绩概览", "2. 需要重点补的内容", "3. 典型错题")
VISUAL_TABLE_KEYS = ("项目", "考查内容", "题号")
  • 区标题与三个小节标题必须出现在落盘 DOCX 里;
  • 表格数 ≥ 3;概览表非空;
  • 典型错题表数据行数 == n_err(空表兜底 1 行);
  • 薄弱内容表数据行数 == 能力项数(len(d["kp"]))。

⚠ 用 len(t.rows) - 1 数数据行(len(t.rows) 含表头,实测差 1 行会误判)。
⚠ 表格里不得出现内部编码(家长版三表全是中文名,验证脚本实测为 0 泄漏)。

层级约定

四段正文用 Heading 1;本区整体 Heading 1、三小节 Heading 2,
避免与教师版的「附一~附六」争抢同级编号(否则目录出现两套并行编号)。


四、数据契约与工具链

单一数据源:所有产物(HTML 讲评稿 / DOCX 家长报告)只从一份 JSON 渲染。
完整字段定义见 references/report-schema.md(动手前先看一遍)。

数据骨架:meta / questions[] / kmap / diagnosis / prescription / evidence。

工作目录约定

<工作目录>/
  诊断数据.json          # 单一数据源(先按 schema 起草)
  out/
    诊断报告.html        # 中间母版(可打印,供教师讲评存档)
    家长版.html          # 四段式家长版(与 DOCX 同源,便于比对)
    诊断报告.docx        # ★ 唯一交付件
    _kmap.json           # 能力项对齐结果(可回填进数据文件)
    _llm_slim.json       # 生成四段正文用的最小充分集
    _profile.json        # ★ 耗时剖面(哪一段花了多少秒)
    _pipeline.log        # 全过程日志
  .report_cache/         # 报告指纹缓存(可安全删除,删了只会变慢)

生成命令

PY   = <本机 Python 3.10+>                    # 标准库即可
VENV = <含 python-docx 的 Python 环境>        # 或给当前环境 pip install python-docx

# ① 知识点定位 → 回填 kmap(先跑)
$PY  scripts/kcode_lookup.py --subject 物理 --stage 初中 --in 诊断数据.json --out out/_kmap.json

# ② HTML 中间母版(含文本级校验)
$PY  scripts/build_report.py 诊断数据.json -o out/诊断报告.html --verify

# ③ 真实交互自检(读落盘交付件)
$PY  scripts/selfcheck_html.py out/诊断报告.html

# ④ DOCX(唯一交付件,从 JSON 直接重建)
$VENV scripts/make_docx.py 诊断数据.json -o out/诊断报告.docx --verify

一键跑完用 scripts/pipeline.py(已去掉 PDF 环节):

$PY scripts/pipeline.py 诊断数据.json --subject 物理 --stage 初中 --name 诊断报告

四轮性能改造的开关可以叠加使用(v1.4.0 的默认行为已是最优组合):

# 全量最优(缓存 + 分档 + 自检门控 默认全开)
$PY scripts/pipeline.py 诊断数据.json --subject 物理 --stage 初中 --tier --layers

# 回归比对(强制全量重跑 + 强制真自检)
$PY scripts/pipeline.py 诊断数据.json --subject 物理 --stage 初中 --no-cache --force-selfcheck

跑完必看耗时剖面(它告诉你哪一段最贵):

$PY scripts/stage_timer.py out/_profile.json

四之二、性能:缓存与预计算(v1.2.0)

先量,再优化

不要凭"感觉慢了"去优化。 报告生成走的是这条链:

算指纹 → 能力项对齐 → 母版 HTML → 家长版 HTML → 无头浏览器自检 → DOCX → 终检

实测结论(本机、8 题样例、_profile.json 可复现):

阶段 冷启动 缓存命中 说明
算三层指纹 0.7s 0.7s 纯 CPU,已是最小
能力项对齐 0.7s 0.0s 图谱编译缓存
母版 HTML 0.7s 0.0s 产物缓存
家长版 HTML 0.7s 0.0s 产物缓存
无头浏览器自检 5.3s 5.3s ★ 单项最大,且不接受缓存
DOCX 1.2s 0.0s 产物缓存
合计 9.7s 4.7s(跳自检 0.8s)

三条必须记住的判断:

  1. 本地脚本不是瓶颈。kmap 对齐在 40 题量级只要 0.1–0.2 秒;就算把
    图谱检索优化到零,总时长也只少零点几秒。真正的耗时在模型侧
    (识卷 / 归因 / 成稿四段),优化精力要花在那里。
  2. 无头浏览器自检是最贵的单项,占一半以上。它检查的是"生成逻辑"而非
    "本次产物",改了渲染脚本才需要重跑。快速迭代用 --no-selfcheck,
    交付前必须补跑。
  3. 缓存省下的是"重复劳动的绝对值",不是百分比。一次全量省 5 秒看着不多,
    但真实工作流是同一份卷子改十遍(改称呼、压条数、补答案),
    十次全量 = 50 秒纯浪费,缓存后只剩首次。

三级指纹:决定"什么变了要重算什么"

缓存粒度不是"整份报告",而是按产物分别判定。指纹分三层:

层 覆盖内容 变更后果
图谱层 图谱文件 size+mtime_ns 全链失效
事实层 逐题 题干/作答/分值/状态/参考答案 + 归因 + 方案 全链失效
呈现层 姓名/日期/卷面名 kmap 可复用,母版与报告重出
措辞层 四段正文(散句 + 条目两种写法) 仅家长版/DOCX 重出

实测行为(report_cache.py 的 fingerprints() 可验证):

场景 kmap 母版 报告/DOCX
只改四段措辞(最高频) 复用 复用 重出
改一道题的判定状态 失效 失效 重出
只改姓名 / 报告日期 复用 重出 重出

缓存红线(★ 违反即等于埋雷)

  1. 事实变了必须失效。status 逐题进指纹 —— 把 pending_answer 悄悄当
    correct 处理会让报告凭空多出"优势项",是本技能最严重的一类错误。
  2. 缓存只跳过生成,绝不跳过校验。命中后仍要过存在性 + 大小断言;
    终检(题数 / 四段字数 / 无编码泄漏)照常执行。
  3. 降级必须安全。缓存损坏 / 不可写 → 静默转为全量生成,不得因此跑不出报告。
  4. 首跑指纹必须稳定。resolve_graph_path() 必须在算指纹之前调用 ——
    否则首跑时 kmap.graph_path 还未写入,图谱层取到 "none",
    回填后才变真哈希,导致首跑永远不命中(已踩)。
  5. 产物必须等价。缓存复用与全量生成的 DOCX 除预期差异外逐部件一致(已验证)。

数据按需裁剪

slice_for_llm.py 把完整数据裁成"生成四段正文的最小充分集":

$PY scripts/slice_for_llm.py 诊断数据.json -o out/_llm_slim.json           # 默认档
$PY scripts/slice_for_llm.py 诊断数据.json -o out/_llm_min.json --level min # 极简档
$PY scripts/slice_for_llm.py 诊断数据.json --check out/_llm_slim.json      # 口径自检

实测:31.1 KB → 11.4 KB(默认档 42%)/ 8.7 KB(极简档 34%)。

裁剪保留:全部失分题与归因(含 blank)、优势候选、补救方案、待确认计数、
允许出现的编号白名单、四段写作契约(段名/句数/字数上限/禁词表)。

裁剪绝不做的事:不裁待确认计数、不裁 blank 题、不改任何数字口径、
不改 error_type。产出后立刻自检数字与题号是否与完整数据逐项一致。

> ⚠ 裁剪稿只是"喂给模型的输入",不是交付数据源。交付仍以完整 JSON 为准。

性能相关开关

--no-cache        禁用全部缓存(强制全量重跑,用于回归比对)
--rebuild-index   强制重建图谱编译缓存
--no-slim         不生成数据裁剪稿
--no-selfcheck    跳过无头浏览器自检(快速迭代用;交付前必须补跑)
--workers N       题目级并发度(0=CPU 核数,1=串行;默认 4)
--split-units     切分题目级工作单元清单(供逐题分派给模型并发调用)
--plan            打印模型侧生成计划(题目并发 + 四段分批 + 分层交付)
--layers          产出分层交付件(核心版 / 完整版)并自检
--time-travel     时序沙盘:对比「四段齐发」与「按依赖分两批」的首屏与总时长
--tier            产出分档模型路由计划(快档做识卷/判分,强档做解析/归因/成稿)
--no-downgrade    配合 --tier:禁用降档(全部按阶段基线,用于对照)
--no-gate         禁用自检门控(强制每次都跑无头浏览器自检)
--force-selfcheck 强制本轮跑无头浏览器自检,并刷新门控指纹
--solo            单产物模式:交付目录只留 DOCX,中间件落 --work-dir(终检后自动清理)
--work-dir DIR    配合 --solo:指定中间件工作目录(默认 tempfile.mkdtemp())
--keep-work       配合 --solo:保留工作目录不清理(排障复盘用)
--keep-html       配合 --solo:额外保留 HTML 母版与家长版(教师讲评预览用)

单产物模式(--solo):交付目录里只有报告

为什么要它:常规模式下中间件与交付件同目录,一轮跑完 out/ 里会堆
59 张裁图 + 6 个中间 JSON + 4 个 HTML,用户要的「一份报告」被淹在里面。

python pipeline.py 诊断数据.json --subject 物理 --stage 初中 --solo
<交付目录>/                 ← 只有报告
    学情诊断报告_初中物理.docx
<workdir>/                  ← 全部中间件,终检通过后自动删除
    _kmap.json  _llm_slim.json  _tiers.json  _profile.json  _pipeline.log
    <name>_诊断报告.html  <name>_家长版.html

四条设计要点(都是踩过坑才定下来的):

  1. 靠目录分离保证"只有一份",不靠"跑完再挑着删"。后者中途失败会留下半成品残骸。
  2. 失败时绝不清理(默认行为,非可选项)。中间件是排障的唯一线索。
  3. 诊断文件要另存:workdir 删掉后剖面/日志会一起消失 → 复制一份到
    .report_cache/_last_profile.json 与 _last_pipeline.log(持久,供事后查阅)。
  4. ⚠ 缓存产物必须 stash 进持久目录。单产物模式下中间件在临时目录、
    跑完即删,若按原路径登记缓存,下一轮 probe 必然「产物已不存在」→ 缓存白做。
    ReportCache.stash() 把产物复制进 .report_cache/ 后再登记。DOCX 落在交付目录
    (持久)无需 stash。

> ⚠ 实测过的两个坑:① 缓存命中时只打印「已复用」却不把产物落到本次目标路径 →
> 单产物模式下报 docx_missing(常规模式因路径恰好相同而侥幸不暴露);
> ② 交付目录里文件名重复后缀(…_初中物理_诊断报告.docx)——
> 单产物模式已改为 <name>.docx,不再重复「诊断报告」四字。


四之三、模型侧并行与流式(v1.3.0)

> ⚠ 本地脚本不是 30 分钟的大头(见 §四之二)。真正的大头在模型侧:
> 识卷、判分、双视角解析、四类归因、四段成稿。本节专治这部分。

三个手段量的是三条不同的时间轴

混为一谈会得出错误的优化结论:

手段 缩短的是 家长感知
题目级并行 「全部完成」的总时长 最终交付变快
流式输出 「看到第一句有用结论」的时长 等待期间有东西看
分层交付 「能拿走成品」的时长 5 分钟内拿到核心版

一、题目级并行(parallel_units.py)

题目之间彼此完全独立:第 3 题看不清不影响第 7 题怎么判。串行处理 40 题就是 40 倍排队。

① 识卷   8 题并发 ┐
② 判分   8 题并发 ├─ 阶段之间串行(判分需要识卷产物)
③ 解析   8 题并发 │   ★ 并行发生在**同一阶段的题目之间**
④ 归因   8 题并发 ┘

实测加速(8 题 × 2 阶段,单题 0.15 秒):

并发度 耗时 加速
1(串行) 2.41s 1.0×
2 1.22s 2.0×
4 0.61s 3.9×
8 0.31s 7.7×

四条设计约束(违反了会出静默错误):

  1. 确定性顺序优先于并发效率。合并时强制按题号排序,与完成先后无关。
    题号一旦随并发抖动,家长会以为「第 3 题」是另一道题。
  2. 单题失败必须隔离。一题失败不能让整份报告作废 → 进 failed[] 并在报告中标「待确认」,
    绝不因为"凑齐"而编造该题结论。这是本技能核心红线的并发版本:宁可少一道,不可编一道。
  3. 并发度默认保守(4)。模型调用有速率限制,开太高触发限流反而比串行更慢。
  4. 串行路径必须保留(workers=1),用于回归比对 —— 并发不得改变业务结果。
# 切分工作单元(供逐题分派给模型并发调用)
$PY scripts/parallel_units.py 诊断数据.json --split -o out/_units.json

# 并发压测:验证加速比 / 顺序稳定 / 失败隔离 / 与串行一致
$PY scripts/parallel_units.py 诊断数据.json --selftest --workers 4

二、四段并发生成(stream_report.py)

四段不是"一起跑"。 依赖关系决定了必须分两批:

批次 依赖 段 理由
批 1 判分完成 总体评价、优势 只用得上判分结果,不必等归因
批 2 归因完成 待提升项、建议 要引用具体失分项与前置根因

硬把批 1 压到归因之后一起并发,是拿「早出两句」换并发度,总时长反而更差。

实测时序对比(模拟单题 0.6 秒、归因前置等待 1.2 秒):

做法 首屏可出 全部完成
❌ 等归因 → 四段齐发 2.06s 2.06s
✅ 按依赖分两批 0.60s 2.64s

首屏快 1.45 秒(约 2.4 倍),总时长只多 0.58 秒。 这是感知等待的胜利,
不是总时长的胜利 —— 家长更早看到「这次考得怎么样」。

$PY scripts/stream_report.py 诊断数据.json --plan          # 看依赖分组
$PY scripts/stream_report.py 诊断数据.json --demo-parallel # 时序沙盘
$PY scripts/stream_report.py 诊断数据.json --demo-stream   # 流式流程演示

三、流式输出的红线

「先流式出核心结论」必须先给已经算出来的东西,不能为了"早点出内容"而先给结论再改。

  • ✅ 分数、得分率、失分题数、待确认数 —— 由脚本算出,确定性,可立即推送
  • ✅ 模型写的定性句 —— 生成完一段推一段
  • ❌ 绝不先给一个估计值再纠正。先给错数字再改,比晚给 20 秒伤害大得多

推送顺序 ≠ 生成顺序。建议按 总体评价 → 待提升项 → 建议 → 优势:
优势是「好消息」,晚一点到不影响家长做决策。

四、分层交付(--layers)

核心版(先行交付)       完整版(随后补上)
  ├ 总体评价              ├ 核心版全部内容
  ├ 优势                  └ 逐题双视角解析 + 溯源与连带明细
  ├ 待提升项                 (教师讲评 / 存档用)
  └ 建议

★ 最重要的一条契约约束:核心版也必须是四段齐全。

分层交付是「细节延后」,不是「结构缺段」。不能因为"优势段还没生成"就让它缺位 ——
那会违反 §三 的报告契约,也会被 build_report 的段数校验判 FAIL。

正确做法:优势段在核心版里返回如实说明(「要等逐题分析完成才能确认,完整版补上」),
而不是留空标题、更不是编一句客套话。占位时置 _strength_placeholder = true 便于追踪。

另外两条:
- 两层四段内容必须逐字一致(不能是"两个版本",否则家长以为看的是两份报告)
- 待确认计数必须带进核心版 —— 它是「诚实」的一部分,不因精简而消失

$PY scripts/stream_report.py 诊断数据.json --layers -o out/

四之四、分档模型与自检门控(v1.4.0)

> 前两阶段回答的是「怎么跑得更快」;这一节回答的是「哪些活根本不该花这个价」。
> 两个手段都不改变任何产出内容 —— 它们只改「用哪个模型」和「哪些检查没必要每轮重做」。

一、分档模型路由(model_tier.py)

核心洞察:五阶段的难度极不均匀,但现在全部用同一个强模型跑。
于是最便宜的活(把字认出来、按分值算个数)和最贵的活(四类归因)同价。

阶段基线档位

阶段 档位 理由
识卷 read 快档 纯视觉转录,不需要推理
判分 grade 快档 按分值比对正误,规则性最强
双视角解析 explain 强档 要讲命题意图与陷阱,需要真理解
归因 attribute 强档(红线) ★ 本技能的智力核心,永不降档
成稿 compose 强档 四段式行文,涉及口径与去行话

题级分档(细粒度,判据全是卷面可观测量)

信号 档位 理由
待确认(unreadable/pending_answer) → 快档 本来就不判分,没必要花强模型
空白题(识卷/判分阶段) → 快档 没内容可推理
客观题(choice/judge/fill) → 快档 规则性强
主观题(answer/essay)在识卷/判分阶段 → 强档(反向升级) 识卷要理解手写推导与图表,比逐字转录难
多空作答(≥2 空)在判分阶段 → 强档 逐空判分易错
单题失分 ≥50% 在解析/成稿阶段 → 强档 必须讲清楚为什么错

★ 反向升级是必须的:不能想当然认为「识卷=快档」。遇到主观题,识卷也要升级 ——
把学生的推导过程看错,后面全盘皆错。

实测(8 题样例)

合计 40 次分派:快档 20(50%)/ 强档 20(50%)
成本量级估算(权重 快档=1 / 强档=8):全强档 320 → 分档后 180,省下约 44%
$PY scripts/model_tier.py 诊断数据.json --plan          # 打印分派计划
$PY scripts/model_tier.py 诊断数据.json --plan --json out/_tiers.json
$PY scripts/model_tier.py --selftest                    # 离线自检(12 项)

模型名走环境变量(XUELIAN_MODEL_FAST / XUELIAN_MODEL_STRONG),脚本自身不硬编码供应商。

分档红线

  1. 归因阶段永不降档。降档等于换了个技能。check() 内置断言。
  2. 分档只改「用哪个模型」,不改判分口径与四段式契约。同一份数据在快档与强档下,
    判分结果与报告结构必须一致。
  3. 降档必须显式记录原因,便于事后审计「这题当时为什么走了快档」。

二、自检门控(selfcheck_gate.py)

核心洞察:无头浏览器自检占总耗时 47–84%,但它检的是「生成逻辑」而非本次产物。
逻辑没变(渲染脚本没改)时,它每一轮都重跑同一套断言 —— 纯浪费。

门控判据(三者任一变化即失效)

判据 为什么
渲染脚本源码 sha256(build_report.py / selfcheck_html.py) 主判据:脚本改了,断言是否还成立就未知了
浏览器可执行文件 + 版本号 Edge/Chrome 升级会改变渲染与 JS 行为
harness 版本号(HARNESS_VERSION) 改断言就必须 +1,否则旧指纹会把新断言跳过

实测(8 题样例,本机)

环节 耗时
门控判定(哈希比对) 0.60 秒
自检·仅文本级 0.62 秒
自检·含浏览器级 3.69 秒
门控命中时自检层合计 1.22 秒
门控关闭时自检层合计 3.69 秒

→ 每轮省下 2.47 秒,约为自检层的 67%。

门控红线(违反即埋雷)

  1. 文本级自检不接受门控。它极快(毫秒级)且检的是本次产物,必须每轮照跑。
    门控只作用于无头浏览器那一层。--no-browser 只跳过浏览器级,文本级必跑。
  2. 门控命中 ≠ 免检,而是「通常不跑 + 定期抽验」:每 SMOKE_EVERY(默认 10)轮
    至少真跑一次,防「脚本没变但行为变了」长期不被发现。
  3. 只有真自检通过(ALLPASS)才登记指纹。失败、跳过一律不登记 ——
    不许"谎报合格"。
  4. 指纹由分项重算,不采信存下来的字符串。若采信字符串,一旦分项被改动
    (脚本更新、浏览器升级、手工编辑状态文件),字符串不会跟着变,该跑的就被跳过了。
    这是本项目实际踩到的一个坑(见 §七 踩坑表)。
$PY scripts/selfcheck_gate.py --data 诊断数据.json --info        # 看状态
$PY scripts/selfcheck_gate.py --data 诊断数据.json --should-run  # 退出码 0=该跑, 3=可跳过
$PY scripts/selfcheck_gate.py --data 诊断数据.json --force       # 强制失效
$PY scripts/selfcheck_gate.py --selftest                         # 离线自检(12 项)

pipeline 里的分层

⑤a 自检门控判定(毫秒级哈希比对)
⑤b 交付件自检:文本级【必跑】 + 浏览器级【按门控】
⑤c 登记门控指纹(★ 仅当浏览器级真跑且 ALLPASS)

五、交付规范(DOCX)

完整版见 references/delivery-spec.md。要点:

为什么从 JSON 直接重建,不走 HTML→docx

报告含表格与底色,Word 没有 CSS 背景概念,HTML 转过来必然丢图丢色。必须用 python-docx
按四段式骨架重新生成。生成逻辑写在 scripts/make_docx.py,不要在生成器外手改 docx。

必设项

  • 中文字体必须写 w:eastAsia(只设 font.name 中文不生效):
    python run.font.name = '宋体' run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
  • 目录域用 w:fldChar 三段式插入。交付时必须提示用户
    「打开后按 Ctrl+A 再按 F9」更新目录域,否则目录是空的。
  • 四段标题用 Heading 级别(供目录与导航窗格识别),段内条目用正文 + 项目符号。
  • 页脚自动页码。
  • ⚠️ 生成脚本里别把变量命名成 qn —— 会遮蔽 docx.oxml.ns.qn 导入,
    报 UnboundLocalError: cannot access local variable 'qn'(已踩)。

中间母版 HTML(仅供讲评存档,不是交付件)

如果要留一份可打印的讲评稿:单文件自包含,宣纸套:#FBF8F1 纸 / #4A5F6B 黛青 / 宋体族。
@page{size:A4 portrait;margin:0} 与 -webkit-print-color-adjust:exact 必须显式声明。
⚠ 母版里也不得出现 PDF 生成步骤——本技能不再产 PDF。


六、自检(交付前必跑)

$PY   scripts/build_report.py 诊断数据.json -o out/诊断报告.html --verify   # 文本级
$PY   scripts/selfcheck_html.py out/诊断报告.html                            # 真实交互
$VENV scripts/make_docx.py 诊断数据.json -o out/诊断报告.docx --verify       # 回读点数

★ v1.4.0:自检分两层,门控只管慢的那层

层 检什么 耗时 是否可门控
文本级 本次产物(占位符、编码泄漏、段数、行话) 毫秒级 否,每轮必跑
浏览器级 生成逻辑(交互、渲染、JS 报错) 秒级~数十秒 是,按指纹

pipeline.py 已自动执行这套分层(⑤a 门控判定 → ⑤b 分层自检 → ⑤c 登记指纹)。
手工跑时也可直接利用:

$PY scripts/selfcheck_html.py out/诊断报告.html --no-browser   # 只跑文本级(毫秒)
$PY scripts/selfcheck_html.py out/诊断报告.html --json r.json  # 落结构化结果
$PY scripts/selfcheck_gate.py --data 诊断数据.json --info      # 看门控为何跑/为何跳

> ⚠ 改了渲染脚本(build_report.py)后,门控会自动失效并在下一轮真跑一次浏览器级 ——
> 这是设计如此,不要用 --no-gate 把它绕过去,那会把「脚本改坏了」的窗口一直敞着。

自检覆盖:题数/得分/满分一致性、错题数与归因条数一致、待确认数一致、
四段齐全且总字数 ≤ 1800、正文无编码泄漏、无未替换占位符、
无 >None</>undefined</nan、交付件不含 SELFCHECK 残留、
打印按钮真实 click 后 window.print 被调用、no-js-error 兜底。

两条口径断言必须显式写(这是 v1.1.0 的验收线):

# ① 字数上限
assert total_chars <= 1800, "四段正文超 1800 字"
# ② 正文无编码:四段正文里不得出现编码形态
import re
CODE = re.compile(r"\b[A-Z]{2,3}-[A-Z0-9]{1,3}(-[A-Z0-9]{1,4}){1,3}\b")
for seg in ("overall", "strength", "improve", "advice"):
    assert not CODE.search(text_of(seg)), "正文出现内部编码"
# ③ 编码只能出现在括号内
for m in CODE.finditer(all_text):
    assert all_text[max(0, m.start()-1)] == "(", "编码未包在括号小字里"

走「一页一容器」的中间母版必须再加两条裁切断言(唯一能查出静默裁切的手段):

var clipped=[], over=[];
document.querySelectorAll('.page').forEach(function(p,i){
  if (p.scrollHeight > p.clientHeight + 2)
    clipped.push('p'+(i+1)+'('+p.scrollHeight+'>'+p.clientHeight+')');
  var pf = p.querySelector('.pf');
  var lim = pf ? pf.getBoundingClientRect().top : p.getBoundingClientRect().bottom;
  [].slice.call(p.children).forEach(function(c){
    if (c.classList.contains('pf')) return;
    var b = c.getBoundingClientRect().bottom;
    if (b > lim + 1) over.push('p'+(i+1)+'.'+c.className+'+'+Math.round(b-lim));
  });
});

别采信脚本的 success,要回读:脚本 exit 0 不等于内容完整。
至少点清业务对象个数(题数、四段字数、待提升项条数)与 JSON 对齐。

终检(必做):从 落盘的 DOCX 里用 python-docx 读回,逐项比对关键数字
(总分/满分/得分率/失分题数)与四段文本是否与数据一致,并确认四段都没有出现编码。


七、踩坑速查

坑 症状 解法
变量名 qn UnboundLocalError: cannot access local variable 'qn' 改名 q_no 等
手写数字常量 文案「3 个主责节点」实算 7 个 全部 len() 算出后注入
正文混进编码 家长看到 SW-G-X1-01-002 一头雾水 正文只写中文名;确需溯源才加括号小字,且不得进标题与结论句
报告写太长 八段式铺陈,家长只想知道「哪弱、怎么补」 固定四段式,总字数 ≤1800,超限先砍铺陈句不砍事实
行话泄漏 「元认知」「命题立意」「核心素养」 换成「为什么错」「出题人想考什么」「这块能力」
自指陷阱 扫「undefined」永远失败 断言范围限定内容容器,或先剥 <script>
只点元素数的自检 「计数正常但页面全空」查不出 加 no-js-error + 真实 click 事件模拟
前置链取 [-3:] 把最远的「抽样调查」当成方差失分的根因 取最近三层再反转
满分不符误报 有题未计分时被报错 区分「合计 < 声明(有未计分题,正常)」与「合计 > 声明(真错误)」
图谱文件口径混淆 同一知识点两套码 用与教材版本匹配的那份;跨项目引用先打印对方字段
空白区渲染成光标题 无失分题时只剩一行标题,读者以为生成失败 每一段在无内容时返回自解释文案,说明「为何空 + 补什么就能有」
空表无兜底行 &lt;tbody&gt;&lt;/tbody&gt; 触发自检 table-rows-nonzero 失败 空表必须塞一行 colspan 说明;同时保留 .empty 样式
只凭答题卡判分 答题卡只有涂卡痕迹,无题干无答案 全部标 pending_answer,不得据「看起来像错的」推断;报告显式声明依据边界
用 kmap.hits 算「知识点正确率」→ 全表假 0%(★ v1.6.0 实拍) hits 只为失分题建立映射,答对题无 hit → 分母里全是失分题,每行都算出 0%、全部标「明显薄弱」。家长读成「六块内容全都没掌握」——数字能算出来 ≠ 数字有意义 该表只报失分分布(题号/题量/常见错法),不报正确率。真正确率需全卷逐题映射,属上游能力边界,如实说明
len(t.rows) 当数据行数 表头占 1 行,24 个能力项被数成 25 行,断言与肉眼同时误判 数据行一律 len(t.rows) - 1
两个技能副本反向分叉 ~/.workbuddy/skills/X/ 与 X__skillhub/ 各自更新了不同文件,整目录覆盖必丢修复 逐文件 diff 取新:本次 kcode_lookup.py 取上架版(含 unit_scope 前缀补全),build_report.py/make_docx.py 取开发版(含 blank 计入失分)
上架版漏了 blank 修复 线上 v1.0.0 的 ERR_STATUS=(&quot;wrong&quot;,&quot;partial&quot;),孩子整题空着不写这件事从报告里彻底消失 两处 ERR_STATUS(build_report.py / make_docx.py)必须同步含 &quot;blank&quot;,改完 grep 双验
单选题答案与卷面不符但痕迹有歧义(v1.4.1 实测) 学生圈注的选项与参考答案不一致,但涂卡区/题号圈注模糊、可能只是草稿;据此判错就是臆造 不判错、不计入失分,改在「依据边界」的 missing_data 里如实说明「因痕迹歧义未据以判定」,并主动索要答题卡清晰照片。宁可少判一题,不可编一题
待确认题仍占 K 码分母(v1.4.1 实测,自相矛盾) 把 unreadable 的满分算进该 K 码分母,于是 WL-J-B4-02-001 显示「得分率 50%」而失分清单为空 —— 百分比凭空掉了一半,家长会以为孩子这块很差 口径:unreadable/pending_answer 分子分母都不计,只登记 todo_qs。聚合后断言:rate &lt; 90 的项必须有非空 loss_qs,否则口径错了
指望 DOCX 里有表格(v1.4.1 实测) 用户要求「统计结果用表格呈现」,但 make_docx.py 按契约只出四段式叙述文档,回读表格数恒为 0,交付后才被发现 DOCX 就是纯叙述件。要表格必须另出 Excel + 打印版 HTML 摘要(make_tables.py 模式:6 张表 = 总体/K码掌握度/逐题/归因/待确认/优先级)。开工先问清「要 Word 还是也要表格」
溯源编号用 · 连接 写成「能力项名·WL-J-B3-05-008」,自检的「编码必须在括号内」断言判 FAIL 统一写「能力项名(编号 WL-J-B3-05-008)」。不要嵌套括号(会变成「…应用(编号 …)」重复),改用破折号引出名:「……还差一步——欧姆定律在串联电路中的应用(编号 …)」
打印版 HTML 自检的三项硬形态(v1.4.1 实测) 自写摘要页在 print-css / kcode-mono / print-button-bound 三项判 FAIL,反复试才对齐 ① @media print 里必须同时含 page-break(写 .page{page-break-after:always});② K 码等宽字体 CSS 必须字面为 .kd{font-family:Consolas(点+类名+d+紧跟花括号,写 .kcode 或加空格都判 FAIL);③ 打印绑定必须写成 document.getElementById(&#x27;btnPrint&#x27;).addEventListener( 连续形态,包一层 (function(){var b=…})() 会 FAIL
关系表键名中英文混用 → 静默丢边 kcode_lookup.py 曾只认含「前置」二字的关系类型,而 kcode_en_primary 的关系表键是纯英文 prereq/parallel/extend → 556 条前置边全丢,前置链/外溢预警/公共根因三节内容集体消失且 exit 0 不报错 脚本已加 REL_TYPE_ALIAS+norm_rel_type()。新增图谱接入后必须断言 _pre/_next 非空,静默丢边比报错危险得多
unit_scope 前缀与节点键不同形 节点键 YY-X-B1-03,传 B1-03 时 startswith 恒假 → unit_total=0、覆盖率失真且不报错 脚本已支持自动补全前缀;接入新图谱后先确认 unit_total &gt; 0
用集合成员判断替代子串匹配 → 归因静默漂移(v1.2.0 实测) 预计算索引时把 hit=[x for x in segs if x in name](子串)写成 x in set(分词结果)(成员)→ 长考点名得分从 172 变 194,同分节点排序错位,考点被对齐到错误的能力项上 search_idx() 必须复刻 search() 的子串语义。改完索引务必跑 --selftest:它会逐例比对索引与直算结果,本次正是它抓出了这处静默漂移
首跑永远不命中缓存 算指纹时 kmap.graph_path 尚未回填 → 图谱层指纹取到 &quot;none&quot;,回填后第二次跑才变真哈希 算指纹前先调 resolve_graph_path() 显式解出路径,使首跑与后续跑指纹一致
指纹层划分错误 → 该失效的没失效 把四段正文混进"事实层"→ 改一句措辞就触发全链重算(白跑);或把 status 漏出事实层 → 改了判定却复用旧报告(最危险) 事实层只收「卷面看得见的事实」,status 必须逐题入指纹;措辞单独成层。改完用 report_cache.py 打印三层指纹验证
缓存把校验也跳过了 命中缓存后不跑终检 → 交付件早被截断也照样"通过" 缓存只跳过生成;存在性 + 大小断言 + 业务数量点清照跑。pipeline.py 的 §⑦ 无条件执行
派生数字在定义之前算 生成器里用占位 hack 引用后面才定义的列表 → 静默出错 派生量一律在被引用对象定义之后算,字段先留 None 再回填
overflow:hidden 静默裁切(最隐蔽) 固定高容器 + overflow:hidden,超出部分被裁掉不留痕迹;测高脚本报「无溢出」因为盒子恒定高度 加 §六 的两条裁切断言;测高脚本报 OK ≠ 没裁切
主表副表同页 优先级表 6 行 + 外溢表 15 行同容器 → 溢出 983px 副表独立成页;表内多项用行内 ; 而非 &lt;br&gt;
自检辅助函数取值写错 → 批量假 FAIL function Q(s){return ...length} 却按 Q(s).length 用 → 12 项断言集体 undefined 全判 FAIL 凡「批量 FAIL 且数值显示 undefined」,先怀疑自检脚本自身
document.title 分隔符 用 \|\| 作分隔符,回读时被「含空格的项」拆断 改用 ~~ 等不会出现在内容里的分隔符
临时目录与交付产物混淆 自检验证完的临时 zip 与真交付件分不清 交付件固定放工作根,临时件用完即删
核心版缺段 → 违反四段式硬契约(v1.3.0 实测) 分层交付初版让核心版只发「总体评价 / 待提升项 / 建议」3 段,把「优势」留给完整版 → 家长拿到手的第一版不是四段式,报告契约当场作废 核心版必须四段齐全;优势段暂无内容时返回如实说明的占位文案并置 _strength_placeholder=True。check_layers() 内置「核心版四段齐全」断言
并发结果顺序漂移 多线程回填后题号乱序 → 报告里题目位置随机跳,两次跑结果不一致 合并前按 _sort_key() 确定性排序(题号数值优先),不依赖完成顺序。跑两遍比对结果应逐字一致
失败题混进结果 某题并发时抛异常,被当作「未作答」静默计入失分 失败与空白是两回事:失败题不进对错统计、不编造判分,显式标记并隔离;自检断言失败数 == 题号 × 参与阶段数
流式先给估计值再纠正(最伤信任) 为抢首屏先推「约 60 分」,算完实际 58 分再改口 流式只推已经算出的确定性数字。宁可等 1 秒,不可先错后改 —— 先给结论再改比晚给伤害大
stream_report 取不存在的派生字段 读 derive() 没有的 n_blank(实际只有 blank_qs 列表)→ 流式里显示 None 派生字段名以其定义为准;取值前先确认键存在,或只从已知键列表里取
并发参数被当成纯加速开关 以为 --workers 越大越好,反而因锁竞争/上下文切换变慢 题量少(<8)或阶段本来就快时不要开并发;先跑 stage_timer.py 确认瓶颈真在模型侧
中文引号里的语法错误 print(&quot;四段不是&quot;一起跑&quot;。&quot;) → SyntaxError 中文语句里的强调引号用「」;英文双引号只做字符串定界
门控采信「存下来的指纹字符串」(v1.4.0 实测) 状态文件里存了算好的 fingerprint,decide() 直接比这个字符串 → 分项被改动(脚本更新/浏览器升级/手工编辑)时字符串不会跟着变,该跑的被静默跳过 指纹必须由存下来的分项重新合成(_stored_fingerprint()),任何一个分项变化都必然导致指纹不同。本次是靠自检第 6/7/10 项 FAIL 抓出来的
门控把文本级自检也跳了 为省时间把整层自检都门控 → 本次产物的占位符/编码泄漏/四段缺段全漏检 门控只作用于无头浏览器那一层;文本级检的是本次产物且只要毫秒,必须每轮照跑
跳过视为免检,长期不抽验 门控命中就一直不跑浏览器级 → 「脚本没变但行为变了」(如浏览器自动更新、字体变化)长期不被发现 记 since_smoke 计数,每 SMOKE_EVERY(默认 10)轮主动真跑一次;跳过一轮则计数 +1
失败也登记门控指纹 自检 HASFAIL 仍写了状态 → 下次直接跳过,缺陷固化 只有 ALLPASS 才登记。失败/跳过一律不写状态,且下次必跑
归因阶段被降档 为省钱把归因也交给快模型 → 归因质量崩塌,等于换了个技能 NEVER_DOWNGRADE = {&quot;attribute&quot;},check() 断言归因阶段不得出现任何非强档
识卷一刀切当快档 认为识卷只是「把字认出来」,主观题也走快档 → 手写推导看错,后面全盘皆错 分档不能只看阶段:主观题在识卷/判分阶段要反向升级到强档,判据用题面 type 而非模型输出
分档改变了产出内容 快档模型给出与强档不同的判分 → 同一份数据两次跑结果不同 分档只改「用哪个模型」;判分口径与四段式契约不变。跑两遍(--tier 与不加)比对判分结果应一致

八、环境

用途 需求
Python 3.10+(build_report / selfcheck / kcode_lookup 只需标准库)
Python 额外依赖 python-docx(出 DOCX 必需);缺库时降级为 [SKIP] 并指路,不算 NG
无头浏览器(可选) Edge / Chrome(msedge.exe、chrome.exe);仅中间母版做真实交互自检时需要
图谱根目录 环境变量 KCODE_ROOT 指向存放 kcode_* 文件夹的目录;未设置时从 cwd 及其祖先自动探测

> ⚠ 本技能不得写死任何开发者本机绝对路径(如 D:/...、C:/Users/...)。
> 图谱定位走 KCODE_ROOT,脚本自身路径走 __file__,解释器走 sys.executable,
> 用户数据走 cwd 或命令行参数。
> 否则他人安装后会在第一步就全线报「图谱文件不存在」——这是发布审核的常见退回原因。


九、可移植性与发布(★ 若要分享/上架,先读这节)

铁律:技能包内不得出现任何开发者本机的绝对路径(包括 SKILL.md 与 references 正文)。

类型 正确写法 错误写法
图谱数据目录 环境变量 KCODE_ROOT,缺失时从 cwd 及祖先自动探测 ROOT = &quot;D:/Work Buddy/教育培训&quot;
脚本自身位置 os.path.dirname(os.path.abspath(__file__)) 写死安装路径
解释器 / 外部工具 sys.executable;外部工具用环境变量 + 候选路径探测,找不到就 [SKIP] 并指路 写死 C:\Users\...\python.exe
用户数据 cwd 或命令行参数 写死开发者的工作目录

发布到 SkillHub(WorkBuddy 的技能入口检索的就是它):
1. 到 https://skillhub.cn 完成实名认证(人脸核身,不做无法发布)。
2. SKILL.md 的 YAML frontmatter 必填字段以平台报错为准(官方示例文档字段名与实际校验不一致):

字段 作用 长度上限 备注
display_name 中文展示名 暂未见限制 必填
display_name_en 英文展示名 ≤ 60 字符 必填;实测 65 字符被退回
description_zh 中文描述 暂未见限制 必填
description_en 英文描述 ≤ 1000 字符 必填;实测 1196 字符被退回
slug 唯一标识 2–128 kebab-case
version 版本号 — 合法 SemVer,如 1.1.0
description 本机技能发现用 — ⚠ 不能删:本机加载器只认这个键,删了就检索不到
summary license tags homepage 建议项 — 不阻断发布

⚠ 三个描述字段必须并存:description(本机)+ description_zh + description_en(平台)。
(本技能 description 与 description_zh 内容相同,一份文案两处复用。)

⚠ 长度用脚本量,不要靠眼估:写进 YAML 之前先实测字符数。
中英混排时肉眼对字符数的判断极不可靠——display_name_en 写 65、description_en 写 1196
都是这么来的。压到上限的 90% 留余量,便于后续微调措辞。

  1. ⚠ 所有描述性字段统一用单引号包裹(内部单引号写成 &#x27;&#x27;)。
    长英文里出现「英文冒号 + 撇号」(如 analysis: an examiner&#x27;s view)会让 YAML 报
    mapping values are not allowed here,加引号一次解决。改完必须 yaml.safe_load 回验。
  2. 打包为 zip(顶层放一个同名技能文件夹,包名 slug@version.zip),剔除 __pycache__ / *.pyc,
    SKILL.md 换行统一 LF,确认目录内没有嵌套同名副本。
  3. 提交后走「内容合规 + 漏洞扫描 + AI 模型安全评估」三线并行审核,1–3 个工作日;
    「提交」≠「上架」,通过后还要在技能列表点上架。

更新已上架的技能:改本地技能目录 → 重打 zip → 用同一 slug、递增 version 重新提交
(平台按 slug 识别为「更新」而非新建),无需先下架。版本号规则:删功能/改契约 → 次版本号 +1。

完整操作手册见工作根目录 技能发布指南-SkillHub.md。


十、脚本清单与参考文件

脚本(scripts/)

脚本 职责 何时用
kcode_lookup.py 能力项对齐 / 前置溯源 / 校验;内置图谱编译缓存 每次:--in 出 kmap;改索引后跑 --selftest
build_report.py 渲染中间母版与家长版四段式 HTML 每次
make_docx.py 从 JSON 直接重建 DOCX(唯一交付件) 每次
selfcheck_html.py 交付件自检:文本级必跑 + 浏览器级(--no-browser 可只跑文本级) 每次;浏览器级受门控
pipeline.py 总编排:指纹 → 对齐 → 母版 → 家长版 → 自检 → DOCX → 终检 默认入口
stage_timer.py 耗时剖面:哪一段花了多少秒 觉得慢时先跑它,别凭感觉优化
report_cache.py 三级指纹缓存 + --info 查看状态 想确认「为什么这次没省下来」时
slice_for_llm.py 数据按需裁剪 + 口径自检 准备让模型写四段正文之前
parallel_units.py 题目级并行调度:拆单元 / 确定性合并 / 失败隔离 题量 ≥8 且逐题阶段慢时;--workers 生效
stream_report.py 四段并发 + 流式 + 分层交付;含 --layers 契约自检 报告已算完核心数字、要尽早出结论时
model_tier.py 分档模型路由:快档 / 强档指派 + 契约自检 想省成本时;--plan 出分派表
selfcheck_gate.py 自检门控:按渲染脚本指纹决定是否重跑无头浏览器 默认启用;改过渲染脚本会自动失效

参考文件(references/)

文件 何时读
references/report-schema.md 动手前必读:数据契约、四段式字段与派生量铁律
references/attribution-rules.md 做 ④ 归因时读:四类判据、认知分析框架、分学段口径
references/kcode-graph-index.md 做知识点定位时读:全库索引、三种存储形态、关系归一
references/delivery-spec.md 做交付时读:DOCX 必设项、版式套、字数校验
assets/sample-junior-physics.json 需要看完整样例数据时(含 4 类归因与四段式成稿)

> ⚠ 诊断报告生成的耗时瓶颈不在本地脚本(实测 kmap 对齐 40 题仅 0.1–0.2 秒)。
> 真正的大头是模型侧的识卷 / 归因 / 成稿与无头浏览器自检。
> 优化前务必先跑 stage_timer.py 拿到剖面 —— 见 §四之二。
>
> 四轮优化分别治的是不同的病(不要混为一谈):
> | 轮次 | 手段 | 治的是 |
> |---|---|---|
> | v1.2.0 | 缓存与预计算 | 「同一份东西重复算」 |
> | v1.3.0 | 题目级并发 / 四段分批 / 流式 / 分层交付 | 「串行等着算」 |
> | v1.4.0 | 分档模型 | 「便宜的活花了贵价」 |
> | v1.4.0 | 自检门控 | 「没必要每轮做的检查」 |


十一、典型用法

用户:「这是孩子的物理卷子照片,帮我批改并分析一下。」
→ 核实教材版本(成都初中物理=教科版)→ 逐题识卷 → 判分 → 双视角解析 → 知识点定位(脚本)
→ 四类归因 + 上游溯源 → 补缺优先级 → 四段式成稿 → 出 DOCX。

用户:「这几张作业拍糊了,能批吗?」
→ 能。模糊题标「待确认」,只对清晰题判定,报告末尾单列补件提示。
不要因为部分糊就拒单,也不要为了凑数去猜。

用户:「不需要那么细,只想知道错在哪、先补什么。」
→ 正是本技能的默认形态(四段式本来就是「错在哪 + 先补什么」)。
把「待提升项」压到 2 条、建议压到 2 条即可,不改结构。

用户:「把上次那份报告改成给学生自己看的版本。」
→ 只改称呼(「孩子」→「你」)与语气,四段结构与字数上限不变。

用户:(只上传答题卡照片)「批改一下。」
→ 这是高频且最容易做错的一类。答题卡上只有涂卡痕迹与作答笔迹,
没有题干、没有参考答案、没有分值分布 —— 因此:
1. 逐题照实识读作答(涂卡选项、填空文字),一个字都不要猜;
2. 全部标 pending_answer(涂改不可辨的标 unreadable),绝不据「像错的」推断对错;
3. 知识点定位改走 points[] 通道:把卷面可见的作答内容映射到能力项,标 role=主;
这只表示「本题涉及该能力项」,不表示失分;
4. 报告仍出四段式,但「优势」「待提升项」走空白兜底文案(如实说明 + 补什么就能有);
5. 交付后必须主动向用户索要:原卷、参考答案/评分细则、缺失页。
同时说明「补齐后重跑本流程即可自动填充」——让用户知道这不是终点。
> ⚠️ 切勿因为「报告不好看」而去编造判分。一份诚实的空白报告 + 明确的补件清单,
> 远比一份编出来的「诊断」有价值。这也是本技能最核心的红线。

常见问题

5 问
答案由本站依据条目字段整理
学-练-测-评一体化怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_edbd5466/xue-lian-ce-ping。安装方式为未标注。装完刷新技能列表或重开客户端。

学-练-测-评一体化支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

学-练-测-评一体化权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

学-练-测-评一体化收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

学-练-测-评一体化用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。