Codebase (2026-06-27): this engine now lives in meno-gaokao-counsellor (
core/…), extracted from reflection-game — see gaokao-standalone-plan. Module paths below use the newcore/layout.
当前实现(2026-06-24)— investigator 已并入
unified_turn独立的
investigate()函数已是 legacy、当前流程不再调用。investigator 的角色(top vs contender + 针对此人的问题 + 来源)现在是unified_turn这一次融合调用的一部分;输出含question / prose / top_take / contender_take / elicit / scene_gist / sources(did_you_know已退役)。新增elicit= 一句最想听学生自己说的追问(UI 渲染成 文本 + 麦克风)。来源纪律_auth_sources()现也接受「雨来-verified」层级。模型:unified_turn 用deepseek-chat,画像/报告用deepseek-v4-pro。
这是什么 · What this is
中文:每一站的调查员——它读什么、问什么、怎么落地。世界推演引擎(WTE)选定维度后,调查员读人类模型(画像 + 不确定性地图)为这个学生定出一个具体问题,再用 grounding(本地KB + 雨来)加实时联网检索去调查它。下面是当前提示词、机制、与输出处理。代码:
core/ranked.py::investigate()。EN: The per-stage investigator — what it reads, what it asks, how it grounds. After the WTE picks a dimension, the investigator reads the human model (profile + uncertainty map) to define a person-specific question, then investigates it using grounding (local KB + 雨来) plus live web search. Below: the current prompt, mechanism, and output handling. Code:
core/ranked.py::investigate().
调查员提示词(当前)/ The investigator prompt (current)
中文。 WTE 选定维度后,调查员先读画像,为这位具体学生在该维度上定出最该弄清的一个问题,再围绕它调查(同一维度对不同人是不同问题)。逐字提示词(注册表 key investigate):
你是"反思均衡"志愿推演里的调查员(investigator)。原则:帮学生想清楚,绝不替他下结论、不说哪个更好。
本站要考量的维度(由世界推演引擎 WTE 选定):【{factor_label}】—— {factor_ask}
学生当前排第1的选择:{top}
该选择的真实背景:
{g_top}
学生的其他候选(择一作为"对比项"——挑在【{factor_label}】这个维度上与第1名*差异最明显*的那个):
{g_rest}
这位学生的画像(务必先读懂——你要据此决定"对这个人、在这个维度上,最该弄清的那一个具体问题"):
{profile_text}
任务:① 先读画像,在【{factor_label}】这个维度里,为*这位具体学生*定出最有信息价值、最戳中他纠结或盲区的**一个具体问题**(因人而异,不要泛泛而谈);② 再围绕这个问题做调查。
{src_rule}
产出一个 JSON 对象(简体中文),不要多余文字:
{{
"question": "你为这个人定的那个具体问题(一句话,因人而异)",
"prose": "一段110字内的、具体写实的'第一人称代入'小场景:学生正过着【{top}】这条路,在这个问题上真切撞见的日常(用真实课程/岗位/细节,可戏剧化不可捏造)",
"contender": "你选作对比项的候选名(从上面候选里选一个)",
"top_take": "一句:{top} 在这个问题上的真实情况(尽量带上检索到的权威数字/事实)",
"contender_take": "一句:对比项在同一问题上有何不同(往往是学生没意识到的)",
"sources": ["你实际采信的权威来源名(2-3个,如'XX大学2023就业质量报告''麦可思2023');没检索就留空[]"]
}}English. After the WTE picks a dimension, the investigator first reads the profile to define the single most-worth-clarifying question for this student on that dimension, then investigates it (same dimension → different question per person). Verbatim prompt (registry key investigate).
JSON output fields: question (因人而异的问题) · prose (第一人称小场景) · top_take/contender_take (第1名 vs 对比项) · sources (权威来源). {src_rule} is the authoritative-source-only rule injected when web search is on — see 机制 / 输出处理 below.
机制 — OpenRouter 网络插件(与模型无关)· Mechanism — OpenRouter web plugin (model-agnostic)
中文:没有单独的「搜索步骤」。我们把调查员那一次正常的 chat-completion 发给 OpenRouter,并挂上网络插件;OpenRouter 根据提示词跑一次检索,把结果注入模型上下文,模型(DeepSeek-V3)在同一次调用里就着这些结果推理。
EN: There is no separate “search step.” We send the investigator’s normal chat-completion to OpenRouter with the web plugin attached; OpenRouter runs a search derived from the prompt, injects the results into the model’s context, and the model (DeepSeek-V3) reasons over them in the same call.
# core/ranked.py :: _llm_json(..., online=True)
payload = {"model": "deepseek/deepseek-chat",
"messages": [{"role": "user", "content": prompt}],
"response_format": {"type": "json_object"},
"max_tokens": 1800, "temperature": 0.6}
if online:
payload["plugins"] = [{"id": "web", "max_results": 4}] # <-- the web search中文:
- 模型:
deepseek/deepseek-chat(V3)。插件与模型无关——V3 仍是我们的推理器;换 Qwen 等也是同一插件、没有优势(若哪天想要原生带引用的检索,备选是 Perplexity Sonar)。 - 开关:
GAOKAO_WEBSEARCH环境变量(默认开)。关掉 → 退回一次普通的 grounded 调用。 - 范围:只有调查那一次调用联网(它能容忍延迟、且对准确性要求最高);问卷是精选的、结尾是确定性的——两者都不检索。
EN:
- Model:
deepseek/deepseek-chat(V3). The plugin is model-agnostic — V3 stays our reasoner; Qwen/others would use the same plugin with no edge (Perplexity Sonar = the alternative if natively-cited search is ever wanted). - Toggle:
GAOKAO_WEBSEARCHenv var (default ON). Off → a plain grounded call. - Scope: only the investigation call runs online (the latency-tolerant, accuracy-critical one); the quiz is curated and the end is deterministic — neither searches.
检索/提示词的输入 · Inputs to the search/prompt
中文:investigate(factor, options, profile_text) 组装:
- 当前因素(如 课程与学业 / 职业前景),
grounding_block(top)——第 1 名选项在 859 专业知识库里的「事实/观点」卡片,grounding_block(其余每个选项)——用于挑对比项,- 玩家画像(
PersonalityFile.serialize_for_prompt()), - SRC_RULE——来源纪律指令(见下),仅在联网时注入。
EN: investigate(factor, options, profile_text) assembles:
- the current factor (e.g. 课程与学业 / 职业前景),
grounding_block(top)— the #1 option’s fact/opinion card from the 859-major KB,grounding_block(each other option)— for picking the contrast,- the player profile (
PersonalityFile.serialize_for_prompt()), - the SRC_RULE — the source-discipline instruction (below), injected only when online.
SRC_RULE(逐字 · verbatim):
**用网络检索核实这一步的关键事实**(只针对【{factor.label}】这一维度、针对 {top} 与你选定的对比项这两者)。
**只采信权威来源**:高校毕业生就业质量报告、麦可思(MyCOS)就业蓝皮书、阳光高考平台、教育部/国家统计局官方数据、该校官网;
**忽略营销软文、随机新闻、贴吧/营销号**。
**铁律**:① 任何具体数字必须来自*明确覆盖'该校+该专业'*的权威来源;检索结果若不含该校该专业的具体数据,就**用定性描述、不要编数字**(如'对口率较高/一般')。
② **绝不**把一个机构/地区的数据安到另一个机构头上(例如拿香港高校网站的数据去描述内地高校)。
③ **不要在正文里插入任何引用标记/链接**,来源只写进 sources 字段,且 sources 里只列真正支持你所述事实的那个来源。
检索不到可靠来源时退回到上面的 grounding。输出 — 接口 + 后处理 · Output — interface + post-processing
中文:模型返回一个 JSON 对象:{prose, contender, top_take, contender_take, did_you_know, sources}(注:did_you_know 已于 2026-06-17 退役,不再生成;后处理逻辑对其余字段仍适用)。然后 investigate() 对它后处理(准确性是在这里被强制的,而不只是被请求):
- 对每个展示字段做
_clean()(prose / top_take / contender_take / did_you_know):剥掉行内引用——[text](url)与裸的[域名]都剥——以及引用被删后残留的「根据,」连接词。引用永不出现在正文里,只活在sources字段。 - 对
sources做_auth_sources():一个确定性过滤器,保留权威名称(域名/关键词:edu.cn、gov.cn、麦可思、就业质量、阳光高考、chsi、报告、蓝皮书…),丢弃新闻/UGC/营销(sina, sohu, 163, qq, baidu, zhihu, tieba, toutiao, ifeng, news., weibo, 小红书, bilibili)。上限 3 条。 - 清洗后的
sources在每一站下方渲染为 来源: …。
EN: The model returns one JSON object: {prose, contender, top_take, contender_take, did_you_know, sources}. Then investigate() post-processes it (this is where accuracy is enforced, not just requested):
_clean()on every displayed field (prose / top_take / contender_take / did_you_know): strips inline citations — both[text](url)and bare[域名]— and orphaned “根据,” connectors left when a citation is removed. Citations never appear in the prose; they live only insources._auth_sources()onsources: a deterministic filter that keeps authoritative names (domains/keywords:edu.cn,gov.cn, 麦可思, 就业质量, 阳光高考, chsi, 报告, 蓝皮书…) and drops news/UGC/marketing (sina, sohu, 163, qq, baidu, zhihu, tieba, toutiao, ifeng, news., weibo, 小红书, bilibili). Capped at 3.- The cleaned
sourcesrender under each stage as 来源: ….
为什么后处理重要(它修过的一个真实 bug)· Why the post-processing matters (a real bug it fixed)
中文:模型曾把一个数字安到不匹配的来源上(把北大的事实引到一个香港招生网站),还把引用写进了正文。提示词规则能减少这种事;而
_clean+_auth_sources过滤器保证展示文本不含行内引用、所示来源只有权威。若检索不到任何权威信息,模型被要求保持定性、退回 grounding 知识库——绝不编数字。EN: The model once attached a number to a mismatched source (a PKU fact cited to an HK admissions site) and inlined the citation. The prompt rules reduce this; the
_clean+_auth_sourcesfilters guarantee the displayed text carries no inline cite and the shown sources are authoritative-only. If nothing authoritative is found, the model is told to stay qualitative and fall back to the grounding KB — never to invent a number.
延迟 · Latency
中文:约 17 秒/次(检索在 ~20 秒基线上几乎不加时)。被全量预取(prefetch-all)藏掉:在用户读当前一站时,后台已把下一站对所有候选都预生成,所以重排几乎是瞬时的。
EN: ~17s/call (search adds little over the ~20s base). Hidden by prefetch-all: while you read the current stop, the next stop is pre-generated for every option in the background, so re-ranking is near-instant.