A Ideia Simples que Exigiu Engenharia Pesada
À primeira vista, as Friend Bubbles parecem uma melhoria de UI trivial: um indicador que mostra quais Reels seus amigos assistiram e reagiram. Mas como revela o episódio do Meta Tech Podcast com as engenheiras Subasree e Joseph, essa feature exigiu resolver alguns dos problemas mais difíceis em computação de grafos sociais e personalização em tempo real.
O desafio central? Construir uma camada de recomendação que exiba atividade de amigos sem sobrecarregar os usuários, respeitando restrições de privacidade e mantendo latência abaixo de 50ms na escala do Facebook. Vamos detalhar como elas fizeram isso.
Evolução do Modelo de ML: Do Cold Start à Personalização
A versão inicial das Friend Bubbles usava uma abordagem simples de filtragem colaborativa: se seu amigo curtiu um Reel, mostre. Mas isso gerou dois problemas:
- Cold start: Novos usuários com poucos amigos viam bolhas vazias.
- Diluição de sinal: Amigos que interagem com tudo criavam ruído.
O time iterou por três gerações de modelos:
- v1 (Baseado em regras): Mostrar Reels se ≥2 amigos interagiram. Simples, mas estático.
- v2 (LightGBM): Features de engenharia como score de afinidade com o amigo, tempo desde a interação e categoria de conteúdo. Melhorou o CTR em 34%.
- v3 (Graph Neural Network): Embedding do grafo social diretamente no pipeline de recomendação. Isso permitiu que o modelo aprendesse quais interações de amigos são mais preditivas do seu próprio engajamento.
# Loop de treinamento simplificado da GNN para predição de afinidade
import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
class FriendAffinityGNN(torch.nn.Module):
def __init__(self, in_channels, hidden_channels, out_channels):
super().__init__()
self.conv1 = GCNConv(in_channels, hidden_channels)
self.conv2 = GCNConv(hidden_channels, out_channels)
def forward(self, x, edge_index):
# x: features dos nós (embeddings de usuário + conteúdo)
# edge_index: arestas do grafo social (conexões de amizade)
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
iOS vs Android: O Abismo Comportamental
Uma descoberta surpreendente foi que usuários de iOS e Android interagiam com as Friend Bubbles de maneiras muito diferentes:
| Comportamento | Usuários iOS | Usuários Android |
|---|---|---|
| Tempo médio na bolha | 2,3s | 4,1s |
| Taxa de clique | 12% | 28% |
| Taxa de swipe-away | 45% | 22% |
Isso levou o time a implementar modelos específicos por plataforma: no iOS, o modelo priorizava recência (já que usuários folheiam rápido), enquanto no Android enfatizava diversidade (já que usuários exploravam mais). O código para a transformação de features específica da plataforma:
# Engenharia de features específica da plataforma
if user_platform == 'ios':
features['recency_score'] = compute_recency(timestamp) * 1.5
features['friend_diversity'] = compute_diversity(friend_set) * 0.8
else: # android
features['recency_score'] = compute_recency(timestamp) * 0.9
features['friend_diversity'] = compute_diversity(friend_set) * 1.3
A Descoberta Surpreendente Que Fez Tudo Funcionar
O avanço veio quando o time percebeu que as bolhas de amigos funcionam melhor quando mostram conteúdo que seus amigos ainda não viram. A suposição original era mostrar Reels já assistidos (prova social), mas o engajamento foi 3x maior quando a bolha destacava Reels que os amigos provavelmente assistiriam em seguida.
Isso mudou o modelo de uma tarefa retrospectiva para preditiva: em vez de "o que meus amigos assistiram?", a pergunta passou a ser "o que meus amigos assistiriam a seguir?". O time usou um mecanismo de atenção temporal em grafo para prever interações futuras:
# Atenção temporal para prever interações futuras de amigos
class TemporalAttention(torch.nn.Module):
def __init__(self, hidden_dim):
super().__init__()
self.query = torch.nn.Linear(hidden_dim, hidden_dim)
self.key = torch.nn.Linear(hidden_dim, hidden_dim)
self.temporal_encoding = torch.nn.Embedding(1000, hidden_dim) # buckets de tempo
def forward(self, user_emb, friend_embs, timestamps):
# Adiciona viés temporal aos embeddings dos amigos
time_enc = self.temporal_encoding(timestamps // 3600) # buckets de hora
friend_embs = friend_embs + time_enc
# Atenção sobre interações futuras
attn_scores = torch.matmul(self.query(user_emb), self.key(friend_embs).T)
attn_weights = F.softmax(attn_scores, dim=-1)
return torch.matmul(attn_weights, friend_embs)
Limitações e Cuidados
- Privacidade: Mesmo contagens agregadas de atividade podem vazar informações. O time implementou privacidade diferencial nas contagens.
- Churn de amigos: Se um usuário perde conexões, a feature degrada. Um fallback para Reels em alta é essencial.
- Impacto na bateria: Polling em tempo real para atualizações de amigos drenava a bateria em dispositivos mais antigos. Migraram para atualizações push.
Próximos Passos e Direção de Estudo
- Explore Graph Neural Networks para recomendação social
- Leia sobre técnicas de ML com preservação de privacidade do Meta
- Para um olhar mais amplo sobre escalabilidade de features sociais, confira nosso guia sobre NVIDIA DOCA In-Silicon Security para fábricas de IA
Conclusão
Friend Bubbles é uma aula de como features "simples" exigem engenharia multidisciplinar profunda: ML, backend, cliente e privacidade. O principal aprendizado? Não subestime a complexidade da descoberta social em escala. Comece com um modelo simples baseado em regras, itere com insights específicos da plataforma e sempre questione suas suposições sobre o comportamento do usuário.
Para mais sobre construção de sistemas de recomendação inteligentes, veja nosso mergulho profundo em automação de inteligência contratual com Doczy.ai na AWS.
Fonte: Meta Tech Podcast – Engineering Friend Bubbles. Episódio completo disponível em engineering.fb.com.


![]()