Morphic用户行为跟踪:事件分析与转化漏斗设计

Morphic用户行为跟踪:事件分析与转化漏斗设计

【免费下载链接】morphic An AI-powered answer engine with a generative UI 【免费下载链接】morphic 项目地址: https://gitcode.com/GitHub_Trending/mo/morphic

一、用户行为跟踪体系概述

Morphic作为AI驱动的问答引擎(Answer Engine),其核心价值在于理解用户查询意图并提供精准反馈。用户行为跟踪系统通过捕获关键交互事件,构建从"问题输入"到"满意输出"的完整转化链路,为产品迭代提供数据支撑。本方案基于Morphic现有架构,设计轻量级事件分析框架与可视化转化漏斗,无需侵入核心业务逻辑即可实现用户行为洞察。

1.1 事件跟踪范围界定

事件类型跟踪目标业务价值实现难度
核心交互事件搜索提交/问题发送/结果点击评估核心功能使用率★☆☆☆☆
界面操作事件侧边栏切换/主题切换/模型选择优化UI/UX设计★★☆☆☆
用户旅程事件登录状态/会话时长/历史记录访问分析用户留存与活跃度★★★☆☆
系统性能事件响应耗时/错误率/工具调用成功率保障服务稳定性★★★★☆

1.2 技术实现约束

在Morphic现有技术栈(Next.js+TypeScript+Supabase)中实施跟踪系统需满足:

  • 无侵入性:通过事件委托模式绑定跟踪逻辑,避免修改业务组件
  • 数据隐私:符合GDPR规范,仅收集匿名交互数据(不含用户识别信息)
  • 性能优先:客户端事件采集延迟需控制在50ms内,不阻塞主线程

二、事件分析模型设计

2.1 事件数据结构定义

基于TypeScript接口定义标准化事件格式,确保前后端数据一致性:

// lib/types/analytics.ts (建议新增文件)
export interface TrackedEvent {
  eventId: string;          // UUIDv4唯一标识
  eventType: EventType;     // 事件类型枚举
  eventName: string;        // 事件名称(如"search_submit")
  timestamp: number;        // 事件发生时间戳(ms)
  metadata: {
    query?: string;         // 搜索查询文本
    model?: string;         // 使用的AI模型
    duration?: number;      // 操作耗时(ms)
    elementId?: string;     // 触发元素ID
    success?: boolean;      // 操作是否成功
    sessionId: string;      // 会话ID
  };
  userId?: string;          // 匿名用户ID(可选)
}

// 核心事件类型枚举
export enum EventType {
  SEARCH = "search",        // 搜索相关事件
  INTERFACE = "interface",  // 界面交互事件
  AUTH = "auth",            // 认证相关事件
  ERROR = "error"           // 错误事件
}

2.2 事件触发机制

采用装饰器模式封装事件跟踪逻辑,实现业务代码与跟踪代码解耦:

// lib/utils/tracker.ts (建议新增文件)
import { v4 as uuidv4 } from 'uuid';

// 事件跟踪装饰器
export function trackEvent(eventName: string, eventType: EventType) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = async function (...args: any[]) {
      // 前置处理:生成事件基本信息
      const startTime = performance.now();
      const eventId = uuidv4();
      
      try {
        // 执行原方法
        const result = await originalMethod.apply(this, args);
        
        // 后置处理:发送成功事件
        sendEvent({
          eventId,
          eventType,
          eventName,
          timestamp: Date.now(),
          metadata: {
            duration: performance.now() - startTime,
            success: true,
            sessionId: getSessionId()
          }
        });
        return result;
      } catch (error) {
        // 异常处理:发送失败事件
        sendEvent({
          eventId,
          eventType: EventType.ERROR,
          eventName: `${eventName}_failed`,
          timestamp: Date.now(),
          metadata: {
            duration: performance.now() - startTime,
            success: false,
            sessionId: getSessionId()
          }
        });
        throw error;
      }
    };
    return descriptor;
  };
}

// 会话ID管理
function getSessionId(): string {
  if (!localStorage.getItem('morphic_session_id')) {
    localStorage.setItem('morphic_session_id', uuidv4());
  }
  return localStorage.getItem('morphic_session_id')!;
}

// 事件发送实现
async function sendEvent(event: TrackedEvent) {
  try {
    await fetch('/api/track', {  // 建议新增事件跟踪API端点
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(event),
      keepalive: true  // 确保页面卸载时事件仍能发送
    });
  } catch (error) {
    console.error('Event tracking failed:', error);
  }
}

三、转化漏斗设计与实现

3.1 核心转化漏斗模型

基于Morphic用户旅程设计的5阶段转化漏斗:

mermaid

