Perplexity : Conception de Recherche Native IA

Comment Perplexity a construit la confiance dans la recherche IA : design citation-first, divulgation progressive, réponses en streaming et raffinement de requête. Avec motifs d'implémentation TypeScript et CSS.

7 min de lecture 1333 mots
Perplexity : Conception de Recherche Native IA screenshot

Perplexity

« Les gens veulent l'information le plus rapidement possible et veulent pouvoir faire confiance à cette information. Au fond, c'est un problème de design assez simple. »

Philosophie

Perplexity représente un nouveau paradigme : la recherche native IA. Alors que la recherche traditionnelle renvoie une liste de liens et que les chatbots renvoient des réponses conversationnelles, Perplexity synthétise l'information provenant de multiples sources en une seule réponse étayée par des citations. Le design incarne une transparence radicale — chaque affirmation est traçable jusqu'à sa source.

L'intuition de l'équipe : la recherche n'est pas une conversation. C'est une mission de recherche d'information. L'interface reflète cela en présentant des sources et des réponses, et non un historique de chat et des personas.


Points Clés

  1. Les citations sont non négociables pour la confiance envers l'IA - Chaque affirmation factuelle renvoie à sa source ; le panneau des sources reste visible pour que les utilisateurs puissent vérifier sans quitter la réponse
  2. Les interfaces familières réduisent les barrières - La barre de recherche ressemble à Google, pas à un prompt de chat ; les utilisateurs peuvent saisir des mots-clés ou des questions complètes sans apprendre des schémas conversationnels
  3. Anticiper les questions de suivi - La plupart des utilisateurs ne savent pas quoi demander ensuite ; suggérer des questions de suivi contextuellement pertinentes maintient leur engagement
  4. Montrer le processus, pas seulement les résultats - Les phases « Recherche → Lecture → Rédaction » construisent la confiance et réduisent le temps d'attente perçu grâce à la transparence
  5. Traiter les résultats faibles comme des états d'échec - Quand une requête produirait des résultats insuffisants, demander des clarifications plutôt que de renvoyer des réponses médiocres

Bibliothèque de Patterns

Design Centré sur les Citations

Perplexity a popularisé les citations en ligne dans les réponses IA, changeant fondamentalement la façon dont les utilisateurs font confiance au contenu généré. Chaque affirmation factuelle renvoie à sa source.

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 design : Les citations ne sont pas optionnelles. Elles sont intégrées dans chaque interaction. Le panneau des sources reste visible pour que les utilisateurs puissent vérifier les affirmations sans quitter la vue de la réponse.


Interface de Recherche Familière

Le champ de saisie de Perplexity ressemble à une barre de recherche traditionnelle, pas à un prompt de chat. Ce design familier abaisse la barrière pour les utilisateurs qui ne sont pas à l'aise avec l'IA conversationnelle.

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>
  );
}

Observation de conception : Même quelques mots-clés suffisent. Les utilisateurs n’ont pas besoin de formuler des prompts élaborés. L’interface accepte aussi bien les requêtes simples que les questions complexes.


Divulgation progressive avec questions de suivi

Au lieu d’attendre des utilisateurs qu’ils posent d’excellentes questions de suivi, Perplexity les prédit et les suggère. Les suggestions prédictives répondent à la réalité : la plupart des utilisateurs ne savent pas quoi demander ensuite.

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" },
  ];
}

Observation de conception : Comme peu de personnes posent des questions à la fin des présentations, la plupart des utilisateurs ne sont pas doués pour poser des questions de suivi. Anticipez ce qu’ils pourraient vouloir savoir.


Réponse en streaming avec rendu progressif

Perplexity utilise les Server-Sent Events (SSE) pour diffuser les réponses en continu, mais l’interface révèle progressivement le contenu d’une manière qui semble naturelle.

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>
  );
}

Enseignement design : Montrez le processus, pas seulement le résultat. Les utilisateurs voient d'abord les sources apparaître (ce qui établit la confiance), puis regardent la réponse s'écrire. La transparence réduit l'anxiété pendant les temps d'attente.


Prévention des erreurs par l'affinage

Lorsqu'une requête est trop large, Perplexity demande des précisions au lieu de retourner des résultats médiocres. Le système traite les résultats insuffisants comme un état d'échec.

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>
  );
}

Observation design : Les autres moteurs de recherche renvoient des résultats médiocres en espérant que les utilisateurs affineront d'eux-mêmes. Perplexity guide activement les utilisateurs vers de meilleures requêtes.


Collections et Spaces

Pour une recherche structurée, Perplexity propose les Spaces, des collections dédiées où les utilisateurs peuvent organiser leurs requêtes, épingler des résultats et téléverser des documents de référence.

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 design : Les Collections reproduisent les piles de recherche à onglets que les universitaires et les journalistes gèrent manuellement, désormais intégrées directement dans le produit.


