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.

5 min de leitura • 1266 palavras
Perplexity: Design Nativo de Busca com IA screenshot

“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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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.


Referências