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.
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
- 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
- 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
- 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
- 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
- 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.