Skip to content
Back to skills

Cnki Edu Exam Score Analysis

ASecurity

中小学考试成绩数据分析与学情诊断:输出 HTML 报告、PDF 与 Excel 结果册三件套。

  • 417 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added November 8, 2026
datapythongobash

Works with

  • mcp

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 10 files and shows the line behind each finding

Scanned November 8, 2026

npx -y skills add infometa/workbuddyskills --skill cnki-edu-exam-score-analysis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cnki Edu Exam Score Analysis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cnki Edu Exam Score Analysis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/infometa-cnki-edu-exam-score-analysis/badge)](https://www.skillsdirectory.com/skills/infometa-cnki-edu-exam-score-analysis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cnki-edu-exam-score-analysis
display_name: 学业质量分析
display_name_en: Score Analysis
description: 中小学考试成绩数据分析与学情诊断:输出 HTML 报告、PDF 与 Excel 结果册三件套。
description_zh: 中小学考试成绩数据分析与学情诊断,输出 HTML 报告、PDF 与 Excel 结果册三件套。
description_en: Analyzes K-12 exam scores and diagnoses learning status, delivering an HTML report, a PDF and an Excel workbook.
category: education
version: 1.0.1
author: 知网 edu
---

# 中小学考试成绩数据分析 Skill

把一次(或多次)考试成绩数据,转化为老师能直接用于**讲评、家长会和教学改进**的完整分析报告。

**标准交付 = 三件套**:HTML 报告(可打印、可另存 PDF)+ PDF + Excel 结果册。Excel 结果册为默认产出,无需用户额外要求。

**`.json` 底稿不交付**(用户要求 2026-10-12):`analysis.json`(统计底稿)与 `narrative.json`(教学解读)
只是**中间产物**,生成后归档到交付目录下的隐藏子目录 `.底稿/`,`present_files` 只传三件套。
理由:老师拿到 `.json` 打不开也看不懂用途,摆在交付目录里只会显得杂乱;报告与结果册已经承载了
全部结论,底稿只在「追问某个数字 / 改话术重出」时才用得上。

## 🔐 前置权限校验(最高优先级,必须最先执行)

> 权限校验的「三态诊断 / 通用版兜底 / 强制转化卡 / 连接器加载指引」统一见本技能 `references/_shared.md`「一、权限固定提示」,本章节仅保留本技能专属说明,不重复展开。

> **权益 ≠ 引用(本技能适用)**:本技能**统计本体**(分数段、四率、得分率、临界生/分层名单、进退步追踪)全程基于用户上传的成绩数据,**纯模型生成、不依赖知网**。但「教学解读 / 改进建议」环节可引用知网实证文献(如《心理月刊》等考试焦虑、学习心理研究)作为专业增强——这属于**弱依赖 / 可选增强**,不是硬依赖:
> - 权益 `true`:解读可引知网实证文献提质;建议优先用 `mcp__<SERVER>__searchVectorBJ` 取真实文献,而非仅凭模型记忆,确保可溯源。
> - 权益非 `true`:统计照常出,解读改用通用教研经验,**不得标注"知网来源"、不得编造知网文献**(严守 `⛔ 严禁编造知网数据` 红线),可在对话交付说明里提示"接入知网后可获取实证文献支撑"。
> 权益是"能不能用知网能力"的闸门,不是"该不该引用"的开关;本技能的统计本体不引用,解读环节可引可不引。

## 何时使用

- 用户上传/粘贴成绩表(Excel、CSV、表格文本),要求分析成绩
- 用户要求"考试质量分析""学情分析""成绩分析报告""讲评优先级""临界生名单"
- 用户给出多次考试数据,要求个体进退步追踪

## 核心机制:学科分析模式(先判断,再执行)

| 模式 | 触发条件 | 执行方式 |
|------|---------|---------|
| A. 单科分析 | 只指定 1 个学科 | 全篇只分析该科,6 个维度全部围绕该科 |
| B. 多科分别分析 | 指定 ≥2 个学科 | 每科独立一章,6 个维度在每科内完整展开;最后加「跨学科横向对比」 |
| C. 全学科分析 | 说"所有学科/全部"或给出完整学科列表 | 同模式 B |

多科报告结构:核心结论摘要(跨学科视角,5 条)→ 各科完整 6 维度 → 跨学科横向对比 → 教学改进建议。
多科模式下,所有图表标题统一加学科名前缀(如「【数学】分数段分布」)。

## 工作流程

### Step 0 · 环境准备

脚本位于本 skill 的 `scripts/` 目录。**分析与渲染本身只用 Python 标准库**(图表为自研内联 SVG,不依赖
matplotlib 之类);唯一的外部依赖是 **openpyxl**,用在三处:① 读 `.xlsx` 成绩数据(`.csv` 不需要它);
② 生成 Excel 结果册;③ 跑 `scripts/selftest.py`(它要造测试用的 xlsx)。

**用哪个解释器(重要)**:**版本目录**下的解释器(`$HOME/.workbuddy/binaries/python/versions/<版本>/python.exe`)
**没有** openpyxl,直接跑会报 ModuleNotFoundError。请统一用受管 venv:

```bash
PY="$HOME/.workbuddy/binaries/python/envs/default/Scripts/python.exe"
"$PY" scripts/exam_analysis.py ...     # 建表 / 分析 / 渲染 / 自测都用它
```

> 路径一律写成 `$HOME/...`(Windows 下 `$HOME` 即用户主目录),文档里不写死具体用户名。
> 若环境变量未生效,可用 `echo "$HOME"` 核对后拼出实际路径。

缺依赖时用**同一个**解释器安装(不要用全局 pip):`"$PY" -m pip install openpyxl`。
`build_excel.py` 在缺 openpyxl 时会打印带解释器路径的安装指引并以退出码 2 结束,不会抛裸异常。

PDF 依赖本机 Edge/Chrome(脚本自动探测);`.xls` 旧格式需先转存为 `.xlsx` 或 `.csv`。
自测整条链路:`"$PY" scripts/selftest.py`(**48 个回归用例**,覆盖曾经踩过的坑);
`"$PY" scripts/make_sample_data.py --out 示例成绩.xlsx` 生成可复现的示例数据。
不确定用哪个工作表时先跑 `"$PY" scripts/exam_analysis.py --data 成绩.xlsx --list-sheets`。

### Step 1 · 执行前确认(必须,用户未说明时逐项询问)

1. 分析学科范围?(单科 / 多科 / 全部 —— 决定模式 A/B/C)
2. **每科满分是多少?**(最容易被忽略、后果最严重的一项 —— 见下方「满分设定」。
   **分制多为 100 分(常规)、150 分、10 分、5 分**;语文/数学可能是 100 也可能是 150,
   英语可能是 100/120,小学科常是 10 分制、5 分制。
   **不要默认按学科名称猜满分**)
3. **主分析班级**是哪一班?(决定逐题统计的「班级层」——见下方「统计范围」。不指定则默认样本中的
   第一个班;**多班样本务必问清**,否则班级层会分析成别的班,老师对着别人的班看半天)
4. 及格线、优秀线、低分线是否用默认值?(默认按满分 ×60%/85%/40%)
5. 是否有年级均分 / 区市均分作为对比基准?
6. 是否有历次成绩?**若有,历次表里有没有「序号」或「日期」列?**(没有的话必须让用户给出考试先后顺序,
   否则趋势判定可能反过来 —— 见「历次成绩顺序」)决定维度 6 用折线追踪还是横截面分层
7. 是否有逐题得分与知识点归属?(决定维度 3、4 是否生成;没有就不生成这几节 ——
   **绝不编造知识点**)。**逐题表里有没有「学号」列很关键**:有它才能把逐题统计分成「班级层 + 年级层」、
   也才能**逐班**给出每道小题的得分率;没有的话两层数字相同、各班对比也不生成。
   (小题分分析**只到班级与年级层,不下到每个学生**——用户要求 2026-10-11)
   可提议由 AI 从题目内容推断知识点,但推断出的归属必须在逐题表的
   「知识点 / 模块」单元格里写明「AI 推断」,并在交付说明里交代
8. 交付格式:默认 **HTML + PDF + Excel 三件套**。仅当用户明确说"只要 HTML/不要 Excel"时才调整——
   记住"三件套"是默认约定,不要主动询问要不要 Excel。`.json` 底稿(`analysis.json` / `narrative.json`)
   **不属于交付物**,归档到隐藏目录 `.底稿/` 即可,也不要问用户要不要。

用户已说"直接分析/不用问"时:满分仍**必须**确认(除非能从数据唯一反推,见下);其余按默认值执行并把
所做假设写进 `data_notes`(报告正文与 Excel 结果册都**不展示**,交付时必须在对话里复述)。

### 满分设定(最严重的一类错误:猜错满分 = 整份报告作废)

满分决定及格线 / 优秀线 / 低分线,进而决定及格率、优秀率、分数段、形态判定与分层名单。

**分制分布:常规分制为 100 分**,其次 150 分、10 分、5 分;120/200/750 等较少见。
「常规」只描述常见程度,**不是任何一科的默认值**——所以引擎的解析顺序是:

| 优先级 | 来源 | 行为 |
|--------|------|------|
| ① | `params.json` 的 `subjects.<学科>.full` | 直接采用,不提示 |
| ② | 命令行 `--full "语文=100,数学=100,物理=10"` | 直接采用,不提示 |
| ③ | 由该列成绩反推(唯一候选) | 采用,但**标记「待确认」**:写进 `meta.full_to_confirm`、各学科章首小字标「待确认」,Excel「01 阅读说明」置顶点名 |
| ④ | 推断不出 / 推断出多个可能 | **停止分析(退出码 3)**,打印待确认清单与补救命令,由你回头问用户 |

- 反推规则:取「最小的大于等于最高分的常见满分」,且要求最高分 ≥ 该满分的 85%
  (例:最高 88 → 100 分制;最高 145 → 150 分制;最高 9 → 10 分制;最高 5 → 5 分制)
- **最高分 < 满分的 85%** 或**多个分制都说得通**(如最高 68 → 70/75/80 都可能)时,一定停下来问用户,
  不要硬猜。用户一句话回答后用 `--full` 重跑即可(全流程自动,成本很低)
- 退出码 3 的清单里,候选分制已按常见度排好(**100 排首位并标「常规」**),并附「常见满分:100(常规)/
  150 / 10 / 5」,把这段原样转达给用户最省事
- 退出码 3 表示「需要用户补充信息」,不是脚本故障
- 用户明确表态"不用问,就按常规分制"时,加 `--full-policy default`(**一律按常规 100 分制**兜底,
  仍会写入「待确认」提示);若某科实际是 150/120/10/5 分制,必须用 `--full` 改正后重跑
- **交付前一定核对** `analysis.json` 的 `meta.full_to_confirm` 是否为空;非空时必须在交付说明里
  向用户复述哪些学科的满分是推断来的

### 统计范围(务必向用户说清)

| 维度 | 统计范围 |
|------|------|
| 1 基础统计量 / 2 分数段 / 5 对比分析 | **主分析班级**(`--focus-class`);未指定则为样本中的第一个班 |
| 3 逐题得分率 | **两层 + 逐班**:班级层 = 主分析班级;年级层 = **全部样本(含各班)**;**各班层** = 每个班在每道小题上的得分率(用户要求 2026-10-10 / 11) |
| 年级层总览 | **全年级**(全部样本):班级总分排名、各学科班级排名、全年级各科四率与分数段 |
| 4 知识点 / 6 个体名单 | 与 1/2/5 一致,收敛到主分析班级 |

引擎会把实际范围写进 `analysis.json`(`meta.individual_scope` / `grade_scope_count` / `two_level_questions`),
并落在报告封面、逐题得分率小节的小字与分节标题、Excel「06 学生成绩与排名」标题上。
**单班样本会自动按班级名标注**(主表没有「班级」列也一样)——否则会出现封面写「初一3班」、排名表却写
「样本(含各班)」的矛盾标签。**不要**把全年级排名当成"班内排名"讲给老师。

**逐题表的「学号」列决定能分几层**(2026-10-10):
- 有学号 → 班级层 + 年级层两层并列,并**逐班**给出每道小题的得分率(报告维度 3 的「各班·逐题得分率」矩阵)
- 没有学号 → 两层数字相同(都是全部样本),各班对比也不生成——逐题表补一列「学号」即可全部启用

`--focus-class` 指定的班级在主表里**不存在**时,范围回退为全部样本,**封面标签也同步改成「全部样本」**
(`meta.focus_class_requested` 保留用户原本给的名字),避免封面写一个并不存在的班。

只分析**部分学科**时(主表里还有别的学科列没算进来),结果册里的合计列写「**所选学科总分**」而不是
「全科总分」——后者会让老师误以为那是学校层面的整份总分(`meta.partial_subjects` / `meta.total_label`)。

### 历次成绩顺序(容易出错,注意核对)

引擎判定先后的优先级:`--history-order` 显式指定 > 历次表的「序号」列 > 「日期」列 > 考试名称里的序号
(「第2次」<「第10次」,中文数字「第一次」与「二模」同样解析)。

- 「第1次月考 / 期中考试 / 第2次月考 / 期末考试」这种混排名称**建议**给「序号」或「日期」列,
  否则用 `--history-order "第1次月考,期中考试,第2次月考,期末考试"` 显式指定
- **排不出顺序时引擎只警告、不阻断**(用户 2026-10-08 定):打印 `[警告]` + 补救命令,把告警写进
  `data_notes`,报告「核心结论摘要」与维度 6 用醒目样式标注、Excel「07」也标注,
  然后**照常出报告**——维度 6 的顺序存疑不该让其余 5 个维度也拿不到
- 为什么还要警告:按名称硬排会把「持续进步」判成「波动」、进步榜点错人,而且**不会报错**,
  属于最危险的一类静默错误。看到这条警告就要在交付说明里提醒老师「趋势结论待核对」
- 有「序号」/「日期」列,或名称里都带序号(如「第1次月考…第10次月考」「第一次…第三次」)时
  顺序可靠(`meta.history_order_source` = `explicit`/`seq`/`single`,`history_order_reliable=True`),
  不会出现告警
- 历次表**只有 1 次考试**时,谈不上趋势:维度 6 自动退回横截面分层,并在 `data_notes` 里交代
- 交付前扫一眼 `analysis.json` 里某个学生的 `individuals.history[0].exams` 是否符合真实时间线

### Step 2 · 整理数据(xlsx/csv,三个工作表可选)

| 工作表 | 形式 | 必需列 |
|--------|------|--------|
| 主表(默认第一个) | 宽表,一行一个学生 | **学科成绩列**(列名=学科名);学号 / 姓名 / 班级**都可缺**,缺学号自动用行号代替 |
| `逐题`(可选) | 长表,**一行 = 一个学生一道小题** | 学科、题号、满分、得分(**学号** —— 有它才能分「班级层/年级层」两层、才能逐班给出每题得分率)、知识点(可选;**没有就不生成维度 4 / Excel 05,引擎绝不编造知识点**) |
| `历次`(可选) | 长表(或带学科列的宽表) | 学号、考试、总分;**强烈建议加「序号」或「日期」列**;**想对比历次各学科就再加学科列(语文/数学…)或改用「学号/考试/学科/分数」长表**;姓名 / 班级 / 排名 可选 |

- 学科列名支持别名:「道法」「德法」≡「道德与法治」,匹配用、输出不改名
- 表头前有合并大标题行会自动跳过;第一个工作表只是封面/说明页时会自动改用下一个有数据的表
- 完整字段说明、params.json / narrative.json 模板见 `references/data-and-params.md`

### Step 3 · 运行分析引擎

```bash
"$PY" scripts/exam_analysis.py \
  --data 成绩.xlsx \
  --exam-name "高二期中考试" \
  --subjects "数学,语文,物理" \
  --full "数学=150,语文=150,物理=100" \
  --focus-class "高二(3)班" \
  --history-order "第1次月考,期中考试,第2次月考,期末考试" \
  --params params.json \
  --out analysis.json
```

- `--subjects` 留空或填"所有学科"则自动识别数值列
- `--full` 各科满分(**推荐显式给**);`--full-policy default` 表示满分缺失时一律按常规 100 分制继续
- `--focus-class` 显式指定时,维度 3/4/6 也收敛到该班(范围统一)
- `--history-order` 可选:历次考试的先后顺序,逗号分隔;历次表既无「序号」也无「日期」、名称又排不出先后时**强烈建议给**(不给只警告不阻断)
- `--params` 可选:学科满分/自定义及格线/基准均分(模板见 references)
- `--list-sheets` 只列出工作簿里的工作表后退出,用于挑 `--sheet`
- 产出 `analysis.json`:全部统计结果,是报告与后续追问的数据底座
- **退出码 3 = 缺少必要信息**(目前只有「满分推不出」会返回 3),看 stderr 的 `[需确认]` 清单并回头问用户;
  历次顺序判不出**不再阻断**,只打 `[警告]` 并在报告里标注(见「历次成绩顺序」)

### Step 4 · 撰写教学解读(narrative.json,可选但推荐)

`analysis.json` 只有数字;**教师视角的解读、归因和建议由你(AI)撰写**,写进 `narrative.json`:

```json
{
  "summary": ["核心结论 1…", "核心结论 2…"],
  "subject_notes": { "数学": { "stats": "…", "bands": "…", "questions": "…", "kp": "…", "comparison": "…", "individual": "…" } },
  "cross_note": "跨学科对比解读…",
  "improvement": { "common": ["…"], "kp_priority": {"数学": ["…"]}, "students": {"数学": ["…"]}, "actions": ["…"] }
}
```

不提供 narrative.json 也能出报告(脚本生成规则化兜底解读),但质量明显更低——**正式交付务必自己写**。
写作要求:结论必须有数字支撑;讲评建议落到具体题号/知识点;学生名单直接点名。

### Step 5 · 渲染三件套(HTML + PDF + Excel)

**一条命令出全套**(推荐):

```bash
"$PY" scripts/report_builder.py \
  --analysis analysis.json \
  --narrative narrative.json \
  --out "高二期中考试_数语物_成绩分析报告.html" \
  --pdf
```

- 输出单文件 HTML(图表内联 SVG,自包含,可浏览器打开、可打印、可另存 PDF)
- `--excel` **默认开启**:自动在同目录生成 `…_成绩分析结果册.xlsx`(**6–10 个工作表**:缺逐题数据时不生成
  「04 逐题得分率」,缺知识点数据时不生成「05 知识点优先级」,单班样本不生成「09 年级班级排名」,
  无历次成绩不生成「10 历次成绩对比」)。
  用 `--no-excel` 关闭;用 `--excel-out 路径.xlsx` 指定输出位置。
- **缺失的板块直接不生成**:维度 3(逐题得分率)、维度 4(知识点热力图)在没数据时**整节不出现**
  (标题、表格、图表都不渲染,章节名也会从「完整 6 维度分析」改为「N 个维度:…」),
  报告里**不写任何「未生成」说明小字**——为什么没有只在**对话交付说明**里讲(用户要求 2026-10-11)。
  **不要**再回头补「数据缺失」占位板块,也不要写占位文字。
- **没有知识点数据时**(用户要求 2026-10-11):凡是涉及知识点的地方**都不显示那一列 / 那一节**——
  维度 4 整节不生成;**Excel 也不要有「05 知识点优先级」这张表**(含「01 阅读说明」的工作表导航,
  不摆空表、不写「数据缺失」占位)。判定「没有知识点数据」只有一处规则(引擎 `norm_kp()`):
  没有「知识点」列、整列为空、**或整列只填了 `-`「/」「—」「无」「未标注」「待定」这类占位符**,
  都算没有——占位符最容易漏判,会造出名字叫「-」的假知识点、让 05 表凭空出现;
  逐题表与高低分试题清单里不摆空白的「知识点」列;跨学科「各学科 TOP3 薄弱知识点」
  **不整块消失**,退回按**每题得分率**给出「各学科 · 薄弱试题 TOP3」;教学建议的「知识点薄弱点
  (讲评优先级)」**改按小题得分数据来分析**,标题换成「薄弱题讲评优先级(按小题得分率)」
- **标题序号全报告统一为「一、(一)1.、(1)a.、(a)」**(用户要求 2026-10-11):章节用 `一、`、
  章内小节用 `(一)`、更细一级用 `1.`。序号由渲染脚本按**实际出现的标题**连续编号、**缺章节不跳号**;
  **「目录」标题与「核心结论摘要」本身不编号**(目录里列出的章名照常带「一、二、…」,与正文同源)。
  各学科章节内的维度小节**不再重复写「维度 N ·」**,只写小节名(如「(三)逐题得分率」「(四)对比分析」)
  ——两套编号并存会在维度缺失时错位成「(四)维度 5」
- **目录不要自动生成的阿拉伯序号**(用户要求 2026-10-11):目录用 `<ul>` + `list-style:none`,
  **不出现 1./2./3.**(条目里已经有「一、二、…」,再加一层是重复编号)
- **含题号的表格一律按题号升序**(用户要求 2026-10-11):班级层逐题表、年级层逐题表、各班逐题矩阵、
  知识点表的「涉及题目」、Excel「04 逐题得分率」——纯数字按数值排(1 → 2 → 10),非数字题号排在后面。
  **讲评优先级 P1…Pn 另按得分率升序单独标注**,不再靠行序表达(行序现在是题号序,两者不是一回事)
- **清单项一律写纯文本**(用户要求 2026-10-11:「`<li>` 这个符号去掉,HTML 和 PDF 都改」):
  列表外壳由 `ulist()` 统一加,且它会先 `esc()` —— 传进去的字符串**不要自己拼 `<li>` / `<b>`**、
  **也不要自己 `esc()`**。自带标签会被转义成字面文本直接印在页面上(曾每份报告印 50 处 `&lt;li&gt;`);
  自己 `esc()` 则会把知识点名里的 `&` 转两次。要加粗就写 `**…**`,交给 `inline_md()`。
- **姓名与学号各占一列**(用户要求 2026-10-11):报告的学生排名表、追踪表,结果册的 06/08 表都是
  **学号一列 + 姓名一列**(不合并、不写成「张三(S01)」);数据里**没有真学号时「学号」列整列不出现**
  ——绝不用 `#1/#2` 这类兜底编号冒充学号(判定见 `meta.has_student_id`)
- **报告里不指向「随附的结果册」**(用户要求 2026-10-11):PDF 是单独一份,读者手上不一定有那份 xlsx,
  写「完整数据见随附的结果册」会让人找不到。只交代「本表仅展示前 N 名,共 M 人」这种事实
- **高分/低分试题清单项不套 `<b>`**(用户要求 2026-10-11):直接写「第6题(共性错题):得分率 …」
- **维度 3 按学科统计,绝不混科**(用户要求 2026-10-10 / 11):1. 班级层逐题(本班,含讲评优先级)
  2. 年级层逐题(全部样本,含判定)
  3. **各班 · 逐题得分率**矩阵(行=题号、列=每个班 + 全年级)
  4. **得分最低**的试题清单 5. **得分最高**的试题清单(按本学科分别给出)。
  两层表格都按**题号升序**;高低分清单按得分率取前 5(语义如此,不按题号排)。小题分**不下到每个学生**
- **分数段一律显示具体分数**(用户要求 2026-10-11):维度 2 本班表及其「年级层 · 分数段分布」、
  维度 5 的逐班分数段表,「分数段」列都按该科满分换算成**实际分数区间**(如「0 – 90 分」「135 – 150 分」),
  不再单列「对应分区间」,也不用百分数
- **「各学科…」的清单/表格一律按学科分别成表**(用户要求 2026-10-11):**每张表正上方用小标题写出学科名称**
  (如「【数学】分数段分布(全年级 · 满分 150 分 · 135 人)」「【语文】TOP3 共性错题」)。
  适用范围:年级层「全年级各学科分数段分布」、历次「年级各学科四率」「班级各学科四率」、
  跨学科「各学科 TOP3 薄弱知识点 / 各学科 · 薄弱试题 TOP3 / 各学科 TOP3 共性错题」
- **新增「年级层 · 班级排名与全年级指标」章节**(用户要求 2026-10-11,多班样本才生成):
  班级总分排名 → 各学科班级排名(格内为**平均分** + 名次,名次按**得分率**排定)→ 全年级各学科四率
  → 全年级各学科分数段分布(**按学科分别成表**、表上方标学科名,分数段写成**实际分数区间**,不用百分数)
- **新增「历次成绩对比(年级 / 班级)」章节**(有历次表才生成):历次年级总分走势、历次年级各科四率
  (**按学科分别成表**)、历次各班总分(单独一张表)与各科(**按学科分别成表**);
  历次表只有总分时如实说明"只到总分维度",**不编造学科历次数据**
- **四率(优秀 / 良好 / 合格 / 不合格)为互斥四档**(用户要求 2026-10-11):优秀 ≥85%|良好 70–85%|
  合格 60–70%|不合格 <60%,四者相加 100%,可与「分数段分布」对照;维度 1 里沿用的「及格率(≥60%)」
  是累计值,与四率不在同一层,两个都保留、讲评时不要混用
- **报告与 Excel 结果册都不承载「数据说明」**(用户要求 2026-10-08):缺失值/统计范围/基准/来源/
  未生成表的原因等数据质量交代一律不进正文,也不进结果册,改由 ① 各学科章首满分小字、
  ② 「核心结论摘要」的 ⚠️(顺序存疑时)、③ **对话交付说明**承载。封面与 Excel「01 阅读说明」
  也不列「满分设定 / 分数线设定 / 数据来源」这类内部字段(满分与三条分数线已逐列写在
  Excel「02 学科总览」,不需要再复述一遍)。
- `--pdf` 自动调用本机 Edge/Chrome 无头打印;失败则提示用户在浏览器"打印 → 另存为 PDF"(A4,边距 2cm)
  - **页眉页脚必须关掉**(用户要求 2026-10-11):脚本已同时给 `--print-to-pdf-no-header` 与
    `--no-pdf-header-footer`。否则每页页脚会印出 `file:///C:/…` 的本地路径与打印时间;
    手工另存时也要在打印对话框取消"页眉和页脚"
  - **PDF / Excel 文件属性里的生成侧元数据要清掉**(用户要求 2026-10-12):无头浏览器会把
    浏览器 UA 与渲染引擎版本写进 PDF 的 `/Creator`、`/Producer`(`Mozilla/5.0 … HeadlessChrome/…`、
    `Skia/PDF m…`),Excel 的工作簿属性会写库名 `openpyxl`——这些在「文档属性 / 文件 → 信息」里可见,
    属于内部信息。脚本已自动处理(PDF 用**等长替换**抹掉、不动 xref;Excel 属性置空),
    有残留会打 `[警告]`。交付前顺手扫一眼属性面板即可
  - **PDF 与 HTML 同源**:报告正文改了就必须连 `--pdf` 一起重跑,不要只重出 HTML
- **报告与结果册必须同步重出**(用户要求 2026-10-11):报告里改了什么(题号升序、学号列、
  分数段用具体分数…),Excel 结果册要跟着改并重出——两处讲的是同一件事,不能只改一头。
  结果册「03 分数段分布」以**具体分数**为主列(「分数段(分数)」在「分段(占满分比例)」之前,
  末档按 `min(hi, 1)` 收成满分、写成「135 – 150 分」,不要拼成「满分 分」);**Excel 单元格是纯文本**,表注里不要写 Markdown 的 `**`
- HTML/PDF/Excel 三者文件名同源:`{考试名}_{学科范围}_成绩分析报告.{html,pdf}` 与 `…_成绩分析结果册.xlsx`
  (学科范围 ≤4 科连写如 `数语物化`,≥5 科写 `全7科`;**不含顿号**,避免路径问题)

**也可单独重跑任一件**:

```bash
# 只重出 Excel(改了数据或想要新命名时)
"$PY" scripts/build_excel.py --analysis analysis.json \
  --out "高二期中考试_数语物_成绩分析结果册.xlsx"
```

Excel 生成器只依赖 `analysis.json`(学生成绩从各科 ranking 还原,无需原始成绩表,也不再需要 narrative.json)。

### Step 6 · 交付

用 **present_files 一次性呈现**,只传下面三项(第一项自动打开预览):

1. **HTML 报告**(会以内嵌浏览器打开)—— `高二期中考试_数语物_成绩分析报告.html`
2. **PDF** —— 同名 .pdf,用于打印/发家长/教研组
3. **Excel 结果册** —— `高二期中考试_数语物_成绩分析结果册.xlsx`(6–10 表,缺数据的表不生成)

**不要传 `analysis.json` / `narrative.json`**(见开头「`.json` 底稿不交付」)。
两者在渲染完成后移入 `<交付目录>/.底稿/`:

```bash
mkdir -p "<交付目录>/.底稿" && mv analysis.json narrative.json "<交付目录>/.底稿/"
```

底稿**不删**——它让「追问某个数字」不必重算、改 `narrative.json` 后可直接重出报告;
用户若明确要求清掉再删,并在回复里说一声。

补充:
- **交付物说明写在对话回复里,不要写进报告**:报告的正文到「教学改进建议」为止,不放
  「附录 · 交付物与脚本说明」之类的章节(Excel 有几个表、文件名怎么命名、脚本怎么复用、配色代码
  都是内部信息,老师/家长看的正式报告里出现这些是越界)。报告末尾只有一行页脚。
- 回复里也**不要罗列 `.json` 底稿**,只讲 HTML / PDF / Excel 三个交付物;底稿位置一句话带过即可
- 若用户要 Word:**本 skill 没有现成的 Word 脚本**,需按 `references/report-spec.md` 临时用 python-docx
  从 analysis.json 重建;图表建议改为"先出 PDF 再转 Word"或截图嵌入,不要在正文里现画 PNG
- 交付时顺带说明本次的统计范围(逐题是**班级层 + 年级层两层**,班级层是哪一班)、被剔除人数、
  以及**满分是否为用户确认**(`meta.full_to_confirm` 非空时必须点名复述),避免老师误读——
  报告与结果册里都**没有**这些交代,全靠这句交付说明
- **逐题的两层与各班矩阵要一句话交代**:班级层是哪个班、年级层多少人、各班矩阵覆盖了哪几个班
  (`meta.two_level_questions` / `meta.has_class_question_detail`);若逐题表没有「学号」列,
  要明确说"本次各班逐题对比未生成,补一列学号即可"
- 本次未生成的板块(缺逐题/知识点数据时)也要一句话说明,并给出补数据的方式
  (结果册的「01 阅读说明」只列实际生成的工作表,不再写"哪张表没生成、为什么")
- 脚本已固化在本 skill,下次换数据只需改 `--data / --subjects / --exam-name / --full`,三件套一起重生
  —— 这句"下次怎么复用"属于回复内容,不要写进报告

### 原始导出表的整理提示(Step 2 补充)

学校/阅卷系统导出的 xlsx 常是"多工作表、每表带合并标题行"的格式(如:全科汇总 + 各科成绩 + 小题得分明细)。
引擎现在能自动**跳过表头前的合并大标题行**、并在**第一个工作表是封面/说明页时自动改用下一个有数据的表**;
但「一行一题的长表」仍不是合法主表,需先整理成标准输入:
主表(学号/姓名/班级/各科总分)+ 逐题长表(学号/学科/题号/满分/得分/知识点)。
可参考「按【学科】…明细表分块解析小题表 → 展平为长表」的做法:
按各科的明细表标题行分块,把「一行一题」的小题表展平成
`学号/学科/题号/满分/得分/知识点` 长表;原表没有知识点列时,**要么留空**(引擎会不生成维度 4、
不编造知识点),**要么**按题号/分值结构/教学进度推断模块归属,但推断出来的归属必须在逐题表的
「知识点 / 模块」单元格里写明「AI 推断」,并在交付说明里交代。整理时注意:各科满分用 `--full "语文=100,数学=100"` 显式给(勿依赖默认值);
「历次」表缺失时维度 6 自动转横截面分层;历次表里没有「序号」/「日期」时,要让用户给出考试先后顺序,
或直接用 `--history-order` 指定。
不确定用哪个工作表时先跑 `--list-sheets`。

## 数据异常处理(不要静默忽略)

引擎自动把缺失值、缺考、超满分/负分、未指定满分、基准缺失等写入 `analysis.json` 的 `data_notes`。
**报告正文与 Excel 结果册都不展示 `data_notes`**(用户要求 2026-10-08):这些交代只留在
`analysis.json` 与命令行输出里,**交付前必须逐条过一遍并在对话里复述**。检查该清单:
- 缺考/空值默认**剔除**(不按 0 分计);如用户要求按 0 分,需说明统计差异
- **被剔除的学生会逐个点名**落在 `analysis.json` 的 `data_excluded`,并写入 Excel「01 阅读说明」的
  「未纳入统计的学生」表(这是结果册里唯一保留的数据质量交代——班主任对名单要用)。
  老师对名单时能看出少了谁、为什么少——**交付时必须说一句"有 N 人被剔除"**,
  别让对方自己发现(报告里已不展示这张表)
- **满分未确认**的学科落在 `meta.full_to_confirm`,各学科章首小字会标「待确认」、Excel「01 阅读说明」
  也会置顶点名;交付时必须复述给用户(见「满分设定」)
- **重复学号**(同一学号出现多行)按同一人合并、**保留最后一条**,合并明细落在 `meta.duplicate_sids`
  与 `data_notes`——过去会被当成两个学生,人数虚高、排名表里同一人出现两次
- **某科整列缺考/非数值**(整列一个分数都没有)时,该科退出分析并在 `data_notes` 里**点名**;
  显式 `--subjects` 要求该科则直接报错。过去是静默丢科,老师会以为"本来就只考了这几科"
- **基准缺失**时用本次全体均分作年级参照,并明确标注"仅供参考"

## 常见问题

- **用户只粘贴了一段表格文本**:先整理成 xlsx/csv 再走 Step 3;列名以用户原表为准
- **表里没有学号 / 姓名 / 班级列**:都能缺,会自动降级(缺学号用行号、缺班级按同一群体处理)
- **学校导出的表打不开**:表头前的合并大标题行会自动跳过;第一个工作表是封面/说明页会自动换表;
  但「一行一题的长表」不是合法主表,需先透视成宽表。报错信息会列出实际表头与可用工作表
- **脚本退出码 3、提示 `[需确认] ... 满分`**:这是设计行为,不是故障 —— 说明该科满分既没给、
  也没法从数据唯一反推(例如最高分 68,70/75/80 分制都说得通)。把清单转达用户,拿到答案后用
  `--full "学科=满分"` 重跑即可
- **报告里少了「逐题得分率」「知识点热力图」**:因为没有逐题/知识点数据,这两节**整节不生成**
  (章节名会变成「N 个维度:…」)。不要虚构数据,也不要去补空板块;把
  「学号/学科/题号/满分/得分/知识点」长表补上即可自动生成
- **逐题表没有「知识点」列(或整列为空、或只填了 `-` 「/」「无」「未标注」这类占位符)**:
  维度 4 与 Excel「05 知识点优先级」不生成(占位符不算知识点数据——列在、每行都有字也可能一个真知识点都没有),
  逐题表里也不留空白「知识点」列 —— **引擎绝不编造「未标注」这类假知识点**(那会让摘要写出
  「共性薄弱知识点集中:数学→未标注」,是假教学结论)。补一列「知识点」即可自动生成
- **报告里没有「各班 · 逐题得分率」矩阵**:说明逐题表缺「学号」列(无法按班归属),或样本只有一个班。
  此时班级层 / 年级层的逐题统计仍然正常;补一列学号(两端格式一致,注意前导零)即可自动生成,
  Excel「04」也会多出各班的得分率列
- **报告里没有「年级层 · 班级排名与全年级指标」**:单班样本没有"班级排名"可言,该章整节不生成
- **报告里没有「历次成绩对比」**:没有历次表(或历次表只有 1 次考试)时不生成;
  历次表只有「总分」列时该节只对比总分,补上学科列即可给出历次各科四率
- **`[警告] ... 无法判断先后顺序`(退出码仍是 0)**:历次表的「考试」列排不出真实时间序
  (如混排的「第1次月考 / 期中考试 / 第2次月考 / 期末考试」)。引擎**照常出报告**,但维度 6 的
  趋势判定 / 进步榜 / 需关注名单可能整体反向,并在摘要、维度 6、Excel 07 都做了标注。
  交付时必须把这条提示转达用户;加一列「序号」/「日期」,或用 `--history-order "考试1,考试2,…"`
  指定后重跑即可修正
- **改坏了 narrative.json**:不会影响交付 —— 脚本打印警告后按「无教师话术」继续出报告
  (可选文件不该拖垮主交付;Excel 结果册已与 narrative 解耦,本来就不读它)。修正该文件后重跑即可恢复话术
- **没有历次成绩**:维度 6 自动改为横截面分层(尖子生/临界优秀/临界及格/学困生);
  历次表只有 1 次考试时同样退回横截面分层
- **多班级数据**:按「班级」列自动分组,`--focus-class` 指定主分析班级,其余班级自动成为对比对象
- **用户追问某个数字**:直接读底稿回答,不要重算。底稿在 `<交付目录>/.底稿/analysis.json`
  (`.json` 不交付,所以问「报告在哪」时不要提它,问「某个数字怎么来的」时再指路)
- **PDF 没生成**:脚本会打印警告;让用户用浏览器打开 HTML → Ctrl+P → 另存为 PDF(A4、边距 2cm、勾选"背景图形"),
  或重跑时加 `--pdf-out 指定路径`
- **Excel 没生成**:多为当前解释器缺 openpyxl。按脚本打印的指引用**同一个**解释器
  `"$PY" -m pip install openpyxl` 后单独重跑 `build_excel.py`
- **只想要 Excel**:`"$PY" scripts/build_excel.py --analysis analysis.json`(默认不生成 HTML/PDF)
- **只想要 HTML/PDF**:渲染时加 `--no-excel`
- **Excel 里要加图表**:结果册刻意只放**纯数据表**(分列、可排序、可透视),图表统一由 HTML 报告承载;
  若要 Excel 原生图表,在 `build_excel.py` 对应 Sheet 里追加 `openpyxl.chart` 对象

## 详细规范(按需加载)

- `references/analysis-spec.md` —— 6 大维度完整计算方式、判定规则、图表要求
- `references/report-spec.md` —— 三件套文件结构、命名、配色、HTML/PDF/Excel/Word 格式要求
- `references/data-and-params.md` —— 输入数据 schema、params.json / narrative.json 完整模板、满分输入方式
- `scripts/exam_analysis.py` —— 计算引擎(成绩表 → analysis.json)
- `scripts/report_builder.py` —— 渲染引擎(analysis.json → HTML + PDF + Excel 三件套)
- `scripts/build_excel.py` —— Excel 结果册生成器(可被 report_builder 调用,也可单独运行)
- `scripts/make_sample_data.py` —— 生成示例数据,用于自测/演示
- `scripts/selftest.py` —— 回归自测(**48 个用例**),**改动任何脚本后都要跑**。
  其中 5 条专盯「交付物不暴露内部元数据」:PDF 属性清理(等长替换 + xref 不失配)、
  真实 PDF 无生成侧标识、HTML/Excel 无接口字段名与工具标识、技能文件无写死个人路径、页脚无工具标识

## 跨场景公共约定

权限固定提示 / 干净输出红线 / 触发词格式 / 版本与完工标准 / MCP 前缀自检:统一见 [_shared.md](references/_shared.md)。本 skill 的前置权限校验口径与「严禁编造知网数据」红线均与之对齐。

Files in this skill

  • SKILL.md38.5 KB
  • references/_shared.md15.1 KB
  • references/analysis-spec.md20.8 KB
  • references/data-and-params.md17.4 KB
  • references/report-spec.md24.1 KB
  • scripts/build_excel.py43.9 KB
  • scripts/exam_analysis.py91 KB
  • scripts/make_sample_data.py6.3 KB
  • scripts/report_builder.py92.7 KB
  • scripts/svg_charts.py22 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in data →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.