Système de design visuel

Typographie : la clarté avant la personnalité

Perplexity utilise un système typographique neutre et hautement lisible. Le contenu est la vedette, pas l'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;
}

Système de couleurs : la confiance par la sobriété

La couleur est utilisée avec parcimonie, principalement pour les citations, les états et les indicateurs de focus.

: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);
}

Patterns d'animation

Transitions de phase

Des transitions fluides entre les phases recherche → lecture → rédaction maintiennent l'utilisateur informé.

/* 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;
  }
}

/* Les sources apparaissent en fondu à mesure qu'elles sont trouvées */
.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);
  }
}

/* Décalage des cartes source */
.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; }

Texte en streaming

La réponse apparaît caractère par caractère, mais avec des blocs groupés pour améliorer la lisibilité.

function TypewriterText({ text }: { text: string }) {
  const [displayedText, setDisplayedText] = useState('');

  useEffect(() => {
    // Le texte est déjà arrivé via SSE - on l'affiche simplement
    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; }
}

Enseignements

1. Les citations sont indispensables pour la confiance envers l'IA

Dans les interfaces d'IA, chaque affirmation factuelle doit être traçable. Perplexity intègre la fidélité des citations dans chaque interaction. Ce n'est ni optionnel ni masqué.

2. Barre de recherche > Prompt de chat

Une interface de recherche familière abaisse les barrières. Les utilisateurs peuvent saisir des mots-clés ou des questions complètes ; les deux fonctionnent. N'imposez pas de schémas conversationnels.

3. Anticiper les questions de suivi

La plupart des utilisateurs ne savent pas quoi demander ensuite. Suggérez des questions de suivi contextuellement pertinentes plutôt que d'attendre que les utilisateurs dirigent la conversation.

4. Montrer le processus

Le streaming apporte de la transparence, pas seulement de la rapidité. Afficher les phases « Recherche → Lecture → Rédaction » renforce la confiance et réduit le temps d'attente perçu.

5. Traiter les résultats faibles comme des échecs

Lorsqu'une requête produirait des résultats insuffisants, demandez un affinement au lieu de renvoyer des réponses médiocres. Guidez les utilisateurs vers de meilleures requêtes.

6. Interface épurée = Signal de confiance

L'interface minimaliste et sans publicité signale que le produit privilégie la qualité de l'information plutôt que la monétisation.


Foire aux questions

Comment fonctionne le système de citations de Perplexity ?

Chaque affirmation factuelle dans une réponse Perplexity inclut des citations numérotées en ligne renvoyant vers les URL sources. Le panneau des sources reste visible à côté de la réponse, affichant le favicon, le domaine et un aperçu de l'extrait. Le survol d'un numéro de citation développe le contexte spécifique de la source. Cela rend la vérification immédiate plutôt que d'obliger les utilisateurs à chercher.

Pourquoi Perplexity ressemble-t-il à un moteur de recherche plutôt qu'à un chatbot ?

L'équipe a constaté que la recherche n'est pas une conversation — c'est une mission de collecte d'informations. Une interface de barre de recherche familière accepte à la fois les mots-clés simples et les questions complexes sans exiger des utilisateurs qu'ils apprennent des patterns de prompts conversationnels. Cela abaisse la barrière pour les utilisateurs mal à l'aise avec les interfaces de chat IA.

Quelle est l'approche de Perplexity pour le streaming des réponses ?

Perplexity utilise les Server-Sent Events (SSE) pour révéler progressivement le contenu en trois phases : « Recherche » (trouver les sources), « Lecture » (analyser les sources) et « Rédaction » (synthétiser la réponse). Les sources apparaissent en premier pour établir la confiance avant que la réponse ne commence à s'afficher. Cette transparence réduit l'anxiété pendant les temps d'attente.

Comment Perplexity gère-t-il les requêtes ambiguës ou trop larges ?

Lorsqu'une requête produirait des résultats faibles, Perplexity demande des clarifications au lieu de renvoyer des réponses médiocres. Le système identifie les termes ambigus, les sujets trop larges ou le contexte manquant, puis suggère des affinements spécifiques. Les utilisateurs peuvent cliquer sur les suggestions ou saisir leur propre clarification.

Que sont les Spaces Perplexity et comment les utilise-t-on ?

Les Spaces sont des collections dédiées à la recherche structurée où les utilisateurs peuvent organiser des requêtes connexes, épingler des résultats importants et télécharger des documents de référence. Ils reproduisent les piles de recherche à onglets que les universitaires et journalistes maintiennent manuellement, désormais intégrées directement dans le produit pour les projets de recherche en cours.


Références