Chat 访谈 - 新增 persona 系统(default / warm_listener / curious_guide)与 background_voice 语气层 - 回复长度由 compute_reply_plan 统一决策(brief / standard / expanded),融合信息密度启发式 - 输入净稿(input_normalize):编排层可选 rules/llm 归一用户口语后再喂模型与记忆检索 - 记忆证据注入:按用户话检索 memory evidence 并注入 prompt Memoir 回忆录 - 口述归一(oral_normalize):segment 原文保留,story 管线取派生净稿作叙事输入 - segment 入队批次门闸:累计字数 + 最长等待秒数,减少零碎提交 - fidelity_check / prompts / narrative_agent 微调 - Alembic 0005:清理跨章节 story 外键 Infra - Dockerfile 加入 ffmpeg - pyproject.toml 新增依赖并同步 uv.lock - .env.example / .env.production 补全新配置项 Tests - 新增 test_background_voice、test_chat_input_normalize、test_experience_regressions - 扩展 test_interview_prompts、test_interview_reply_length、test_story_route_oral_invariant Made-with: Cursor
61 lines
2.6 KiB
Python
61 lines
2.6 KiB
Python
"""
|
||
访谈 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, "")
|