每一回合背后的完整后端 · The complete backend behind every game turn

中文:每一回合游戏背后的完整后端——构造什么 prompt、如何校验、人生如何保持连贯、跑哪些模型。MenoClaw · 2026-06-13。

EN: The complete backend behind every game turn — prompt anatomy, the gates, coherence, models. MenoClaw · 2026-06-13.

1. 系统形态 · Shape of the system

中文:高考志愿变体复用 emergent 世界引擎core/emergent.py)作为底座。一个「回合」 = 一个人生关键阶段(大一 → 毕业 → 求职 → 回望)。学生一次走一阶段地活两条人生(选项 A 和 B)——每次点击 = 一次 LLM 调用gaokao/interactive.py::InteractiveSession),所以节奏是刻意的(「不要一次性给出所有结果」)。

EN: The 高考志愿 variant reuses the emergent world-engine (core/emergent.py) as the substrate. One “turn” = one pivotal life stage (大一 → 毕业 → 求职 → 回望). The student lives two lives (option A and option B) one stage at a time — every click is one LLM call (gaokao/interactive.py::InteractiveSession), so pacing is deliberate (“don’t dump all results at once”).

intake (two real options + profile + archetype)
   → live A, stage by stage (choose at every "假如…你怎么办?")
   → live B, stage by stage
   → backward-reasoning mirror over both lives  (compare.py)
   → 反思均衡 cost-acceptance gate ("我能接受,我不后悔")

2. 单阶段管线(精确)· The per-stage pipeline (exact)

中文:每个阶段,InteractiveSession._gen(side) 执行:

EN: For each stage, InteractiveSession._gen(side) runs:

sm.begin_turn()
seed   = build_gaokao_seed(option, profile.serialize_for_prompt(), archetype, side)
for attempt in range(4):                      # bounded regeneration
    raw  = generator.generate(seed, skills_brief="",
                              state_memory=sm.serialize_for_prompt(),
                              turn_index, turn_cap)        # ← one LLM call
    turn = validate_emergent_payload(parse_emergent_json(raw))   # instrument-validity gate
    if not sm.apply(turn.state_delta).applied:  # consistency gate
        continue                                # state_delta contradicts established fiction → regen
    return turn
# EmergentValidationError → regen;  API/429/timeout → sleep 3·(attempt+1)s, regen

中文:三道闸门,最多 4 次尝试:

  1. 解析parse_emergent_json)——必须是恰好一个合法 JSON 对象。
  2. 工具有效性validate_emergent_payload)——prose + 2~3 个选项,每个都带非空、且只用 8 维 rubric pole 名的 dimension_vector
  3. 一致性StateManager.apply(state_delta))——新事实不得与这条命里先前确立的内容矛盾;矛盾则拒绝 + 重生成。

EN: Three gates, up to 4 attempts:

  1. Parse (parse_emergent_json) — must be exactly one valid JSON object.
  2. Instrument validity (validate_emergent_payload) — prose + 2–3 options, each with a non-empty dimension_vector over the 8-dim rubric pole names.
  3. Consistency (StateManager.apply(state_delta)) — the new facts must not contradict anything established earlier in this life; on contradiction, reject + regenerate.

中文:合法回合之后:所选选项的 dimension_vector 折进运行中的画像(profile.update_from_choice),StateManager.record_choice 记录分支。

EN: After a valid turn: the chosen option’s dimension_vector folds into the running profile (profile.update_from_choice), and StateManager.record_choice logs the branch.

3. Prompt 解剖(build_emergent_prompt)· Prompt anatomy (build_emergent_prompt)

中文:prompt 这样拼接,使得 stable prefix 在一个 session 的各回合间逐字节相同——它落在 provider 的前缀缓存里(主要的延迟杠杆):

EN: The prompt is assembled so the stable prefix is byte-identical across turns of a session — it sits in the provider’s prefix cache (the main latency lever):

[ STABLE PREFIX ]                       ← cached across the whole session
   skills_brief         (currently "" for gaokao — a known gap)
   _rubric()            the 8-dimension preference rubric (pole names + meaning)
   WORLD-BIBLE SEED     _seed_text(seed): every seed field rendered as "key: value"
