Perplexity: Design Nativo de Busca com IA
Como o Perplexity construiu confianca na busca com IA: design baseado em citacoes, revelacao progressiva, respostas em streaming e refinamento. Codigo incluido.
“As pessoas querem informação o mais rápido possível e querem poder confiar nessa informação. Bom, então é, na verdade, um problema de design bem simples.”
Filosofia
O Perplexity representa um novo paradigma: busca nativa em IA. Enquanto a busca tradicional devolve uma lista de links e os chatbots devolvem respostas conversacionais, o Perplexity sintetiza informações de várias fontes em uma única resposta sustentada por citações. O design encarna a transparência radical: cada afirmação pode ser rastreada até a sua fonte.
A sacada da equipe: busca não é conversa. É uma missão em busca de informação. A UI reflete isso ao apresentar fontes e respostas, e não histórico de chat e personas.
Pontos-chave
- Citações são inegociáveis para a confiança em IA - Toda afirmação factual tem link para a sua fonte; o painel de fontes fica visível para que os usuários possam verificar sem sair da resposta
- Interfaces familiares reduzem barreiras - A caixa de busca parece a do Google, não um prompt de chat; os usuários podem digitar palavras-chave ou perguntas completas sem precisar aprender padrões conversacionais
- Preveja as perguntas de acompanhamento - A maioria dos usuários não sabe o que perguntar em seguida; sugerir perguntas de acompanhamento relevantes para o contexto mantém o engajamento
- Mostre o processo, não só os resultados - As fases “Buscando → Lendo → Escrevendo” constroem confiança e, pela transparência, reduzem o tempo de espera percebido
- Trate resultados fracos como estados de falha - Quando uma consulta produziria resultados insuficientes, peça esclarecimento em vez de devolver respostas medíocres
Biblioteca de padrões
Design centrado em citações
O Perplexity popularizou as citações inline em respostas de IA e mudou de forma fundamental a maneira como os usuários confiam em conteúdo gerado. Toda afirmação factual tem link para a sua fonte.
interface Citation {
index: number;
url: string;
title: string;
favicon: string;
snippet: string;
domain: string;
}
interface AnswerBlock {
text: string;
citations: number[]; // Indices into citation array
}
function CitedAnswer({ blocks, citations }: {
blocks: AnswerBlock[];
citations: Citation[];
}) {
return (
<article className="answer">
{blocks.map((block, i) => (
<p key={i}>
{block.text}
{block.citations.map(citationIndex => (
<CitationMarker
key={citationIndex}
citation={citations[citationIndex]}
index={citationIndex + 1}
/>
))}
</p>
))}
{/* Source panel always visible */}
<aside className="sources-panel">
<h3>Sources</h3>
{citations.map((citation, i) => (
<SourceCard key={i} citation={citation} index={i + 1} />
))}
</aside>
</article>
);
}
function CitationMarker({ citation, index }: {
citation: Citation;
index: number;
}) {
const [expanded, setExpanded] = useState(false);
return (
<span className="citation-wrapper">
<sup
className="citation-marker"
onMouseEnter={() => setExpanded(true)}
onMouseLeave={() => setExpanded(false)}
>
[{index}]
</sup>
{/* Expandable snippet preview */}
{expanded && (
<div className="citation-preview">
<img src={citation.favicon} alt="" className="citation-favicon" />
<span className="citation-domain">{citation.domain}</span>
<p className="citation-snippet">{citation.snippet}</p>
</div>
)}
</span>
);
}
Insight de design: citações não são opcionais. Elas estão embutidas em cada interação. O painel de fontes fica visível para que os usuários possam verificar as afirmações sem sair da visualização da resposta.
Interface de busca familiar
O campo de entrada do Perplexity parece uma caixa de busca tradicional, não um prompt de chat. O design familiar reduz a barreira para quem não se sente à vontade com IA conversacional.
function SearchInput({ onSubmit }: { onSubmit: (query: string) => void }) {
const [query, setQuery] = useState('');
return (
<div className="search-container">
{/* Intentionally looks like Google/traditional search */}
<div className="search-box">
<SearchIcon className="search-icon" />
<input
type="text"
className="search-input"
placeholder="Ask anything..."
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && onSubmit(query)}
/>
{query && (
<button
className="clear-button"
onClick={() => setQuery('')}
>
<XIcon />
</button>
)}
<button
className="submit-button"
onClick={() => onSubmit(query)}
>
<ArrowRightIcon />
</button>
</div>
{/* Optional context chips */}
<div className="focus-chips">
<Chip icon={<GlobeIcon />}>All</Chip>
<Chip icon={<AcademicIcon />}>Academic</Chip>
<Chip icon={<CodeIcon />}>Code</Chip>
<Chip icon={<VideoIcon />}>Video</Chip>
</div>
</div>
);
}
Insight de design: até umas poucas palavras-chave funcionam. Os usuários não precisam elaborar prompts sofisticados. A interface aceita tanto consultas simples quanto perguntas complexas.
Divulgação progressiva com perguntas de acompanhamento
Em vez de esperar que os usuários façam ótimas perguntas de acompanhamento, o Perplexity as prevê e sugere. As sugestões preditivas lidam com uma realidade: a maioria dos usuários não sabe o que perguntar em seguida.
interface FollowUpSuggestion {
question: string;
reasoning: string; // Why this might be relevant
}
function FollowUpSuggestions({
suggestions,
onSelect
}: {
suggestions: FollowUpSuggestion[];
onSelect: (question: string) => void;
}) {
return (
<div className="follow-ups">
<h4>Related</h4>
{/* Show one at a time - progressive disclosure */}
{suggestions.slice(0, 4).map((suggestion, i) => (
<button
key={i}
className="follow-up-chip"
onClick={() => onSelect(suggestion.question)}
>
<span className="follow-up-text">{suggestion.question}</span>
<ArrowRightIcon className="follow-up-arrow" />
</button>
))}
</div>
);
}
// Predict follow-ups based on query context
function generateFollowUps(query: string, answer: string): FollowUpSuggestion[] {
// AI generates contextually relevant next questions
return [
{ question: "How does this compare to alternatives?", reasoning: "comparison" },
{ question: "What are the limitations?", reasoning: "critical analysis" },
{ question: "Can you provide specific examples?", reasoning: "concrete details" },
{ question: "What's the historical context?", reasoning: "background" },
];
}
Insight de design: assim como pouca gente faz perguntas no fim de uma keynote, a maioria dos usuários não é boa em formular perguntas de acompanhamento. Preveja o que eles podem querer saber.
Resposta em streaming com renderização progressiva
O Perplexity usa Server-Sent Events (SSE) para fazer o streaming das respostas, mas a UI revela o conteúdo aos poucos, de um jeito que parece natural.
function StreamingAnswer({ query }: { query: string }) {
const [sources, setSources] = useState<Citation[]>([]);
const [answer, setAnswer] = useState<string>('');
const [phase, setPhase] = useState<'searching' | 'reading' | 'writing'>('searching');
useEffect(() => {
const eventSource = new EventSource(`/api/search?q=${encodeURIComponent(query)}`);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'sources':
setPhase('reading');
setSources(data.sources);
break;
case 'chunk':
setPhase('writing');
setAnswer(prev => prev + data.text);
break;
case 'done':
eventSource.close();
break;
}
};
return () => eventSource.close();
}, [query]);
return (
<div className="streaming-answer">
{/* Phase indicator */}
<PhaseIndicator phase={phase} />
{/* Sources appear first */}
{sources.length > 0 && (
<SourceCards sources={sources} />
)}
{/* Answer streams in */}
<div className="answer-content">
<TypewriterText text={answer} />
{phase === 'writing' && <BlinkingCursor />}
</div>
</div>
);
}
function PhaseIndicator({ phase }: { phase: 'searching' | 'reading' | 'writing' }) {
const phases = {
searching: { icon: <SearchIcon />, text: 'Searching the web...' },
reading: { icon: <BookIcon />, text: 'Reading sources...' },
writing: { icon: <PenIcon />, text: 'Writing answer...' },
};
return (
<div className="phase-indicator">
{phases[phase].icon}
<span>{phases[phase].text}</span>
<LoadingDots />
</div>
);
}
Insight de design: mostre o processo, não só o resultado. Os usuários veem as fontes aparecerem primeiro (o que constrói confiança) e depois acompanham a resposta sendo escrita. A transparência reduz a ansiedade durante a espera.
Prevenção de erros por meio do refinamento
Quando uma consulta é ampla demais, o Perplexity pede esclarecimento em vez de devolver resultados fracos. O sistema trata resultados insuficientes como um estado de falha.
interface ClarificationRequest {
type: 'ambiguous' | 'too_broad' | 'missing_context';
suggestions: string[];
originalQuery: string;
}
function QueryRefinement({ request, onRefine }: {
request: ClarificationRequest;
onRefine: (refinedQuery: string) => void;
}) {
const messages = {
ambiguous: "I found multiple meanings. Which one did you mean?",
too_broad: "This topic is quite broad. Can you be more specific?",
missing_context: "I need a bit more context to give you a useful answer.",
};
return (
<div className="refinement-prompt">
<p className="refinement-message">{messages[request.type]}</p>
<div className="refinement-suggestions">
{request.suggestions.map((suggestion, i) => (
<button
key={i}
className="refinement-option"
onClick={() => onRefine(suggestion)}
>
{suggestion}
</button>
))}
</div>
<div className="refinement-custom">
<input
type="text"
placeholder="Or type your own refinement..."
onKeyDown={(e) => {
if (e.key === 'Enter') {
onRefine((e.target as HTMLInputElement).value);
}
}}
/>
</div>
</div>
);
}
Insight de design: outros buscadores devolvem resultados fracos e torcem para que o usuário refine a consulta por conta própria. O Perplexity conduz ativamente os usuários a consultas melhores.
Collections e Spaces
Para pesquisa estruturada, o Perplexity oferece os Spaces, coleções dedicadas em que os usuários podem organizar consultas, fixar resultados e fazer upload de material de referência.
interface Space {
id: string;
name: string;
threads: Thread[];
documents: Document[];
createdAt: Date;
}
interface Thread {
id: string;
query: string;
answer: Answer;
citations: Citation[];
pinned: boolean;
}
function SpacesSidebar({ spaces, activeSpace, onSelect }: {
spaces: Space[];
activeSpace: string;
onSelect: (id: string) => void;
}) {
return (
<aside className="spaces-sidebar">
<header>
<h2>Spaces</h2>
<button className="new-space">
<PlusIcon /> New Space
</button>
</header>
<nav className="space-list">
{spaces.map(space => (
<button
key={space.id}
className={`space-item ${space.id === activeSpace ? 'active' : ''}`}
onClick={() => onSelect(space.id)}
>
<FolderIcon />
<span className="space-name">{space.name}</span>
<span className="thread-count">{space.threads.length}</span>
</button>
))}
</nav>
</aside>
);
}
function SpaceView({ space }: { space: Space }) {
return (
<div className="space-view">
<header className="space-header">
<h1>{space.name}</h1>
<div className="space-actions">
<button><ShareIcon /> Share</button>
<button><UploadIcon /> Add Files</button>
</div>
</header>
{/* Pinned threads */}
<section className="pinned-threads">
<h3>Pinned</h3>
{space.threads.filter(t => t.pinned).map(thread => (
<ThreadCard key={thread.id} thread={thread} />
))}
</section>
{/* All threads */}
<section className="all-threads">
<h3>All Threads</h3>
{space.threads.map(thread => (
<ThreadCard key={thread.id} thread={thread} />
))}
</section>
{/* Embedded documents */}
{space.documents.length > 0 && (
<section className="space-documents">
<h3>Reference Materials</h3>
{space.documents.map(doc => (
<DocumentCard key={doc.id} document={doc} />
))}
</section>
)}
</div>
);
}
Insight de design: as Collections espelham as pilhas de pesquisa em abas que acadêmicos e jornalistas mantêm manualmente, agora embutidas diretamente no produto.
Sistema de design visual
Tipografia: clareza acima da personalidade
O Perplexity usa um sistema tipográfico neutro e muito legível. A estrela é o conteúdo, não a interface.
:root {
/* System font stack for fastest load */
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'SF Mono', Monaco, 'Courier New', monospace;
/* Type scale - optimized for reading */
--text-sm: 13px;
--text-base: 15px;
--text-lg: 17px;
--text-xl: 20px;
--text-2xl: 24px;
/* Line heights - generous for readability */
--leading-tight: 1.3;
--leading-normal: 1.6;
--leading-relaxed: 1.8;
}
/* Answer text - optimized for long-form reading */
.answer-content {
font-size: var(--text-base);
line-height: var(--leading-relaxed);
max-width: 680px; /* Optimal reading width */
}
/* Citations - smaller, unobtrusive */
.citation-marker {
font-size: var(--text-sm);
color: var(--accent-primary);
cursor: pointer;
vertical-align: super;
}
/* Source cards - scannable metadata */
.source-card {
font-size: var(--text-sm);
line-height: var(--leading-tight);
}
.source-domain {
font-family: var(--font-mono);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
Sistema de cores: confiança pela contenção
A cor é usada com parcimônia, principalmente em citações, status e estados de foco.
:root {
/* Neutral foundation */
--bg-primary: #ffffff;
--bg-secondary: #f7f7f8;
--bg-tertiary: #ededef;
/* Text hierarchy */
--text-primary: #1a1a1b;
--text-secondary: #57575a;
--text-tertiary: #8e8e93;
/* Citation accent - trustworthy blue */
--accent-citation: #0066cc;
--accent-citation-hover: #0052a3;
/* Focus states */
--focus-ring: 0 0 0 2px var(--accent-citation);
/* Phase indicators */
--phase-searching: #f59e0b;
--phase-reading: #3b82f6;
--phase-writing: #10b981;
}
/* Clean, ad-free interface */
.search-results {
background: var(--bg-primary);
padding: 24px;
border-radius: 12px;
}
/* Citation hover state */
.citation-marker:hover {
background: var(--accent-citation);
color: white;
border-radius: 2px;
}
/* Source card - subtle boundary */
.source-card {
border: 1px solid var(--bg-tertiary);
border-radius: 8px;
padding: 12px;
transition: border-color 0.15s ease;
}
.source-card:hover {
border-color: var(--accent-citation);
}
Padrões de animação
Transições de fase
Transições suaves entre as fases buscando → lendo → escrevendo mantêm os usuários informados.
/* Phase indicator */
.phase-indicator {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--bg-secondary);
border-radius: 20px;
font-size: var(--text-sm);
color: var(--text-secondary);
}
/* Loading dots animation */
.loading-dots {
display: flex;
gap: 4px;
}
.loading-dots span {
width: 4px;
height: 4px;
background: var(--text-tertiary);
border-radius: 50%;
animation: dot-pulse 1.4s infinite ease-in-out;
}
.loading-dots span:nth-child(2) { animation-delay: 0.2s; }
.loading-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes dot-pulse {
0%, 80%, 100% {
transform: scale(0.6);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}
/* Sources fade in as they're found */
.source-card {
animation: fade-in-up 0.3s ease-out;
}
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Stagger source cards */
.source-card:nth-child(1) { animation-delay: 0ms; }
.source-card:nth-child(2) { animation-delay: 100ms; }
.source-card:nth-child(3) { animation-delay: 200ms; }
.source-card:nth-child(4) { animation-delay: 300ms; }
Texto em streaming
A resposta aparece caractere por caractere, mas em blocos agrupados para facilitar a leitura.
function TypewriterText({ text }: { text: string }) {
const [displayedText, setDisplayedText] = useState('');
useEffect(() => {
// Text already arrived from SSE - just display it
setDisplayedText(text);
}, [text]);
return (
<div className="typewriter">
{displayedText}
</div>
);
}
function BlinkingCursor() {
return (
<span className="cursor" aria-hidden="true">|</span>
);
}
.cursor {
animation: blink 1s step-end infinite;
color: var(--text-secondary);
}
@keyframes blink {
50% { opacity: 0; }
}
Lições aprendidas
1. Citações são inegociáveis para a confiança em IA
Em interfaces de IA, toda afirmação factual deve ser rastreável. O Perplexity incorpora a fidelidade das citações em cada interação. Ela não é opcional nem fica escondida.
2. Caixa de busca > prompt de chat
Uma interface de busca familiar reduz barreiras. Os usuários podem digitar palavras-chave ou perguntas completas; as duas formas funcionam. Não force padrões conversacionais.
3. Preveja as perguntas de acompanhamento
A maioria dos usuários não sabe o que perguntar em seguida. Sugira perguntas de acompanhamento relevantes para o contexto em vez de esperar que o usuário conduza a conversa.
4. Mostre o processo
O streaming oferece transparência, não apenas velocidade. Mostrar as fases “Buscando → Lendo → Escrevendo” constrói confiança e reduz o tempo de espera percebido.
5. Trate resultados fracos como falhas
Quando uma consulta produziria resultados insuficientes, peça um refinamento em vez de devolver respostas fracas. Conduza os usuários a consultas melhores.
6. Interface limpa = sinal de confiança
A interface minimalista e sem anúncios sinaliza que o produto coloca a qualidade da informação acima da monetização.
Perguntas frequentes
Como funciona o sistema de citações do Perplexity?
Toda afirmação factual em uma resposta do Perplexity traz citações numeradas inline, com links para as URLs de origem. O painel de fontes permanece visível ao lado da resposta, com favicon, domínio e uma prévia do trecho. Ao passar o mouse sobre o número de uma citação, ela se expande e mostra o contexto específico da fonte. Assim, a verificação é imediata, sem obrigar o usuário a garimpar.
Por que o Perplexity parece um mecanismo de busca e não um chatbot?
A equipe percebeu que busca não é conversa: é uma missão em busca de informação. Uma caixa de busca familiar aceita tanto palavras-chave simples quanto perguntas complexas, sem exigir que o usuário aprenda padrões de prompt conversacional. Isso reduz a barreira para quem não se sente à vontade com interfaces de chat de IA.
Qual é a abordagem do Perplexity para respostas em streaming?
O Perplexity usa Server-Sent Events (SSE) para revelar o conteúdo progressivamente em três fases: “Buscando” (encontrando fontes), “Lendo” (analisando as fontes) e “Escrevendo” (sintetizando a resposta). As fontes aparecem primeiro, para construir confiança antes que a resposta comece a chegar em streaming. Essa transparência reduz a ansiedade durante a espera.
Como o Perplexity lida com consultas ambíguas ou amplas?
Quando uma consulta produziria resultados fracos, o Perplexity pede esclarecimento em vez de devolver respostas medíocres. O sistema identifica termos ambíguos, temas amplos demais ou falta de contexto e, em seguida, sugere refinamentos específicos. O usuário pode clicar nas sugestões ou digitar o próprio esclarecimento.
O que são os Spaces do Perplexity e como são usados?
Spaces são coleções dedicadas à pesquisa estruturada, em que os usuários podem organizar consultas relacionadas, fixar resultados importantes e fazer upload de documentos de referência. Eles espelham as pilhas de pesquisa em abas que acadêmicos e jornalistas mantêm manualmente, agora embutidas diretamente no produto para projetos de pesquisa em andamento.