这是什么 · What this is
中文:对重新设计后的游戏(排名列表 + 调查员)逐组件的注解。7 个「站」共享同一条由「因素」参数化的生成流水线,所以这份文档拆解的是一个站的解剖结构 + 它周边的各个部件:每一部分是什么、怎么生成、用哪个模型、确切的提示词。代码:
gaokao/。EN: A component-by-component annotation of the redesigned game (ranked-list + investigator). The 7 “stops” share one generation pipeline parameterized by a factor, so this documents the anatomy of a stop + the pieces around it: what each part is, how it’s generated, which model, and the exact prompt. Code:
gaokao/.
✏️ 这些提示词可以直接编辑 · Edit these prompts live
中文:开发者可在 提示词编辑器里直接改下面这些生成提示词(
investigate调查员 /translate_major看懂这个专业 /frame_test框架测试),保存后游戏下一次调用即生效,无需重新部署。编辑器路径 = 高考服务的/prompts(当前开发隧道:easy-justify-…/prompts,隧道为临时,以最新分享的链接为准)。保存有护栏:删掉任一必需占位符(如{top}/{g})会被拒绝,线上游戏不会被改坏。底层:gaokao/prompts.json(可编辑)+prompts.defaults.json(出厂默认,供 Reset)。EN: Developers can edit the generative prompts below (
investigate/translate_major/frame_test) directly in the prompt editor; saves take effect on the game’s next call, no redeploy. Editor path =/promptson the gaokao service (current dev tunnel: easy-justify-…/prompts — tunnel is ephemeral, use the latest shared link). Guarded: dropping a required placeholder (e.g.{top}/{g}) is rejected, so the live game can’t be broken from the editor. Under the hood:gaokao/prompts.json(editable) +prompts.defaults.json(factory default for Reset).
模型与调用 · Model & call
中文:
- 模型:
deepseek/deepseek-chat(DeepSeek-V3,非推理)经 OpenRouter——快速档(~20 秒/次,对比 V4-Pro 的 ~50 秒),偏创意而非推理的活。覆盖项:GAOKAO_TRAJECTORY_MODEL。 - 调用:
gaokao/ranked.py::_llm_json()——POST 到openrouter.ai/.../chat/completions,response_format=json_object,带退避的 4 次重试。下面每个部件都是这样一次调用。 - 网络检索:调查那一次调用跑网络检索 grounded(DeepSeek-V3 + OpenRouter 网络插件,
plugins:[{id:web}];开关GAOKAO_WEBSEARCH)。它有来源纪律:提示词限定权威来源,一个过滤器(_auth_sources)从展示引用里剔除新闻/UGC,若检索不到权威信息就退回 grounding 知识库。来源显示在每一站下方。
EN:
- Model:
deepseek/deepseek-chat(DeepSeek-V3, non-reasoning) via OpenRouter — the fast tier (~20s/call vs ~50s for V4-Pro), creative-not-reasoning work. Override:GAOKAO_TRAJECTORY_MODEL. - Call:
gaokao/ranked.py::_llm_json()— POST toopenrouter.ai/.../chat/completions,response_format=json_object, 4 retries w/ backoff. Every piece below is one such call. - Web search: the investigation call runs web-search-grounded (DeepSeek-V3 + OpenRouter web plugin,
plugins:[{id:web}]; toggleGAOKAO_WEBSEARCH). It’s source-disciplined: the prompt restricts to authoritative sources, a filter (_auth_sources) drops news/UGC from the displayed citations, and it falls back to the grounding KB if nothing authoritative is found. Sources show under each stage.
延迟:推测式预取 · Latency: speculative prefetch
中文:每次调查都是一次 ~20 秒的网络检索调用。与其让学生干等,我们把它藏到他的阅读时间背后——他读一站 + 决定要不要重排所花的时间,远多于生成下一站所需的时间。
怎么运作的(gaokao/ranked.py + web.py):
- 一站刚被送出(
/rank_start、/rank_next)的那一刻,一个后台线程(_spawn_prefetch)就调用RankedSession.prefetch_next()——它为当前第 1 名生成下一站,存进以(stage_index, top_label)为键的内存缓存里。 - 趁它在炖着,学生正在阅读。当他点下一站,
next_stage()查缓存:命中则瞬时送出(~0 秒);未命中则当场生成。 - 如果他重排了第 1 名,缓存的预取是给旧的榜首准备的,所以它被清除——下一次点击会为新的第 1 名重新生成(轨迹仍正确地转向)。一次重排只花一次普通生成的成本。
结果:已验证——预取过的一站在 0.00 秒内送出,对比冷启动 ~23 秒。大多数点击(学生没动第 1 名)是瞬时的;只有重排才付等待的代价。
范围 / 扩展:v1 只预取当前第 1 名的下一站(主流情形)。一个自然的扩展是同时预取当前第 2 名的下一站,这样重排到第 2 名也瞬时——代价是每站多一次后台调用。默认不开(网络检索 × 2 = 更多 $/延迟);若重排被证明常见,很容易启用。
EN: Each investigation is a ~20s web-search call. Rather than make the student wait, we hide it behind their read-time — they spend far longer reading a stage + deciding whether to re-rank than the next stage takes to generate.
How it works (gaokao/ranked.py + web.py):
- The moment a stage is served (
/rank_start,/rank_next), a background thread (_spawn_prefetch) callsRankedSession.prefetch_next()— it generates the next stage for the current #1 and stores it in an in-memory cache keyed by(stage_index, top_label). - While that cooks, the student is reading. When they click 下一站,
next_stage()checks the cache: a hit serves instantly (~0s); a miss generates on the spot. - If they re-rank #1, the cached prefetch is for the old top, so it’s cleared — the next click regenerates for the new #1 (the trajectory still pivots correctly). A re-rank just costs one normal generation.
Result: verified — a prefetched stage serves in 0.00s vs ~23s cold. Most clicks (the student didn’t move #1) are instant; only a re-rank pays the wait.
Scope / extensions: v1 prefetches only the current #1’s next stage (the dominant case). A natural extension is to also prefetch the current #2’s next stage, so a re-rank to #2 is instant too — at the cost of a second background call per stage. Not on by default (web search × 2 = more $/latency); easy to enable if re-ranks prove common.
7 个站(因素序列)· The 7 stops (factor sequence)
中文:轨迹跟随学生的当前第 1 名;每一站是一个因素,隐式地织进去(不标注「第 1 年」):
EN: The trajectory follows the student’s current #1; each stop is one factor, woven in implicitly (not labelled “year 1”):
| # | key | 维度 | what it probes |
|---|---|---|---|
| 1 | course | 课程与学业 | 大一大二真正学的课、强度、扛不扛得住 |
| 2 | daily | 日常与社群 | 校园日常、城市生活、社群归属(最常被忽视) |
| 3 | interest | 兴趣与擅长 | 做这些事是享受还是煎熬 |
| 4 | finance | 经济与回报 | 学费/家庭负担、起薪与长期收入 |
| 5 | city | 城市与机会 | 城市能级、实习就业机会、离家远近 |
| 6 | career | 职业前景 | 对口岗位、天花板、行业周期、35岁 |
| 7 | cost | 代价与放弃 | 选它放弃了什么(机会成本) |
一站 = 一次调用 → 三个部件 · One stop = ONE call → three pieces
③ Tip「你可能没考虑过」(did_you_know) 已于 2026-06-17 退役(易产生无依据对比);④「看懂」与 ⑤ 框架测试也已退役。详见末尾 已退役 / Legacy。
中文:一站由 ranked.py::investigate(factor, options, profile) 产出。一次 LLM 调用返回一个 JSON,包含全部四个页面部件。输入:因素、第 1 名的 grounded 事实(grounding.grounding_block(top))、其余 4 个候选的 grounded 事实、以及玩家画像。
EN: A stop is produced by ranked.py::investigate(factor, options, profile). One LLM
call returns a JSON with all four on-page pieces. Inputs: the factor, the grounded
facts of the #1 (grounding.grounding_block(top)), the grounded facts of the other 4
candidates, and the player profile.
| On-page piece | JSON field | what it is |
|---|---|---|
| ① Storyline | prose | a ≤110-字 first-person vignette of living the #1 and hitting this factor, using real courses/jobs from the grounding |
| ② Investigation | top_take + contender_take | how #1 fares on this factor vs one contender the model picks — now web-search-grounded against authoritative sources, so it carries real figures |
did_you_know | 已下线 — 曾提示本维度被忽视的信息,因易生成无依据对比而退役;见末尾 Legacy | |
| (selection) | contender | which of the other 4 it chose to contrast |
| 来源 | sources | 2-3 authoritative citations (就业质量报告 / 麦可思 / .edu.cn…), news/UGC filtered out |
中文:所有部件的确切提示词见下方 All prompts (verbatim) 附录。 EN: The exact prompts for all pieces are in the All prompts (verbatim) appendix below.
grounding 块 · The grounding block
中文:grounding 块是带事实/观点标注的(课程 · 职业 · 路径 · 薪资 · 日常现实 · 失败模式 · 转向),取自 859-专业知识库——见 Grounding Layer。那份具体性契约禁止编造数字/雇主。
EN: The grounding block is fact/opinion-labeled (courses · careers · paths · salary · daily reality · failure modes · pivots) from the 859-major KB — see Grounding Layer. The concreteness contract forbids inventing numbers/employers.
④「看懂这个专业」按钮 (已退役 RETIRED 2026-06-17,见 Legacy) · ④ “看懂这个专业” button — RETIRED (on-demand, separate call)
中文:每站可选。ranked.py::translate_major(top) → 端点 /rank_translate。从第 1 名的 grounding 出发一次 V3 调用 → 三部分:
EN: Per stop, optional. ranked.py::translate_major(top) → endpoint /rank_translate.
One V3 call from the #1’s grounding → three parts:
| field | shown as |
|---|---|
official | 📋 招生简章怎么说(官腔原文模仿) |
plain | 🗣️ 说人话(一句:到底学什么/干什么) |
hidden | ⚠️ 没告诉你的(3-5 条真实坑:数学要求/新设专业/对口率/35岁…) |
⑤ 框架稳定性测试 (已退役 RETIRED 2026-06-17,见 Legacy) · ⑤ Framing-stability test — RETIRED (formerly after stop 7)
中文:ranked.py::frame_test(top, profile) → 端点 /rank_frametest。一次 V3 调用,把第 1 名放进三种说服框架重述,每一种都标注它所利用的认知偏差:
EN: ranked.py::frame_test(top, profile) → endpoint /rank_frametest. One V3 call reframes
the #1 under three persuasion frames, each tagged with the cognitive bias it exploits:
| frame | bias |
|---|---|
| 恐惧框架 | 损失厌恶 |
| 机会框架 | 乐观偏差 |
| 权威框架 | 权威服从 |
中文:学生标记每一种是否动摇了自己;框架不变 = 一个反思均衡信号;动摇则定位出一处偏差。(BE 2.0 ——ideal-preference checklist。)
EN: The student marks whether each sways them; frame-invariance = a 反思均衡 signal; wavering localizes a bias. (BE 2.0 — ideal-preference checklist.)
首尾两端(无 LLM)· Bookends (no LLM)
中文:
- 开头(
gaokao/quiz.py):5 项排名列表 + 一个信心评分 + 一份画像问卷——6 道精选单选题(非生成,所以瞬时),每个选项标注 8 极dimension_vector,折叠进PersonalityFile。 - 结尾(
ranked.py::ending()):完全确定性——新排名、初始→最终的位移、n_reranks、框架稳定计数 + 动摇的偏差、叶晓阳的 6 项反思均衡检查清单(gaokao/checklist.py)、以及最终对比初始的信心。
EN:
- Starter (
gaokao/quiz.py): the ranked list of 5 + a confidence rating + a profiling quiz — 6 curated MCQs (not generated, so it’s instant), each option tagged with 8-poledimension_vectors that fold into thePersonalityFile. - End (
ranked.py::ending()): fully deterministic — the new ranking, initial→final shift, n_reranks, the frames-stable count + biases wavered on, 叶晓阳’s 6-item 反思均衡检查清单 (gaokao/checklist.py), and final-vs-initial confidence.
重排 = 那个转向 · Re-ranking = the pivot
中文:重排侧边列表(/rank_reorder)会改变选项顺序;下一次 investigate() 读 options[0],所以移动第 1 名会把整条轨迹转向到新的榜首,从下一站起生效。
EN: Reordering the side list (/rank_reorder) mutates the option order; the next
investigate() reads options[0], so moving #1 pivots the whole trajectory onto the
new top choice from the next stop on.
去哪里读它 · Where to read it
全部提示词(逐字)· All prompts (verbatim)
中文:游戏发送的每一条提示词,与构建时一模一样({...} = 插值字段)。模型:deepseek/deepseek-chat(V3);调查那次带网络插件运行。
EN: Every prompt the game sends, exactly as built ({...} = interpolated fields). Model:
deepseek/deepseek-chat (V3); the investigation runs with the web plugin.
② 调查 — ranked.py::investigate()(已移至 investigator)· ② Investigation — moved to investigator
中文:调查员的当前提示词、机制、与输出处理已整理到独立页 → Investigator(原 websearch 页重命名)。 EN: The investigator’s current prompt, mechanism, and output handling now live on their own page → investigator (the former websearch page, renamed).
④ 看懂这个专业 — ranked.py::translate_major()
把高考专业「{label}」翻译给一个高中生看。基于真实背景:
{grounding_block(label)}
只输出一个 JSON 对象(简体中文),不要多余文字:
{
"official": "一段官腔的专业介绍(模仿高校招生简章口吻,2-3句)",
"plain": "一句说人话:这个专业到底在干什么、学完干什么",
"hidden": ["3-5 条'招生简章没告诉你的'真实情况,如数学要求高/是不是新设专业/技术更新快/热门=竞争激烈/对口率/天坑点(取自上面的真实背景,不要编造)"]
}⑤ 框架稳定性测试 — ranked.py::frame_test() · ⑤ Framing-stability test — ranked.py::frame_test()
学生当前第 1 选择是「{top}」。用三种"框架"重新描述这个选择,测试他的决定稳不稳——真正想清楚的选择,不会因为换个说法就动摇。三种框架各对应一个认知偏差:
- 恐惧框架(利用 损失厌恶):强调选它/不选它的可怕后果
- 机会框架(利用 乐观偏差):把它包装成不可错过的绝佳机会
- 权威框架(利用 权威服从):假托父母/老师/专家的口吻施压
真实背景(可引用,不要编造):{grounding_block(top)}
只输出一个 JSON 对象(简体中文):
{"frames":[
{"frame":"恐惧框架","bias":"损失厌恶","pitch":"一段 45 字内、用这个框架施压的话"},
{"frame":"机会框架","bias":"乐观偏差","pitch":"..."},
{"frame":"权威框架","bias":"权威服从","pitch":"..."}
]}
这些是"诱导话术",用来让学生看清自己会不会被带跑;不要替他下结论。问卷与结尾 · The quiz and the end
中文:画像问卷(
gaokao/quiz.py)是精选的、非生成的——无提示词;结尾(ranked.py::ending())是确定性的——无提示词。EN: The profiling quiz (
gaokao/quiz.py) is curated, not generated — no prompt; the end (ranked.py::ending()) is deterministic — no prompt.
已退役 · Legacy (retired 2026-06-17)
中文。 以下部件在 ZH 实测后退役。机制说明保留在本页(上方,已标注 已退役)以备日后参考/复活;它们不在当前线上流程里:
- ③ Tip「你可能没考虑过」(
did_you_know) — 会编造无依据的跨校/跨专业对比(典型:声称”在 X 校比在北大更易拓展人脉”,无来源、未检索)。已从场景 UI 和investigate提示词中移除。现在的调查由 WTE 选定维度 → 因人而异的具体问题 → grounded 的第1名 vs 对比项 承担。 - ④「看懂这个专业」按钮 (
translate_major//rank_translate) — 暂退;端点保留待命,日后做更有据可依的版本再启用。 - ⑤ 框架稳定性测试 (
frame_test//rank_frametest) — 暂退;第 7 站后直接进入结尾。端点保留待命。
English. These pieces were retired after ZH’s live testing. Their mechanics are kept above (tagged RETIRED) for reference/revival; they are not in the current live flow:
- ③ “你可能没考虑过” (
did_you_know) — fabricated unsourced cross-school/major comparisons; removed from the UI and theinvestigateprompt. The WTE-chosen dimension → person-specific question → grounded 1-vs-contender now carries the investigation. - ④ “看懂这个专业” (
translate_major//rank_translate) — retired; endpoint kept dormant for a future more grounded version. - ⑤ Framing-stability test (
frame_test//rank_frametest) — retired; the last stop goes straight to the ending. Endpoint kept dormant.