1. 建立问题库大纲,对应每个人生阶段槽位
2. 鼓励使用更生活化的交流语言共情与总结
3. 降低评审模型可能发生截断的概率
4. 成稿质量维度强化情感表达和上下文连贯性
This commit is contained in:
yangshilin
2026-04-09 15:32:35 +08:00
parent 064ad2161d
commit e1341c6d18
49 changed files with 938 additions and 271 deletions

View File

@@ -0,0 +1,193 @@
"""
按人生阶段 × 叙述槽位slot固化「问题大纲」供访谈提示词引用。
- 同一 slot key 在不同 stage 语义不同(如 education.change vs family.change必须分 stage 配置。
- 条目是采集方向/示意问法,模型须在对话中情景化改写,禁止照抄题库原句。
"""
from __future__ import annotations
from app.agents.stage_constants import STAGE_SLOT_KEYS, VALID_CHAT_STAGES
# (stage, slot) -> 有序大纲:从宽泛落到具体,供缺口推进时优先参考
SLOT_QUESTION_OUTLINES: dict[tuple[str, str], tuple[str, ...]] = {
# --- 童年时光 ---
("childhood", "place"): (
"小时候主要是在哪儿长大的——城市、镇上还是村里,能具体到一片街区或一座院子吗?",
"住的地方大概什么样,有没有到现在还记得清的角落(厨房、院子、门槛)?",
"外人一眼能认出的地标或某种气味、声音(河、庙、集市、某种树)是什么?",
),
("childhood", "people"): (
"那时候最黏、最怕或最佩服的是谁,和你们日常是怎么相处的?",
"带你玩或管你最多的是家人还是祖辈、邻居孩子?有没有一位到现在还会突然想起的人?",
"有没有某个人一句话或一个动作,小时候的你特别当回事?",
),
("childhood", "daily_life"): (
"不上学的一天通常怎么过,有没有固定的小规矩或小乐趣?",
"放学之后最常去哪儿、和谁在一起,那种日子现在回想是什么颜色的?",
"记忆里常重复出现的一个场景(吃饭、睡午觉、出门玩)愿意多说两句吗?",
),
("childhood", "emotion"): (
"回想小时候,身体哪个地方会先「有感觉」——收紧、发暖还是发酸?",
"那时候整体更像踏实、兴奋、还是有点孤单或紧张?能举一个具体小事吗?",
"有没有一件当时觉得天塌了或特别亮堂的事,现在看又不太一样?",
),
("childhood", "turning_event"): (
"有没有一件事让小时候的你一下子觉得「我跟以前不一样了」?",
"难忘不一定是大事——一次搬家、一次生病、一次被骂或一次被护着也算,你愿意从画面讲起吗?",
"那之后别人对待你的方式,或你对自己的看法,哪儿变了?",
),
# --- 求学经历 ---
("education", "school"): (
"印象最深的一所学校是哪段,校园里你记得清的细节是什么(光线、气味、铃声、操场)?",
"有没有一门课、一位老师或一间教室,想到还会心里一动?",
"那时候和同学之间,最典型的相处方式是什么样的?",
),
("education", "city"): (
"求学待过哪些城或镇,第一次到那儿下车或进校园时是什么感觉?",
"和老家比,那边最陌生的地方是什么——人、节奏还是规矩?",
"后来有没有哪条街、哪个小店或公交站,和你的一段日子绑在一起?",
),
("education", "motivation"): (
"当时为什么读书或选这个方向——是自愿、家里期待,还是偶然被推向那条路?",
"有没有谁的一句话、一本书或一件事,真正推了你一把?",
"撑不下去的时候,是靠什么念头把自己劝回书桌前的?",
),
("education", "challenge"): (
"求学阶段最难的一段是什么——考试、钱、适应环境,还是家里的事?",
"最难的那会儿,一天里通常怎么扛过去,有没有人帮你垫了一下?",
"回头看,那段难有没有改变你对自己的看法?",
),
("education", "change"): (
"毕业或离开那段求学生活时,和刚入学比,你觉得自己哪块最明显变了?",
"是更知道自己要什么,还是更知道不要什么?能各举一个细节吗?",
"如果有机会对当时的自己说一句话,你会叮嘱什么?",
),
# --- 职业生涯 ---
("career", "job"): (
"那段工作里你具体在做什么,一天里真实在忙的核心事是什么?",
"有没有一个小场景能代表那份活(开会、跑现场、对客户、写东西)?",
"你最熟练或最头疼的环节是哪一块?",
),
("career", "environment"): (
"上班或干活的场子什么样——吵、静、乱中有序,还是总在移动?",
"同事或搭档大概怎么相处,有没有固定的小 ritual抽烟、吃饭、对表",
"那个环境里,什么让你待得下去,什么让你想逃?",
),
("career", "decision"): (
"换工作、入行或接某个项目时,有没有一次关键决定是你拍板的?",
"当时心里在权衡什么——钱、体面、家庭、兴趣、还是别的东西?",
"如果重来,你还会那么选吗,哪一步可能会松一点或紧一点?",
),
("career", "pressure"): (
"压力最大的阶段是什么,外界逼你还是自己逼自己更多?",
"身体或情绪上最先亮红灯的信号是什么(睡不着、胃、脾气)?",
"后来是环境变了,还是你换了应对方式,才缓过来的?",
),
("career", "growth"): (
"哪一段经历让你觉得能力、心气或看人的眼光真的上了一层?",
"有没有一件当时觉得过不去的事,做完反而长出了新本事?",
"现在回望,你愿意把哪段职业经历称为自己的「底色」?",
),
# --- 家庭生活 ---
("family", "relationship"): (
"和伴侣、父母或孩子之间,最近最常见的一个相处画面是什么?",
"亲昵和疏远在你家里大概怎么分配——是话说得多还是活儿帮得多?",
"有没有一种默契是你们家的「规矩外规矩」?",
),
("family", "conflict"): (
"家里有没有一次争执或冷战让你印象最深,起因其实是什么?",
"后来是时间抹平的还是有人先伸手,中间最难受的是哪几天?",
"那段矛盾过后,关系里是多了道疤还是多了一层理解?",
),
("family", "support"): (
"难的时候谁最站你这边,对方具体做过一件什么事你记到现在?",
"你又是怎么支持家里人的——出钱、出力、还是稳稳在场?",
"有没有一次你觉得「没有ta那次就真的悬了」",
),
("family", "responsibility"): (
"在家里你扛的主责是什么——钱、照料、决策、还是情绪托底?",
"从什么时候开始你觉得自己是「要主动揽过来」的那个人?",
"这份责任有没有让你骄傲,也有没有让你委屈的时候?",
),
("family", "change"): (
"成家或角色变了(当父母、当主心骨)之后,生活节奏或心态最明显的一处变化是什么?",
"和以前单身或二人世界比,你最怀念和最怕失去的各是什么?",
"如果现在给家里关系打分,你会先改哪一件小事?",
),
# --- 人生信念 ---
("belief", "value"): (
"若要把诚实、自由、家庭、成就、平安排个序,你心里默认的前两位是什么?",
"有没有一条线是你不太愿意让步的,哪怕会吃亏?",
"这套看重的东西,是家里传下来的还是你自己摔打出来的?",
),
("belief", "regret"): (
"若重来会犹豫的一件选择是什么,当时缺的是信息还是勇气?",
"遗憾现在还在拉扯你,还是已经能放在一旁?你怎么和它相处?",
"这份遗憾有没有悄悄改了你后来做决定的方式?",
),
("belief", "pride"): (
"不一定要大成就——一件你心底觉得「这事我做得对、做得像我自己」的事?",
"那时候外人怎么看不重要,你自己凭什么觉得踏实?",
"骄傲里有没有夹着一点后怕或侥幸?",
),
("belief", "lesson"): (
"如果只能留一句话给后辈或给年轻时的自己,你会留什么?",
"这个道理是从谁身上、哪段经历里磨出来的?",
"有没有一次你差点不信这句话,最后还是被生活按着头认了?",
),
}
def _validate_outlines() -> None:
for stage, slots in STAGE_SLOT_KEYS.items():
for slot in slots:
key = (stage, slot)
if key not in SLOT_QUESTION_OUTLINES:
raise RuntimeError(f"slot_question_bank missing outline for {key}")
_validate_outlines()
def outlines_for_stage_slots(
stage: str, empty_slots: list[str]
) -> list[tuple[str, tuple[str, ...]]]:
"""返回 [(slot key, 大纲句...), ...],仅含本阶段且仍在 empty_slots 中的槽。"""
if stage not in VALID_CHAT_STAGES:
return []
empty_set = set(empty_slots)
order = STAGE_SLOT_KEYS.get(stage, ())
out: list[tuple[str, tuple[str, ...]]] = []
for slot in order:
if slot not in empty_set:
continue
key = (stage, slot)
lines = SLOT_QUESTION_OUTLINES.get(key, ())
if not lines:
continue
out.append((slot, lines))
return out
def format_slot_question_outline_block(stage: str, empty_slots: list[str]) -> str:
"""供 system prompt 注入;无缺口时返回空串。"""
from app.agents.chat.prompts_conversation import SLOT_NAME_MAP
rows = outlines_for_stage_slots(stage, empty_slots)
if not rows:
return ""
blocks = [
"## 本阶段问题大纲(仅列仍缺的叙述槽;条目是**采集目标与思路**,不是台词)\n"
"- 每条大纲按**由宽到细**排序;推进缺口时通常优先靠上的条目,但**用户情绪明显起伏时,宁可停在大纲外多接两轮**,不要为凑进度硬问。\n"
"- 发问前必须把大纲句**打散、改写**,嵌进对方刚说的名词/动作/比喻;禁止整段背诵题库原句。\n"
"- 每轮若需要推进缺口,**全段只服务一个槽、最多一个问句**(或无问句只承接)。\n\n"
]
for slot, lines in rows:
label = SLOT_NAME_MAP.get(slot, slot)
blocks.append(f"### {label}\n")
for i, line in enumerate(lines, start=1):
blocks.append(f"{i}. {line}\n")
blocks.append("\n")
return "".join(blocks).rstrip() + "\n\n"