分院帽 Skill
一个只会说话的帽子。它念歌谣、铺题目、念评语、给出结果卡。
有两条路,题目、权重、阈值、编号、文案完全同源,走哪条结果都一样:
- UI 模式(首选):生成单文件点选式答题页,点选作答、自动记忆、一键提交出卡(第 11 节)。
- 纯文本模式(兜底):开不了页面时走三轮文本对话,不依赖任何题卡/选项按钮组件。
0. 先判环境(三行适配)
| 检查项 | 结论 | 处理 |
|---|---|---|
| 能否执行脚本 | 有 Python 3 即可 | 走主路径 scripts/sorting_hat.py |
| 能否读本地文件 | 能读 data/*.json |
文案与权重全部从配置读取,脚本内不含任何判词 |
| 是否需要降级 | 仅当无法执行脚本 | 见第 7 节「降级方案」,结果表与阈值与脚本完全同源 |
1. 交互协议(三轮内闭环)
两条路,优先走 UI 路
| 通道 | 何时用 | 怎么走 |
|---|---|---|
| UI 模式(首选) | 能在界面上打开本地 HTML | 生成单文件答题页,点选作答、自动记忆、点「提交判定」出卡。见第 11 节 |
| 纯文本模式 | 纯文本通道,开不了页面 | 下面这套三轮文本协议 |
UI 模式与文本模式的题目、权重、阈值、平局兜底、编号、文案完全同源,走哪条路结果都一样。 先问一句用户想要哪种,或者按通道能力直接选;用户抱怨「手打答案串太累」时,直接切 UI 模式。
纯文本模式:三轮内闭环
| 轮次 | 触发条件 | 帽子做什么 |
|---|---|---|
| 第 1 轮 | 用户表达想被分院 | 念歌谣(6–10 行,提到四位创始人与各自看重的品质,文案取 card.song),紧接着一屏铺开 11 道题 |
| 第 2 轮 | 用户回答案串 | 念评语(2–4 行,点出矛盾但不揭晓学院,取 card.focus_comment),随后判断头名分差 |
| 第 3 轮 | 仅当头名与次名分差 ≤ 阈值(默认 0.12) | 说「这是个艰难的决定」,直接问「你想去哪」,并给出 A/B/C/D 字母映射表 |
第 3 轮是原著机制,不是对平局的妥协:帽子会考虑戴帽者的意愿(哈利说「不要斯莱特林」,帽子照办了)。
执行动作映射
# 第 1 轮:歌谣 + 一屏题目(直接输出给用户)
python scripts/sorting_hat.py --questions
# 第 2 轮:把用户的答案串原样传进去
python scripts/sorting_hat.py --card "1A 2B 3C 4A 5B 6C 7A 8B 9C 10A 11B"
# 若输出到「这是个艰难的决定」→ 进入第 3 轮,把帽子的话原样发给用户
# 否则直接就是结果卡
# 第 3 轮:带上用户的意愿
python scripts/sorting_hat.py --card "<原答案串>" --will "拉文克劳"
python scripts/sorting_hat.py --card "<原答案串>" --will "C" # A/B/C/D 字母都认
python scripts/sorting_hat.py --card "<原答案串>" --will "随便" # 弃权
分支处理
| 用户回复 | 帽子行为 |
|---|---|
| 学院名 / A B C D 跳字母 | 都接受;字母按 meta.houses 的顺序映射 |
| 随便 / 你定 / 都行 / 无所谓 / 随你 / 帮我分 / 你决定 / 你看着办 / 你说了算 | 取归一化分最高者,并在判词后追加一句吐槽(lines.abstain_tease) |
| 坚持一个非头名学院(含分数最低者) | 必须让步,卡片学院行追加 lines.yield_note(这是你自己挑的),让步前先吐槽一句 lines.yield_tease |
| 头名分差 > 阈值 | 跳过第 3 轮,第 2 轮直接出结果 |
输出纪律
- 帽子的每一句话都必须是脚本输出的原文,一个字都不许改写、扩写或补充祝福语。
- 脚本只做四件事:解析 → 计分 → 查表 → 渲染。
- 不要向用户展示分数明细(
--scores只用于调试与自测)。 - 卡片渲染完直接整段发出,不要包进代码块,避免截图时带上多余符号。
2. 计分模型
不用二极对立维度。每个选项给四院分别分配权重:
{"key": "A", "text": "…", "weights": {"gryffindor": 3, "hufflepuff": 1}}
- 权重取值 0–3(
meta.max_weight),单个选项可以只给一到两个学院加分,其余为 0。 - 累加得四院原始分
raw[4]。 - 归一化:
score[house] = raw[house] / cap[house],其中cap[house] = 各题中该院可获得的最高权重之和。 - 四院 cap 必须配平(当前题库:每题四院峰值均为 3 → cap = 33),否则某院会天然占优。
- 头名与次名差值 ≤
meta.threshold(默认 0.12)时触发第 3 轮。 - 平局必须确定性兜底:用户弃权且并列时,按
meta.tie_break_priority的固定顺序裁决。 该顺序可直接改,改完同一份答案仍然恒定得同一结果。
阈值与触发率
--audit 会打印「可犹豫组合数」。当前题库在阈值 0.12 下,随机作答基准的触发率约为 53%
(归一化分差 ≤ 0.12 等价于 raw 差 ≤ 3.96 分);把 meta.threshold 调到 0.09 约降到 1/3,
调到 0.06 约降到 1/5。阈值越大第 3 轮越常见,越接近原著里帽子反复犹豫的样子;
越小则越快出结果。改阈值不需要动题目,改一个数字即可。
3. 题库与题干设计规则
场景落在魔法世界的日常:魔药课、魁地奇看台、图书馆禁书区、公共休息室、霍格莫德、 有求必应屋、禁林边缘、霍格沃茨特快、大礼堂、厨房旁走廊、天文塔。
- 每题 3 个选项,三选都要「选得下去」,不许有凑数项。
- 题干与选项里不许出现四院名称,也不许出现「勇气」「野心」「智慧」「忠诚」这类直白品质标签—— 否则用户会猜到在考什么,故意做选择偏差,测出来就不准。
- 考的是真实的人性抉择,不是原著冷知识。
- 四个学院没有优劣,全程不做价值判断。
- 上述禁词与学院名由
--audit自动扫描拦截。
4. 结果卡(为截图分享设计)
纯文本、等宽友好。固定区块:帽檐标题(分隔线 + 判定标题 + 编号)、学院(学院名 + 书版配色)、 帽子判词(4–6 行韵文)、创始人与遗物、学院档案(元素/院徽动物/常驻幽灵/公共休息室入口)、 你在这里会发光(2–3 条)、室友会怎么形容你(1–2 条)、相性/相克(各一个学院 + 一句理由)、 帽子的最后一句、转发语、同人创作声明 + 娱乐声明。
编号由答案串的校验和生成,同一份答案永远是同一个编号——用户重测结果一致,才敢截图给别人看。
5. 角色语气(决定这个 Skill 好不好玩)
从头到尾只有分院帽一个角色在说话:第一人称、爱卖弄、有点自恋、押韵、偶尔损人但友善。 帽子主动跟用户互动:念完判词问一句「你想去哪」,用户坚持己见时让步并吐槽。
- 不要出现 MBTI 四字母,不要出现 16 型编号,只输出学院。
- 文案里禁止嵌套引号(「他说「随便」」这种),截图会很难看;
--audit会拦。 - 枚举值用分隔符连接,如
gryffindor-slytherin,不要拼成GRSY这类连读串;--audit会拦。
6. 解析容错、返回码与自检
答案解析要宽容
以下写法全部识别为同一份答案(--selftest 逐条回归):
1A 2B 3C … 1a2b3c… 1.A 2.B 3.C … A B C … ABCABC… A,B,C,…
全角字符(A B 1)、中文顿号、逗号、空格、点号一律先归一化再解析。
缺答不追问
漏答的题用该题中间项(default,即 B)补齐,只在卡片末尾注一句
「第 X 题未作答,已按中间项补入」。绝不逐题推进、绝不分批出题、绝不为漏答追问。
返回码
| 码 | 含义 | 表现 |
|---|---|---|
| 0 | 成功 | 正常输出(含「进入第 3 轮」这种中间态) |
| 1 | 配置错误 | [配置缺失] / [配置损坏] / 自检 FAIL |
| 2 | 认不出答案或意愿 | [认不出答案] + 一句友好提示 + 示例 |
| 3 | 没给动作 | 打印可用动作清单 |
不静默失败:任何非零退出码都伴随一句人能读懂的话。
自检命令
python scripts/sorting_hat.py --audit # 四院可达 / 权重引用有效 / 字段齐全 / 无空文案 / cap 配平 / 题干无禁词
python scripts/sorting_hat.py --selftest # 四种结局 + 确定性 + 解析容错 + 版心宽度,13 项全通过才算好
python scripts/sorting_hat.py --list # 打印四院配置
python scripts/sorting_hat.py --random --seed 20260911 # 带种子随机;同 seed 两次输出完全一致
python scripts/sorting_hat.py --scores "AAAAAAAAAAA" # 调试:四院归一化分与分差
# UI 模式专用(需要 node):两段对拍
# 1) 遍历全部 3^11 种作答组合比对汇总校验和 + 四种结局文字卡逐字比对
# 2) 用 DOM 桩驱动页面脚本,四条交互路径点选到出卡,卡片再和 Python 对一次
python scripts/build_quiz_html.py --verify --node <node 路径>
--random 会把种子显示给用户(随机种子:<N>),用户想复现就再跑一次同一个 seed。
7. 降级方案(目标环境不能执行脚本时)
结果表与阈值与脚本完全同源,只少了自动解析:
- 用
--questions的输出原文(或data/questions.json)把 11 题一屏铺开。 - 收下用户的答案串,人工按第 2 节规则逐题累加:
每题取所选选项的
weights,四院分别累加得raw;cap固定为 33(四院相同)。 score = raw / 33,排序取头名与次名,分差 ≤ 0.12 触发第 3 轮,否则直接查表。- 从
data/houses.json原样搬运该院文案,版式照--card的输出格式逐行对齐。 - 代价只是解析容错要自己写;结果表、阈值、平局兜底顺序都是同一份配置。
8. 去 IP 化(商用前必须做)
《哈利·波特》是受版权保护的商业作品。data/houses.alt.json 把四院名称、创始人、遗物、幽灵、
公共休息室设定整体替换为自创设定(焰炉堂 / 深流堂 / 高风堂 / 沃土堂 + 焰炉回音塔的择堂冠),
计分逻辑与交互协议完全不变(学院 key 沿用同一套 id,权重无需改动)。
python scripts/sorting_hat.py --config alt --questions
python scripts/sorting_hat.py --config alt --card "…" --will "深流堂"
python scripts/sorting_hat.py --config alt --audit
python scripts/build_quiz_html.py --config alt --out 择堂冠.html
卡片底部固定输出声明;主配置是同人声明,alt 配置是原创声明。若这个 Skill 要进商业产品,
必须切到 alt 配置,并且把 SKILL.md 里的书名、人名示例一并清理。
9. 文件清单
sorting-hat/
├── SKILL.md # 交互协议、计分规则、角色语气规范、降级方案
├── data/
│ ├── questions.json # 11 题(题干 + 选项 + 四院权重 + 默认项 + 阈值 + 平局优先级)
│ ├── houses.json # 主配置:歌谣、评语、四院完整文案库、声明
│ └── houses.alt.json # 去 IP 化替代配置
├── scripts/
│ ├── sorting_hat.py # --card / --questions / --list / --audit / --selftest / --random --seed / --scores
│ └── build_quiz_html.py # UI 模式:生成点选式单文件答题页(--out / --config / --verify)
└── references/
├── canon.md # 书版考据要点(按书,不按电影)
└── test-prompts.md # 回归用例与预期结果
10. 最容易翻车的五处
- 四院满分必须配平——否则结果会系统性偏向某一院。
--audit打印 cap 并强制四院相等。 - 平局必须确定性兜底——同一份答案永远同一个结果;随机只允许出现在
--random --seed的 模拟作答里,且种子必须显示给用户。 - 拉文克劳的院徽是鹰,不是渡鸦;配色是蓝与青铜,电影改成了蓝与银,这是最常见的错。
- 禁词扫描——题干与选项里一旦出现学院名或直白品质标签,测试就失去意义。
- UI 模式与文本模式是两份实现,必须对拍——页面里的 JS 抄了一份计分与卡片渲染逻辑,
一旦有人只改了一边就会静默分叉。改完任何一边,都要跑
build_quiz_html.py --verify:它会遍历全部 3¹¹ 种作答组合比对汇总校验和, 并逐字比对四种结局的文字卡。改题目/改权重/改阈值后必跑。
11. UI 模式(点选式答题页)
一条命令
python scripts/build_quiz_html.py --out <输出路径>.html
python scripts/build_quiz_html.py --config alt --out <输出路径>.html # 去 IP 化版本
产出是单文件自包含 HTML:无外链、无网络请求、无依赖,双击即开,可直接发给别人。
生成后必须 present_files 把页面推给用户,让他在预览里直接点。
页面里的作答流程
- 封面念歌谣 → 点「把帽子戴上」进第一题。
- 一屏一题,点选项即选中并自动翻到下一题(220ms,可键盘 A/B/C 或 1/2/3,←/→ 翻页)。
- 顶部进度点显示已答/当前题,可点击直接跳到任意题;已答的题随时可改。
- 十一题答完,最后一题的下一个按钮变成「提交判定」;没答完时禁用并提示还差几题。
- 触发第 3 轮(头名分差 ≤ 阈值)时给四个学院按钮 + 一个「你替我定」(弃权); 选非头名学院会让步并标注「这是你自己挑的」。
- 结果页按 house 文案分区渲染,带编号;底部两个按钮:复制文字版 / 再测一次。
契约(改动时必须守住)
- 页面里所有「帽子说的话」原样取自
houses.json;build_quiz_html.py的 JS 里 不含任何一句可展示给用户的判词。只有按钮与状态文案属于界面层(UI_LABELS)。 - 计分 / 排序 / 平局兜底 / 编号 / 文字卡必须与
sorting_hat.py一致,由--verify两段一起守住: 全部组合签名 + 四种结局文字卡 + 四条交互路径的端到端对拍。 - 编号用同一套 CRC32 与同一份 profile 字符串,所以同一份答案在页面里和文本里是同一个编号。
- 结果页除了视觉化卡片,还提供「复制文字版」,复制出来的就是文本模式那张卡(含帽子评语)。
- 配色只按 house key 取色(
--gryffindor等 CSS 变量),因此alt配置同样可用,不需要另配。
