2026-01-07 11:56:53 +08:00
|
|
|
|
"""
|
2026-04-06 22:22:50 +08:00
|
|
|
|
对话 Agent 提示词模板(精简:事实块 + 行为指引,由模型自行判断追问/长度/闲聊)。
|
2026-01-07 11:56:53 +08:00
|
|
|
|
"""
|
2026-03-19 14:36:14 +08:00
|
|
|
|
|
2026-03-31 23:55:26 +08:00
|
|
|
|
from typing import Dict, List, Optional
|
|
|
|
|
|
|
|
|
|
|
|
from app.agents.chat.background_voice import (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
get_background_voice_tone_hint,
|
2026-03-31 23:55:26 +08:00
|
|
|
|
normalize_background_voice,
|
|
|
|
|
|
)
|
2026-04-01 11:49:33 +08:00
|
|
|
|
from app.agents.chat.occupation_context import get_occupation_chat_hint
|
2026-04-08 15:37:09 +08:00
|
|
|
|
from app.agents.chat.output_rules import chat_output_rules
|
2026-03-31 23:55:26 +08:00
|
|
|
|
from app.agents.chat.personas import (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
get_interview_persona_tone_hint,
|
2026-03-31 23:55:26 +08:00
|
|
|
|
normalize_interview_persona,
|
|
|
|
|
|
)
|
2026-04-03 13:34:27 +08:00
|
|
|
|
from app.agents.stage_constants import CHAT_STAGES, STAGE_DISPLAY_ZH, STAGE_ERA_HINTS
|
2026-03-26 12:13:36 +08:00
|
|
|
|
from app.core.config import settings
|
2026-01-07 11:56:53 +08:00
|
|
|
|
|
2026-01-21 22:31:03 +01:00
|
|
|
|
SLOT_NAME_MAP = {
|
|
|
|
|
|
"place": "成长的地方",
|
|
|
|
|
|
"people": "重要的人",
|
|
|
|
|
|
"daily_life": "日常生活",
|
|
|
|
|
|
"emotion": "童年感受",
|
|
|
|
|
|
"turning_event": "难忘的事",
|
|
|
|
|
|
"school": "学校经历",
|
|
|
|
|
|
"city": "求学的城市",
|
|
|
|
|
|
"motivation": "学习动力",
|
|
|
|
|
|
"challenge": "遇到的挑战",
|
|
|
|
|
|
"change": "成长变化",
|
|
|
|
|
|
"job": "工作内容",
|
|
|
|
|
|
"environment": "工作环境",
|
|
|
|
|
|
"decision": "重要决定",
|
|
|
|
|
|
"pressure": "压力与困难",
|
|
|
|
|
|
"growth": "职业成长",
|
|
|
|
|
|
"relationship": "家人关系",
|
|
|
|
|
|
"conflict": "矛盾与化解",
|
|
|
|
|
|
"support": "相互支持",
|
|
|
|
|
|
"responsibility": "家庭责任",
|
|
|
|
|
|
"value": "核心价值观",
|
|
|
|
|
|
"regret": "遗憾与释怀",
|
|
|
|
|
|
"pride": "骄傲的事",
|
|
|
|
|
|
"lesson": "人生经验",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 20:09:09 +01:00
|
|
|
|
|
2026-04-08 15:37:09 +08:00
|
|
|
|
def _compact_era_hint(
|
|
|
|
|
|
current_stage: str,
|
|
|
|
|
|
*,
|
|
|
|
|
|
birth_year: int | None = None,
|
|
|
|
|
|
era_place: str = "",
|
|
|
|
|
|
) -> str:
|
|
|
|
|
|
"""单行时代联想,可选附在进度后。出生年与地点由调用方从用户资料结构化传入。"""
|
2026-04-06 22:22:50 +08:00
|
|
|
|
if not birth_year:
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
2026-04-08 15:37:09 +08:00
|
|
|
|
birth_place = (era_place or "").strip()
|
|
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
age_range = STAGE_ERA_HINTS.get(current_stage, (0, 30))
|
|
|
|
|
|
era_start = birth_year + age_range[0]
|
|
|
|
|
|
era_end = birth_year + age_range[1]
|
|
|
|
|
|
|
|
|
|
|
|
era_events = []
|
|
|
|
|
|
decade_events = {
|
|
|
|
|
|
1950: "新中国成立初期、土地改革、抗美援朝",
|
|
|
|
|
|
1960: "大跃进、三年自然灾害、中苏关系变化",
|
|
|
|
|
|
1970: "文化大革命、知青上山下乡、中美建交",
|
|
|
|
|
|
1980: "改革开放、恢复高考、个体经济兴起、电视普及",
|
|
|
|
|
|
1990: "社会主义市场经济、下海潮、香港回归、互联网初期",
|
|
|
|
|
|
2000: "加入WTO、房地产兴起、手机普及、北京奥运",
|
|
|
|
|
|
2010: "移动互联网爆发、微信时代、共享经济、双创浪潮",
|
|
|
|
|
|
2020: "新冠疫情、直播经济、人工智能崛起",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for decade, events in decade_events.items():
|
|
|
|
|
|
if era_start <= decade + 9 and era_end >= decade:
|
|
|
|
|
|
era_events.append(f"{decade}年代:{events}")
|
2026-01-29 20:09:09 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
if not era_events:
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
place_hint = f" {birth_place}" if birth_place else ""
|
2026-04-02 12:00:00 +08:00
|
|
|
|
return (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
f"时代联想(口述里一两句带过即可):约 {era_start}-{era_end} 年{place_hint};"
|
|
|
|
|
|
f"可提及 {era_events[0]}"
|
|
|
|
|
|
+ (f";{era_events[1]}" if len(era_events) > 1 else "")
|
|
|
|
|
|
+ "。"
|
2026-04-02 12:00:00 +08:00
|
|
|
|
)
|
2026-01-29 20:09:09 +01:00
|
|
|
|
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-03-11 14:39:39 +08:00
|
|
|
|
def get_opening_prompt(
|
|
|
|
|
|
current_stage: str,
|
|
|
|
|
|
empty_slots_readable: List[str],
|
|
|
|
|
|
user_profile_context: str = "",
|
2026-03-31 23:55:26 +08:00
|
|
|
|
persona: str = "default",
|
|
|
|
|
|
background_voice: str = "default",
|
2026-04-01 11:49:33 +08:00
|
|
|
|
occupation: str = "",
|
2026-03-11 14:39:39 +08:00
|
|
|
|
) -> str:
|
2026-03-19 10:54:48 +08:00
|
|
|
|
"""空对话时 AI 先开口的提示词"""
|
2026-04-02 12:00:00 +08:00
|
|
|
|
stage_name = STAGE_DISPLAY_ZH.get(current_stage, current_stage)
|
2026-03-20 15:15:35 +08:00
|
|
|
|
if empty_slots_readable:
|
|
|
|
|
|
topics_str = "、".join(empty_slots_readable)
|
|
|
|
|
|
topics_heading = (
|
|
|
|
|
|
f"## 当前建议话题({stage_name})\n可以从中选一个来问:{topics_str}"
|
|
|
|
|
|
)
|
|
|
|
|
|
task_question = (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"2. 接着问一个**具体、好回答**的问题,引导用户开始分享;"
|
2026-03-20 15:15:35 +08:00
|
|
|
|
"优先落在上述还未聊透的方向上。不要问太宽泛的「有什么想聊的」。"
|
|
|
|
|
|
)
|
2026-03-26 12:13:36 +08:00
|
|
|
|
_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"],
|
2026-03-20 15:15:35 +08:00
|
|
|
|
)
|
2026-03-31 23:55:26 +08:00
|
|
|
|
bv = normalize_background_voice(background_voice)
|
|
|
|
|
|
if bv == "cadre":
|
|
|
|
|
|
style_examples += (
|
|
|
|
|
|
"\n(干部/机关语境:问候稳重、不用「嗨~」;示例可参考)\n"
|
|
|
|
|
|
'"您好,想听听您的人生故事。您小时候是在哪儿长大的?哪一段印象最深?"\n或\n'
|
|
|
|
|
|
'"您好。今天想从您印象最深的一件事聊起,可以吗?"'
|
|
|
|
|
|
)
|
|
|
|
|
|
elif bv == "military":
|
|
|
|
|
|
style_examples += (
|
|
|
|
|
|
"\n(军队语境:简洁、得体;不用「嗨~」;示例可参考)\n"
|
|
|
|
|
|
'"您好。想听听您的经历。您童年印象最深的一件事是什么?"\n或\n'
|
|
|
|
|
|
'"您好,有空的话想聊聊您的人生故事。您小时候在哪儿长大?"'
|
|
|
|
|
|
)
|
2026-03-20 15:15:35 +08:00
|
|
|
|
else:
|
|
|
|
|
|
topics_heading = (
|
|
|
|
|
|
f"## 当前阶段({stage_name})\n"
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"这一阶段的主要话题在素材侧**已有覆盖**。"
|
|
|
|
|
|
"开场要像老朋友重逢:接近况、接续上次聊过的事、或新片段;"
|
|
|
|
|
|
"**禁止**为了凑问题而从「童年在哪长大」等已覆盖模板重头盘问。"
|
2026-03-20 15:15:35 +08:00
|
|
|
|
)
|
|
|
|
|
|
task_question = (
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"2. **问候 + 轻巧引子**:温暖接话;若自然可问一个与近况或回忆有关的问题,"
|
|
|
|
|
|
"不适合追问时问候 + 开放式引子即可。"
|
2026-03-20 15:15:35 +08:00
|
|
|
|
)
|
|
|
|
|
|
style_examples = (
|
|
|
|
|
|
"示例(仅供参考风格):\n"
|
|
|
|
|
|
'"嘿,又见面啦~ 今天有没有哪件事突然从脑子里冒出来,想跟我说说?"\n或\n'
|
|
|
|
|
|
'"在的!上次聊到那儿我还记着,你后来还有想起什么细节吗?"'
|
|
|
|
|
|
)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
|
|
|
|
|
|
profile_lines: List[str] = []
|
|
|
|
|
|
if user_profile_context.strip():
|
|
|
|
|
|
profile_lines.append(user_profile_context.strip())
|
|
|
|
|
|
occ = get_occupation_chat_hint(occupation, background_voice)
|
|
|
|
|
|
if occ:
|
|
|
|
|
|
profile_lines.append(occ)
|
|
|
|
|
|
profile_section = ""
|
|
|
|
|
|
if profile_lines:
|
|
|
|
|
|
profile_section = "## 用户信息\n" + "\n".join(profile_lines) + "\n"
|
|
|
|
|
|
|
2026-03-31 23:55:26 +08:00
|
|
|
|
persona_key = normalize_interview_persona(persona)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
persona_tone = get_interview_persona_tone_hint(persona_key)
|
|
|
|
|
|
voice_tone = get_background_voice_tone_hint(background_voice)
|
|
|
|
|
|
tone_bits = [t for t in (persona_tone, voice_tone) if t]
|
|
|
|
|
|
tone_paragraph = ""
|
|
|
|
|
|
if tone_bits:
|
|
|
|
|
|
tone_paragraph = " " + " ".join(tone_bits) + "\n\n"
|
|
|
|
|
|
|
2026-03-31 23:55:26 +08:00
|
|
|
|
bv = normalize_background_voice(background_voice)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
opening_head = (
|
|
|
|
|
|
"你是「岁月知己」。用户刚进对话,**还没说话**,请你先开口。"
|
|
|
|
|
|
"**短、像微信**,一两句问候 + 一个具体问题即可,不要排比、不要文学描写。\n\n"
|
|
|
|
|
|
)
|
|
|
|
|
|
if bv != "default":
|
2026-03-31 23:55:26 +08:00
|
|
|
|
opening_head = (
|
|
|
|
|
|
"你是「岁月知己」。用户刚进对话,**还没说话**,请你先开口。"
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"**短**;两三句内问候 + 一个具体问题;不要排比、不要文学描写。\n\n"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
|
|
|
|
|
|
return f"""{opening_head}{tone_paragraph}{profile_section}{topics_heading}
|
2026-03-26 12:13:36 +08:00
|
|
|
|
## 任务
|
|
|
|
|
|
1. 简短问候。
|
2026-03-20 15:15:35 +08:00
|
|
|
|
{task_question}
|
2026-03-26 12:13:36 +08:00
|
|
|
|
3. 自然、温暖,但**字数要少**。
|
2026-03-11 14:39:39 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
## 格式
|
|
|
|
|
|
- 可用 [SPLIT] 分成最多 2 条;或一条里「问候 + 问题」。
|
2026-04-03 13:34:27 +08:00
|
|
|
|
- {chat_output_rules()} 不要替用户编回答。
|
2026-03-11 14:39:39 +08:00
|
|
|
|
|
2026-03-20 15:15:35 +08:00
|
|
|
|
{style_examples}
|
2026-03-11 14:39:39 +08:00
|
|
|
|
|
2026-04-03 14:06:55 +08:00
|
|
|
|
直接输出(仅自然口语,无 Markdown):"""
|
2026-03-11 14:39:39 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-01-21 22:31:03 +01:00
|
|
|
|
def get_guided_conversation_prompt(
|
|
|
|
|
|
current_stage: str,
|
|
|
|
|
|
empty_slots: List[str],
|
|
|
|
|
|
filled_slots: Dict[str, str],
|
2026-03-31 23:55:26 +08:00
|
|
|
|
all_stages_coverage: Optional[Dict[str, Dict]] = None,
|
2026-02-13 21:45:56 +01:00
|
|
|
|
detected_user_stage: str = "",
|
2026-03-01 10:12:23 +01:00
|
|
|
|
user_profile_context: str = "",
|
2026-03-31 23:55:26 +08:00
|
|
|
|
persona: str = "default",
|
|
|
|
|
|
memory_evidence_text: str = "",
|
|
|
|
|
|
background_voice: str = "default",
|
2026-04-01 11:49:33 +08:00
|
|
|
|
occupation: str = "",
|
2026-04-08 15:37:09 +08:00
|
|
|
|
profile_birth_year: Optional[int] = None,
|
|
|
|
|
|
profile_era_place: str = "",
|
2026-01-21 22:31:03 +01:00
|
|
|
|
) -> str:
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"""生成状态感知的对话提示词;用户原话仅以 HumanMessage 传入,不写入本 system 文本。"""
|
2026-03-31 23:55:26 +08:00
|
|
|
|
persona_key = normalize_interview_persona(persona)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
persona_tone = get_interview_persona_tone_hint(persona_key)
|
|
|
|
|
|
voice_tone = get_background_voice_tone_hint(background_voice)
|
|
|
|
|
|
tone_bits = [t for t in (persona_tone, voice_tone) if t]
|
|
|
|
|
|
tone_line = ""
|
|
|
|
|
|
if tone_bits:
|
|
|
|
|
|
tone_line = " " + " ".join(tone_bits)
|
2026-02-13 21:45:56 +01:00
|
|
|
|
|
2026-04-02 12:00:00 +08:00
|
|
|
|
current_stage_name = STAGE_DISPLAY_ZH.get(current_stage, current_stage)
|
2026-03-19 14:36:14 +08:00
|
|
|
|
user_stage_name = (
|
2026-04-02 12:00:00 +08:00
|
|
|
|
STAGE_DISPLAY_ZH.get(detected_user_stage, "") if detected_user_stage else ""
|
2026-03-19 14:36:14 +08:00
|
|
|
|
)
|
2026-04-02 12:00:00 +08:00
|
|
|
|
user_jumped = bool(detected_user_stage and detected_user_stage != current_stage)
|
2026-02-13 21:45:56 +01:00
|
|
|
|
|
2026-01-21 22:31:03 +01:00
|
|
|
|
empty_slots_readable = [SLOT_NAME_MAP.get(s, s) for s in empty_slots]
|
2026-03-19 14:36:14 +08:00
|
|
|
|
empty_slots_str = (
|
2026-04-02 12:00:00 +08:00
|
|
|
|
"、".join(empty_slots_readable)
|
|
|
|
|
|
if empty_slots_readable
|
|
|
|
|
|
else "本阶段暂无明显缺口"
|
2026-03-19 14:36:14 +08:00
|
|
|
|
)
|
2026-02-13 21:45:56 +01:00
|
|
|
|
|
2026-01-21 22:31:03 +01:00
|
|
|
|
filled_info = []
|
|
|
|
|
|
for key, value in filled_slots.items():
|
|
|
|
|
|
readable_key = SLOT_NAME_MAP.get(key, key)
|
2026-03-19 14:36:14 +08:00
|
|
|
|
filled_info.append(
|
|
|
|
|
|
f"{readable_key}: {value[:50]}..."
|
|
|
|
|
|
if len(value) > 50
|
|
|
|
|
|
else f"{readable_key}: {value}"
|
|
|
|
|
|
)
|
2026-01-21 22:31:03 +01:00
|
|
|
|
filled_slots_str = "\n".join(filled_info) if filled_info else "刚开始聊"
|
|
|
|
|
|
|
2026-04-02 12:00:00 +08:00
|
|
|
|
progress_lines: List[str] = []
|
2026-02-13 21:45:56 +01:00
|
|
|
|
if all_stages_coverage:
|
2026-04-02 12:00:00 +08:00
|
|
|
|
cur_cn = STAGE_DISPLAY_ZH.get(current_stage, current_stage)
|
|
|
|
|
|
progress_lines.append(f"当前阶段:{cur_cn}")
|
|
|
|
|
|
for stage in CHAT_STAGES:
|
2026-02-13 21:45:56 +01:00
|
|
|
|
cov = all_stages_coverage.get(stage, {})
|
|
|
|
|
|
filled_n = cov.get("filled", 0)
|
|
|
|
|
|
total_n = cov.get("total", 0)
|
2026-04-02 12:00:00 +08:00
|
|
|
|
sname = STAGE_DISPLAY_ZH.get(stage, stage)
|
|
|
|
|
|
if total_n <= 0:
|
|
|
|
|
|
continue
|
2026-02-13 21:45:56 +01:00
|
|
|
|
if filled_n == 0:
|
2026-04-02 12:00:00 +08:00
|
|
|
|
progress_lines.append(f" {sname}:未聊")
|
2026-02-13 21:45:56 +01:00
|
|
|
|
elif filled_n < total_n:
|
2026-04-02 12:00:00 +08:00
|
|
|
|
progress_lines.append(f" {sname}:{filled_n}/{total_n}")
|
2026-02-13 21:45:56 +01:00
|
|
|
|
progress_str = "\n".join(progress_lines) if progress_lines else ""
|
|
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
active_stage = (
|
|
|
|
|
|
detected_user_stage if user_jumped and detected_user_stage else current_stage
|
2026-04-02 12:00:00 +08:00
|
|
|
|
)
|
2026-04-06 22:22:50 +08:00
|
|
|
|
era_line = ""
|
|
|
|
|
|
if settings.chat_era_context_enabled:
|
2026-04-08 15:37:09 +08:00
|
|
|
|
era_line = _compact_era_hint(
|
|
|
|
|
|
active_stage,
|
|
|
|
|
|
birth_year=profile_birth_year,
|
|
|
|
|
|
era_place=profile_era_place,
|
|
|
|
|
|
)
|
2026-03-31 23:55:26 +08:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
if user_jumped:
|
|
|
|
|
|
topic_desc = (
|
|
|
|
|
|
f"你们原本在聊「{current_stage_name}」,"
|
|
|
|
|
|
f"用户自然地聊到了「{user_stage_name}」——跟着他/她的节奏,别硬拉回。"
|
2026-04-02 12:00:00 +08:00
|
|
|
|
)
|
|
|
|
|
|
else:
|
2026-04-06 22:22:50 +08:00
|
|
|
|
topic_desc = f"你们在聊「{current_stage_name}」这阶段的话题。"
|
|
|
|
|
|
|
|
|
|
|
|
user_info_parts: List[str] = []
|
|
|
|
|
|
if user_profile_context.strip():
|
|
|
|
|
|
user_info_parts.append(user_profile_context.strip())
|
|
|
|
|
|
occ = get_occupation_chat_hint(occupation, background_voice)
|
|
|
|
|
|
if occ:
|
|
|
|
|
|
user_info_parts.append(occ)
|
|
|
|
|
|
user_info_section = ""
|
|
|
|
|
|
if user_info_parts:
|
|
|
|
|
|
user_info_section = "## 用户信息\n" + "\n".join(user_info_parts) + "\n\n"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
|
|
|
|
|
|
memory_section = ""
|
|
|
|
|
|
mem_trim = (memory_evidence_text or "").strip()
|
|
|
|
|
|
if mem_trim:
|
|
|
|
|
|
memory_section = (
|
|
|
|
|
|
"## 相关记忆摘录(仅供衔接,禁止编造)\n"
|
|
|
|
|
|
"以下为系统从用户**过往口述**中检索到的摘录,**不是**用户本轮亲口新说的内容。\n"
|
2026-04-06 22:22:50 +08:00
|
|
|
|
"承接时可自然用「你之前提过……」等口语,不要把摘录里的细节写成本轮用户新说的;"
|
|
|
|
|
|
"禁止编造摘录未出现的内容。\n\n"
|
2026-03-31 23:55:26 +08:00
|
|
|
|
f"{mem_trim}\n\n"
|
|
|
|
|
|
)
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
progress_block = f"## 进度\n{progress_str}\n" if progress_str else ""
|
|
|
|
|
|
era_block = f"{era_line}\n" if era_line else ""
|
2026-03-01 10:12:23 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
return f"""你是「岁月知己」,像老朋友陪用户聊人生。短句为主,像微信聊天。{tone_line}
|
2026-02-13 21:45:56 +01:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
{topic_desc}
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
{user_info_section}## 当前对话状态
|
|
|
|
|
|
已聊:
|
|
|
|
|
|
{filled_slots_str}
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
还可聊的方向:{empty_slots_str}
|
2026-01-29 20:09:09 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
{progress_block}{era_block}{memory_section}## 你要做的
|
|
|
|
|
|
- **先接住对方**——一句真诚回应,不要写成总结或讲评。
|
|
|
|
|
|
- 你自己判断该追问还是只承接:有新线头就顺着问一个具体的事;情绪浓就好好接住、不必急着追问;明显闲聊就陪聊;用户只说「嗯」「对」则结合上文承接或换个角度。
|
|
|
|
|
|
- 可以用「我能想象……」「那时候大概……」轻轻接话,但不可编造具体人名、时间、事件等你不知道的细节。
|
|
|
|
|
|
- 不要重复上一轮问过的事;用户跳到别的人生阶段,跟着聊,别硬拉回。
|
|
|
|
|
|
- 追问与承接服务于人生故事素材,但不要让对方觉得在走审问式流程;**最多**抛一个具体问题,也可以不追问。
|
|
|
|
|
|
- 可用 [SPLIT] 分成**最多 2 条**消息。
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-03-31 23:55:26 +08:00
|
|
|
|
## 不要做的
|
2026-04-03 13:34:27 +08:00
|
|
|
|
{chat_output_rules()}
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
2026-04-03 14:06:55 +08:00
|
|
|
|
直接输出(仅自然口语,无 Markdown,无任何括号前缀或旁白):"""
|
2026-01-21 22:31:03 +01:00
|
|
|
|
|
2026-04-06 22:22:50 +08:00
|
|
|
|
|
|
|
|
|
|
__all__ = [
|
|
|
|
|
|
"SLOT_NAME_MAP",
|
|
|
|
|
|
"get_guided_conversation_prompt",
|
|
|
|
|
|
"get_opening_prompt",
|
|
|
|
|
|
]
|