[ WORLD-STATE MEMORY ]                   ← varies each turn (StateManager ledger)
[ THE ASK ]                              ← fixed JSON schema request

中文ASK 要求恰好一个 JSON 对象: {"prose", "options":[{"label","dimension_vector":{DIM:-1..1}}, …2-3…], "state_delta":{…}} —— prose 与每个 label 用简体中文;只有 dimension_vector 的键保留英文 rubric pole 名;state_delta 不得与既有事实矛盾;任何选项都不是「正确答案」。

EN: The ASK demands exactly one JSON object: {"prose", "options":[{"label","dimension_vector":{DIM:-1..1}}, …2-3…], "state_delta":{…}} — prose + every label in 简体中文; only dimension_vector keys stay the English rubric pole names; state_delta must not contradict established facts; no option is a “right answer.”

4. 种子(build_gaokao_seed)· The seed (build_gaokao_seed)

中文:模型据以戏剧化的 grounding。字段:

EN: The grounding the model dramatizes from. Fields:

fieldmeaning
premisecompressed multi-year sim, not a prediction; advance through life stages
the_choice_madewhich option this life took (option_A / option_B)
school, majorthe concrete choice
MUST_HIT_worst_caseauthored worst case the path must confront (symmetric 红利/代价)
MUST_HIT_daily_realityauthored daily texture the path must show
this_path_upside, this_path_costthe upside and the price
realism_ruledramatize but never fabricate; no numeric prophecy; no verdicts
player_profileprofile.serialize_for_prompt() — relevance-only, never affirmation
school_factsschool_tier.tier_phrase(lookup(school)) — 985/211/双一流 tier

「泛化」的来源 · Where today's genericness comes from

中文:那 4 句 MUST_HIT_* / upside / cost每个 archetype 手写的(data_seed.json 里 5 个)。管线里没有任何专业/职业级知识——详见整改计划 §1。

EN: The four MUST_HIT_* / upside / cost strings are hand-authored per archetype (5 archetypes in data_seed.json). There is no per-major/per-career knowledge — see the integration plan §1.

5. 结局(compare.py)· The ending (compare.py)

中文

  • cross_life_signal —— 确定性:某个价值在两条命里都被往同一方向推,即为揭示出的内核(它在两个世界都活了下来)。
  • backward_reflection —— 对两条 dim-trace 做 LLM 镜像:从「活出来的选择」倒推当下的抉择。是镜子,不是推荐器。
  • path_costs —— 把每条路手写的代价摆出来,供代价接受闸门用。

EN:

  • cross_life_signaldeterministic: a value pushed the same way in both lives is a revealed core (it survived both worlds).
  • backward_reflection — an LLM mirror over both dim-traces: reasons the present choice backward from what the lived choices revealed. A mirror, not a recommender.
  • path_costs — surfaces each path’s authored cost for the acceptance gate.

6. 模型与延迟 · Models & latency

中文

EN:

rolemodelnote
trajectory generationDeepSeek-V3 (deepseek/deepseek-chat)~19s/stage, ~2.5–3× faster than V4-Pro
backward mirrorV4-Proricher reasoning; max_tokens=8000 to avoid reasoning-truncation

中文max_tokens=8000(从 2000 上调——之前 V4-Pro 的推理吃光预算、把第一回合 JSON 截断)。provider 对单 key 的并发限流——并行跑两条命的 wall-clock 收益很小(266s vs 串行 ~300s)。

EN: max_tokens=8000 (raised from 2000 after V4-Pro’s reasoning ate the budget and truncated turn-1 JSON). Provider throttles concurrent calls on a single key — parallelizing two lives gave little wall-clock gain (266s vs ~300s serial).

7. 状态持久化 · State persistence

中文:交互 session pickle 到磁盘/data/reflection-game/gaokao-data/ig_sessions),内存未命中时重新载入,所以服务器重启不会让玩家中途掉档。pickle 前丢掉 generator 句柄,载入时重新挂上。

EN: Interactive sessions are pickled to disk (/data/reflection-game/gaokao-data/ig_sessions) and reloaded on a memory miss, so a server restart doesn’t drop a player mid-game. The generator handle is dropped before pickling and re-attached on load.