漏斗阶段定义
阶段关键事件指标数据采集点转化障碍分析
访问页面页面加载完成事件app/layout.tsx中的onMount首屏加载速度、网络稳定性
输入查询查询框聚焦事件+输入字符数>5components/chat-panel.tsx输入框UI设计、初始引导提示
查看结果搜索提交事件+结果渲染完成lib/actions/chat.tsAI响应速度、结果相关性
完成任务结果点击/复制/展开详情components/message.tsx结果展示清晰度、交互便捷性
二次访问24小时内重复会话lib/utils/tracker.ts中的sessionId结果保存功能、用户价值感知

3.2 漏斗分析SQL实现

在Supabase中创建转化漏斗分析视图:

-- 在Supabase SQL编辑器中执行
CREATE VIEW conversion_funnel AS
WITH session_events AS (
  SELECT 
    session_id,
    MIN(CASE WHEN event_name = 'page_view' THEN timestamp END) AS visit_time,
    MIN(CASE WHEN event_name = 'query_input' THEN timestamp END) AS input_time,
    MIN(CASE WHEN event_name = 'search_submit' THEN timestamp END) AS search_time,
    MIN(CASE WHEN event_name = 'result_interaction' THEN timestamp END) AS interaction_time,
    MIN(CASE WHEN event_name = 'result_save' THEN timestamp END) AS save_time
  FROM tracked_events
  WHERE timestamp > NOW() - INTERVAL '7 days'
  GROUP BY session_id
)
SELECT
  '访问页面' AS stage,
  COUNT(session_id) AS users,
  100.0 AS conversion_rate
FROM session_events
UNION ALL
SELECT
  '输入查询',
  COUNT(input_time),
  ROUND(COUNT(input_time)*100.0/COUNT(session_id),1)
FROM session_events
UNION ALL
SELECT
  '查看结果',
  COUNT(search_time),
  ROUND(COUNT(search_time)*100.0/COUNT(input_time),1)
FROM session_events
UNION ALL
SELECT
  '完成任务',
  COUNT(interaction_time),
  ROUND(COUNT(interaction_time)*100.0/COUNT(search_time),1)
FROM session_events
UNION ALL
SELECT
  '二次访问',
  COUNT(save_time),
  ROUND(COUNT(save_time)*100.0/COUNT(interaction_time),1)
FROM session_events;

3.3 漏斗优化策略矩阵

低转化阶段数据表现特征优化方案实施优先级
输入查询访问-输入转化率<60%1. 添加热门问题推荐
2. 优化移动端输入体验
P0
查看结果输入-搜索转化率<70%1. 减少搜索按钮点击距离
2. 添加语音输入
P1
完成任务搜索-交互转化率<40%1. 优化结果排版
2. 添加一键复制功能
P0
二次访问交互-留存转化率<20%1. 实现查询历史云同步
2. 添加结果收藏夹
P2

四、前端事件埋点实践

4.1 关键组件埋点示例

搜索交互埋点(聊天面板组件)
// components/chat-panel.tsx (修改)
import { useState } from 'react';
import { trackEvent } from '@/lib/utils/tracker';
import { Button } from './ui/button';
import { Input } from './ui/input';

export function ChatPanel() {
  const [query, setQuery] = useState('');
  
  // 使用装饰器跟踪搜索提交事件
  const handleSubmit = trackEvent('search_submit', 'SEARCH')(
    async (e: React.FormEvent) => {
      e.preventDefault();
      if (!query.trim()) return;
      
      // 原有搜索逻辑...
      await submitSearch(query);
    }
  );
  
  // 跟踪查询输入事件
  const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setQuery(value);
    
    // 输入超过5个字符且2秒未输入时触发
    if (value.length > 5) {
      clearTimeout(window.inputTimeout);
      window.inputTimeout = setTimeout(() => {
        trackEvent('query_input', 'SEARCH')(() => {})(null);
      }, 2000);
    }
  };
  
  return (
    <form onSubmit={handleSubmit} className="flex gap-2 p-4">
      <Input
        value={query}
        onChange={handleInput}
        onFocus={() => {
          // 跟踪输入框聚焦事件
          trackEvent('query_focus', 'INTERFACE')(() => {})(null);
        }}
        placeholder="输入您的问题..."
        className="flex-1"
      />
      <Button type="submit">搜索</Button>
    </form>
  );
}
结果交互埋点(消息组件)
// components/message.tsx (修改)
import { trackEvent } from '@/lib/utils/tracker';
import { Codeblock } from './ui/codeblock';
import { TooltipButton } from './ui/tooltip-button';

