这是什么 · What this is
中文:MenoClaw 对 ZH 在 2026-06-13 反馈「高考志愿这个游戏太泛」的回应。针对全部 4 个问题 + 预生成 + 模糊,给出 根因 → 修复 → 数据来源 → 工作量。先出计划——游戏行为只在获批后才改(现已批准;grounding 构建进行中)。
EN: MenoClaw’s response to ZH’s 2026-06-13 feedback that the 高考志愿 game is too generic. Root cause → fix → data source → effort, for all 4 problems + pre-gen + blur. Plan first — game behaviour only changes on approval (now given; grounding build in progress).
高考志愿「A/B 路径推演」— 质量整改计划
更新 2026-06-13 · Update 2026-06-13
中文:§1 grounding 层 v1 已上线:Grounding Layer。模糊已修。§2/§3(intake + 身份锁/选项 gate)接着做。
EN: §1 grounding layer v1 shipped: Grounding Layer. Blur fixed. §2/§3 (intake + identity-lock/option-gate) next.
Callout
中文:仅为计划——在你批准之前游戏不会有任何改动。 MenoClaw · 2026-06-13 · 回应 ZH 的反馈讨论串。
EN: Plan only — nothing in the game changes until you approve this. MenoClaw · 2026-06-13 · in response to ZH’s feedback thread.
中文:这回应你提出的四个问题(具体性 / 人物建模 / 一致性 / 细节),外加预生成和模糊两问。每一项都是 根因 → 修复 → 数据从哪来 → 工作量/风险,并附文件引用,让诊断可核查、而非空谈。
EN: This responds to the four problems you raised (具体性 / 人物建模 / 一致性 / 细节), plus the pre-generation and blur questions. Each item is root cause → fix → where the data comes from → effort/risk, with file references so the diagnosis is checkable, not hand-waved.
0. 诊断总览(一张表)· Diagnostic overview (one table)
中文:
| # | 你看到的问题 | 根因 (代码层面) | 修复方向 | 数据来源 |
|---|---|---|---|---|
| 1 | 剧情太泛、“冷门专业”是哪个专业都不知道 | data_seed.json 只有 5 个手写 archetype + 一句 school-tier;管线里没有任何专业/职业级知识 | 建一个真实grounding知识层,按 (专业, 院校层次, 阶段) 检索具体事实注入 seed | 就业质量报告 + 麦可思 + 阳光高考培养方案 + LLM蒸馏专业图谱(标注为观点的张雪峰式解读) |
| 2 | 完全没考虑我的性格/画像 (“我是设计师,创作是必走的路”) | profile 有传进去,但只是 seed 里一行抽象的 pole 强度,权重低;身份事实没被采集/强调 | 采集鲜活身份 + 把画像提到 prompt 顶部当硬性相关约束 | 现有 intake + voice-profile (已接入 free_text) |
| 3 | 选项不连贯 (设计师却给”考研/research/互联网实习”;材料vs设计却冒出CS/law) | 选项是模型自由发明的,没锁定到所选专业/身份;A/B 两条命共享上下文→领域串味 | 每条人生锁定各自身份 + 新增选项合法性 gate(拒绝引入未确立领域/把你从喜欢的专业上”劝退”的选项) | 同 #1 的 grounding |
| 4 | 细节像 shit、跨命串领域 | = #3(无锁定) + #1(无专业grounding) 的叠加 | 由 #1+#3 一并解决 | — |
| 5 | 预生成有在做吗? | SessionPrefetcher 只在通用 emergent 流程里,没移植到交互式 A/B 流程 | 把投机预取移植到 InteractiveSession | — |
| 6 | ”人生A""第一幕”等字模糊 | 文字画在 <canvas> 上,没做 devicePixelRatio 缩放→视网膜屏发虚 | canvas 按 dpr 缩放,~5 行 | — |
EN:
| # | Problem you saw | Root cause (code level) | Fix direction | Data source |
|---|---|---|---|---|
| 1 | 剧情太泛、“冷门专业”是哪个专业都不知道 | data_seed.json 只有 5 个手写 archetype + 一句 school-tier;管线里没有任何专业/职业级知识 | 建一个真实grounding知识层,按 (专业, 院校层次, 阶段) 检索具体事实注入 seed | 就业质量报告 + 麦可思 + 阳光高考培养方案 + LLM蒸馏专业图谱(标注为观点的张雪峰式解读) |
| 2 | 完全没考虑我的性格/画像 (“我是设计师,创作是必走的路”) | profile 有传进去,但只是 seed 里一行抽象的 pole 强度,权重低;身份事实没被采集/强调 | 采集鲜活身份 + 把画像提到 prompt 顶部当硬性相关约束 | 现有 intake + voice-profile (已接入 free_text) |
| 3 | 选项不连贯 (设计师却给”考研/research/互联网实习”;材料vs设计却冒出CS/law) | 选项是模型自由发明的,没锁定到所选专业/身份;A/B 两条命共享上下文→领域串味 | 每条人生锁定各自身份 + 新增选项合法性 gate(拒绝引入未确立领域/把你从喜欢的专业上”劝退”的选项) | 同 #1 的 grounding |
| 4 | 细节像 shit、跨命串领域 | = #3(无锁定) + #1(无专业grounding) 的叠加 | 由 #1+#3 一并解决 | — |
| 5 | 预生成有在做吗? | SessionPrefetcher 只在通用 emergent 流程里,没移植到交互式 A/B 流程 | 把投机预取移植到 InteractiveSession | — |
| 6 | ”人生A""第一幕”等字模糊 | 文字画在 <canvas> 上,没做 devicePixelRatio 缩放→视网膜屏发虚 | canvas 按 dpr 缩放,~5 行 | — |
1. 真实性 / 具体化 —— 这是真正的命门 · Realism / specificity — the real crux
中文:
根因. gaokao/trajectory.py::build_gaokao_seed 把 data_seed.json 里某个
archetype 的 worst_case / daily_reality / upside / cost 四句手写的泛化字符串,
加上 school_tier.tier_phrase() 一句院校层次,塞进 seed。core/emergent.py::_seed_text
会把它们原样渲染进 prompt。整条管线里没有任何”专业 → 课程 / 出路 / 日常 / 转折”
的知识。所以模型想具体也无米下锅——“被调剂到冷门专业”只能停留在抽象。
修复:建一个真实 grounding 知识层。 结构化、可检索,按 (专业, 院校层次) 为键:
- 专业知识图谱 (每个专业一张卡):核心课程、典型出路(升学/就业/转行 + 真实比例)、 日常真实(课业/实验/作品集/实习强度)、常见转折(转专业/双学位/辅修/考研/保研/留学/ 就业/创业)、真实失败模式(就业难/天坑/对口率低/35岁问题…)。
- 检索注入:按 (major, school_tier, 当前阶段) 取出一段具体事实块,替换/增强现在那 4 句泛化 archetype。模型从具体出发去戏剧化,无法凭空捏造。
- 具体性契约 (prompt 规则):每个场景必须引用 grounding 块里的具体课程/公司/数字; 禁止编造无出处的具体信息(可写实化的”色彩”另算,见开放问题)。
数据来源 (诚实地说).
- ✅ 教育部就业质量报告(校级,公开可下载 PDF)、麦可思就业蓝皮书(专业级 薪资/对口率/
满意度)、阳光高考平台(专业目录 + 培养方案)、已有的 2347 校录取数据 (
real_data/). - ⚠️ 知乎/小红书 实时 UGC 抓取——已验证不可行(反爬军备:x-zse-96 签名 + 完整 cookie, 上次 z_c0 失效后放弃)。所以 corpus = 已发布报告(可下载) + LLM 蒸馏的专业图谱(用报告 校验),不是实时 UGC 抓取。我不会再在抓取上烧时间。
- LLM 蒸馏的”张雪峰式”解读会明确标注为观点(opinion)而非事实(fact),避免把网络段子当真。
工作量/风险. 这是最大的一块。第一版可先覆盖报考量 top ~50 专业(开放问题见 §8), 其余 fallback 到”通用但诚实”的模板。风险:报告是校/专业聚合,落到”某人某专业”仍需模型插值—— 靠具体性契约 + 出处约束控制编造。
EN:
Root cause. gaokao/trajectory.py::build_gaokao_seed takes the four hand-written, generic strings worst_case / daily_reality / upside / cost from some archetype in data_seed.json, plus one school-tier line from school_tier.tier_phrase(), and stuffs them into the seed. core/emergent.py::_seed_text renders them verbatim into the prompt. Nowhere in the pipeline is there any “major → courses / outcomes / daily life / turning points” knowledge. So even if the model wants to be specific it has nothing to cook with — “被调剂到冷门专业” can only stay abstract.
Fix: build a real grounding knowledge layer. Structured, retrievable, keyed by (major, school tier):
- Major knowledge graph (one card per major): core courses, typical outcomes (further study / employment / career switch + real proportions), daily reality (coursework / labs / portfolio / internship intensity), common turning points (changing major / double degree / minor / postgrad exam / recommended postgrad / study abroad / employment / entrepreneurship), real failure modes (hard job market / 天坑 majors / low field-match rate / the 35-year-old problem…).
- Retrieval injection: by (major, school_tier, current stage) pull out a concrete fact block that replaces/augments the current four generic archetype lines. The model dramatizes from the concrete, unable to fabricate from thin air.
- Specificity contract (prompt rule): every scene must cite concrete courses / companies / numbers from the grounding block; fabricating source-less specifics is forbidden (realizable “colour” is separate — see open questions).
Data source (honestly stated).
- ✅ MOE employment-quality reports (school-level, publicly downloadable PDFs), MyCOS employment blue books (major-level salary / field-match / satisfaction), 阳光高考 platform (major catalog + curricula), and the existing 2347-school admissions data (
real_data/). - ⚠️ Zhihu/Xiaohongshu live UGC scraping — verified infeasible (anti-scrape arms race: x-zse-96 signature + full cookie; abandoned after z_c0 expired last time). So the corpus = published reports (downloadable) + an LLM-distilled major graph (validated against the reports), not live UGC scraping. I won’t burn more time on scraping.
- The LLM-distilled “张雪峰-style” interpretations are explicitly labeled as opinion, not fact, to avoid taking internet memes as truth.
Effort/risk. This is the biggest chunk. v1 can first cover the top ~50 majors by application volume (open question in §8), with the rest falling back to a “generic but honest” template. Risk: reports are school/major aggregates, so pinning to “this person, this major” still needs model interpolation — controlled by the specificity contract + sourcing constraint.
2. 人物建模 · Character modeling
中文:
根因. gaokao/profile.py::serialize_for_prompt 确实把画像传给了生成器——但只是
一行抽象的 pole 强度 (TRUTH:+0.80, …),夹在 ~11 行 seed 中间,权重很低。你的真实身份
(“我是设计师,创作是我必走的路”)要么 intake 没采到,要么没被强调。
修复.
- 更扎实的 intake:采集身份事实(我是谁 / 我擅长 / 我必走的路 / 我怕什么)作为 free_text + 几个结构化锚点(意向专业契合度、风险姿态)。voice-profile 已经喂 free_text,确认其权重。
- prompt 提级:把 PLAYER PROFILE 移到 stable prefix 最顶端,并把身份复述为硬约束 (“此人是设计师;所有场景必须与设计/创作世界相关”)。
- 守住护栏:相关性 ≠ 迎合。画像只决定你会遇到哪些岔路,绝不决定哪个选项看起来对——
否则就成了回音室,违背”偏好无对错”原则(这是
profile.py里既有的 guardrail,保留)。
工作量/风险. 中等。主要是 intake UI + prompt 重排 + 一个”身份锁”。
EN:
Root cause. gaokao/profile.py::serialize_for_prompt does pass the profile to the generator — but only as one line of abstract pole strengths (TRUTH:+0.80, …), buried in the middle of ~11 seed lines, low weight. Your real identity (“我是设计师,创作是我必走的路”) was either not captured by intake or not emphasized.
Fix.
- Sturdier intake: capture identity facts (who I am / what I’m good at / the path I must take / what I fear) as free_text + a few structured anchors (intended-major fit, risk posture). voice-profile already feeds free_text; confirm its weight.
- Prompt promotion: move PLAYER PROFILE to the very top of the stable prefix, and restate the identity as a hard constraint (“此人是设计师; all scenes must relate to the design/creation world”).
- Keep the guardrail: relevance ≠ pandering. The profile only decides which forks you encounter, never which option looks right — otherwise it becomes an echo chamber, violating the “preferences have no right/wrong” principle (this is an existing guardrail in
profile.py, kept).
Effort/risk. Medium. Mainly intake UI + prompt reordering + an “identity lock”.
3. 一致性 / 选项连贯 · Consistency / option coherence
中文:
根因. 选项由 emergent 引擎自由发明,没有”必须从所选专业/身份衍生”的硬约束;而且 A、B
两条命共享 profile 上下文,领域会串味(材料-vs-设计的局里冒出 CS/law)。StateManager
只保证事实不自相矛盾,不保证选项与身份相关。
修复.
- 每条人生身份锁:每条命锁定各自的 (school, major, the_choice);seed 明示 “本条人生 = 选择了 X;所有场景与选项必须从 X 衍生,不得引入未确立的领域”。
- 选项合法性 gate (新增,类比现有 consistency gate):拒绝任何 (a) 引入 state/grounding 里未确立领域的选项;(b) 在你因为喜欢而选的专业上、没有你自己的价值驱动就把你”劝退”的选项。 失败则 regen。
- 杜绝跨命泄漏:A、B 各自独立的 grounding 上下文;校验 A 这条永不引用 B 的领域。
- 你那句”我喜欢这个专业,凭什么因为它热门就劝我换”——直接编码:引擎不得把”放弃你喜欢的选择” 呈现为默认/“明智”路径;岔路来自你的价值,不来自暗含的正确答案。
工作量/风险. 中等。gate 是确定性校验 + bounded regen,和现有 consistency gate 同构。
EN:
Root cause. Options are freely invented by the emergent engine, with no hard constraint that they “must derive from the chosen major/identity”; and lives A and B share profile context, so domains bleed (a 材料-vs-设计 setup throws up CS/law). StateManager only guarantees facts don’t self-contradict, not that options relate to identity.
Fix.
- Per-life identity lock: each life locks its own (school, major, the_choice); the seed states explicitly “this life = chose X; all scenes and options must derive from X, no introducing unestablished domains”.
- Option-legality gate (new, analogous to the existing consistency gate): reject any option that (a) introduces a domain not established in state/grounding; (b) on a major you chose because you like it, “talks you out of it” without your own value drive. On failure, regen.
- Eliminate cross-life leakage: A and B each get an independent grounding context; verify life A never references B’s domains.
- Your line “我喜欢这个专业,凭什么因为它热门就劝我换” — encoded directly: the engine must not present “giving up the choice you like” as a default / “wise” path; forks come from your values, not from an implied correct answer.
Effort/risk. Medium. The gate is a deterministic check + bounded regen, isomorphic to the existing consistency gate.
4. 细节连贯 · Detail coherence
中文:= #3(无身份锁) + #1(无专业 grounding) 的叠加症状。由 #1 + #3 一并解决,不单列。
EN: = the compound symptom of #3 (no identity lock) + #1 (no major grounding). Solved together by #1 + #3, not listed separately.
5. 预生成 (延迟优化) · Pre-generation (latency optimization)
中文:
现状. plot/prefetch.py::SessionPrefetcher 存在,但只服务通用 emergent 流程;
没有移植到 gaokao/interactive.py::InteractiveSession(它是每次点击一发 LLM 调用)。
计划. 当用户读当前幕 / 在犹豫时,投机生成当前这条命接下来 ≤N 个”每选项后续”幕 (以及另一条命的第一幕)。按 (side, stage, 所选选项 hash) 缓存。点击时命中即秒出,未命中再现生成。 受 provider 单 key 限流约束,预取并发设上限。预期:把多数点击的 ~20s 等待降到接近 0。
工作量/风险. 中等。注意 provider 对同一 key 的并发节流(实测并行收益有限)。放在质量修好之后做。
EN:
Status. plot/prefetch.py::SessionPrefetcher exists, but only serves the generic emergent flow; it’s not ported to gaokao/interactive.py::InteractiveSession (which fires one LLM call per click).
Plan. While the user is reading the current act / hesitating, speculatively generate this life’s next ≤N “per-option follow-up” acts (plus the other life’s first act). Cache by (side, stage, chosen-option hash). On click, a hit is instant; a miss regenerates. Subject to provider single-key rate limits, prefetch has a concurrency cap. Expected: cut most clicks’ ~20s wait to near 0.
Effort/risk. Medium. Watch the provider’s concurrency throttling on the same key (measured parallelism gains are limited). Do it after quality is fixed.
6. Blur 修复 (视觉) · Blur fix (visual)
中文:
根因. gaokao/web.py::drawScene 把”人生A""第N幕”和正文用 ctx.fillText 画在
<canvas> 上,但 canvas 的位图分辨率按 CSS 像素算,没乘 devicePixelRatio——视网膜屏上
被放大 2x 显示就发虚。
修复 (~5 行). cv.width = cssW * dpr; cv.height = cssH * dpr; cv.style.width=cssW+'px'; ctx.scale(dpr,dpr)。纯前端、零风险,可随时单独做(甚至先于整改)。
EN:
Root cause. gaokao/web.py::drawScene draws “人生A”, “第N幕” and body text with ctx.fillText on a <canvas>, but the canvas’s bitmap resolution is computed in CSS pixels, not multiplied by devicePixelRatio — so on a retina screen it’s scaled up 2x for display and looks fuzzy.
Fix (~5 lines). cv.width = cssW * dpr; cv.height = cssH * dpr; cv.style.width=cssW+'px'; ctx.scale(dpr,dpr). Pure front-end, zero risk, can be done standalone any time (even before the overhaul).
7. 建议的执行顺序 (待你 go) · Suggested execution order (pending your go)
中文:
- #1 grounding 知识层 —— 脊柱,最大投入,决定一切。
- #2 人物建模 + #3 一致性 —— 骑在 grounding 上。
- #6 blur —— 5 分钟快赢,可先做。
- #5 预生成 —— 质量对了之后再压延迟。
并行可做:#6 随时;#1 的数据采集(下载报告)可与 3 的 prompt 改造并行。
EN:
- #1 grounding knowledge layer — the spine, biggest investment, decides everything.
- #2 character modeling + #3 consistency — ride on top of grounding.
- #6 blur — a 5-minute quick win, can go first.
- #5 pre-generation — squeeze latency once quality is right.
Parallelizable: #6 any time; #1’s data collection (downloading reports) can run in parallel with 3’s prompt rework.
8. 需要你拍板的开放问题 · Open questions for you to decide
中文:
- Grounding 深度:第一版先覆盖报考量 top ~50 专业,还是要全量?(全量会拖慢首版)
- LLM 蒸馏可接受吗:既然实时 UGC 抓取被封死,专业图谱用LLM 蒸馏 + 报告校验生成、 并标注 opinion/fact,你能接受吗?还是只用已发布报告里能直接查到的事实?
- 具体性契约松紧:严格(禁止一切无出处的具体)还是柔性(优先 grounded,允许合理的写实色彩)?
- 专业范围:先做你/测试者真实在纠结的那几个(设计/材料/CS/法学…)做样板,还是先铺广度?
EN:
- Grounding depth: should v1 cover the top ~50 majors by application volume, or go full-scale? (Full-scale slows the first release.)
- Is LLM distillation acceptable: since live UGC scraping is blocked, is it OK to generate the major graph via LLM distillation + report validation, labeled opinion/fact? Or only facts directly findable in published reports?
- Specificity-contract strictness: strict (forbid all source-less specifics) or soft (prefer grounded, allow reasonable realistic colour)?
- Major scope: start with the few you/testers are really agonizing over (设计/材料/CS/法学…) as a template, or spread breadth first?
Callout
中文:这些定了,我就按 §7 顺序开工。在你批准之前,游戏行为零改动。
EN: Once these are settled, I’ll start in the §7 order. Until you approve, zero changes to game behaviour.