//! Cold start prompt generation for conversation-driven onboarding. //! //! Generates stage-specific system prompts that guide the agent through //! the 6-phase cold start flow without requiring form-filling. /// Cold start phases matching the frontend state machine. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ColdStartPhase { Idle, AgentGreeting, IndustryDiscovery, IdentitySetup, FirstTask, Completed, } impl ColdStartPhase { pub fn from_str(s: &str) -> Self { match s { "idle" => Self::Idle, "agent_greeting" => Self::AgentGreeting, "industry_discovery" => Self::IndustryDiscovery, "identity_setup" => Self::IdentitySetup, "first_task" => Self::FirstTask, "completed" => Self::Completed, _ => Self::Idle, } } } /// Industry-specific task suggestions for first_task phase. struct IndustryTasks { tasks: &'static [(&'static str, &'static str)], } const HEALTHCARE_TASKS: IndustryTasks = IndustryTasks { tasks: &[ ("排班查询", "今天有需要处理的排班问题吗?"), ("数据报表", "需要我帮你整理上周的数据报表吗?"), ("政策查询", "最近有医保政策变化需要了解吗?"), ], }; const EDUCATION_TASKS: IndustryTasks = IndustryTasks { tasks: &[ ("课程安排", "需要帮你安排下周的课程吗?"), ("成绩分析", "有学生成绩需要分析吗?"), ("测验生成", "需要帮学生出一份测验吗?告诉我科目和年级就行。"), ], }; const GARMENT_TASKS: IndustryTasks = IndustryTasks { tasks: &[ ("订单跟踪", "有需要跟踪的订单吗?"), ("生产排期", "需要安排生产计划吗?"), ("成本核算", "有需要核算的成本数据吗?"), ], }; const ECOMMERCE_TASKS: IndustryTasks = IndustryTasks { tasks: &[ ("库存检查", "需要检查库存情况吗?"), ("销售分析", "想看看最近的销售数据吗?"), ("商品文案", "有新商品需要写详情页吗?"), ], } ; /// Generate the cold start system prompt for a given phase and optional industry. pub fn generate_cold_start_prompt(phase: ColdStartPhase, industry: Option<&str>) -> String { match phase { ColdStartPhase::Idle | ColdStartPhase::AgentGreeting => format!( "你是一个正在认识新用户的 AI 管家。\n\n\ ## 当前任务\n\ 向用户打招呼并了解他们的工作。用简短自然的方式询问。\n\n\ ## 规则\n\ - 每条消息不超过 3 句话\n\ - 不要问\"你的行业是什么\",而是问\"你每天最常处理什么事?\"\n\ - 保持热情友好,像一个新同事在打招呼\n\ - 用中文交流" ), ColdStartPhase::IndustryDiscovery => { let industry_hint = match industry { Some("healthcare") => "用户可能从事医疗行政工作。", Some("education") => "用户可能从事教育培训工作。", Some("garment") => "用户可能从事制衣制造工作。", Some("ecommerce") => "用户可能从事电商零售工作。", _ => "继续了解用户的工作场景。", }; format!( "你是一个正在了解用户工作场景的 AI 管家。\n\n\ ## 当前阶段:行业发现\n\ {industry_hint}\n\n\ ## 规则\n\ - 根据用户的回答确认行业\n\ - 如果检测到行业,主动说出你的理解,让用户确认\n\ - 每条消息不超过 3 句话\n\ - 用中文交流" ) } ColdStartPhase::IdentitySetup => { let name_suggestion = match industry { Some("healthcare") => "小医", Some("education") => "小教", Some("garment") => "小织", Some("ecommerce") => "小商", _ => "小助手", }; format!( "你是一个正在为自己起名字的 AI 管家。\n\n\ ## 当前阶段:身份设定\n\ 根据你了解的行业信息,向用户提议一个合适的名字和沟通风格。\n\n\ ## 建议\n\ - 可以提议叫\"{name_suggestion}\"或其他合适的名字\n\ - 说明你选择的沟通风格(专业/亲切/简洁)\n\ - 让用户确认或提出自己的想法\n\ - 每条消息不超过 3 句话\n\ - 用中文交流" ) } ColdStartPhase::FirstTask => { let task_prompt = match industry { Some("healthcare") => HEALTHCARE_TASKS.tasks[2].1, Some("education") => EDUCATION_TASKS.tasks[2].1, Some("garment") => GARMENT_TASKS.tasks[2].1, Some("ecommerce") => ECOMMERCE_TASKS.tasks[2].1, _ => "有什么我可以帮你的吗?", }; format!( "你是一个 AI 管家,用户已经完成了初始设置。\n\n\ ## 当前阶段:首次任务引导\n\ 引导用户完成第一个实际任务,让他们体验你的能力。\n\n\ ## 建议\n\ - {task_prompt}\n\ - 根据用户需求灵活调整\n\ - 保持简短,1-2 句话\n\ - 用中文交流" ) } ColdStartPhase::Completed => String::new(), } } /// Check if a cold start prompt should be injected for the given phase. pub fn should_inject_prompt(phase: ColdStartPhase) -> bool { !matches!(phase, ColdStartPhase::Idle | ColdStartPhase::Completed) } #[cfg(test)] mod tests { use super::*; #[test] fn test_phase_from_str() { assert_eq!(ColdStartPhase::from_str("idle"), ColdStartPhase::Idle); assert_eq!(ColdStartPhase::from_str("agent_greeting"), ColdStartPhase::AgentGreeting); assert_eq!(ColdStartPhase::from_str("industry_discovery"), ColdStartPhase::IndustryDiscovery); assert_eq!(ColdStartPhase::from_str("identity_setup"), ColdStartPhase::IdentitySetup); assert_eq!(ColdStartPhase::from_str("first_task"), ColdStartPhase::FirstTask); assert_eq!(ColdStartPhase::from_str("completed"), ColdStartPhase::Completed); assert_eq!(ColdStartPhase::from_str("unknown"), ColdStartPhase::Idle); } #[test] fn test_greeting_prompt_not_empty() { let prompt = generate_cold_start_prompt(ColdStartPhase::AgentGreeting, None); assert!(!prompt.is_empty()); assert!(prompt.contains("AI 管家")); } #[test] fn test_industry_discovery_with_industry() { let prompt = generate_cold_start_prompt(ColdStartPhase::IndustryDiscovery, Some("healthcare")); assert!(prompt.contains("医疗行政")); } #[test] fn test_identity_setup_suggests_name() { let prompt = generate_cold_start_prompt(ColdStartPhase::IdentitySetup, Some("education")); assert!(prompt.contains("小教")); } #[test] fn test_first_task_has_suggestion() { let prompt = generate_cold_start_prompt(ColdStartPhase::FirstTask, Some("ecommerce")); assert!(!prompt.is_empty()); assert!(prompt.contains("库存") || prompt.contains("销售") || prompt.contains("商品")); } #[test] fn test_completed_returns_empty() { let prompt = generate_cold_start_prompt(ColdStartPhase::Completed, None); assert!(prompt.is_empty()); } #[test] fn test_should_inject() { assert!(!should_inject_prompt(ColdStartPhase::Idle)); assert!(should_inject_prompt(ColdStartPhase::AgentGreeting)); assert!(should_inject_prompt(ColdStartPhase::IndustryDiscovery)); assert!(should_inject_prompt(ColdStartPhase::IdentitySetup)); assert!(should_inject_prompt(ColdStartPhase::FirstTask)); assert!(!should_inject_prompt(ColdStartPhase::Completed)); } }