Files
life-echo/api/app/agents/chat/prompts_profile.py
Kevin a3f61fcc0f feat(api+app): 对话阶段化、回忆录流水线与客户端会话体验
- DB: segments 用户输入文本(Alembic 0002)
- Chat: 阶段检测/阶段提示/回复限制,编排与访谈/画像 prompts 调整
- Memoir: 忠实度检查 agent,叙事与分类等链路更新
- Core: agent 日志、Alembic 启动、LangChain/日志/配置等
- Story: time_hints;Memory 检索与相关测试
- Expo: 助手头像、会话页与消息拆分、实时会话与文案/i18n
- Docs/scripts/tests: 迁移脚本、LLM JSON/记忆检索文档、新增单测
2026-03-26 12:13:36 +08:00

191 lines
6.4 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
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}
在正式聊人生故事之前,你需要先了解一些基本信息。还需要了解的信息有:{missing_str}
## 你的任务
用自然、亲切的方式,像老朋友聊天一样,向用户询问这些基础信息。
## 规则
1. 不要一次问所有问题,每次只问 1-2 个
2. 如果用户已经在对话中提到了某些信息,不要重复问
3. 用口语化、亲切的方式提问
4. 当所有信息都收集完后,自然过渡到人生故事访谈
## 提问示例
- "你是哪一年出生的呀?"
- "你是在哪里出生的?小时候也是在那里长大的吗?"
- "你现在是做什么工作的呀?或者之前主要从事什么职业?"
## 严格禁止
- 禁止输出括号注释、思考过程
- 禁止说"我需要收集信息"之类的机械话
- 禁止一次列出所有问题
## 回复格式
- 如果内容较多,可以用 [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}"
**JSON 输出**:接口已启用 `response_format=json_object`DeepSeek JSON 模式),你必须只输出一个合法 JSON 对象。
需要提取的字段(只提取确实在对话中出现过的):
{missing_names}
请返回 JSON 格式,只包含确实提到的字段:
{{
"birth_year": 1965,
"birth_place": "湖南长沙",
"grew_up_place": "湖南长沙",
"occupation": "教师"
}}
规则:
1. birth_year 填整数(四位数),如"65年出生"转为 1965
2. 如果用户在任一轮说过出生地/成长地/职业等,都要提取
3. 只提取明确提到的信息,不要猜测
4. 如果没有提取到任何信息,返回空对象 {{}}
只返回 JSON不要其他内容。"""
def get_profile_followup_prompt(
missing_fields: List[str],
filled_fields: Dict[str, str],
user_message: 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}
用户刚才说:"{user_message}"
请对用户的回答做出温暖的回应,然后自然地过渡到人生故事的访谈。
可以说类似「了解了!那我们现在开始聊聊你的人生故事吧」这样的话;{stage_hint}
**不要**默认只问童年,除非用户刚才聊的正是童年。
回复格式:多条消息用 [SPLIT] 分隔。
直接输出你要说的话:"""
return f"""你是「岁月知己」,正在和用户聊天收集基本信息。
## 已知信息(严禁再次询问以下任何一项)
{filled_str}
## 还需要了解
{missing_str}
用户刚才说:"{user_message}"
请先对用户说的内容做出自然回应,然后**只**询问「还需要了解」中的信息(每次问 1-2 个)。
语气要像朋友聊天一样自然亲切。
严格禁止:
- **严禁再次询问「已知信息」中已列出的内容**(例如已知出生年份就绝不要再问哪年出生)
- 禁止输出括号注释、思考过程
- 禁止说"我注意到""我需要了解"
回复格式:多条消息用 [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