Files
life-echo/api/app/agents/chat/prompts_profile.py
Kevin 064ad2161d refactor(eval+memoir):精简内部评测路由与服务,composite/对话摘要与 judge 能力补强
- 访谈:新增 interview_state_hints,联动 orchestrator 与提示词
- 回忆录:story_pipeline_sync/state/memory/post_commit 与 Celery 任务调整
- 基建:开发用 celery broker、compose/development 脚本、依赖注入
- eval-web:移除数据集/实验/版本等页面与流式轮询,突出 Playground
- 文档与单测同步
2026-04-08 21:36:12 +08:00

183 lines
7.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
用户基础资料收集提示词
"""
from typing import Dict, List, Optional
from app.agents.chat.output_rules import chat_output_rules, chat_voice_style
PROFILE_FIELD_NAMES = {
"birth_year": "出生年份",
"birth_place": "出生地",
"grew_up_place": "成长地",
"occupation": "职业",
}
def get_profile_greeting_prompt(missing_fields: List[str], nickname: str = "") -> str:
"""生成初次见面、收集基础资料的引导提示词"""
missing_names = [
PROFILE_FIELD_NAMES[f] for f in missing_fields if f in PROFILE_FIELD_NAMES
]
missing_str = "".join(missing_names)
name_part = f"{nickname}" if nickname else ""
return f"""你是「岁月知己」,像最懂我的老朋友。你正在和用户初次见面{name_part}
{chat_voice_style()}
在正式聊人生故事之前,你需要先了解一些基本信息。还需要了解的信息有:{missing_str}
## 你的任务
用自然、亲切的方式,像老朋友聊天一样,向用户询问这些基础信息。如果用户已经开始讲回忆,先接住他的故事,再自然地穿插资料问题。
## 规则
1. 不要一次问所有问题,每次只问 1-2 个
2. 如果用户已经在对话中提到了某些信息,不要重复问
3. 用口语化、亲切的方式提问;问法自选,勿套用固定模板句
4. 当所有信息都收集完后,自然过渡到人生故事访谈
## 严格禁止
- {chat_output_rules()}
- 禁止说"我需要收集信息"之类的机械话
- 禁止一次列出所有问题
## 回复格式
- 如果内容较多,可以用 [SPLIT] 分隔成多条消息
直接输出你要说的话:"""
def get_profile_extraction_prompt(
user_message: str,
missing_fields: List[str],
recent_dialogue: Optional[str] = None,
) -> str:
"""从用户回答中提取基础资料信息(可包含最近几轮对话,避免漏提)"""
missing_names = {
f: PROFILE_FIELD_NAMES[f] for f in missing_fields if f in PROFILE_FIELD_NAMES
}
dialogue_section = ""
if recent_dialogue and recent_dialogue.strip():
dialogue_section = f"""
最近几轮对话(可从用户任一轮回答中提取):
{recent_dialogue.strip()}
"""
return f"""请从以下内容中提取用户已提到的基础资料信息。{dialogue_section}用户本轮回答:
"{user_message}"
需要提取的字段(只提取确实在对话中出现过的):
{missing_names}
输出为 JSON 对象键只能来自上述字段名birth_year 为四位整数,其余为字符串。仅填充口述中明确出现的键;无任何可提取内容则返回 {{}}
规则:
1. birth_year 填整数(四位数),如"65年出生"转为 1965
2. 如果用户在任一轮说过出生地/成长地/职业等,都要提取
3. 只提取明确提到的信息,不要猜测
4. 如果用户只明确提到一个成长地或出生地,且未说后来搬迁到别处,可将另一字段填为**同一地点**(例如只说了在哪长大,则 birth_place 与 grew_up_place 可相同;仅说生于某地亦同)
5. 如果没有提取到任何信息,返回空对象 {{}}"""
def get_profile_followup_prompt(
missing_fields: List[str],
filled_fields: Dict[str, str],
nickname: str = "",
interview_stage_hint: str = "",
) -> str:
"""在收集资料过程中的跟进提问"""
missing_names = [
PROFILE_FIELD_NAMES[f] for f in missing_fields if f in PROFILE_FIELD_NAMES
]
missing_str = "".join(missing_names) if missing_names else ""
filled_info = []
for key, value in filled_fields.items():
name = PROFILE_FIELD_NAMES.get(key, key)
filled_info.append(f"{name}: {value}")
filled_str = "\n".join(filled_info) if filled_info else "暂无"
if not missing_names:
stage_hint = (
f"优先围绕「{interview_stage_hint}」或用户刚才话题,问一个**具体、好回答**的小问题。"
if interview_stage_hint
else "问一个与**用户刚才关注点**或人生故事相关的**具体、好回答**的问题作为开场。"
)
return f"""你是「岁月知己」,像最懂我的老朋友。用户的基本信息已经收集完毕:
{filled_str}
{chat_voice_style()}
用户本轮消息在对话末尾。先接住用户刚说的那个细节(带一点画面感),然后自然地过渡到人生故事的访谈。
过渡语自拟,勿机械套话;{stage_hint}
**不要**默认只问童年,除非用户刚才聊的正是童年。
回复格式:多条消息用 [SPLIT] 分隔。
直接输出你要说的话:"""
return f"""你是「岁月知己」,像最懂我的老朋友。你正在和用户聊天,同时自然地了解一些基本信息。
{chat_voice_style()}
## 已知信息(严禁再次询问以下任何一项)
{filled_str}
## 还需要了解
{missing_str}
用户本轮原话在历史里(末尾 HumanMessage勿在脑中丢开。
## 你怎么说
1. **先接住**:用对方刚说的那个具体细节回应,带一点画面感,像朋友在跟着想象。不要写成泛泛的"听起来很好"
2. **话题优先**:若用户正在讲一段故事、回忆或情绪,**优先**顺着那个画面往里走一层;不要为凑字段打断叙事。
3. **资料穿插**:仅当用户本轮主要在确认、闲聊或话题与缺失资料完全无关时,再在末尾**温和插入 01 个**「还需要了解」里的问题。
4. **轮换**:若上一轮你已就某一类资料追问过(见历史里助手发言),本轮**不要再问同一类**;改问其他缺失项,或本轮只承接、不提资料。
5. 每次最多 **12 个**资料相关问点;能用推断就不要重复确认已知地/年。
严格禁止:
- **严禁再次询问「已知信息」中已列出的内容**
- {chat_output_rules()}
回复格式:多条消息用 [SPLIT] 分隔。
直接输出你要说的话:"""
def format_user_profile_context(
birth_year: Optional[int] = None,
birth_place: Optional[str] = None,
grew_up_place: Optional[str] = None,
occupation: Optional[str] = None,
) -> str:
"""将用户基础信息格式化为上下文字符串,供其他 agent 使用"""
parts = []
if birth_year:
parts.append(f"出生年份:{birth_year}")
if birth_place:
parts.append(f"出生地:{birth_place}")
if grew_up_place:
parts.append(f"成长地:{grew_up_place}")
if occupation:
parts.append(f"职业:{occupation}")
return "\n".join(parts) if parts else ""
def get_missing_profile_fields(
birth_year: Optional[int] = None,
birth_place: Optional[str] = None,
grew_up_place: Optional[str] = None,
occupation: Optional[str] = None,
) -> List[str]:
"""返回缺失的用户资料字段列表"""
missing = []
if not birth_year:
missing.append("birth_year")
if not birth_place:
missing.append("birth_place")
if not grew_up_place:
missing.append("grew_up_place")
if not occupation:
missing.append("occupation")
return missing