用 React Native + AI Agent 做宠物社交App,我踩了这些坑

4 阅读5分钟

用 React Native + AI Agent 做宠物社交App,我踩了这些坑

说实话,最开始听到"AI宠物陪伴Agent"这个概念的时候,我第一反应是——这是不是又一个为了蹭AI热点而做的项目?🤔

但当我真正深入了解 PawPal 宠友圈 这个项目之后,发现事情没那么简单。它不只是简单的"AI+宠物",而是把 抖音风格的短视频流Tinder式的宠物匹配AI Agent 这三个东西揉在了一起。听起来挺有意思的,对吧?

先说说这个项目是啥

GitHub: github.com/ava-agent/d…

PawPal 是一个用 React Native + Expo + Supabase 开发的宠物社交App。核心功能有三个:

  1. 📹 短视频流 - 像抖音那样刷宠物视频
  2. 💕 宠物匹配 - 左右滑动给宠物找朋友(或者找对象?)
  3. 🤖 AI Agent陪伴 - 这才是重点,后面细说

技术栈选型挺接地气的:TypeScript + React Native,后端用Supabase(PostgreSQL + 实时订阅),没搞那些花里胡哨的微服务架构。

技术架构拆解

1. 短视频流的实现

短视频流看着简单,做起来全是坑。我之前也做过类似的东西,踩过同样的坑——视频预加载内存管理

// 简化的视频流组件结构
const VideoFeed = () => {
  const [currentIndex, setCurrentIndex] = useState(0);
  const flatListRef = useRef<FlatList>(null);

  // 关键:只渲染当前+前后各1个视频,其他的卸载
  const getItemLayout = (_, index) => ({
    length: SCREEN_HEIGHT,
    offset: SCREEN_HEIGHT * index,
    index,
  });

  return (
    <FlatList
      ref={flatListRef}
      data={videos}
      renderItem={({ item, index }) => (
        <VideoItem
          video={item}
          isActive={index === currentIndex}
          // 距离当前超过1个的视频直接不渲染
          shouldRender={Math.abs(index - currentIndex) <= 1}
        />
      )}
      pagingEnabled
      vertical
      getItemLayout={getItemLayout}
      onScroll={(e) => {
        const index = Math.round(e.nativeEvent.contentOffset.y / SCREEN_HEIGHT);
        setCurrentIndex(index);
      }}
    />
  );
};

关键点

  • pagingEnabled 实现整页滚动
  • 只渲染当前可见的视频,其他用占位符
  • getItemLayout 提前告知列表项高度,避免动态计算

但说实话,在低端Android机上还是会卡顿。Expo的Video组件在某些机型上表现不太稳定,这个问题到现在也没完全解决。

2. Tinder式卡片匹配

这个交互现在挺常见的了,但自己实现起来还是得注意细节。

const SwipeCard = ({ pet, onLike, onDislike }) => {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = PanResponder.create({
    onMoveShouldSetPanResponder: () => true,
    onPanResponderMove: (_, gesture) => {
      pan.setValue({ x: gesture.dx, y: gesture.dy });
    },
    onPanResponderRelease: (_, gesture) => {
      if (gesture.dx > 120) {
        // 右滑喜欢
        Animated.spring(pan, {
          toValue: { x: SCREEN_WIDTH, y: 0 },
          useNativeDriver: true,
        }).start(() => onLike(pet));
      } else if (gesture.dx < -120) {
        // 左滑不喜欢
        Animated.spring(pan, {
          toValue: { x: -SCREEN_WIDTH, y: 0 },
          useNativeDriver: true,
        }).start(() => onDislike(pet));
      } else {
        // 回弹
        Animated.spring(pan, {
          toValue: { x: 0, y: 0 },
          useNativeDriver: true,
        }).start();
      }
    },
  });

  const rotate = pan.x.interpolate({
    inputRange: [-SCREEN_WIDTH/2, 0, SCREEN_WIDTH/2],
    outputRange: ['-10deg', '0deg', '10deg'],
  });

  return (
    <Animated.View
      style={[styles.card, { transform: [{ translateX: pan.x }, { translateY: pan.y }, { rotate }] }]}
      {...panResponder.panHandlers}
    >
      {/* 卡片内容 */}
    </Animated.View>
  );
};

一个小技巧: 用 interpolate 让卡片在拖动时微微旋转,这样看起来更自然。输入范围是屏幕宽度的一半,输出角度控制在±10度,太大会显得夸张。

