
Je suis Jules Ginhac, Co-Founder & ingénieur IA chez Apogée Consult à Lyon. Je conçois et déploie des architectures IA génératives (RAG, agents, LLMOps) pour des PME, startups et organisations publiques.
Onboarding d'un nouvel utilisateur dans un produit IA : trois choses qu'on aurait dû faire dès le jour 1
- ia-produit
L'onboarding d'un produit IA n'est pas l'onboarding d'un SaaS classique. Trois erreurs qu'on a faites en early stage, avec les chiffres de rétention qui les ont révélées.
Onboarding d'un nouvel utilisateur dans un produit IA : trois choses qu'on aurait dû faire dès le jour 1
Notre rétention à J7 était de 23 %. Pour un SaaS B2B, c'est bas. Pour un produit IA en early stage avec 120 utilisateurs, c'est un signal. On a regardé les traces Langfuse des sessions des utilisateurs qui ne sont pas revenus. Le pattern était clair : la première session durait en moyenne 4 minutes, se terminait sur une réponse hors périmètre ou incorrecte, et l'utilisateur ne revenait pas.
Ces abandons n'étaient pas causés par un modèle défaillant. Ils étaient causés par un onboarding qui ne préparait pas les utilisateurs à ce qu'ils allaient rencontrer.
1. On n'a pas montré le périmètre avant la première interaction
Notre onboarding ressemblait à celui d'un chatbot générique : un champ texte avec un message "Comment puis-je vous aider ?" et une animation. L'utilisateur tapait n'importe quoi. Parfois ça marchait. Souvent, le modèle répondait qu'il ne pouvait pas traiter la demande.
Le problème n'était pas la réponse du modèle. C'était que l'utilisateur découvrait les limites par l'échec.
Ce qu'on a mis en place : des exemples cliquables qui déclenchent une vraie interaction.
// components/onboarding/ExamplePrompts.tsx
const EXAMPLE_PROMPTS = [
{
label: "Résumer un document",
prompt: "Résume ce contrat en 5 points clés : [collez votre texte]",
category: "synthesis",
},
{
label: "Extraire des données structurées",
prompt: "Extrais les montants, dates et parties de cette facture : [collez votre texte]",
category: "extraction",
},
{
label: "Générer un compte-rendu",
prompt: "Génère un compte-rendu de réunion à partir de ces notes : [collez vos notes]",
category: "generation",
},
];
export function ExamplePrompts({ onSelect }: { onSelect: (prompt: string) => void }) {
return (
<div className="grid gap-2">
<p className="text-sm text-muted-foreground mb-1">
Ce que vous pouvez faire avec cet assistant :
</p>
{EXAMPLE_PROMPTS.map((example) => (
<button
key={example.category}
onClick={() => onSelect(example.prompt)}
className="text-left p-3 rounded-lg border border-border hover:border-primary transition-colors"
>
<span className="font-medium text-sm">{example.label}</span>
<span className="block text-xs text-muted-foreground mt-0.5 truncate">
{example.prompt}
</span>
</button>
))}
</div>
);
}Résultat mesuré après déploiement : le taux d'utilisation des exemples lors de la première session était de 61 %. Pour les utilisateurs ayant cliqué sur un exemple, la rétention J7 est passée de 23 % à 41 %. Ce n'est pas la seule variable, mais la corrélation est nette.
2. On n'a pas expliqué pourquoi le modèle se trompait parfois
Un LLM se trompe. Un utilisateur non préparé à ça interprète la première erreur comme une défaillance du produit. On avait un message d'erreur générique pour les cas hors périmètre, mais rien pour les cas où le modèle répondait avec confiance et se trompait sur un fait.
On a mesuré dans Langfuse le taux de sessions contenant un feedback négatif explicite (bouton "mauvaise réponse"). Ce taux était de 18 % à la semaine 2. En croisant avec les traces, on a identifié que 70 % de ces feedbacks négatifs arrivaient lors de la première session, avant que l'utilisateur ait eu le temps de calibrer ses attentes.
Ce qu'on a mis en place : une bannière d'information contextuelle affichée uniquement lors de la première session, disparaissant après le premier message envoyé.
// hooks/useFirstSession.ts
export function useFirstSession() {
const [isFirstSession, setIsFirstSession] = useState(false);
useEffect(() => {
const hasSeenOnboarding = localStorage.getItem("onboarding_v2_seen");
if (!hasSeenOnboarding) {
setIsFirstSession(true);
}
}, []);
const markSeen = useCallback(() => {
localStorage.setItem("onboarding_v2_seen", "true");
setIsFirstSession(false);
}, []);
return { isFirstSession, markSeen };
}
// Dans le composant chat
function ChatInterface() {
const { isFirstSession, markSeen } = useFirstSession();
const handleFirstMessage = () => {
if (isFirstSession) markSeen();
// ... envoi du message
};
return (
<>
{isFirstSession && (
<div className="rounded-lg bg-blue-50 border border-blue-200 p-3 mb-3 text-sm text-blue-900">
Cet assistant génère des réponses à partir de votre base documentaire.
Il peut se tromper sur des faits précis, vérifiez les informations
critiques avant de les utiliser.
</div>
)}
{/* ... reste du chat */}
</>
);
}Trois semaines après ce déploiement, le taux de feedbacks négatifs en première session est passé de 18 % à 9 %. Les feedbacks négatifs en sessions suivantes n'ont pas changé, signe que le problème était bien la surprise initiale, pas la qualité des réponses.
3. On a caché la mécanique pour ne pas "casser la magie"
On avait passé du temps à construire une UX fluide. Pas d'indicateur de chargement explicite, pas de mention du modèle, pas de visibilité sur le fait que le système utilisait l'historique de la conversation pour construire le contexte.
Ça a créé deux problèmes mesurables.
Les utilisateurs répétaient la même question espérant une réponse différente. Dans nos logs, 34 % des sessions à faible satisfaction contenaient au moins deux requêtes quasi identiques envoyées en moins de 2 minutes.
Les utilisateurs ne reformulaient pas après une réponse insuffisante. Sans modèle mental ("le système garde le contexte, je peux compléter ma demande"), ils abandonnaient la session.
Ce qu'on a ajouté : une indication de contexte active et un message de guidance après une réponse courte ou incertaine.
// Côté serveur, détection d'une réponse "courte" ou incertaine
function classifyResponseQuality(response: string): "full" | "partial" | "uncertain" {
const uncertaintyMarkers = [
"je ne suis pas certain",
"il m'est difficile de",
"je n'ai pas suffisamment",
"vous pourriez préciser",
];
const isUncertain = uncertaintyMarkers.some((marker) =>
response.toLowerCase().includes(marker)
);
const isShort = response.split(" ").length < 40;
if (isUncertain) return "uncertain";
if (isShort) return "partial";
return "full";
}
// Le client affiche un hint contextuel selon la qualité
function ResponseHint({ quality }: { quality: "full" | "partial" | "uncertain" }) {
if (quality === "full") return null;
const hint =
quality === "uncertain"
? "Cette réponse est incertaine. Vous pouvez ajouter des précisions ou des exemples pour obtenir une réponse plus fiable."
: "Vous pouvez continuer avec une question complémentaire, le système garde le contexte de cette conversation.";
return (
<p className="text-xs text-muted-foreground mt-1 italic">{hint}</p>
);
}Résultat à 6 semaines : le taux de "reformulation productive" (deuxième message dans la même session qui obtient un feedback positif) est passé de 12 % à 29 %.
Ce que ces trois erreurs ont en commun
Les trois viennent du même biais : traiter l'onboarding IA comme l'onboarding d'un produit déterministe. Un SaaS classique peut se découvrir par exploration, les chemins heureux et les erreurs sont prévisibles. Un produit IA, non. Les erreurs sont probabilistes, les réponses variables, le comportement non intuitif pour un utilisateur qui n'a jamais interagi avec un LLM dans un contexte métier.
L'onboarding IA a une contrainte supplémentaire : transmettre un modèle mental minimal avant la première interaction. Pas après. Avant.
La question qu'on se pose maintenant : qu'est-ce que l'utilisateur doit comprendre avant son premier message pour que cette interaction soit une réussite ? La réponse à cette question structure l'onboarding. Tout ce qui n'y contribue pas en est absent.