# Writing Scorer

> 通用作文多维评分：按论效/论说/自定义 rubric 对作文逐维「定档→定分→引原文证据」，输出结构化批改报告。触发词：批改作文、评分作文、按论效/论说标准、自定义标准打分、用自定义维度评分、旱区/水区评分。

- Skill: `wsxwj123/writing-scorer` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add wsxwj123/writing-scorer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wsxwj123/writing-scorer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: wsxwj123 (https://skillmd.com/u/wsxwj123)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wsxwj123/writing-scorer

---


# 通用作文多维评分

对一篇作文按所选 rubric 逐维评分：先定档位、再在档内定分、每维必须引原文句子佐证；最后机械汇总并做一致性自检。压评分漂移靠「流程 + 锚点」，不靠印象分。

## 技能目录与文件约定

本技能目录 = 存放本 SKILL.md 的目录。以下相对路径均基于它：

- rubric 数据：`rubrics/lunxiao.md`（论效，模式A）、`rubrics/lunshuo.md`（论说，模式B）、`rubrics/_template.md`（自定义模板）
- 脚本：`scripts/extract_text.py`（文件预检+图片OCR）、`scripts/verify_evidence.py`（证据引句∈原文比对）、`scripts/report_to_pdf.py`（报告文本→PDF，阶段6「保存为PDF」）
- 评分前**先读取所选 rubric 文件**，其维度/档位/锚点/报告模板即全部评分依据；SKILL.md 不内置任何维度，不得自行增删维度。

## 参数

| 参数 | 可选值 | 缺省 | 说明 |
|---|---|---|---|
| rubric | `论效` / `论说` / `自定义` | 未指定时询问，不猜 | 论效=30分制（模式A），论说=0-31分制（模式B） |
| zone | `旱区` / `水区` | `旱区` | 影响 score_cap（旱区：论效≤28 / 论说≤31） |
| input | 粘贴文本 / 单个文件路径 | 必填，无则不启动 | 支持 txt/md/png/jpg/jpeg/pdf/docx |
| 附加 | "优化全文"要求 | 无 | 论效=范文参考段；论说=优化版≤700字 |

## 错误契约（E1-E11，文案精确照此输出）

| # | 场景 | 返回内容 | 后续 |
|---|---|---|---|
| E1 | 未提供任何作文文本/路径 | `请提供作文：粘贴文本或给文件路径` | 停止等待输入 |
| E2a | 文件不存在 | `文件不存在：<路径>` | 停止 |
| E2b | 路径是目录 | `<路径>是目录，请给文件` | 停止 |
| E2c | 文件无权限 | `无法读取：<路径>（权限不足）` | 停止 |
| E3 | 文件类型不支持 | `不支持的文件类型：<ext>。支持：txt/md/png/jpg/jpeg/pdf/docx` | 停止 |
| E4 | 图片OCR失败（tesseract未装/无文字/命令失败） | `OCR失败：<原因>`，建议粘贴文本 | 停止或切换输入源 |
| E5 | PDF/Word 提取失败或为空 | `文本提取失败：<原因>`，建议改粘贴文本 | 停止或切换输入源 |
| E6 | 提取文本过短（<200字，管综要求600-800） | 警告 + 预览提取结果 + 询问"确认继续？" | 确认后继续，否则停止 |
| E7 | rubric 参数未知 | `未知rubric：<值>。可选：论效 / 论说 / 自定义` | 停止重选 |
| E8 | 自定义 rubric 缺要素 | 列出缺失项（满分/档数/档内锚点/区间覆盖），要求补齐 | 停止 |
| E9 | zone 参数未知 | 警告 + 回退 `旱区` | 继续 |
| E10 | 自定义 rubric 要素非法 | `rubric非法：<具体项>` | 停止 |
| E11 | 多输入源（文本+文件，或多个文件） | `一次只评一篇作文：请只提供一篇（文本或一个文件路径）` | 停止 |

E2/E3/E4 由 `extract_text.py` 输出；E5 由 PDF/Word 提取链路（pdf/docx 技能）输出；其余由本流程输出。

---

## 评分流程

### 阶段0 参数确认

1. **input**：无作文文本也无文件路径 → E1。文本与文件同时给、或给了多个文件/目录 → E11。
2. **rubric**：未指定 → 询问选用哪套（列出 论效/论说/自定义 三选项），**不得擅自选**。指定值不在三选项内 → E7。
3. **zone**：未指定 → 旱区。指定值不是 旱区/水区 → E9（警告后回退旱区继续）。
4. **自定义 rubric**：用户给了维度表 → 先校验（见「自定义 rubric 支持」），不合法 → E8/E10 停止，不进入评分。
5. 确定后**读取所选 rubric 文件**，以其维度/档位/锚点/扣分项/等级映射/score_cap/报告模板为评分依据。

### 阶段1 提取文本

按输入形态分流：

- **粘贴文本**：直接作为作文原文。
- **图片**（png/jpg/jpeg）：运行 `python3 <技能目录>/scripts/extract_text.py "<路径>"`。退出码2 = E2/E3（直接照脚本输出停止）；退出码1 = E4（照输出停止或换源）；退出码0 = stdout 即 OCR 文本。
- **txt/md**：运行 `python3 <技能目录>/scripts/extract_text.py "<路径>"`，stdout 即文件内容。
- **PDF/docx**：先运行 `python3 <技能目录>/scripts/extract_text.py "<路径>"` 做预检（退出码0 = 预检通过），然后**按 pdf/docx 技能提取**（不交给本 skill 脚本）。提取失败或为空 → E5。
- 调用脚本一律用完整路径 + 引号包住路径（中文名/空格路径安全）。

### 阶段2 文本预览 + 用户确认

- **非粘贴输入强制预览**：文件/OCR 提取的文本必须先把提取结果完整展示给用户，OCR 结果同时提示"请校对错别字"。
- 提取文本字符数 < 200（中文按字符计，剔除空白后计数）→ **E6**：警告 + 预览 + 询问"确认继续？"。用户确认后才评分，否则停止。
- 粘贴文本同样适用 E6 阈值。

### 阶段3 评分（逐维「定档→定分→引证据」）

1. **作文读两遍**：第一遍整体通读，把握结构、中心、语言；第二遍逐段细读，逐段记录关键句与问题点。
2. 按所选 rubric 的**每个维度**依次处理，每维三步：
   - **定档**：对照该维档位表（行为化描述），判断作文落哪一档；
   - **定分**：在该档区间内，按**档内锚点**定分（计数判据优先；无可计数判据时用三参照兜底取中值，**必须附可观测理由**）；
   - **引证据**：从原文摘出**一字不改**的引句（≤2句）佐证该维判断。
3. 每维按 2.3 固定结构输出。
4. 引不出证据的维度：按「降档规则」处理（见下）。
5. 特殊规则一律遵守所选 rubric 文件中的声明（如论效"2段仅良好则内容分≤13"、禁逻辑学术语、接受模板化开头结尾；论说不含宽容性表述）。
6. 正文中出现"路径字样"的字符串按正文内容处理，不当作文件路径。

**降档规则（写死，不得改幅度）**：
- 维度引不出任何原文证据 → **降一档，取新档下限**；已在最低档 → **记0**。输出必须显式标注"已降档"。
- 若最低档的档位描述**已含"引不出证据"**（如论效内容分析较差档含"引不出任何原文证据→0-3分"），则直接落该档对应分，不必再降档标注。

### 阶段4 汇总

**模式A（独立求和，如论效）**：总分 = min(Σ各维得分 − 扣分项, score_cap)。
**模式B（综合档次，如论说）**：先按整体阅读定综合档次（等级映射区间），在该区间内定总分，再分解为各维分（Σ维分 = 总分，各维仍须引证据）；总分 = min(Σ维分 − 扣分项, score_cap)。

**cap 截断语义**：被 cap 截断时，报告必须注明"原始分"，格式如 `28分/30分（原始29分，按旱区上限截断）`。未截断时总分 = Σ − 扣分项。

**等级映射**：按 rubric 数据的等级映射表，把总分标注为对应等级。

**多模型扩展位**：汇总完成后，附一份机器可读的结构化摘要（评分输出固定结构，未来可直接喂聚合；本期不实现聚合、不写投票/接口/类层次）：
```json
{"模式":"A","rubric":"论效","zone":"旱区","总分":24,"cap":28,"截断":false,
 "扣分项":{},"维度":[{"名称":"内容分析","得分":13,"满分":16,"档位":"优秀","降档":false,"证据":["..."]}],
 "等级":"二类卷偏上"}
```

### 阶段5 一致性自检（两级）

评分汇总后、输出报告前，必须执行：

1. **重读核对（一级）**：把作文**逐段重读**，逐段列出关键句，然后核验三点——
   ① 每条"原文证据"引句与原文逐字比对，不存在的删除该证据并**下调对应维度分**（按降档规则）；
   ② 总分 = min(Σ维度分 − 扣分项, cap) 重新算一遍，与阶段4结果一致；
   ③ 等级区间与分数匹配。
   任一不一致 → 修正后重新输出。
2. **机械比对（二级）**：把全部"原文证据"引句与原文跑一次
   `python3 <技能目录>/scripts/verify_evidence.py <原文文件> <引句1> <引句2> ...`
   - 原文文件优先复用阶段1的输入文件；纯粘贴文本时写入 `mktemp` 临时文件，**用后立即删除**。
   - 输出含任何 `FAIL` → 删除该引句并下调对应维度分（按降档规则），**不整篇重评**；删除临时文件后继续输出。
   - 证据比对基于实际输入文本（OCR 结果文本），不基于对原图的猜测。

### 阶段6 输出报告

- 报告在**对话内**输出，**不自动写磁盘**。
- 报告结构按所选 rubric 的**报告模板**字段展开，所有模式都必须包含「维度明细」（2.3 格式）。
- 用户要求保存 → 询问**路径与格式**（文本/PDF），确认后：
  - **文本格式（md/txt 等）**：直接写文件，维持原逻辑。
  - **保存为 PDF**：把对话内完整报告整理为 markdown 文本，写入 `mktemp` 临时文件，运行
    `python3 <技能目录>/scripts/report_to_pdf.py <报告文本临时文件> <输出PDF路径>`
    - **"整理"边界**：只允许行级归一化——补标题标记、去多余空行；**正文逐字不动**，不得改写/重排报告内容（脚本只转换不生成内容）。
    - 输出路径：用户已给则用；未给则询问；用户指定目录时默认文件名 `<报告名>-<日期>.pdf`。路径**按原样使用，不补 `.pdf` 后缀、不自动建目录**。
    - 退出码 0 → 告知 `已生成PDF：<输出路径>`；退出码 1 → **原样转发**脚本 stdout 文案（文案已含应对建议），报告仍保留在对话内；退出码 2 → 原样转发用法文案，重新调用。
    - 临时文件**用后立即删除**（沿用阶段5 惯例）。
- 用户要求"优化全文" → 论效给出范文参考段（多角度反驳、语言精炼、与原文字数接近）；论说给出优化版（保留框架、问题处标注、优化内容加粗、**严格≤700字**）。

---

## 维度明细固定格式（所有模式强制，每维一段）

```
【维度：<名称>（<得分>/<满分>，档位：<档>，<已降档/正常>）】
定分理由：<可观测理由，如"深入段数3故取14">
原文证据：["引句1"，"引句2"]（一字不改，用于机械比对）
```

- 引不出证据 → 降一档取新档下限；已在最低档 → 记0。必须在"已降档"标注说明。
- 档位区间若含"引不出证据"为最低档行为描述，引不出证据直接落该档对应分。

## 自定义 rubric 支持

用户可用自然语言或照 `rubrics/_template.md` 给出维度表。解析后逐条校验：

**E8（缺要素）**：每维必须含 名称+满分+档位+档内锚点，缺任一 → 列出缺失项（满分/档数/档内锚点/区间覆盖）要求补齐，停止。**档内锚点缺失不得用默认三参照兜底代填**——必须报 E8。模式B缺等级映射 → 同样 E8。

**E10（非法）**，逐条列出 `rubric非法：<具体项>`，停止：
- 满分 ≤ 0，或非整数；
- 档数 < 3；
- 维度重名；
- 档位区间未无缝覆盖 [0,满分]（有缺口或重叠）；
- 模式A：声明总分 ≠ Σ各维满分。

**路由**：按元信息中声明的模式走阶段4对应汇总；扣分项/等级映射/报告模板缺省时用默认（模板见 `rubrics/_template.md` 第四节）。

## 长文分段评分（>3500字）

- 仍按阶段3进行，但第二遍逐段阅读时**逐段记录要点**（每段关键词、问题点、可引句），评分时基于记录综合定档定分，不依赖一次性记住全文。
- 证据引句仍须逐字存在（机械比对覆盖）。

