- Drop interview_reply_length and utterance_substance; always run stage LLM and memory retrieval when enabled; trim Settings fields and .env.example. - Replace guided/opening prompts with compact fact blocks plus unified behavior guidance; slim background_voice and persona to tone hints. - InterviewAgent uses fixed chat_interview max_tokens/chars/segments. Also includes stacked work: profile followup/extract path, evaluation rubric and judge schema updates, transcript SPLIT handling in execution service, user export markdown split tests, and golden case fixture.
114 lines
4.3 KiB
Python
114 lines
4.3 KiB
Python
"""面向体验的回归测试:保护「聊得下去」与回忆录文笔两个核心目标。
|
|
|
|
与 test_interview_prompts 不同,这组测试不绑定已删除的启发式分档;
|
|
访谈侧仅验证 prompt 仍包含关键行为指引。
|
|
"""
|
|
|
|
from app.agents.chat.prompts_conversation import (
|
|
get_guided_conversation_prompt,
|
|
get_opening_prompt,
|
|
)
|
|
from app.agents.memoir.prompts import (
|
|
get_creative_title_json_prompt,
|
|
get_narrative_editor_system_prompt,
|
|
get_narrative_json_prompt,
|
|
)
|
|
from app.features.memoir import story_pipeline_sync as sps
|
|
|
|
|
|
class TestChatExperienceRegressions:
|
|
"""保护「聊得下去」体验。"""
|
|
|
|
def test_guided_prompt_encourages_flexible_followup(self) -> None:
|
|
"""模型自主判断追问 vs 承接,不应再出现「本轮判定」硬分支文案。"""
|
|
p = get_guided_conversation_prompt(
|
|
current_stage="childhood",
|
|
empty_slots=["place", "people"],
|
|
filled_slots={},
|
|
detected_user_stage="childhood",
|
|
user_profile_context="",
|
|
persona="default",
|
|
)
|
|
assert "本轮追问判定" not in p
|
|
assert "你自己判断" in p or "该追问" in p
|
|
|
|
def test_guided_prompt_topic_switch_not_hardcoded_in_prompt(self) -> None:
|
|
p = get_guided_conversation_prompt(
|
|
current_stage="childhood",
|
|
empty_slots=["place", "people", "emotion"],
|
|
filled_slots={"daily_life": "放学后去河边玩"},
|
|
detected_user_stage="childhood",
|
|
user_profile_context="",
|
|
persona="default",
|
|
)
|
|
assert "聊得差不多了" not in p
|
|
|
|
def test_guided_prompt_intro_mentions_connect_first(self) -> None:
|
|
p = get_guided_conversation_prompt(
|
|
current_stage="childhood",
|
|
empty_slots=["place"],
|
|
filled_slots={},
|
|
detected_user_stage="childhood",
|
|
user_profile_context="",
|
|
persona="default",
|
|
)
|
|
assert "接住" in p
|
|
|
|
def test_opening_prompt_stays_short_task_shape(self) -> None:
|
|
p = get_opening_prompt(
|
|
current_stage="childhood",
|
|
empty_slots_readable=["成长的地方"],
|
|
user_profile_context="",
|
|
persona="default",
|
|
)
|
|
assert "问候" in p
|
|
assert "任务" in p or "具体问题" in p
|
|
|
|
|
|
class TestMemoirStyleRegressions:
|
|
"""保护「回忆录有文笔」体验。"""
|
|
|
|
def test_title_prompt_allows_literary_expression(self) -> None:
|
|
prompt = get_creative_title_json_prompt(
|
|
stage="childhood",
|
|
emotion="warm",
|
|
slots={"place": "湖南老家", "turning_event": "爷爷背我过河"},
|
|
)
|
|
assert "禁止虚构" in prompt
|
|
assert "平实" not in prompt.lower()
|
|
|
|
def test_title_prompt_uses_facts_only_not_plain(self) -> None:
|
|
prompt = get_creative_title_json_prompt(
|
|
stage="childhood",
|
|
emotion="warm",
|
|
slots={"place": "老家"},
|
|
)
|
|
assert "优雅" in prompt or "书面语" in prompt or "文采" in prompt
|
|
|
|
def test_narrative_prompt_encourages_literary_quality(self) -> None:
|
|
sys_prompt = get_narrative_editor_system_prompt()
|
|
assert "温度" in sys_prompt or "优雅" in sys_prompt
|
|
assert "画面感" in sys_prompt or "生动" in sys_prompt
|
|
|
|
def test_narrative_json_prompt_allows_emotion_rendering(self) -> None:
|
|
prompt = get_narrative_json_prompt(
|
|
stage="childhood",
|
|
slots={"turning_event": "爷爷背我过河"},
|
|
new_content="【本段用户口述】\n那年下大雨,爷爷背我过河,鞋全湿了,他一直笑。",
|
|
)
|
|
assert "文采服务于真实" in prompt or "虚构描写" in prompt
|
|
|
|
def test_merge_shrink_only_on_extreme_loss(self) -> None:
|
|
existing = "这是一段已有的故事正文,讲述了童年在河边的回忆。" * 20
|
|
assert len(existing) > 400
|
|
half_content = existing[: len(existing) // 2]
|
|
import json
|
|
|
|
raw = json.dumps(
|
|
{"paragraphs": [{"content": half_content}]}, ensure_ascii=False
|
|
)
|
|
out, ft = sps._apply_narrative_fallbacks(
|
|
raw, "新的口述补充", existing, chapter_category="childhood"
|
|
)
|
|
assert ft == "none"
|