export function Message({ content, isUser }) {
  // 跟踪结果复制事件
  const handleCopy = trackEvent('result_copy', 'SEARCH')(
    async (text: string) => {
      await navigator.clipboard.writeText(text);
    }
  );
  
  // 跟踪结果展开事件
  const handleExpand = trackEvent('result_expand', 'SEARCH')(
    () => {
      setExpanded(!expanded);
    }
  );
  
  return (
    <div className="message">
      {/* 原有消息内容渲染 */}
      <div className="content">{content}</div>
      
      {/* 交互按钮 */}
      <div className="actions">
        <TooltipButton 
          onClick={() => handleCopy(content)} 
          icon="copy" 
        />
        {content.length > 200 && (
          <TooltipButton 
            onClick={handleExpand} 
            icon={expanded ? "collapse" : "expand"} 
          />
        )}
      </div>
    </div>
  );
}

4.2 页面级事件跟踪

// app/layout.tsx (修改)
import { useEffect } from 'react';
import { trackEvent } from '@/lib/utils/tracker';

export default function RootLayout({ children }) {
  useEffect(() => {
    // 页面加载完成事件
    trackEvent('page_view', 'INTERFACE')(() => {})(null);
    
    // 页面离开事件
    const handleBeforeUnload = () => {
      trackEvent('page_unload', 'INTERFACE')(() => {})(null);
    };
    
    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, []);
  
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

五、数据分析与可视化实现

5.1 数据查询API设计

// app/api/analytics/route.ts (新增)
import { NextResponse } from 'next/server';
import { createServerClient } from '@/lib/supabase/server';
import { revalidatePath } from 'next/cache';

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const period = searchParams.get('period') || '7d';
  const stage = searchParams.get('stage');
  
  const supabase = createServerClient();
  const { data, error } = await supabase
    .from('conversion_funnel')
    .select('stage, users, conversion_rate')
    .eq('stage', stage)
    .single();
  
  if (error) return NextResponse.json({ error: error.message }, { status: 500 });
  
  return NextResponse.json(data);
}

5.2 管理后台仪表盘组件

// components/analytics/dashboard.tsx (新增)
'use client';

import { useEffect, useState } from 'react';
import { Card } from '@/components/ui/card';
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';

export function AnalyticsDashboard() {
  const [funnelData, setFunnelData] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function fetchFunnelData() {
      setLoading(true);
      const res = await fetch('/api/analytics?period=7d');
      const data = await res.json();
      setFunnelData(data);
      setLoading(false);
    }
    
    fetchFunnelData();
    // 每5分钟刷新一次数据
    const interval = setInterval(fetchFunnelData, 5 * 60 * 1000);
    return () => clearInterval(interval);
  }, []);
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 gap-6 p-6">
      <Card className="col-span-1">
        <h3 className="text-lg font-semibold p-4">转化漏斗趋势</h3>
        {loading ? (
          <div className="h-80 flex items-center justify-center">加载中...</div>
        ) : (
          <ResponsiveContainer width="100%" height={300}>
            <AreaChart data={funnelData}>
              <defs>
                <linearGradient id="colorUsers" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor="#3b82f6" stopOpacity={0.8}/>
                  <stop offset="95%" stopColor="#3b82f6" stopOpacity={0}/>
                </linearGradient>
              </defs>
              <XAxis dataKey="date" />
              <YAxis />
              <CartesianGrid strokeDasharray="3 3" />
              <Tooltip />
              <Area 
                type="monotone" 
                dataKey="users" 
                stroke="#3b82f6" 
                fillOpacity={1} 
                fill="url(#colorUsers)" 
              />
            </AreaChart>
          </ResponsiveContainer>
        )}
      </Card>
      
      <Card className="col-span-1">
        <h3 className="text-lg font-semibold p-4">漏斗转化率</h3>
        {loading ? (
          <div className="h-80 flex items-center justify-center">加载中...</div>
        ) : (
          <div className="p-4">
            {funnelData.map((stage, index) => (
              <div key={index} className="mb-4">
                <div className="flex justify-between mb-1">
                  <span>{stage.stage}</span>
                  <span>{stage.conversion_rate}%</span>
                </div>
                <div className="w-full bg-gray-200 rounded-full h-2">
                  <div 
                    className="bg-gradient-to-r from-orange-500 to-red-500 h-2 rounded-full"
                    style={{ width: `${stage.conversion_rate}%` }}
                  ></div>
                </div>
              </div>
            ))}
          </div>
        )}
      </Card>
    </div>
  );
}

六、实施路线图与最佳实践

6.1 分阶段实施计划

timeline
    title Morphic用户行为跟踪系统实施路线图
    section 第一阶段<br/><small>(1-2周)</small>
        事件数据结构设计       :done, des1, 2025-09-01, 3d
        核心事件跟踪实现       :done,

【免费下载链接】morphic An AI-powered answer engine with a generative UI 【免费下载链接】morphic 项目地址: https://gitcode.com/GitHub_Trending/mo/morphic

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值