test/ 调整prompt,提高共情能力

This commit is contained in:
Kevin
2026-04-08 17:10:09 +08:00
parent 78b61c076e
commit 2a0c80987d
8 changed files with 113 additions and 85 deletions

View File

@@ -224,6 +224,8 @@ class InterviewAgent:
user_profile_context: str = "",
background_voice: str = "default",
occupation: str = "",
profile_birth_year: Optional[int] = None,
profile_era_place: str = "",
) -> List[str]:
"""生成空对话开场白,不持久化(由 Orchestrator 负责)"""
if not self.llm:
@@ -239,6 +241,8 @@ class InterviewAgent:
persona=persona,
background_voice=background_voice,
occupation=occupation,
profile_birth_year=profile_birth_year,
profile_era_place=profile_era_place,
)
hw = await get_history_with_window(
conversation_id,

View File

@@ -403,6 +403,8 @@ class ChatOrchestrator:
user_profile_context: str = "",
background_voice: str = "default",
occupation: str = "",
profile_birth_year: Optional[int] = None,
profile_era_place: str = "",
) -> List[str]:
"""
委托 InterviewAgent 生成访谈开场白(持久化由调用方 ConversationHistoryStore 负责)。
@@ -413,4 +415,6 @@ class ChatOrchestrator:
user_profile_context=user_profile_context,
background_voice=background_voice,
occupation=occupation,
profile_birth_year=profile_birth_year,
profile_era_place=profile_era_place,
)

View File

@@ -26,8 +26,14 @@ def get_interview_persona_tone_hint(persona: str) -> str:
if key == "default":
return ""
if key == "warm_listener":
return "偏倾听与承接,语气柔和、少打断;不审问感,一次最多一个具体问题。"
return "爱把人往一个具体细节里带;短句像微信,一次最多一个具体问题,不重复上文已清楚的事"
return (
"偏倾听与承接,语气柔和、少打断;不审问感,一次最多一个具体问题"
"对方愿意展开时,可温和多问一层意义或影响。"
)
return (
"爱把人往一个具体细节里带;事实清楚后可追问对自我认知或后来选择的影响;"
"短句像微信,一次最多一个具体问题,不重复上文已清楚的事。"
)
def get_interview_persona_block(persona: str) -> str:

View File

@@ -76,16 +76,22 @@ def _compact_era_hint(
if era_start <= decade + 9 and era_end >= decade:
era_events.append(f"{decade}年代:{events}")
if not era_events:
return ""
place_hint = f" {birth_place}" if birth_place else ""
return (
f"时代联想(口述里一两句带过即可):约 {era_start}-{era_end}{place_hint}"
f"可提及 {era_events[0]}"
+ (f"{era_events[1]}" if len(era_events) > 1 else "")
+ ""
parts: List[str] = []
if era_events:
place_hint = f" {birth_place}" if birth_place else ""
parts.append(
f"时代联想(口述里一两句带过即可):约 {era_start}-{era_end}{place_hint}"
f"可提及 {era_events[0]}"
+ (f"{era_events[1]}" if len(era_events) > 1 else "")
+ ""
)
parts.append(
"时代与流行文化(开放式,自然带入):\n"
"- 可从当时的街景、媒介、校园与市井、年节习俗等**泛泛**起头,邀请用户讲自己的版本,勿替用户断言细节。\n"
"- **优先开放式**问法;少用「你是不是也……」式半封闭逼认。\n"
"- 与大事记呼应时点到为止,勿展开成长串史实。"
)
return "\n".join(parts) + "\n"
def get_opening_prompt(
@@ -95,9 +101,12 @@ def get_opening_prompt(
persona: str = "default",
background_voice: str = "default",
occupation: str = "",
profile_birth_year: Optional[int] = None,
profile_era_place: str = "",
) -> str:
"""空对话时 AI 先开口的提示词"""
stage_name = STAGE_DISPLAY_ZH.get(current_stage, current_stage)
bv_open = normalize_background_voice(background_voice)
if empty_slots_readable:
topics_str = "".join(empty_slots_readable)
topics_heading = (
@@ -107,50 +116,6 @@ def get_opening_prompt(
"2. 接着问一个**具体、好回答**的问题,引导用户开始分享;"
"优先落在上述还未聊透的方向上。不要问太宽泛的「有什么想聊的」。"
)
_opening_examples = {
"childhood": (
"示例(仅供参考风格):\n"
'"你好呀~ 想听听你的人生故事。你小时候是在哪儿长大的?那边有什么特别让你怀念的?"\n\n'
'"在的!今天想聊聊你。你童年里印象最深的一件事是什么?"'
),
"education": (
"示例(仅供参考风格):\n"
'"嗨~ 想听听你求学那段日子。你印象最深的是哪段学校时光?"\n\n'
'"在呢!你读书时有没有一位老师或同学,到现在还会想起?"'
),
"career": (
"示例(仅供参考风格):\n"
'"你好呀~ 想听听你工作这条路上故事。你第一份工作还记得吗,当时什么心情?"\n\n'
'"在的!你现在或过去做过的工作里,哪一段你最想先聊聊?"'
),
"family": (
"示例(仅供参考风格):\n"
'"嗨~ 想听听你家里的事。和家里人相处时,有没有特别暖或难忘的一刻?"\n\n'
'"在呢!如果用一个词形容你心里的「家」,你会想到什么?"'
),
"belief": (
"示例(仅供参考风格):\n"
'"你好呀~ 想听听你心里看重的东西。有没有一句你一直信到现在的话?"\n\n'
'"在的!你觉得自己走到今天,最放不下或最骄傲的是什么?"'
),
}
style_examples = _opening_examples.get(
current_stage,
_opening_examples["childhood"],
)
bv = normalize_background_voice(background_voice)
if bv == "cadre":
style_examples += (
"\n(干部/机关语境:问候稳重、不用「嗨~」;示例可参考)\n"
'"您好,想听听您的人生故事。您小时候是在哪儿长大的?哪一段印象最深?"\n\n'
'"您好。今天想从您印象最深的一件事聊起,可以吗?"'
)
elif bv == "military":
style_examples += (
"\n(军队语境:简洁、得体;不用「嗨~」;示例可参考)\n"
'"您好。想听听您的经历。您童年印象最深的一件事是什么?"\n\n'
'"您好,有空的话想聊聊您的人生故事。您小时候在哪儿长大?"'
)
else:
topics_heading = (
f"## 当前阶段({stage_name}\n"
@@ -162,10 +127,21 @@ def get_opening_prompt(
"2. **问候 + 轻巧引子**:温暖接话;若自然可问一个与近况或回忆有关的问题,"
"不适合追问时问候 + 开放式引子即可。"
)
style_examples = (
"示例(仅供参考风格):\n"
'"嘿,又见面啦~ 今天有没有哪件事突然从脑子里冒出来,想跟我说说?"\n\n'
'"在的!上次聊到那儿我还记着,你后来还有想起什么细节吗?"'
if bv_open == "cadre":
opening_style_rules = (
"## 语境与语气(干部/机关)\n"
"- 问候稳重、敬语适度;避免官样排比与过轻佻的网络撒娇语气。\n"
)
elif bv_open == "military":
opening_style_rules = (
"## 语境与语气(军队相关口述常见交流方式)\n"
"- 简洁、得体;不用「嗨~」类过轻佻起势;不堆军事辞藻、不编军旅细节。\n"
)
else:
opening_style_rules = (
"## 风格\n"
"- 像微信短聊:口语、自然;可轻快但不要排比和长段文学描写。\n"
)
profile_lines: List[str] = []
@@ -186,29 +162,42 @@ def get_opening_prompt(
if tone_bits:
tone_paragraph = " " + " ".join(tone_bits) + "\n\n"
bv = normalize_background_voice(background_voice)
opening_head = (
"你是「岁月知己」。用户刚进对话,**还没说话**,请你先开口。"
"**短、像微信**,一两句问候 + 一个具体问题即可,不要排比、不要文学描写。\n\n"
)
if bv != "default":
if bv_open != "default":
opening_head = (
"你是「岁月知己」。用户刚进对话,**还没说话**,请你先开口。"
"**短**;两三句内问候 + 一个具体问题;不要排比、不要文学描写。\n\n"
)
era_opening_line = ""
if (
settings.chat_era_context_enabled
and profile_birth_year is not None
and _compact_era_hint(
current_stage,
birth_year=profile_birth_year,
era_place=profile_era_place,
)
):
era_opening_line = (
"4. 用户资料里已有出生年份与时代参考时,问候里的具体问题可**轻轻带一点年代氛围**(点到为止),"
"勿写成长段描写或排比。\n"
)
return f"""{opening_head}{tone_paragraph}{profile_section}{topics_heading}
## 任务
1. 简短问候。
{task_question}
3. 自然、温暖,但**字数要少**。
{era_opening_line}
## 格式
- 可用 [SPLIT] 分成最多 2 条;或一条里「问候 + 问题」。
- {chat_output_rules()} 不要替用户编回答。
{style_examples}
{opening_style_rules}
直接输出(仅自然口语,无 Markdown"""
@@ -310,13 +299,13 @@ def get_guided_conversation_prompt(
memory_section = (
"## 相关记忆摘录(仅供衔接,禁止编造)\n"
"以下为系统从用户**过往口述**中检索到的摘录,**不是**用户本轮亲口新说的内容。\n"
"承接时可自然用「你之前提过……」等口语,不要把摘录里的细节写成本轮用户新说的;"
"承接时可点明来自先前口述,不要把摘录里的细节写成本轮用户新说的;"
"禁止编造摘录未出现的内容。\n\n"
f"{mem_trim}\n\n"
)
progress_block = f"## 进度\n{progress_str}\n" if progress_str else ""
era_block = f"{era_line}\n" if era_line else ""
era_block = f"## 时代与氛围参考\n{era_line}\n" if era_line else ""
return f"""你是「岁月知己」,像老朋友陪用户聊人生。短句为主,像微信聊天。{tone_line}
@@ -330,8 +319,10 @@ def get_guided_conversation_prompt(
{progress_block}{era_block}{memory_section}## 你要做的
- **先接住对方**——一句真诚回应,不要写成总结或讲评。
- **共情与轻量自我表露**:在接住的基础上,可用**一两句极短**的第一人称情绪承接(不展开成故事),**不得**编造具体时间、地点、人物与事件等你不知道的细节。
- **意义向深挖(看准时机)**:当对方已讲出较具体的情节、人或选择时,可温和多问一层——当时怎么看这件事、后来有没有反过来影响性格或抉择;与「还可聊的方向」并存时,优先用这类意义问题**补缺口**,而非机械换话题。**情绪仍浓时**只承接、不深问。
- 你自己判断该追问还是只承接:有新线头就顺着问一个具体的事;情绪浓就好好接住、不必急着追问;明显闲聊就陪聊;用户只说「嗯」「对」则结合上文承接或换个角度。
- 可以用「我能想象……」「那时候大概……」轻轻接话,但不可编造具体人名、时间、事件等你不知道的细节。
- 可泛泛接话以承接氛围或感受,但不可编造具体人名、时间、事件等你不知道的细节。
- 不要重复上一轮问过的事;用户跳到别的人生阶段,跟着聊,别硬拉回。
- 追问与承接服务于人生故事素材,但不要让对方觉得在走审问式流程;**最多**抛一个具体问题,也可以不追问。
- 可用 [SPLIT] 分成**最多 2 条**消息。

View File

@@ -32,14 +32,9 @@ def get_profile_greeting_prompt(missing_fields: List[str], nickname: str = "") -
## 规则
1. 不要一次问所有问题,每次只问 1-2 个
2. 如果用户已经在对话中提到了某些信息,不要重复问
3. 用口语化、亲切的方式提问
3. 用口语化、亲切的方式提问;问法自选,勿套用固定模板句
4. 当所有信息都收集完后,自然过渡到人生故事访谈
## 提问示例
- "你是哪一年出生的呀?"
- "你是在哪里出生的?小时候也是在那里长大的吗?"
- "你现在是做什么工作的呀?或者之前主要从事什么职业?"
## 严格禁止
- {chat_output_rules()}
- 禁止说"我需要收集信息"之类的机械话
@@ -75,13 +70,7 @@ def get_profile_extraction_prompt(
需要提取的字段(只提取确实在对话中出现过的):
{missing_names}
输出示例(只含确实提到的字段;无则 {{}}
{{
"birth_year": 1965,
"birth_place": "湖南长沙",
"grew_up_place": "湖南长沙",
"occupation": "教师"
}}
输出为 JSON 对象键只能来自上述字段名birth_year 为四位整数,其余为字符串。仅填充口述中明确出现的键;无任何可提取内容则返回 {{}}
规则:
1. birth_year 填整数(四位数),如"65年出生"转为 1965
@@ -119,7 +108,7 @@ def get_profile_followup_prompt(
{filled_str}
用户本轮消息在对话末尾。请对用户的回答做出温暖的回应,然后自然地过渡到人生故事的访谈。
可以说类似「了解了!那我们现在开始聊聊你的人生故事吧」这样的话;{stage_hint}
过渡语自拟,勿机械套话;{stage_hint}
**不要**默认只问童年,除非用户刚才聊的正是童年。
回复格式:多条消息用 [SPLIT] 分隔。

View File

@@ -19,14 +19,14 @@ def get_chat_stage_detection_prompt(user_message: str, current_stage: str) -> st
allowed = "".join(CHAT_STAGES)
return f"""你是访谈助手。根据用户**本轮**话语,判断其**主要**在谈论哪一段人生经历。
系统当前跟踪的阶段(仅供参考,不要默认沿用;以用户实质内容为准):{current_stage}
系统当前跟踪的阶段(默认沿用;以用户实质内容为准):{current_stage}
可选阶段detected_stage 的值必须恰好为下列之一):{allowed}
用户话语:
"{user_message}"
输出形状示例:{{"detected_stage":"education"}}
输出一行 JSON且只含键 detected_stage值为上列英文阶段键之一。
规则:
1. 根据**本轮**与人生故事相关的实质内容判断主阶段;不要因系统当前阶段而强行归类。