IndustrialisationDu notebook au service : industrialiser un prototype
· 5 min de lecture · par l'équipe Agenticiel
Un prototype d’agent ou d’outil d’IA naît presque toujours dans un notebook Jupyter ou Google Colab, et c’est exactement là qu’il doit naître. Le notebook permet d’explorer vite, de tester un modèle, de valider une idée en quelques heures. Le problème commence quand on veut passer de ce prototype à quelque chose qui tourne tous les jours.
Le passage du notebook au service est un vrai chantier, pas un simple copier-coller. Ce qui marchait dans un environnement interactif se heurte, en production, à des exigences que le prototype n’avait pas : être lancé automatiquement, résister aux erreurs, être observable, être modifiable sans tout casser.
Cet article décrit les étapes de ce passage, dans l’ordre où il faut les mener, avec à chaque fois ce qui change concrètement. Vous pourrez l’appliquer à votre propre prototype, qu’il s’agisse d’un agent, d’un RAG ou d’un simple script d’analyse.
Pourquoi un notebook n’est pas un service
Un notebook et un service ne répondent pas aux mêmes contraintes. Le notebook s’exécute à la main, dans un ordre que son auteur connaît, avec des variables qui restent en mémoire d’une cellule à l’autre. Un service s’exécute seul, à la demande, dans un ordre arbitraire, sans état persistant entre les appels.
Les défauts du notebook deviennent des pannes en production : les variables implicites, les imports dispersés, les chemins codés en dur, les résultats affichés au lieu d’être renvoyés. Aucun de ces défauts ne gêne l’exploration, tous deviennent des sources d’erreur une fois le code lancé par une machine.
Le passage au service consiste donc à transformer un récit d’exploration, qui se lit de haut en bas, en un programme qui répond à des entrées. C’est un changement de nature, pas de simple mise en forme. Concrètement, la logique finit le plus souvent derrière une petite API, avec FastAPI en Python, ou dans un worker qui traite une file de tâches.
Extraire la logique du notebook
La première étape est d’extraire la logique utile du notebook et de la réorganiser en fonctions claires, chacune avec des entrées et une sortie définies. Tout ce qui relevait de l’exploration, les cellules de test, les affichages intermédiaires, les expérimentations avortées, doit être retiré.
Cette étape ne change pas le comportement, elle le rend manipulable. Une fonction est testable, réutilisable, documentable ; une cellule ne l’est pas. C’est aussi le moment de nommer les choses : les variables à une lettre, les fonctions sans nom, les chemins magiques laissent place à des noms qui disent ce que fait le code.
Le critère de réussite est simple : quelqu’un qui n’a pas écrit le notebook doit pouvoir lire le code extrait et comprendre ce qu’il fait, sans exécuter quoi que ce soit.
Dépendances et configuration
Le prototype s’exécutait dans un environnement précis, celui de la machine de son auteur, avec des versions de bibliothèques que personne n’avait notées. En production, cet environnement doit être reconstruit à l’identique, faute de quoi le code se comporte différemment sans raison visible.
Deux choses règlent ce problème. La première est la déclaration explicite des dépendances, avec leurs versions, dans un fichier de projet géré par uv ou Poetry, puis une image Docker qui fige l’environnement complet. La seconde est la sortie de toute configuration du code : les clés d’API, les chemins, les paramètres se lisent dans un fichier de configuration ou des variables d’environnement, jamais en dur.
Ce travail paraît bureaucratique, il est en réalité ce qui permet de déployer le même code sur plusieurs environnements et de le reconstruire demain. Sans lui, le service ne fonctionne que sur une machine, et encore.
Gestion des erreurs et journalisation
Dans un notebook, une erreur est visible : elle interrompt l’exécution et s’affiche à l’écran. Dans un service, une erreur non gérée fait échouer une requête silencieusement, et l’utilisateur ne voit qu’un message générique, ou rien. Il faut donc prévoir ce qui se passe quand les choses tournent mal.
La gestion d’erreur commence par les entrées : que faire si l’entrée est vide, mal formée, hors des limites prévues ? Elle se poursuit par les dépendances : que faire si le modèle ou une API externe ne répond pas ? Chaque cas a une réponse définie, au lieu de laisser l’exception remonter jusqu’à l’utilisateur.
La journalisation accompagne cette gestion : chaque appel, chaque erreur, chaque décision importante est enregistré avec suffisamment de contexte pour être compris plus tard. C’est elle qui permettra de comprendre ce qui s’est passé quand un incident surviendra, et sans elle, tout incident est un mystère. Pour les appels au modèle, un outil comme Langfuse ou LangSmith enregistre prompts, réponses, latence et coût sans code supplémentaire notable.
Tests et validation
Un prototype se valide sur quelques exemples choisis par son auteur. Un service se valide sur un jeu de tests qui couvre les cas qu’il rencontrera réellement, y compris les cas qui échouent. Ce jeu de tests est la preuve que le service fait ce qu’on attend, et le filet qui permet de le modifier sans le casser.
Pour un service d’IA, les tests portent sur deux niveaux. Le niveau du code : les fonctions extraites se comportent correctement, la configuration se charge, les erreurs sont gérées, ce que couvrent des tests pytest classiques. Le niveau du comportement : sur un jeu de cas représentatifs, la sortie produite répond aux critères de qualité.
Le second niveau est plus exigeant, car la sortie d’un modèle n’est pas déterministe. Il se traite avec un jeu d’évaluation et des critères de réussite explicites, outillé par Promptfoo ou DeepEval, comme on le ferait pour juger un agent avec des evals. Les deux niveaux sont nécessaires : le premier garantit la solidité, le second la qualité.
Déploiement et surveillance
Une fois le code extrait, configuré, testé, il reste à le déployer et à le surveiller. Le déploiement consiste à exécuter le service dans un environnement maîtrisé, avec une procédure reproductible et la possibilité de revenir en arrière, idéalement via une chaîne CI/CD pensée pour l’IA. La surveillance consiste à voir, en continu, si le service fait ce qu’il doit.
Le minimum de surveillance reprend ce qui a été dit plus haut : les journaux, les métriques d’erreur et de latence, et pour un service d’IA, le coût par requête et la qualité sur le jeu d’évaluation. C’est ce qui transforme un service qui tourne en un service qu’on exploite.
Le point commun de toutes ces étapes est qu’elles ne demandent rien d’exotique. Ce sont des pratiques d’ingénierie ordinaires, appliquées à un objet nouveau. Le passage du notebook au service est moins une question d’outils qu’une question de discipline.
En pratique : industrialiser votre prototype
Passer un prototype du notebook au service fait partie de nos missions courantes, pour des équipes qui ont validé une idée et veulent en faire un outil exploitable au quotidien. Ce qui compte, c’est l’ordre des étapes et la connaissance des pièges.
Le principe qu’on applique : industrialiser sans réécrire. La logique qui a fait ses preuves dans le notebook est conservée, restructurée en fonctions, sortie de sa configuration en dur, puis dotée des tests, des evals et de la surveillance décrits plus haut. C’est le cœur de notre méthode de mise en production.
La même démarche vaut pour un prototype qui n’est pas né dans un notebook mais dans Lovable, Bolt, v0 ou Cursor : l’idée est validée, le code n’est pas prêt à tourner tous les jours. Dans ce cas, c’est le terrain de la reprise de produits construits vite.
