""" 访谈 Agent 可配置性格(Persona):仅影响语气与追问倾向,不替代事实边界与槽位约束。 """ from __future__ import annotations from typing import Final # 与 settings.chat_interview_persona 及文档保持一致 VALID_INTERVIEW_PERSONAS: Final[frozenset[str]] = frozenset( {"default", "warm_listener", "curious_guide"} ) def normalize_interview_persona(raw: str | None) -> str: """未知或空值回退 default,避免部署拼写错误导致空提示。""" key = (raw or "default").strip().lower() if key in VALID_INTERVIEW_PERSONAS: return key return "default" def get_interview_persona_block(persona: str) -> str: """ 返回注入到访谈 prompt 的「访谈性格」段落(不含 default,由调用方跳过)。 """ key = normalize_interview_persona(persona) if key == "default": return "" blocks = { "warm_listener": ( "## 访谈性格:温柔倾听\n" "在遵守「回忆录导向与闲聊」的前提下,优先把对话引向可写进回忆录的素材;明显闲聊时先陪聊。\n" "你更偏倾听与承接,语气柔和、少打断;" "但一旦用户说出**新的人名、新的关系、或新的情节线**(上文未展开)," "仍必须按本提示中的「追问触发」规则,在承接后带**一个**具体问题,不能用纯感慨代替。\n" "禁止审问感、禁止一次抛多个问题。" ), "curious_guide": ( "## 访谈性格:好奇引导\n" "在遵守「回忆录导向与闲聊」的前提下,追问尽量落在人生故事与未覆盖方向上;明显闲聊时先陪聊。\n" "你更愿意把人往**一个具体细节**里带:时间、场景、对方反应、你心里一闪而过的念头;" "每轮**最多一个**具体问题,短句、像微信。\n" "若本轮触发「追问触发」,优先追问用户刚抛出的新信息,不要为了凑问题去重复上文已清楚的事。" ), } return blocks.get(key, "") def get_opening_persona_line(persona: str) -> str: """开场白用的一行性格提示(短,避免喧宾夺主)。""" key = normalize_interview_persona(persona) if key == "default": return "" lines = { "warm_listener": "语气偏倾听、少打断;但仍须完成「问候 + 一个具体问题」。", "curious_guide": "语气偏好奇、爱往细节里带一个具体问题;不要一次问很多。", } return lines.get(key, "")