3. AI Agent 的实现(重点)

这是项目最有趣的部分。PawPal不只是记录宠物信息,而是给每个宠物创建了一个真正的AI Agent。

Agent架构

// 简化的Agent定义
interface PetAgent {
  // 宠物基本信息
  profile: {
    name: string;
    breed: string;
    age: number;
    personality: string[]; // ["活泼", "胆小", "贪吃"]
    preferences: string[];  // ["喜欢球", "怕陌生人"]
  };

  // Agent核心:每日状态
  dailyState: {
    mood: 'happy' | 'hungry' | 'tired' | 'playful';
    energyLevel: number; // 0-100
    lastInteraction: Date;
  };

  // AI生成内容
  async generateDailyUpdate(): Promise<{
    text: string;      // "今天天气不错,我想去公园玩!"
    suggestedAction: string; // "带它去散步30分钟"
  }>;
}

Agent的工作原理

  1. 记忆系统 - 用向量数据库存储宠物的"记忆"(喜欢的玩具、害怕的东西、习惯)
  2. 情绪模型 - 根据时间、天气、上次互动时间计算当前情绪状态
  3. 内容生成 - 调用LLM生成符合宠物性格的"动态"

举个实际的例子:

// Agent生成动态
const generatePost = async (agent: PetAgent) => {
  const prompt = `
你是一只${agent.profile.breed},名字叫${agent.profile.name}。
你的性格:${agent.profile.personality.join('、')}。
当前状态:精力${agent.dailyState.energyLevel}%,心情${agent.dailyState.mood}。
上次互动是${timeSince(agent.dailyState.lastInteraction)}前。

请生成一条"朋友圈"动态(50字以内,口语化,带emoji):
`;

  // 调用LLM生成内容
  const content = await llm.generate(prompt);

  return {
    content,
    timestamp: new Date(),
    mood: agent.dailyState.mood,
  };
};

生成的内容可能是:

"主人已经3小时没理我了 😢 沙发角的拖鞋看起来好好咬...算了,我再去门口等等吧 🐕💨"

哈哈,是不是挺有意思的?比那种机械式的"您的宠物需要喂食"有趣多了。

遇到的真实问题

1. Supabase实时订阅的坑

本来想用Supabase的实时功能做消息推送,结果发现免费版有并发连接限制。用户一多就掉线,后来改成了轮询+本地缓存的折中方案。

2. 视频压缩策略

用户上传的宠物视频动不动就几十MB,直接传太慢了。我们用了Expo的VideoManipulator做客户端压缩,但Android和iOS的表现不一致,调了好久。

// 视频压缩(实际情况比这复杂多了)
const compressVideo = async (uri: string) => {
  try {
    const { uri: compressedUri } = await VideoManipulator.compressAsync(
      uri,
      {
        compression: VideoManipulator.VideoCompressQuality.Medium,
        maxDuration: 60, // 限制60秒
      }
    );
    return compressedUri;
  } catch (e) {
    // 压缩失败就用原图,总比崩溃强
    console.warn('压缩失败,使用原视频', e);
    return uri;
  }
};

3. AI生成内容的"温度"控制

LLM有时候生成的内容太"人类"了(比如"今天工作压力好大"),完全不像一只狗的口吻。我们加了系统提示词约束,还做了后处理过滤。

客观说说优缺点

优点

  • 技术栈选型务实,开发效率高
  • AI Agent的设计有新意,不只是噱头
  • 交互体验做得挺流畅的

缺点

  • 目前只有1个star(哈哈,确实需要推广)
  • 视频相关的功能在低端机上有性能问题
  • AI生成内容的质量还不够稳定

写在最后

做这个项目的过程中,我觉得最有价值的是对"AI Agent"这个概念的理解——它不是取代人的工具,而是扩展交互的可能性。宠物不会说话,但通过Agent,它们可以"表达"自己的情绪和需求。

当然,这个项目还有很多可以改进的地方。比如:

  • 加入多模态能力(宠物照片生成表情包?)
  • 更智能的匹配算法(不只是看品种和距离)
  • 社区功能(宠物主人之间的交流)

你们有没有做过类似AI+垂直领域的项目?遇到最大的坑是什么?欢迎在评论区聊聊 👇


项目开源地址:github.com/ava-agent/d… 技术栈:React Native + Expo + Supabase + TypeScript