生活化AI助手的产品化复盘:从单点功能到可维护系统的关键决策
生活化AI助手的产品化复盘:从单点功能到可维护系统的关键决策
一、从Demo到产品的脆弱拐点:单点功能为何撑不起真实生活
生活化AI助手在Demo阶段通常呈现"单一场景惊艳"的特征。一个饮食推荐Prompt在Demo中可以流畅给出建议,一个情绪日记生成器在录制视频时表现自然。但当这些功能放入同一产品、面向真实用户连续使用超过一周时,单点架构的脆弱性就显现了。
以晨间简报功能为例,初期实现仅调用一个大模型API、传递当天天气与日历数据即可生成摘要。上线两周后,用户反馈"简报经常缺内容",排查发现:当日历API超时或天气API返回异常格式时,整个生成流程直接中断,而非降级为简短版本。这暴露了单点功能产品化时的核心矛盾——功能逻辑与异常处理耦合在一起,每个新功能的异常都会波及整体体验。
更普遍的问题是,多个AI功能(晨间简报、情绪记录、待办分析)各自拥有独立的Prompt模板、API调用逻辑和缓存策略。三个功能意味着三套完全独立的AI调用链路,维护成本随功能数量线性增长,而用户期望的"智能联动"(如简报中提及昨天记录的沮丧情绪)却无法实现。
二、功能解耦与上下文共享:AI能力层的统一抽象
产品化的第一步是将AI能力从业务逻辑中解耦。上图中的"统一AI调度器"承担了所有大模型交互的中转职责:接收来自不同功能的请求,根据功能类型匹配Prompt模板,聚合相关的用户上下文,调用模型,最后统一格式化输出。
核心设计是上下文聚合器。它不直接持有用户数据,而是按需从数据层拉取与当前功能相关的信息子集。例如晨间简报只需"最近7天情绪摘要"而非完整的日记内容;待办分析则需要"未完成事项列表"加上"最近的情感倾向标签"。这种按需聚合模式避免了将所有用户数据塞入Prompt的膨胀问题,同时保证了跨功能的信息联动。
实测数据显示,引入统一调度层后,新增一个AI功能的代码量从约400行降至约120行——主要是定义Prompt模板和输出格式规则。异常处理也不再散落在各功能中,而是在调度层统一实现重试和降级策略。
三、统一调度器的核心实现:关注点分离的生产代码
// AI能力调度器:统一管理大模型调用的入口、异常处理与降级策略 // 设计意图:将AI调用逻辑从业务功能中抽离,实现关注点分离 interface AIRequest { featureType: 'morning_brief' | 'emotion_diary' | 'todo_analysis'; userId: string; priority: 'high' | 'normal' | 'low'; metadata?: Record<string, unknown>; } interface AIResponse { content: string; tokens: number; fallbackUsed: boolean; latency: number; } class AIDispatcher { private cache: Map<string, { data: AIResponse; timestamp: number }>; private rateLimiter: Map<string, number[]>; constructor( private promptManager: PromptManager, private contextAggregator: ContextAggregator, private llmClient: LLMClient, private config: { maxRetries: number; cacheTTL: number; rateLimitWindow: number } ) { this.cache = new Map(); this.rateLimiter = new Map(); } async dispatch(request: AIRequest): Promise<AIResponse> { const startTime = Date.now(); // 速率限制:同一用户1分钟内最多3次AI调用 if (this.checkRateLimit(request.userId)) { return this.buildFallbackResponse('稍后再试,当前请求过于频繁'); } // 缓存优先:相同参数的请求在TTL内直接返回缓存 const cacheKey = `${request.featureType}:${request.userId}:${JSON.stringify(request.metadata)}`; const cached = this.checkCache(cacheKey); if (cached) return { ...cached, fallbackUsed: false, latency: Date.now() - startTime }; try { const prompt = await this.promptManager.getTemplate( request.featureType, request.metadata ); // 按需聚合上下文,而非全量加载 const context = await this.contextAggregator.gather( request.userId, request.featureType ); const response = await this.callWithRetry(prompt, context, request.metadata); this.setCache(cacheKey, response); return { ...response, fallbackUsed: false, latency: Date.now() - startTime }; } catch (error) { // 统一异常处理:记录错误后返回降级响应 console.error(`[AIDispatcher] 功能 ${request.featureType} 调用失败:`, error); return this.buildFallbackResponse('当前服务繁忙,请稍后重试'); } } private checkRateLimit(userId: string): boolean { const now = Date.now(); const window = this.config.rateLimitWindow; const timestamps = this.rateLimiter.get(userId) || []; const recent = timestamps.filter(t => now - t < window); this.rateLimiter.set(userId, recent); if (recent.length >= 3) return true; recent.push(now); return false; } private async callWithRetry( prompt: string, context: ContextData, metadata?: Record<string, unknown> ): Promise<AIResponse> { let lastError: Error | null = null; for (let attempt = 0; attempt < this.config.maxRetries; attempt++) { try { const result = await this.llmClient.complete({ systemPrompt: prompt, userContext: JSON.stringify(context), params: metadata }); return { content: result.text, tokens: result.usage.totalTokens }; } catch (error) { lastError = error as Error; // 指数退避:每次重试等待时间翻倍 await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000)); } } throw lastError || new Error('所有重试均失败'); } private buildFallbackResponse(message: string): AIResponse { return { content: `抱歉,${message}。`, tokens: 0, fallbackUsed: true, latency: 0 }; } }调度器将Prompt管理、上下文聚合和LLM调用三大职责分离为独立模块。每个AI功能只需声明自己的featureType和少量元数据,调度器自动处理缓存、限流和降级。这种设计使功能开发者无需关注底层AI调用的可靠性细节,专注于Prompt质量优化。
四、统一调度层的边界与成本:并非所有场景都适用
统一调度层带来了明显的架构收益,但也引入了自身的成本和边界。
额外延迟:上下文聚合器需要从多个数据源拉取信息。在低延迟场景(如对话式实时交互)中,聚合耗时可能超过用户容忍度。实测中,含用户偏好、7天摘要和当天数据的完整聚合约需200~400ms,如果LLM调用本身只需1秒,这一开销占比不小。
Prompt模板耦合:不同功能共享同一调度器意味着Prompt模板的格式受到约束。当一个功能需要特殊参数(如多轮对话历史)时,调度器的通用接口可能无法很好适配,需要不断扩展接口参数,最终破坏抽象层的简洁性。
适用边界:此架构最适用于功能数量≥5个、功能间需要上下文共享的产品。对于仅有1~2个AI功能的早期项目,统一调度层属于过度设计,直接在业务逻辑中调用API更为高效。
禁用场景:实时对话场景(延迟敏感)、异构模型调用场景(不同功能使用完全不同的模型提供商)以及每个功能的上下文完全不重叠的场景。
五、总结
AI生活工具从Demo走向产品的核心挑战在于架构设计而非算法精度。关键决策点包括:
- 功能解耦:将AI调用逻辑从业务代码中剥离为独立调度层,减少功能间的代码重复和异常传播。
- 上下文按需聚合:避免全量用户数据注入Prompt,根据功能类型选择性聚合相关信息,降低Token消耗同时保持跨功能联动。
- 统一异常处理:在调度层集中实现重试、缓存和降级策略,防止单一功能异常影响全局体验。
- 架构时机判断:功能数量<3时无需引入调度层;功能间无共享上下文时无需聚合器;延迟敏感场景需评估聚合开销。
- 演变路径:先从功能内联调用开始,当维护成本和用户对跨功能联动的需求同时上升时,再引入统一调度层进行重构。