独立产品 AI 智能通知:别用推送轰炸用户

📅 2026/7/11 0:27:23
独立产品 AI 智能通知:别用推送轰炸用户
独立产品 AI 智能通知别用推送轰炸用户一、通知疲劳的恶性循环为什么要重新思考推送策略推送通知的打开率正在逐年下降。数据显示移动应用的推送通知打开率已降至 3% 以下而用户主动关闭通知权限的比例持续上升。对于独立产品而言每一次不当的推送都在消耗用户对产品的信任。传统的通知系统通常采用简单的触发规则用户触发了某个事件就发送通知。这种点火即发的模式忽略了用户的上下文状态和接收意愿导致用户在非预期时间收到大量无关通知。AI 驱动的智能通知系统通过理解用户行为模式、内容相关性和时间窗口实现在正确的时间、以正确的方式、发送正确的内容的精准触达。graph TD A[触发事件] -- B[AI 通知决策引擎] B -- C{用户在线?} C --|是| D[实时推送] C --|否| E[延迟队列] B -- F{内容相关性br/评分} F --|高| G[发送] F --|低| H[丢弃/合并] B -- I{最优发送br/时间窗口} I --|立即| D I --|延迟| E E -- J[定时任务] J -- D D -- K[用户设备] K -- L{用户行为} L --|打开| M[正向反馈] L --|忽略| N[负向反馈] L --|关闭| O[退订] M -- B N -- B二、AI 通知决策引擎的架构设计智能通知系统的核心是一个决策引擎它综合多个维度来判断是否发送、何时发送、如何发送通知。2.1 用户行为模式学习通过分析用户的历史行为AI 可以学习每个用户的最佳接收时间和内容偏好。但在实际落地中冷启动阶段是一个核心挑战新用户没有历史交互数据偏好学习器无法给出有意义的推荐。冷启动处理策略对于数据不足的用户系统采用基于相似用户群的协同策略。通过用户画像注册渠道、设备类型、时间段偏好匹配相似用户借用群体的统计结论作为初始默认值同时以较低的决策权重参与判断留给新产品更灵活的首周探索期。cookieId在未登录阶段即可沉淀网页/落地页的行为基线方便注册后无缝迁移也让学习器在新用户注册后能立即使用这份预收集信息。/** * 冷启动场景下的通知策略 * 通过用户画像匹配相似用户群体借用群体偏好 */ async function resolveColdStartPreferences(userId, userProfile) { try { // 1. 检查是否有最近一周的同群组学习结果 const groupKey buildGroupKey(userProfile); // 例如 iosorganicmorning const cachedGroup await redis.get(coldstart:${groupKey}); if (cachedGroup) { return JSON.parse(cachedGroup); } // 2. 查询相似用户的聚合偏好从最近活跃用户中采样 const similarUsers await db.query( SELECT notification_type, AVG(opened) as avg_open_rate, MODE() WITHIN GROUP (ORDER BY hour_of_day) as best_hour FROM notification_logs WHERE user_id IN ( SELECT user_id FROM user_profiles WHERE acquisition_channel $1 AND device_type $2 AND first_session_hour BETWEEN $3 AND $4 ) AND created_at NOW() - INTERVAL 7 days GROUP BY notification_type , [userProfile.channel, userProfile.deviceType, userProfile.sessionHour - 2, userProfile.sessionHour 2]); const groupPreferences buildGroupPreferences(similarUsers); // 3. 缓存群组偏好1小时有效 await redis.setEx( coldstart:${groupKey}, 3600, JSON.stringify(groupPreferences) ); return groupPreferences; } catch (error) { console.error(冷启动策略解析失败使用默认偏好:, error); return getDefaultPreferences(); } } function buildGroupKey(profile) { return ${profile.deviceType}:${profile.channel}:${Math.floor(profile.sessionHour / 4)}; }常见踩坑偏好数据的时效性衰减用户的通知偏好会随时间变化。一个月前的偏好晚上10点接收通知可能因为用户换了作息而不再准确。在实际项目中需要给近期数据更高的权重/** * 时间衰减加权近7天的交互权重更高 */ function calculateWeightedPreferences(interactions) { const now Date.now(); let weightedScores {}; for (const interaction of interactions) { const daysAgo (now - new Date(interaction.recordedAt).getTime()) / (86400000); // 指数衰减越久远的数据权重越低 const weight Math.exp(-daysAgo / 7); // 7天半衰期 if (interaction.opened) { const hour new Date(interaction.sentAt).getHours(); weightedScores[hour] (weightedScores[hour] || 0) weight; } } return weightedScores; }2.2 通知决策引擎核心逻辑import { createClient } from redis/client;import OpenAI from openai;class NotificationPreferenceLearner {constructor(redisClient, openaiClient) {this.redis redisClient;this.ai openaiClient;}/**分析用户通知交互历史提取偏好特征param {string} userId - 用户 IDreturns {Promise} 用户通知偏好*/async learnUserPreferences(userId) {try {// 1. 从 Redis 获取用户通知交互历史const interactionKey user:${userId}:notification_interactions;const interactions await this.redis.lRange(interactionKey, 0, -100);if (interactions.length 10) {// 数据不足返回默认策略return this.getDefaultPreferences();}// 2. 解析交互数据const parsedInteractions interactions.map(i JSON.parse(i));// 3. 使用 AI 分析模式const preferences await this.aiAnalyzePreferences(parsedInteractions);// 4. 缓存计算结果1小时有效期const cacheKey user:${userId}:notification_preferences;await this.redis.setEx(cacheKey,3600,JSON.stringify(preferences));return preferences;} catch (error) { console.error(用户偏好学习失败:, error); return this.getDefaultPreferences(); }}async aiAnalyzePreferences(interactions) {const prompt 分析以下用户的通知交互历史提取通知偏好特征。交互数据${interactions.map((i, idx) ${idx 1}. 通知类型: ${i.type} 发送时间: ${new Date(i.sentAt).toLocaleString()} 是否打开: ${i.opened} 是否点击: ${i.clicked} 设备类型: ${i.deviceType}).join(\n)}分析要求请返回 JSON 格式的分析结果{optimalTimeWindows: [{ start: 09:00, end: 11:00, probability: 0.8 }],preferredTypes: [comment, mention],unwantedTypes: [marketing, digest],devicePreference: mobile,frequencyPreference: max_3_per_day,bestDayOfWeek: [Tuesday, Wednesday, Thursday]};const response await this.ai.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: prompt }], response_format: { type: json_object }, temperature: 0.2 }); return JSON.parse(response.choices[0].message.content);}getDefaultPreferences() {return {optimalTimeWindows: [{ start: 09:00, end: 11:00, probability: 0.5 },{ start: 14:00, end: 16:00, probability: 0.5 }],preferredTypes: [comment, mention, direct_message],unwantedTypes: [marketing],devicePreference: any,frequencyPreference: max_5_per_day,bestDayOfWeek: [Monday, Tuesday, Wednesday, Thursday, Friday]};}/**记录用户通知交互供后续学习使用*/async recordInteraction(userId, interaction) {const key user:${userId}:notification_interactions;await this.redis.lPush(key, JSON.stringify({...interaction,recordedAt: new Date().toISOString()}));// 保留最近 200 条记录 await this.redis.lTrim(key, 0, 199);}}### 2.2 通知决策引擎核心逻辑 javascript /** * AI 通知决策引擎 * 决定是否发送、何时发送、如何发送通知 */ class AINotificationDecisionEngine { constructor(preferenceLearner, options {}) { this.learner preferenceLearner; this.options { // 每日最大通知数硬上限 maxDailyNotifications: 5, // AI 决策开关 enableAIDecision: true, // 静默时间不发送通知 quietHours: { start: 22, end: 8 }, ...options }; } /** * 处理通知发送请求 * param {Object} notification - 通知对象 * returns {PromiseObject} 决策结果 */ async decide(notification) { try { const { userId, type, content, priority } notification; // 1. 检查静默时间 if (this.isQuietHours()) { return { decision: defer, reason: 当前处于静默时间, scheduledTime: this.getNextActiveTime() }; } // 2. 检查用户当日已接收通知数 const dailyCount await this.getDailyNotificationCount(userId); if (dailyCount this.options.maxDailyNotifications priority ! urgent) { return { decision: defer, reason: 已达到每日通知上限${this.options.maxDailyNotifications}, scheduledTime: this.getTomorrowActiveTime() }; } // 3. 获取用户偏好 const preferences await this.learner.learnUserPreferences(userId); // 4. 检查通知类型是否被用户屏蔽 if (preferences.unwantedTypes.includes(type)) { return { decision: suppress, reason: 用户不接收 ${type} 类型通知 }; } // 5. AI 决策综合评估发送时机和方式 if (this.options.enableAIDecision) { const aiDecision await this.aiDecide(notification, preferences); if (aiDecision.decision suppress) { return aiDecision; } if (aiDecision.decision defer) { return { ...aiDecision, scheduledTime: aiDecision.suggestedTime || this.getNextActiveTime() }; } } // 6. 批准发送 return { decision: send, reason: 通过所有检查, channel: this.selectChannel(notification, preferences), scheduledTime: this.getOptimalSendTime(preferences) }; } catch (error) { console.error(通知决策失败:, error); // 失败时使用保守策略延迟发送 return { decision: defer, reason: 决策引擎异常延迟发送, scheduledTime: new Date(Date.now() 30 * 60 * 1000) // 30分钟后 }; } } /** * AI 综合决策 */ async aiDecide(notification, preferences) { const prompt 作为一个通知决策系统判断是否应该发送以下通知。 ## 通知信息 - 类型: ${notification.type} - 优先级: ${notification.priority} - 内容摘要: ${notification.content.summary} ## 用户偏好 - 偏好的通知类型: ${preferences.preferredTypes.join(, )} - 不想要的类型: ${preferences.unwantedTypes.join(, )} - 最佳发送时间窗口: ${preferences.optimalTimeWindows.map(w ${w.start}-${w.end}).join(, )} - 频率偏好: ${preferences.frequencyPreference} ## 当前时间 ${new Date().toLocaleString()} ## 决策要求 请返回 JSON { decision: send | defer | suppress, reason: 决策原因, suggestedTime: 如果 defer建议的发送时间ISO 8601 } ; const response await this.learner.ai.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: prompt }], response_format: { type: json_object }, temperature: 0.2 }); return JSON.parse(response.choices[0].message.content); } isQuietHours() { const hour new Date().getHours(); const { start, end } this.options.quietHours; if (start end) { // 跨天情况如 22:00 - 08:00 return hour start || hour end; } return hour start hour end; } getDailyNotificationCount(userId) { // 实际实现中查询 Redis 或数据库 return Promise.resolve(0); // 示意 } getOptimalSendTime(preferences) { // 基于用户偏好时间窗口选择最佳发送时间 const now new Date(); const currentHour now.getHours(); for (const window of preferences.optimalTimeWindows) { const [startHour] window.start.split(:).map(Number); if (currentHour startHour) { const scheduled new Date(now); scheduled.setHours(startHour, 0, 0, 0); return scheduled; } } // 没有合适时间窗口推迟到明天第一个窗口 const tomorrow new Date(now); tomorrow.setDate(tomorrow.getDate() 1); const [firstStart] preferences.optimalTimeWindows[0].start.split(:).map(Number); tomorrow.setHours(firstStart, 0, 0, 0); return tomorrow; } selectChannel(notification, preferences) { // 根据通知优先级和用户设备偏好选择发送渠道 if (notification.priority urgent) { return push; // 紧急通知强制推送 } if (preferences.devicePreference mobile) { return push; } return in-app; // 默认使用应用内通知 } }三、通知内容个性化从模板到 AI 生成优质的 notification 内容是提高打开率的关键。AI 可以根据通知上下文和用户特征生成高度个性化的通知文案。3.1 动态内容生成/** * AI 通知内容生成器 * 为每个用户生成个性化的通知文案 */ class AINotificationContentGenerator { constructor(openaiClient) { this.client openaiClient; } /** * 生成个性化通知内容 * param {Object} params - 生成参数 * returns {PromiseObject} 生成的内容 */ async generateContent(params) { const { notificationType, triggerEvent, recipientUser, senderUser, entityInfo, language zh-CN } params; const prompt this.buildContentPrompt({ notificationType, triggerEvent, recipientUser, senderUser, entityInfo, language }); try { const response await this.client.chat.completions.create({ model: gpt-4, messages: [ { role: system, content: 你是一位专业的通知文案撰写者。你的目标是撰写简洁、相关且不会引起用户反感的通知内容。保持口语化避免营销套话。 }, { role: user, content: prompt } ], response_format: { type: json_object }, temperature: 0.7 }); const result JSON.parse(response.choices[0].message.content); // 验证生成结果 if (!result.title || !result.body) { throw new Error(生成的内容格式不完整); } return { title: result.title.slice(0, 50), // 标题限制 50 字符 body: result.body.slice(0, 150), // 正文限制 150 字符 actionText: result.actionText || 查看详情, metadata: result.metadata || {} }; } catch (error) { console.error(通知内容生成失败:, error); // 返回默认内容 return this.getDefaultContent(notificationType, triggerEvent); } } buildContentPrompt(params) { return 为以下场景生成通知内容简体中文。 ## 场景信息 - 通知类型: ${params.notificationType} - 触发事件: ${params.triggerEvent} - 接收用户名称: ${params.recipientUser.name} - 发送用户名称: ${params.senderUser?.name || 系统} - 相关实体: ${params.entityInfo.type} - ${params.entityInfo.title} ## 要求 1. 标题不超过 50 个字符 2. 正文不超过 150 个字符 3. 使用简体中文口语化表达 4. 避免使用尊敬的用户等通用称呼 5. 包含具体的价值信息如评论内容摘要 ## 返回 JSON 格式 { title: 通知标题, body: 通知正文, actionText: 操作按钮文字, metadata: {} } ; } getDefaultContent(type, event) { const defaults { comment: { title: 新的评论, body: 有人评论了你的内容, actionText: 查看评论 }, mention: { title: 有人提到了你, body: 有人在内容中提到了你, actionText: 查看 } }; return defaults[type] || { title: 新通知, body: 你有新的通知, actionText: 查看 }; } /** * 多语言和语气适配 * 根据用户所在地区和交互历史动态调整通知的语言和语气 */ async adaptLanguageAndTone(params) { const { recipientUser, baseContent } params; // 1. 检测用户语言偏好 const userLocale recipientUser.locale || zh-CN; const preferredTone await this.getUserTonePreference(recipientUser.id); // 2. 本地化适配 const adapted await this.client.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: 将以下通知文案适配为 ${userLocale}使用${preferredTone}的语气 标题: ${baseContent.title} 正文: ${baseContent.body} 要求 - 保持原意不变 - 使用当地化的表达方式非直译 - ${preferredTone casual ? 使用口语化、亲近的表达 : 使用正式、得体的表达} }], temperature: 0.5 }); return JSON.parse(adapted.choices[0].message.content); } async getUserTonePreference(userId) { // 基于用户历史交互判断偏好的语气 const recentInteractions await this.redis.lRange( user:${userId}:notification_interactions, 0, -50 ); if (recentInteractions.length 5) return neutral; // 分析用户对casual通知的打开率 vs formal通知的打开率 const parsed recentInteractions.map(i JSON.parse(i)); const casualOpenRate getOpenRate(parsed, casual); const formalOpenRate getOpenRate(parsed, formal); return casualOpenRate formalOpenRate ? casual : formal; } }四、通知聚合与智能摘要减少打扰频率对于高频触发的通知如收到 20 条新评论逐条发送会造成严重的通知疲劳。AI 可以将相似通知聚合并生成摘要。聚合维度与分组策略通知聚合的关键在于选择合适的聚合维度。常见的分组策略包括按通知类型同类评论聚合成一拨、按时间窗口15分钟内、按关联实体同一篇文章的互动。选择错误的聚合维度常见场景将好友私信和系统更新混在一起聚合结果摘要写成了你收到 3 条消息和 1 条系统通知用户完全搞不清楚状况实际上私信和系统通知应该独立聚合、独立推送。聚合时效性约束并非所有通知都适合长时间等待聚合。安全类通知异常登录、密码变更必须即时发送不能进入聚合批次。在tryAggregate流程中需要加入紧急通知跳过开关确保安全通知零延迟到达用户设备。/** * 聚合决策器根据通知类型判断是否需要即时发送 */ function shouldBypassAggregation(notification) { const immediateTypes [ security_alert, // 安全告警 payment_failure, // 支付失败 account_suspension, // 账号异常 otp_verification // 验证码 ]; return immediateTypes.includes(notification.type) || notification.priority critical; }踩坑聚合摘要的质量控制AI 生成的摘要在某些极端场景下会过度总结丢失关键信息。例如5 条通知中有 3 条来自不同用户对同一话题的讨论、各有不同观点摘要如果只输出收到 5 条评论用户无法判断是否值得打开。解决方案是携带预览数据——摘要正文里嵌入第一条/最有价值的单条通知的截断内容帮助用户做打开决策。async function generateSummary(batchData) { // 1. 从批次中提取最有价值的 1-2 条详情作为预览 const previewItems batchData .sort((a, b) (b.priorityScore || 0) - (a.priorityScore || 0)) .slice(0, 2) .map(item item.body?.slice(0, 30) || item.title); const prompt 将以下 ${batchData.length} 条通知聚合成一条摘要通知。 ## 通知列表 ${batchData.map((n, i) ${i 1}. ${n.title}: ${n.body}).join(\n)} ## 关键预览 ${previewItems.map((p, i) - ${p}).join(\n)} ## 要求 生成简洁的摘要说明有多少条通知、涉及哪些内容。 标题不超过 50 字正文不超过 100 字。 必须在正文中包含前几条的关键信息摘要。 返回 JSON { title: 摘要标题, body: 摘要正文含关键预览 } ; const response await this.ai.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: prompt }], response_format: { type: json_object } }); return JSON.parse(response.choices[0].message.content); } class NotificationAggregator { constructor(redisClient, openaiClient) { this.redis redisClient; this.ai openaiClient; } /** * 尝试聚合通知 * param {Object} newNotification - 新通知 * returns {PromiseObject|null} 聚合后的通知或 null表示不聚合 */ async tryAggregate(newNotification) { const { userId, type, groupKey } newNotification; // 1. 查找可聚合的通知批次 const batchKey notification:batch:${userId}:${type}:${groupKey || default}; const batch await this.redis.get(batchKey); if (!batch) { // 没有可聚合的批次创建新批次 await this.redis.setEx( batchKey, 3600, // 1小时内的同类通知会被聚合 JSON.stringify([newNotification]) ); return null; // 返回 null 表示暂不发送等待更多通知 } // 2. 将新通知加入批次 const batchData JSON.parse(batch); batchData.push(newNotification); // 3. 判断是否达到发送阈值 if (batchData.length 5 || this.isBatchOldEnough(batchData)) { // 生成聚合摘要 const summary await this.generateSummary(batchData); // 清除批次 await this.redis.del(batchKey); return { type: ${type}_summary, title: summary.title, body: summary.body, metadata: { originalCount: batchData.length, notifications: batchData.slice(0, 5) // 携带前 5 条详情 } }; } // 4. 更新批次 await this.redis.setEx(batchKey, 3600, JSON.stringify(batchData)); return null; } async generateSummary(batchData) { const prompt 将以下 ${batchData.length} 条通知聚合成一条摘要通知。 ## 通知列表 ${batchData.map((n, i) ${i 1}. ${n.title}: ${n.body}).join(\n)} ## 要求 生成简洁的摘要说明有多少条通知、涉及哪些内容。 标题不超过 50 字正文不超过 100 字。 返回 JSON { title: 摘要标题, body: 摘要正文 } ; const response await this.ai.chat.completions.create({ model: gpt-4, messages: [{ role: user, content: prompt }], response_format: { type: json_object } }); return JSON.parse(response.choices[0].message.content); } isBatchOldEnough(batchData) { const firstTime new Date(batchData[0].createdAt).getTime(); const now Date.now(); return (now - firstTime) 30 * 60 * 1000; // 超过 30 分钟就发送 } }五、总结AI 驱动的智能通知系统通过用户行为学习、内容个性化生成和通知聚合策略在提升通知价值的同时显著降低对用户打扰。核心设计原则是尊重用户注意力每次通知都应该是用户想要的、在合适的时间收到的、内容相关的信息。落地路线建立用户通知交互数据收集 → 实现偏好学习和决策引擎 → 集成 AI 内容生成 → 添加通知聚合逻辑 → 建立 A/B 测试持续优化决策策略。