Retour au catalogue
Season 2 15 Épisodes 52 min 2026

Learning DSPy (v3.1 - 2026 Edition)

Un programme complet et progressif pour apprendre DSPy, passant de prompts fragiles basés sur des chaînes de caractères à une programmation modulaire et structurée, ainsi qu'à une optimisation automatisée.

Frameworks AI/ML Prompt Engineering
Learning DSPy (v3.1 - 2026 Edition)
Lecture en cours
Click play to start
0:00
0:00
1
Programmer, pas prompter
Cet épisode aborde la philosophie fondamentale de DSPy : s'éloigner des prompts fragiles basés sur des chaînes de caractères pour aller vers une programmation modulaire et structurée. Les auditeurs découvriront pourquoi la séparation de l'architecture du système et des instructions du modèle de langage permet de créer des applications d'IA plus robustes.
3m 24s
2
Configurer les modèles de langage
Apprenez à configurer et gérer les modèles de langage dans DSPy. Cet épisode explique comment définir les modèles par défaut, gérer la mise en cache, remplacer les paramètres de génération et accéder à différents fournisseurs de modèles via LiteLLM.
3m 16s
3
Prompting déclaratif avec les Signatures
Découvrez comment les Signatures de DSPy remplacent le prompting traditionnel. Cet épisode explique comment définir le comportement d'entrée et de sortie d'un module de manière déclarative, en utilisant à la fois des chaînes de caractères en ligne et des définitions basées sur des classes avec un typage strict.
3m 46s
4
Les blocs de construction avec les Modules
Explorez les Modules de DSPy, les blocs de construction fondamentaux pour les programmes de modèles de langage. Cet épisode couvre dspy.Predict, dspy.ChainOfThought, et la manière de composer plusieurs modules en un pipeline plus vaste et cohérent.
3m 27s
5
Connecter les modèles avec les Adapters
Comprenez le rôle des Adapters dans DSPy. Cet épisode explique comment ChatAdapter et JSONAdapter font le pont entre les signatures abstraites de DSPy et les véritables messages multi-tours envoyés aux APIs des modèles de langage.
3m 59s
6
Gérer les données avec les Examples
Apprenez comment DSPy gère les jeux de données pour le machine learning. Cet épisode couvre l'objet dspy.Example, la distinction entre les clés d'entrée et les labels, et la préparation des données pour l'évaluation et l'optimisation.
3m 25s
7
Définir le succès avec les Metrics
Découvrez comment évaluer les programmes DSPy à l'aide de métriques. Cet épisode vous apprend à écrire des fonctions Python personnalisées pour noter les sorties, à utiliser l'argument trace, et même à exploiter l'IA en tant que juge pour les évaluations de formats longs.
3m 46s
8
Une introduction aux Optimizers
Entrez dans la magie fondamentale de DSPy : les Optimizers. Cet épisode offre un aperçu de ce que font les optimizers, du cycle d'optimisation itératif et de la stratégie inhabituelle de division des données 20/80 pour l'optimisation des prompts.
3m 19s
9
Apprentissage Few-Shot automatique
Apprenez comment DSPy automatise le prompting few-shot. Cet épisode se concentre sur BootstrapFewShot et BootstrapFewShotWithRandomSearch, en expliquant comment ils synthétisent, filtrent et injectent des exemples de haute qualité dans vos prompts.
3m 09s
10
Optimisation des instructions avec MIPROv2
Plongez dans le réglage automatique des instructions. Cet épisode explore MIPROv2 et COPRO, montrant comment DSPy utilise l'optimisation bayésienne et la montée de coordonnées pour découvrir des instructions de prompt supérieures et contre-intuitives.
3m 32s
11
Finetuning avec BootstrapFinetune
Découvrez comment distiller des modèles de langage massifs en modèles plus petits et efficaces. Cet épisode couvre BootstrapFinetune, expliquant comment convertir un programme DSPy basé sur des prompts en un modèle personnalisé avec mise à jour des poids.
3m 23s
12
Utilisation automatisée d'outils avec ReAct
Apprenez à donner aux modèles de langage l'accès à des outils externes. Cet épisode couvre le module dspy.ReAct, démontrant comment construire des agents autonomes qui raisonnent et interagissent dynamiquement avec des APIs.
3m 30s
13
Gestion manuelle des outils pour plus de contrôle
Prenez le contrôle total sur l'exécution des outils. Cet épisode couvre la gestion manuelle des outils dans DSPy en utilisant dspy.Tool, dspy.ToolCalls, et l'appel de fonctions natif pour les applications sensibles à la latence.
3m 35s
14
Intégration d'outils avec MCP
Connectez vos agents à des serveurs d'outils universels. Cet épisode explique comment utiliser le Model Context Protocol (MCP) dans DSPy pour exploiter des outils standardisés à travers différents frameworks avec une configuration minimale.
3m 25s
15
Ensembles et Méta-optimisation
Poussez DSPy dans ses retranchements. L'épisode final couvre les transformations de programmes via dspy.Ensemble et le méta-optimizer expérimental BetterTogether, qui combine le réglage de prompts avec le finetuning des poids pour des performances maximales.
3m 15s

Épisodes

1

Programmer, pas prompter

3m 24s

Cet épisode aborde la philosophie fondamentale de DSPy : s'éloigner des prompts fragiles basés sur des chaînes de caractères pour aller vers une programmation modulaire et structurée. Les auditeurs découvriront pourquoi la séparation de l'architecture du système et des instructions du modèle de langage permet de créer des applications d'IA plus robustes.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 1 sur 15. Tu passes trois heures à peaufiner un prompt pour que ton modèle de langage génère les bons outputs. Ensuite, un fournisseur sort un nouveau modèle, tu changes la clé API, et tout ton pipeline s'effondre. Tu te retrouves coincé à maintenir des strings fragiles au lieu de créer du logiciel. C'est le problème que résout une philosophie appelée Programming, Not Prompting. On entend souvent parler de DSPy et on s'imagine que c'est juste un autre outil de prompt templating pour insérer des variables dans des blocs de texte. Ce n'est pas le cas. DSPy est un framework pour compiler et optimiser le control flow. Prends un setup standard pour un système qui lit des documents et génère un rapport avec des citations. Dans une approche traditionnelle, tu écris un énorme bloc de texte. Tu expliques la tâche, tu injectes les documents, tu ajoutes des instructions manuelles comme think step by step, et tu spécifies exactement à quoi doivent ressembler les citations. Cette approche couple étroitement l'architecture de ton système avec des choix accessoires. Ton architecture, c'est la logique cœur. Ça veut dire extraire des faits, rédiger un résumé et ajouter des citations. Les choix accessoires, ce sont les mots précis que tu as utilisés pour amadouer un modèle de langage particulier et le forcer à t'obéir. Ces mots exacts ne fonctionneront pas de manière optimale sur un autre modèle, ou même sur une version différente du même modèle. Quand les données changent légèrement, le prompt casse. DSPy sépare l'architecture de ton système de ces choix de prompt accessoires. Tu arrêtes d'écrire de longues strings d'instructions. À la place, tu définis ta tâche uniquement en termes d'inputs et d'outputs. Pour le générateur de rapport, tu déclares que l'input est une liste d'extraits de texte, et que l'output est un brouillon de texte et un ensemble de références de citations. Une fois les inputs et les outputs définis, tu les relies entre eux en utilisant du code standard. Tu crées un composant d'extraction, tu lui passes les documents, et tu récupères les faits. Ensuite, tu passes ces faits à un composant de rédaction. Enfin, tu peux utiliser une simple boucle pour vérifier le brouillon par rapport aux faits d'origine. Il n'y a pas de strings manuelles qui supplient le modèle de formater son output correctement. Il n'y a que de la logique structurée. Voici l'idée clé. Parce que ton architecture est définie comme du code modulaire, un compilateur peut traduire automatiquement cette structure en véritables prompts requis par le modèle de langage que tu utilises. DSPy traite les instructions du modèle, les étapes de raisonnement et les exemples few-shot comme des paramètres internes. Ce sont des variables qui doivent être optimisées par le framework, plutôt que du texte statique que tu tapes à la main. Tu construis le pipeline, tu définis les formats de données, et tu écris les étapes d'exécution en Python standard. Le framework gère la tâche imprévisible de découvrir la meilleure façon de demander au modèle de langage d'exécuter ces étapes de manière fiable. Ça change fondamentalement l'expérience développeur. Tu passes ton temps à débugger la logique de ton application, pas à deviner quel adjectif va forcer le modèle à faire attention à la fin d'une phrase. L'architecture de ton système devrait survivre aux caprices du modèle de langage vers lequel tu envoies tes requêtes aujourd'hui. Merci d'avoir écouté, et bon code à tous !
2

Configurer les modèles de langage

3m 16s

Apprenez à configurer et gérer les modèles de langage dans DSPy. Cet épisode explique comment définir les modèles par défaut, gérer la mise en cache, remplacer les paramètres de génération et accéder à différents fournisseurs de modèles via LiteLLM.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 2 sur 15. Faire un seul appel API à un modèle de langage, c'est facile. Mais gérer plusieurs providers, mettre en cache les réponses et suivre l'historique des prompts t'oblige généralement à créer et maintenir un wrapper personnalisé. Configurer les modèles de langage dans DSPy élimine ces tâches fastidieuses. Tu pourrais penser que tu as besoin du SDK OpenAI pour les modèles GPT, du SDK Anthropic pour Claude et d'une librairie distincte pour les modèles locaux. Ce n'est pas le cas. DSPy gère ça de manière uniforme grâce à une seule classe LM, propulsée par LiteLLM sous le capot. Pour utiliser un modèle, tu instancies un objet DSPy LM et tu passes une string contenant le nom du provider, un slash et le nom du modèle. Par exemple, tu passes open ai slash gpt-4o-mini. Quand tu crées cet objet, tu peux aussi passer des paramètres standards comme la température ou les max tokens. Grâce au backend unifié, les noms de ces paramètres restent les mêmes, quel que soit le provider que tu appelles réellement. Tu peux interagir directement avec cet objet LM. Appelle-le comme une fonction Python normale, en lui passant soit une simple string de texte, soit une liste de dictionnaires de chat. Il traite l'input et renvoie une liste de strings générées. Par défaut, il renvoie une seule string dans cette liste, mais tu peux demander plusieurs complétions. Cette utilisation directe est simple, mais passer manuellement un objet modèle à chaque fonction dans une grosse codebase devient vite le bazar. Pour résoudre ça, DSPy utilise un système de configuration global. Tu définis ton modèle de langage par défaut une seule fois en appelant dspy dot configure, en assignant ton objet LM instancié comme cible. Chaque opération DSPy suivante est automatiquement routée via ce modèle. Mais que faire si tu veux comparer les sorties entre différents providers ? Disons que tu veux tester comment Claude 3.5 Sonnet gère une fonction spécifique par rapport à ton modèle GPT par défaut. Au lieu d'écraser l'état global, tu utilises dspy dot context. Ça crée un scope temporaire. Tu ouvres un bloc with Python en utilisant dspy dot context, tu assignes Claude comme modèle par défaut local, et tu exécutes ton code. Quand le bloc se termine, DSPy revient automatiquement à ton modèle GPT-4o-mini global. Ça couvre le routage des requêtes. Qu'en est-il des performances ? Par défaut, DSPy met en cache chaque génération de modèle pour gagner du temps et réduire les coûts d'API. Si tu lances exactement le même prompt avec exactement les mêmes paramètres, il sert la réponse en cache instantanément. Voici l'astuce. Parfois, tu as besoin d'une nouvelle génération sans changer ton prompt ni ajuster la température. Pour faire ça, DSPy utilise un paramètre appelé rollout id. Quand tu passes un nouveau rollout id, comme un entier unique, DSPy le traite comme une requête distincte et contourne le cache. Ça force le modèle à générer une nouvelle séquence, te donnant le contrôle sur la diversité de la génération tout en gardant les inputs de base statiques. Enfin, quand tu fais des expérimentations, tu as besoin de voir exactement ce qui a transité sur le réseau. Chaque objet LM conserve son propre log d'interactions. Tu peux accéder aux données brutes via l'attribut history sur l'objet modèle. Pour un résumé lisible par un humain, tu appelles la méthode inspect history. Elle affiche le prompt exact envoyé au provider et la réponse exacte reçue. La vraie valeur de cette couche de configuration, c'est qu'elle détache entièrement la logique de ton application des particularités des providers, transformant la sélection du modèle et le caching en de simples switchs déclaratifs. Merci de m'avoir écouté, et happy coding à tous !
3

Prompting déclaratif avec les Signatures

3m 46s

Découvrez comment les Signatures de DSPy remplacent le prompting traditionnel. Cet épisode explique comment définir le comportement d'entrée et de sortie d'un module de manière déclarative, en utilisant à la fois des chaînes de caractères en ligne et des définitions basées sur des classes avec un typage strict.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 3 sur 15. Les signatures de fonctions Python standards indiquent à ton code les types de données attendus. Mais et si une signature pouvait dicter la logique même de la fonction, sans que tu aies à écrire explicitement les instructions ? C'est le principe du prompting déclaratif avec les signatures. Tu pourrais facilement confondre une signature DSPy avec une signature de fonction Python standard. Elles se ressemblent, mais leurs rôles sont fondamentalement différents. Une signature Python standard définit une interface de données stricte. Une signature DSPy, en revanche, déclare et initialise le comportement du modèle de langage. Tu n'écris pas un prompt. Tu écris une spécification déclarative de ce qui doit se passer. Le framework prend cette spécification, regarde les attentes en input et en output, et construit le prompt sous-jacent pour toi. La façon la plus simple de définir une signature, c'est inline, en utilisant une courte string. Tu spécifies tes variables d'input, tu écris une flèche directionnelle, et tu spécifies tes variables d'output. Par exemple, la string question arrow answer indique à DSPy que le modèle recevra une question et devra générer une réponse. Tu peux passer plusieurs inputs, comme context comma question arrow answer. C'est là que ça devient intéressant. Les noms de variables que tu choisis ont un vrai poids sémantique. DSPy utilise exactement ces noms de strings pour assigner des rôles dans le prompt. Si tu nommes un input context, le modèle l'interprète comme une information de fond. Ne fais pas d'over-engineering sur ces noms et n'essaie pas de hacker les mots-clés avec des astuces de prompt. Utilise des mots anglais clairs et descriptifs pour définir les rôles. Quand les strings inline ne sont pas assez expressives, tu passes aux signatures basées sur des classes. Tu crées une nouvelle classe qui hérite de la classe de base Signature de DSPy. À l'intérieur de cette classe, tu définis tes inputs et outputs comme attributs. Tu assignes ces attributs en utilisant les fonctions InputField et OutputField fournies par DSPy. Cette approche te donne un contrôle très fin sur le comportement du modèle. La docstring de la classe elle-même devient l'instruction principale pour le modèle de langage, et définit la tâche globale. Prends l'exemple d'un scénario de classification d'images multimodale. Tu veux passer une image et une question texte à un modèle de vision, et extraire la race spécifique d'un chien. Tu crées une classe appelée ClassifyDogBreed. En haut de la classe, tu écris une docstring qui dit : Identifie la race du chien en fonction de l'image et de la question fournies. Ensuite, tu définis tes inputs. Tu crées un attribut nommé image et tu l'assignes comme InputField. Tu crées un deuxième attribut nommé question et tu l'assignes comme InputField. Enfin, tu définis un attribut nommé breed et tu l'assignes comme OutputField. À l'intérieur de cet OutputField, tu peux passer un argument description qui dit : Le nom exact de la race du chien, sans texte supplémentaire. Les signatures basées sur des classes gèrent aussi la résolution de types. Tu peux spécifier des type hints Python standards pour tes champs. Si tu mets un type hint boolean sur ton champ d'output, DSPy comprend que le modèle doit retourner une valeur true ou false. Le framework traite ces annotations de type et injecte automatiquement des contraintes dans la structure du prompt, pour guider le modèle vers le bon format d'output. La structure de tes données et les noms de tes variables sont les véritables instructions. Un champ clairement nommé et une docstring précise dans une signature déclarative dicteront le comportement du modèle de manière bien plus fiable que des paragraphes entiers de prompt engineering fait à la main. Merci d'avoir écouté, et bon code à tous !
4

Les blocs de construction avec les Modules

3m 27s

Explorez les Modules de DSPy, les blocs de construction fondamentaux pour les programmes de modèles de langage. Cet épisode couvre dspy.Predict, dspy.ChainOfThought, et la manière de composer plusieurs modules en un pipeline plus vaste et cohérent.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 4 sur 15. D'habitude, quand tu veux qu'un modèle de langage raisonne sur un problème, tu te retrouves à bricoler des strings, en ajoutant au hasard des phrases comme "think step by step" à ton prompt. Tu emmêles la logique de ton application avec des instructions textuelles fragiles. Dans DSPy, les techniques de prompting ne sont pas des strings. Ce sont des composants structurés et interchangeables appelés Modules. C'est facile de confondre les modules et les signatures. Vois une signature comme le contrat. Elle définit le "quoi", en mappant des champs d'input spécifiques à des champs d'output spécifiques. Un module définit le "comment". C'est un objet paramétré et callable qui prend ta signature et applique une stratégie de prompting spécifique pour remplir ce contrat. Le module le plus basique est le module Predict. Tu l'initialises en lui passant ta signature comme argument. Si ta signature demande de transformer un document en résumé, le module Predict gère le formatage du prompt et appelle le modèle de langage. Mais peut-être que la tâche est complexe et nécessite une logique intermédiaire. Tu peux facilement remplacer Predict par le module Chain of Thought. Tu ne changes pas ta signature. Tu la passes simplement au module Chain of Thought à la place. Sous le capot, ce module modifie automatiquement l'architecture du prompt. Il demande au modèle de langage de générer une trace de raisonnement étape par étape avant de produire les champs d'output finaux que tu as définis. Quand tu appelles le module Chain of Thought avec tes données d'input, il retourne un objet contenant tes outputs demandés. Parce que tu as utilisé Chain of Thought, cet objet inclut aussi un nouveau champ contenant le raisonnement du modèle. Tu peux inspecter exactement comment le modèle de langage est arrivé à sa réponse, complètement séparé de la valeur extraite finale. Voici l'idée clé. Tu peux imbriquer ces modules intégrés pour créer des programmes complexes, un peu comme tu empilerais des couches de réseaux de neurones dans PyTorch. On peut construire un pipeline de retrieval multi-hop pour voir ça en action. Tu commences par définir une classe custom. Dans sa phase d'initialisation, tu déclares les plus petits modules dont tu auras besoin. Pour une architecture multi-hop, tu pourrais déclarer un module générateur de requêtes utilisant Chain of Thought, et un module de synthèse de réponse utilisant le Predict standard. Ensuite, tu définis une méthode forward pour router les données entre eux. La méthode forward prend une question initiale de l'utilisateur. Elle passe cette question à ton module générateur de requêtes, qui produit une requête de recherche. Tu exécutes cette recherche sur ta base de données pour récupérer un document. Si tu as besoin d'un deuxième hop, tu repasses le document récupéré et la question originale dans le module générateur de requêtes pour produire une requête de recherche plus affinée. Enfin, tu passes tous les documents récupérés et la question de l'utilisateur dans le module de synthèse de réponse pour générer la réponse finale. Tu viens de construire un graphe custom et exécutable à partir de composants modulaires. Quand tu chaînes plusieurs appels ensemble comme ça, c'est crucial de voir exactement ce qui est envoyé au modèle en arrière-plan. DSPy suit l'utilisation de ton modèle de langage globalement. Tu peux appeler la commande inspect history sur ton objet de modèle de langage pour afficher les interactions les plus récentes. Ça affiche la string exacte que le modèle a reçue et la string exacte qu'il a générée, pour t'assurer que ton pipeline composé assemble le contexte correctement. En séparant la définition de ta tâche en signatures et ta stratégie d'exécution en modules paramétrés, tu transformes le prompting d'une corvée d'édition de texte en une décision architecturale, ce qui te permet d'améliorer la capacité de raisonnement de ton pipeline simplement en changeant un nom de classe. Merci d'avoir écouté, happy coding tout le monde !
5

Connecter les modèles avec les Adapters

3m 59s

Comprenez le rôle des Adapters dans DSPy. Cet épisode explique comment ChatAdapter et JSONAdapter font le pont entre les signatures abstraites de DSPy et les véritables messages multi-tours envoyés aux APIs des modèles de langage.

Télécharger
Salut, ici Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 5 sur 15. Tu écris une signature propre et fortement typée dans ton code, tu la passes à un modèle de langage, et d'une manière ou d'une autre, tu obtiens en retour un objet Python parfaitement structuré. Entre ton code propre et l'API raw text du modèle se cache une couche de traduction chaotique. Cette couche invisible, c'est le concept de connecter les modèles avec des Adapters. Avant qu'on regarde comment ils fonctionnent, clarifions une confusion fréquente. Tu pourrais confondre les Adapters avec les Modules. Les Modules gèrent la stratégie de raisonnement. Ils décident si le modèle doit utiliser Chain of Thought ou s'appuyer sur des outils externes. Les Adapters ne se soucient pas de la stratégie. Un Adapter est purement la couche de traduction. Il gère la raw string et la sérialisation JSON qui sont réellement envoyées sur le réseau à l'API du modèle. Les modèles de langage ne comprennent pas les signatures déclaratives. Ils attendent des arrays de messages multi-turn contenant des rôles et des blocs de texte spécifiques. L'Adapter comble cet écart. L'outil par défaut pour ça dans DSPy, c'est le ChatAdapter. Quand tu invoques un Module, le ChatAdapter intercepte ta signature et la formate en un chat history standard. L'instruction principale de la signature est mappée directement dans le system prompt. Tes champs d'input sont rassemblés et placés dans le user message. Voici l'élément clé. Le ChatAdapter utilise des marqueurs de texte spécifiques pour garder tes inputs strictement organisés. Il encadre chaque nom de champ avec des doubles crochets et des doubles dièses. Si ton champ d'input s'appelle contexte, le modèle de langage voit un marqueur avec des crochets et des dièses autour du mot contexte, immédiatement suivi des données de contexte réelles. Cette frontière visuelle empêche le modèle de confondre accidentellement tes instructions système avec le user input. Il répète ce schéma pour les champs d'output attendus, incitant le modèle à générer exactement les mêmes marqueurs dans sa réponse. Imagine un scénario où tu extrais des actualités scientifiques. Ton input est un article en raw text, et ton output doit correspondre à une classe Pydantic avec des champs spécifiques pour le titre et la découverte scientifique principale. Quand tu passes cette exigence au ChatAdapter, il inspecte ta classe Pydantic, génère un schéma JSON complet, et injecte ce schéma directement dans le system prompt. Il dit explicitement au modèle de langage comment formater sa réponse texte. Quand le modèle finit par répondre, le ChatAdapter récupère la raw text string. Il cherche les marqueurs d'output attendus, extrait le bloc de texte entre eux, et parse ces données pour recréer les objets Python exacts dont ton application a besoin. Ça couvre les inputs et le parsing pour les interactions basées sur le texte. Mais les modèles de langage modernes ont souvent un support natif pour les structured outputs. C'est là que le JSONAdapter entre en jeu. Au lieu de modifier lourdement le system prompt et de s'appuyer sur des marqueurs de texte, le JSONAdapter prend une route plus directe. Il délègue les contraintes de formatage au mode JSON natif du fournisseur du modèle ou à son API de structured outputs. Le modèle est forcé au niveau du protocole de renvoyer un objet JSON valide qui contient tous tes champs d'output demandés. Parce que l'API du modèle gère la structure nativement, ça évite à l'Adapter de devoir chercher des string markers dans du raw text. Si ton modèle cible supporte cette capacité, passer ton pipeline sur le JSONAdapter donne généralement une latence plus faible et un parsing nettement plus fiable. L'Adapter est la frontière rigide entre la logique déterministe de ton application et la génération de texte non structuré du modèle de langage. En contrôlant exactement comment les inputs sont sérialisés et les outputs sont parsés, les Adapters garantissent que ton pipeline ne cassera jamais à cause d'une string mal formatée. Merci de m'avoir écouté, happy coding à tous !
6

Gérer les données avec les Examples

3m 25s

Apprenez comment DSPy gère les jeux de données pour le machine learning. Cet épisode couvre l'objet dspy.Example, la distinction entre les clés d'entrée et les labels, et la préparation des données pour l'évaluation et l'optimisation.

Télécharger
Salut, ici Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 6 sur 15. Tu lances un optimizer pour améliorer ton pipeline de modèle de langage, mais il obtient un score parfait du premier coup. En y regardant de plus près, tu te rends compte que tu as accidentellement passé les réponses cibles directement dans le prompt. Pour traiter les modèles de langage comme des composants de machine learning traditionnels, tu as besoin d'une méthode infaillible pour gérer tes sets de training, de dev et de test sans faire fuiter les réponses. Gérer les données avec des Examples dans DSPy sert exactement à ça. Dans DSPy, la structure de données fondamentale est l'objet Example. Tu l'utilises pour construire tous tes datasets. En apparence, il se comporte beaucoup comme un dictionnaire Python standard. Tu en crées un en lui passant des paires clé-valeur qui représentent tes données. Prenons une tâche de résumé. Tu crées un nouvel objet Example et tu lui donnes deux champs. Tu assignes une longue string à un champ appelé report, et une courte string à un champ appelé summary. Tu peux relire ces valeurs à tout moment en utilisant la dot notation standard, en demandant le champ report ou le champ summary directement à l'objet. Il est courant de considérer l'objet Example comme un simple wrapper de dictionnaire, mais utiliser un simple dictionnaire va casser le processus de compilation. Quand tu passes un dataset à un optimizer DSPy, le compilateur a besoin de séparer ce qui entre dans le pipeline de ce qui est utilisé pour scorer le pipeline. Il exige des limites explicites entre les données en input et les réponses attendues. C'est là que ça devient intéressant. L'objet Example contrôle ces limites grâce à une méthode spécifique appelée with_inputs. Quand tu instancies ton Example contenant le report et le summary, tu chaînes la méthode with_inputs tout à la fin. Tu lui passes la string report. Ça tague explicitement le champ report comme étant l'input. Tout champ que tu ne spécifies pas dans cette méthode devient automatiquement un label. L'optimizer sait maintenant qu'il ne doit envoyer que le report à ton pipeline. Le summary reste totalement masqué pendant l'inférence. Une fois que tu as configuré un seul exemple, tu regroupes plusieurs exemples dans des listes Python standard pour former tes sets de training, de dev et de test. Parce que DSPy aborde le prompt engineering comme un problème d'optimisation de machine learning, avoir ces datasets clairement partitionnés est une exigence stricte. Quand l'optimizer exécute ton pipeline sur le set de training, il traite un Example à la fois. Il retire les labels, transmet les inputs, capture l'output généré, puis évalue le résultat. Quand tu écris des métriques d'évaluation personnalisées, tu auras besoin d'accéder à ces champs séparés. L'objet Example fournit deux méthodes pour cette extraction. Appeler la méthode inputs renvoie un dictionnaire contenant uniquement les données que tu as marquées comme inputs. Appeler la méthode labels renvoie un dictionnaire contenant les données cibles masquées. Ta fonction d'évaluation appelle la méthode labels pour récupérer le summary cible, le compare au texte généré, et attribue un score en fonction de leur correspondance. Bien configurer tes objets Example garantit que ton pipeline apprend réellement à mapper les inputs vers les outputs. La séparation stricte des inputs et des labels empêche le data leakage pendant l'optimisation, ce qui garantit que ton système s'améliore au lieu de simplement mémoriser les réponses fournies. Merci pour ton écoute, et happy coding tout le monde !
7

Définir le succès avec les Metrics

3m 46s

Découvrez comment évaluer les programmes DSPy à l'aide de métriques. Cet épisode vous apprend à écrire des fonctions Python personnalisées pour noter les sorties, à utiliser l'argument trace, et même à exploiter l'IA en tant que juge pour les évaluations de formats longs.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 7 sur 15. Tu ne peux pas améliorer durablement ce que tu ne peux pas mesurer, et quand on travaille avec des modèles de langage, se fier à l'intuition humaine pour évaluer la qualité de l'output, ça ne scale tout simplement pas. Pour réécrire automatiquement tes prompts ou optimiser ton système, le compilateur a besoin d'un repère mathématique, et c'est exactement ce qu'apporte le fait de définir le succès avec des metrics. Dans DSPy, une metric est une fonction Python standard. Elle prend deux arguments principaux. Le premier est un example, qui représente l'input de référence et l'output attendu de ton dataset. Le second est une prediction, c'est-à-dire la réponse réelle générée par ton programme DSPy. La fonction de metric compare la prediction avec l'example et renvoie un score. Ce score est généralement un float, un integer, ou une simple valeur boolean comme true ou false. Pour des tâches de classification basiques, ta metric peut être de la simple logique Python. Tu pourrais écrire une fonction d'exact match qui vérifie si la string prédite est parfaitement égale à la string attendue. Pour exécuter cette mesure systématiquement sur tes données, DSPy fournit un utilitaire intégré appelé Evaluate. Tu passes à cet utilitaire ton dataset de développement, ta fonction de metric, et des paramètres d'exécution comme le nombre de threads en parallèle. L'utilitaire Evaluate lance ta metric sur chaque prediction, agrège les résultats, et renvoie un seul score numérique qui représente la performance globale de ton système. Cependant, l'exact matching est presque toujours trop rigide pour les tâches de génération de langage. C'est là que tu passes de simples checks de strings à l'utilisation du feedback de l'IA, un pattern communément appelé LLM-as-a-judge. Comme les modules DSPy sont juste du code Python, ta fonction de metric peut instancier et appeler un programme DSPy plus petit et séparé pour évaluer des outputs sémantiques complexes. Imagine un scénario concret. Tu construis un système qui génère un tweet promotionnel pour répondre à la question d'un utilisateur. Une metric d'exact match échoue complètement ici, parce qu'un bon tweet peut être formulé d'innombrables façons valides. À la place, ta fonction de metric doit évaluer plusieurs dimensions de l'output. D'abord, elle utilise un simple check de longueur en Python pour s'assurer que le texte généré fait moins de deux cent quatre-vingts caractères. Ensuite, elle vérifie si le texte contient la réponse factuelle requise par l'example. Enfin, elle passe le texte généré à une signature DSPy spécialisée qui demande à un plus petit modèle de langage d'évaluer si le tweet est engageant. Ta fonction de metric combine ensuite le check de longueur, le fact check, et le score d'engagement du modèle de langage en une seule valeur mathématique finale. Quand tu finis par compiler et optimiser ces programmes, ta fonction de metric doit accepter un troisième argument optionnel. Il s'appelle trace. Les auditeurs confondent souvent l'argument trace avec un log de debugging qui print des erreurs dans la console ou l'historique d'exécution. Ce n'est pas du tout ça. L'argument trace est un objet spécifique utilisé par le compilateur DSPy pendant l'optimisation pour valider les étapes de raisonnement intermédiaires. Si ton programme chaine plusieurs appels de modèles de langage ensemble, la trace contient le chemin de raisonnement spécifique que le modèle a pris pour arriver à la fin. En accédant à la trace à l'intérieur de ta metric, ta fonction peut vérifier non seulement que le tweet final était bon, mais que les étapes intermédiaires utilisées pour le rédiger étaient logiquement cohérentes. C'est ça la partie qui compte. Ta metric définit strictement à quoi ressemble le succès, et le compilateur DSPy va optimiser ton système impitoyablement pour maximiser ce score spécifique. Si ta metric est défectueuse, ton programme compilé sera défectueux exactement de la même manière. Merci d'avoir écouté, happy coding tout le monde !
8

Une introduction aux Optimizers

3m 19s

Entrez dans la magie fondamentale de DSPy : les Optimizers. Cet épisode offre un aperçu de ce que font les optimizers, du cycle d'optimisation itératif et de la stratégie inhabituelle de division des données 20/80 pour l'optimisation des prompts.

Télécharger
Salut, ici Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 8 sur 15. Suppose que tu écrives un logiciel, et qu'au lieu de modifier manuellement sa logique interne pour passer tes tests, un compilateur réécrive automatiquement les instructions pour que le programme soit plus performant de lui-même. Tu ne touches pas au code. Tu fournis juste le jeu de tests. C'est exactement ce que fait DSPy grâce à un concept appelé Optimizers. Les Optimizers, qu'on appelait avant teleprompters dans les anciennes versions du framework, sont des algorithmes qui ajustent les paramètres de ton programme. En machine learning traditionnel, les paramètres correspondent aux poids du réseau de neurones. Dans DSPy, les paramètres désignent principalement les prompt strings et les instructions envoyées au modèle de langage, même s'ils peuvent aussi inclure des poids. Le rôle de l'Optimizer est d'ajuster ces paramètres pour maximiser une métrique que tu as déjà définie. Ce processus se passe avant que tu fasses le deploy de ton application. C'est du pur compute en phase de pré-inférence. Tu dépenses de la puissance de calcul en amont pour trouver les meilleures instructions, pour que ton application tourne avec précision par la suite. Quand tu entends le mot Optimizer, tu pourrais penser que tu as besoin de datasets massifs, comme tu le ferais pour le fine-tuning d'un modèle traditionnel. Ce n'est pas le cas. Les prompt optimizers sont très efficaces. Ils ne demandent généralement que trente à trois cents exemples. Comme le dataset est si petit, DSPy recommande une approche inhabituelle pour splitter tes données. Au lieu du split standard quatre-vingt vingt où la majorité des données va au training, tu l'inverses. Tu utilises vingt pour cent pour le training et quatre-vingts pour cent pour la validation. Si tu as cinquante exemples, tu en donnes dix à l'Optimizer pour construire les prompts, et tu utilises les quarante restants pour évaluer si ces prompts généralisent vraiment. Ce reverse split empêche l'Optimizer de faire de l'overfitting sur les prompts générés avec un tout petit set d'inputs. Voici l'idée clé. Le cycle de développement itératif dans DSPy tourne autour de l'exécution de cette boucle d'optimisation. Prenons un scénario concret. Tu construis un bot de questions-réponses basique. D'abord, tu définis ton programme DSPy et ta métrique. Ensuite, tu rassembles ton dataset de cinquante questions non labellisées. Tu splittes ces données, en passant la petite portion de training à un objet Optimizer. Tu dis à l'Optimizer de compiler ton programme en utilisant tes données de training et ta métrique. L'Optimizer tourne, en expérimentant avec différentes structures de prompts sous le capot. Il vérifie les outputs par rapport à ta métrique, apprend ce qui marche, et affine les prompts. Quand l'Optimizer a terminé, il renvoie une nouvelle version compilée de ton programme. Ce programme compilé contient les paramètres nouvellement ajustés. Tu n'as pas besoin de lancer cette étape d'optimisation à chaque fois que ton application démarre. À la place, tu appelles la méthode save sur le programme compilé, en fournissant un chemin de fichier. Ça écrit tous les prompts et configurations optimisés dans un fichier JSON standard. Quand tu fais le deploy de ton application en production, ton code instancie simplement le programme de base et appelle la méthode load, en pointant vers ce fichier JSON exact. Ton bot est immédiatement prêt à répondre aux questions en utilisant les instructions optimisées. La vraie puissance des Optimizers DSPy, c'est qu'ils découplent la logique de ton application de la formulation exacte de tes prompts, en laissant le compute trouver les meilleurs mots pour toi. Merci d'avoir écouté, bon code à tous !
9

Apprentissage Few-Shot automatique

3m 09s

Apprenez comment DSPy automatise le prompting few-shot. Cet épisode se concentre sur BootstrapFewShot et BootstrapFewShotWithRandomSearch, en expliquant comment ils synthétisent, filtrent et injectent des exemples de haute qualité dans vos prompts.

Télécharger
Salut, ici Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 9 sur 15. Choisir manuellement les meilleurs exemples à mettre dans un prompt est fastidieux et source de biais. Tu devines quels exemples sont importants, tu les hardcodes dans tes strings, et tu espères que le modèle y fera attention. DSPy synthétise, teste et sélectionne activement les démonstrations parfaites pour toi. Ce processus, c'est le few-shot learning automatique, et DSPy le gère via trois optimizers spécifiques. L'approche la plus simple est LabeledFewShot. Tu fournis un set d'exemples d'entraînement labellisés. L'optimizer sélectionne au hasard un sous-ensemble de ces paires input et output, et les insère directement dans tes prompts comme démonstrations. Ça donne au modèle un pattern de base à suivre. Ça marche bien si tes données d'entraînement correspondent exactement aux étapes intermédiaires dont ton programme a besoin. En général, ce n'est pas le cas. Ce qui nous amène à BootstrapFewShot. Une erreur courante est de penser que BootstrapFewShot choisit juste au hasard des exemples dans ton set d'entraînement. Ce n'est pas le cas. Il génère activement des étapes de raisonnement intermédiaires qui n'ont jamais existé dans tes données brutes. Voici comment se déroule le processus de bootstrapping. L'optimizer a besoin d'un programme teacher. Par défaut, c'est juste la version non optimisée, en zero-shot, de ton propre programme. Le teacher parcourt tes exemples d'entraînement. Pour chaque exemple, il tente de générer une réponse. DSPy passe ensuite cette réponse à ta métrique d'évaluation. Si la métrique dit que l'output est correct, DSPy sauvegarde la trace complète de cette exécution réussie. Cette trace inclut l'input, l'output, et surtout, tout le travail intermédiaire que le programme a fait pour y arriver. Prends un classifieur de sentiments. Ton dataset brut contient uniquement des avis clients et un label positif ou négatif. Ton programme DSPy demande au modèle de langage d'utiliser un raisonnement en chain-of-thought avant de sortir le sentiment. Lors du bootstrapping, le teacher lit un avis et rédige un paragraphe de raisonnement avant de deviner le sentiment. Si la prédiction finale correspond au vrai label, ce raisonnement généré est considéré comme un succès. L'optimizer collecte ces traces réussies. Il en prend quatre et les injecte dans les futurs prompts. Ton classifieur zero-shot est maintenant un classifieur expert en four-shot, complet avec des étapes de raisonnement synthétisées. BootstrapFewShot s'arrête une fois qu'il a trouvé assez de traces réussies. Mais les premières traces réussies ne sont pas toujours les meilleures. Voici l'idée clé. BootstrapFewShotWithRandomSearch résout ça en exécutant tout le processus de bootstrap plusieurs fois. À chaque fois, il tire un sous-échantillon au hasard de tes données d'entraînement. Ça crée plusieurs sets candidats différents de démonstrations few-shot. L'optimizer prend ensuite tous ces sets candidats et les évalue par rapport à tes données de validation. Il teste quelle combinaison spécifique de démonstrations donne le meilleur score global. Il élimine les sets faibles et garde le gagnant mathématique. La vraie puissance du few-shot learning automatique, ce n'est pas juste de te faire gagner du temps pour écrire des prompts, mais de découvrir des chemins de raisonnement intermédiaires réussis que ton dataset ne contenait jamais explicitement. Merci pour ton écoute, happy coding à tous !
10

Optimisation des instructions avec MIPROv2

3m 32s

Plongez dans le réglage automatique des instructions. Cet épisode explore MIPROv2 et COPRO, montrant comment DSPy utilise l'optimisation bayésienne et la montée de coordonnées pour découvrir des instructions de prompt supérieures et contre-intuitives.

Télécharger
Salut, ici Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 10 sur 15. Parfois, l'instruction la plus efficace pour un modèle de langage semble incompréhensible pour un humain. Tu passes des heures à peaufiner la formulation parfaite, pour finalement constater qu'un prompt automatisé, même légèrement décousu, surpasse complètement ton travail. C'est pourquoi tu devrais laisser les algorithmes écrire tes prompts. On s'intéresse à l'Instruction Optimization avec MIPROv2. D'abord, oublie le prompt templating. Il ne s'agit pas d'injecter des variables dans une string statique. L'optimisation des instructions réécrit en réalité les instructions systémiques qui régissent ton pipeline. Les algorithmes précédents, comme COPRO et SIMBA, abordaient ce problème en générant des variations de prompts étape par étape et en les affinant avec le temps. MIPROv2 pousse ce concept beaucoup plus loin en traitant les instructions et les exemples few-shot comme un espace de recherche unifié. MIPROv2 fonctionne en trois étapes distinctes. La première étape est le bootstrapping. L'optimizer exécute ton programme non optimisé sur tes données d'entraînement pour construire un ensemble de traces d'exécution. Ces traces contiennent les inputs, les étapes intermédiaires et les outputs réels qui circulent dans ton système. La deuxième étape est la grounded proposal. L'optimizer ne devine pas les nouvelles instructions à l'aveugle. Il utilise un modèle de langage distinct, appelé le prompter, pour analyser ces traces générées. En analysant où ton pipeline a réussi et où il a échoué, le prompter prépare un ensemble de nouvelles instructions candidates. Ces candidates sont directement ancrées dans le comportement réel de ton programme, et non dans des templates génériques. La troisième étape est la discrete search. MIPROv2 évalue les nouvelles instructions avec différentes combinaisons de traces few-shot. Pour faire ça efficacement, il s'appuie sur l'optimisation bayésienne. Au lieu de brute-forcer toutes les combinaisons possibles, MIPROv2 construit un surrogate model. Ce surrogate model agit comme un proxy léger. Il prédit quelles combinaisons d'instructions et de traces donneront le meilleur score sur ta métrique d'évaluation spécifique. L'optimisation bayésienne permet au surrogate model de cartographier l'espace des prompts et des démonstrations. Elle calcule l'amélioration attendue en testant une nouvelle combinaison. Ça équilibre systématiquement l'exploration d'instructions non testées et l'exploitation des combinaisons qui ont déjà un bon score. L'optimizer cible la configuration optimale sans exécuter des milliers d'appels réseau redondants. Prenons un exemple concret. Tu construis un agent ReAct pour répondre à des requêtes complexes. Initialement, sa précision est de 24 %. Tu passes cet agent dans MIPROv2, tu le configures pour tourner en light mode, et tu fournis un dataset de 500 questions. L'optimizer bootstrap des traces, propose des grounded instructions, et explore l'espace en utilisant le surrogate model. Quand il a terminé, la précision de ton agent passe de 24 % à 51 %. Le prompt final à l'origine de ce bond de performance contiendra probablement des instructions et des sélections de traces qu'un humain n'aurait jamais rédigées. Voici l'idée clé. MIPROv2 élimine le bottleneck de l'intuition humaine. Il traite tes instructions en langage naturel exactement comme des poids ajustables dans un modèle mathématique, transformant la création de prompts d'une forme d'art imprévisible en un problème d'optimisation déterministe. Merci d'avoir écouté, happy coding à tous !
11

Finetuning avec BootstrapFinetune

3m 23s

Découvrez comment distiller des modèles de langage massifs en modèles plus petits et efficaces. Cet épisode couvre BootstrapFinetune, expliquant comment convertir un programme DSPy basé sur des prompts en un modèle personnalisé avec mise à jour des poids.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 11 sur 15. Le prompting de modèles massifs est super pour lancer un prototype. Mais quand cette logique passe en production, la latence et le coût d'un modèle à soixante-dix milliards de paramètres deviennent vite un problème. Tu as besoin de la puissance de raisonnement du grand modèle, mais avec la vitesse et le prix d'un modèle à huit milliards de paramètres. C'est exactement ce que gère BootstrapFinetune. BootstrapFinetune compile ton programme DSPy en un modèle fine-tuné. C'est l'optimisation ultime pour gagner en efficacité. Il met à jour les poids réels d'un modèle cible plus petit pour imiter exactement le comportement de ton pipeline lourd. On pense souvent à tort que pour fine-tuner un modèle, tu dois rassembler manuellement des milliers d'exemples, les formater dans des fichiers JSONL fastidieux, et surveiller une training loop. BootstrapFinetune automatise complètement tout ça. Il gère la génération du dataset, le formatage et la mise à jour des poids, entièrement grâce aux traces d'exécution de ton programme. Prends un scénario concret avec un classifieur d'intentions bancaires. Le programme prend un message client un peu brouillon et le catégorise. Au début, tu construis un module DSPy en utilisant un modèle très performant comme GPT-4o-mini, configuré pour utiliser le chain-of-thought. Le modèle réfléchit étape par étape à la formulation du client avant de sortir l'intention. Il obtient les bonnes réponses, mais il est trop lent et trop cher pour un chat en temps réel. Pour optimiser ça, tu initialises BootstrapFinetune. Tu lui donnes ta métrique d'évaluation pour mesurer le succès, et tu spécifies le modèle cible, plus petit et moins cher, que tu veux deploy. Ensuite, tu compiles le programme. Quand tu lances la compilation, DSPy fait tourner ton programme non optimisé sur tes données de training. Il utilise le modèle teacher, plus lourd, pour générer les outputs. L'optimizer observe cette exécution. À chaque fois que le modèle teacher obtient la bonne réponse selon ta métrique, BootstrapFinetune capture la trace. Il enregistre les inputs, le raisonnement étape par étape, et l'output final. Il mappe la logique interne du modèle massif dans un format que le petit modèle cible peut ingérer. Une fois qu'assez de traces réussies sont collectées, BootstrapFinetune les structure automatiquement en un dataset de training. Il déclenche ensuite le processus de fine-tuning sur ton modèle cible. Le petit modèle est entraîné directement sur les chemins de raisonnement de haute qualité générés par le grand modèle. Voici l'idée clé. Le modèle plus petit apprend la distribution spécifique de la tâche et le style de raisonnement requis pour la résoudre, sans avoir à exécuter le lourd chain-of-thought au moment de l'inférence. Dans notre exemple de classifieur bancaire, un petit modèle standard pourrait n'atteindre que soixante-six pour cent d'accuracy de base. Mais après la compilation avec BootstrapFinetune, ce même petit modèle grimpe à quatre-vingt-sept pour cent d'accuracy. Le fine-tuning n'est plus un projet d'infrastructure à part ; c'est simplement une autre étape de compilation qui transforme un pipeline de raisonnement coûteux en un atout de production rapide et pas cher. Merci d'avoir écouté, happy coding à tous !
12

Utilisation automatisée d'outils avec ReAct

3m 30s

Apprenez à donner aux modèles de langage l'accès à des outils externes. Cet épisode couvre le module dspy.ReAct, démontrant comment construire des agents autonomes qui raisonnent et interagissent dynamiquement avec des APIs.

Télécharger
Bonjour, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 12 sur 15. Donner à un LLM l'accès à des API externes le rend incroyablement puissant, mais écrire la boucle pour gérer son raisonnement, parser les outputs, et récupérer des erreurs d'exécution est un véritable casse-tête. La solution, c'est l'utilisation entièrement automatisée de tools avec le module DSPy ReAct. On confond souvent ReAct avec du simple function calling. Le function calling est simplement le mécanisme d'API qui permet à un modèle de langage de formater son output sous forme de requête de données structurées. ReAct est un paradigme comportemental spécifique. Ça signifie Reason and Act. C'est une boucle d'exécution où le modèle parcourt trois étapes distinctes : un Thought, une Action, et une Observation. Le module DSPy ReAct gère entièrement cette orchestration pour toi. Tu n'as pas à écrire la boucle d'exécution. Tu ne catch pas manuellement les exceptions d'API. ReAct wrap une signature DSPy et une liste de tools, transformant un prompt statique en un agent autonome. Pour l'utiliser, tu définis d'abord tes tools. Dans DSPy, les tools sont simplement des fonctions Python standard. Tu écris une fonction, tu définis ses paramètres d'input, et tu fournis une docstring claire. Cette docstring est critique. DSPy extrait le nom de la fonction et la docstring, puis les passe au modèle de langage pour qu'il sache exactement ce que fait le tool et quand le deploy. Imagine un scénario où tu construis un agent de recherche et de météo basique. Tu écris une fonction Python nommée get weather qui accepte un nom de ville comme string et requête une API pour retourner la température actuelle. Tu instancies le module dspy dot ReAct, en lui passant une signature question-réponse standard avec une liste contenant ta fonction get weather. Quand tu demandes au module quelle est la météo à Tokyo, la boucle ReAct commence. D'abord, le modèle génère un Thought. Il raisonne qu'il a besoin des données météorologiques actuelles pour Tokyo. Ensuite, il génère une Action. Il décide d'appeler ton tool get weather, en passant Tokyo comme argument. Voici le point clé. Tu n'exécutes pas cette fonction toi-même. Le module DSPy ReAct intercepte l'Action du modèle, exécute ta fonction Python en arrière-plan, et capture l'output. Si la fonction réussit, DSPy renvoie les données de température au modèle comme une Observation. Si le modèle hallucine un paramètre ou si la fonction throw une erreur Python, DSPy catch cette erreur et renvoie le message d'erreur comme Observation. Le modèle lit l'erreur, génère un nouveau Thought pour corriger son erreur, et essaie une nouvelle Action. Une fois que le modèle observe les bonnes données de température, il reconnaît que son but est atteint. Il sort de la boucle et formate la réponse finale pour l'utilisateur. Pour éviter les exécutions infinies, ce cycle est strictement limité par un paramètre appelé max iters, qui signifie maximum iterations. Ce paramètre dicte combien de cycles de Thought, Action, et Observation le module est autorisé à faire. Si le modèle a du mal à trouver les bonnes données et atteint la limite d'itérations, ReAct le force à arrêter de chercher et à générer une réponse finale en utilisant uniquement les informations qu'il a réussi à collecter. La vraie puissance de ce module, c'est qu'il abstrait le control flow fragile et sujet aux erreurs des boucles d'agents, te permettant de traiter le raisonnement complexe augmenté par des tools comme un simple composant prévisible de plus dans ton pipeline. Merci d'avoir écouté, et happy coding tout le monde !
13

Gestion manuelle des outils pour plus de contrôle

3m 35s

Prenez le contrôle total sur l'exécution des outils. Cet épisode couvre la gestion manuelle des outils dans DSPy en utilisant dspy.Tool, dspy.ToolCalls, et l'appel de fonctions natif pour les applications sensibles à la latence.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 13 sur 15. Les agents automatisés sont super quand tu as une tâche un peu floue ou ouverte. Mais quand tu as besoin d'un contrôle absolu et déterministe sur comment, quand, et si une fonction externe est déclenchée, laisser complètement le volant au modèle de langage est trop risqué. Tu dois soulever le capot et gérer l'exécution toi-même. C'est exactement là que le manual tool handling entre en jeu pour garder le contrôle. Utiliser une boucle d'agent automatisé abstrait la couche d'exécution, ce qui peut causer une latence imprévisible ou cacher des erreurs au runtime. La gestion manuelle est l'alternative pour les power-users. Ça te redonne le contrôle sur la récupération des erreurs, les limites de timeout et l'ordre exact d'exécution. Pour construire ça dans DSPy, tu commences par wrapper une fonction Python standard en utilisant la classe dspy point Tool. Imagine que tu as une fonction Python qui sert de calculatrice pour multiplier deux nombres. Tu passes cette fonction dans dspy point Tool. Si ta fonction gère des requêtes de base de données ou des requêtes réseau, tu peux aussi wrapper des fonctions asynchrones, et la classe Tool gérera l'exécution async nativement. Une fois que ton tool de calculatrice est prêt, tu dois l'exposer au modèle de langage. Tu fais ça en passant une liste qui contient ton tool directement dans un module Predict de DSPy. Tu définis un paramètre appelé tools dans ton appel à Predict. Quand le modèle traite l'input, il évalue le prompt et décide s'il a besoin de la calculatrice pour générer la réponse finale. Quand le modèle décide d'utiliser ton tool, il s'appuie sur un mécanisme sous-jacent appelé un Adapter. Par défaut, DSPy utilise un JSONAdapter. Cet Adapter traduit automatiquement ton tool Python dans le format de function calling natif requis par l'API du modèle de langage spécifique que tu utilises. Ça garantit que le modèle sort un JSON structuré et fiable quand il requête un tool. Fais bien attention à cette partie. C'est facile de supposer qu'utiliser le tool calling natif produit automatiquement des outputs de meilleure qualité. La documentation de DSPy prévient explicitement que c'est une idée fausse. Le tool calling natif offre une meilleure fiabilité pour la syntaxe de la requête, mais ça ne garantit pas une meilleure qualité de raisonnement qu'un parsing basé sur du texte standard. Le modèle n'est pas soudainement plus intelligent juste parce qu'il formate du JSON. Comme tu gères ce processus manuellement, le modèle ne lance pas vraiment la calculatrice. Il s'arrête et retourne une réponse contenant son intention. Tu accèdes à cette intention en inspectant response outputs point tool calls. Cette propriété retourne un objet dspy point ToolCalls, qui se comporte comme une liste d'instructions. Chaque élément de cette liste spécifie quel tool le modèle veut utiliser et les arguments exacts qu'il a générés, comme cinq et dix pour la calculatrice. Ensuite, tu écris une boucle Python standard pour itérer sur ces tool calls demandés. Pour chaque appel, tu invoques manuellement sa méthode execute. Invoquer execute déclenche ton vrai code Python en utilisant les arguments générés par le modèle et retourne le résultat. Si les arguments sont invalides, ou si la calculatrice lève une erreur, ta boucle Python l'attrape. Tu gères l'échec à ta façon, plutôt que d'espérer qu'une boucle automatisée récupère toute seule. Le manual tool handling sépare proprement la décision du modèle de demander une action, de l'exécution physique de cette action, ce qui donne à ton application la fiabilité déterministe que les environnements de production exigent. Merci d'avoir écouté, happy coding tout le monde !
14

Intégration d'outils avec MCP

3m 25s

Connectez vos agents à des serveurs d'outils universels. Cet épisode explique comment utiliser le Model Context Protocol (MCP) dans DSPy pour exploiter des outils standardisés à travers différents frameworks avec une configuration minimale.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 14 sur 15. À chaque fois que tu adoptes un nouveau framework d'IA, tu finis généralement par réécrire les mêmes wrappers Python custom pour tes requêtes de base de données, tes recherches web et tes lecteurs de fichiers. Au lieu de maintenir une infinité de wrappers d'API dupliqués, imagine si tes agents pouvaient se connecter instantanément à des serveurs de tools universels et standardisés ? C'est la promesse du Model Context Protocol, et aujourd'hui, on va regarder l'intégration de tools avec MCP. Le Model Context Protocol est un standard ouvert introduit par Anthropic. Il offre une méthode universelle pour connecter les modèles d'IA à des sources de données et des tools externes. En adoptant ce standard, les développeurs écrivent un tool une seule fois, l'hébergent sur un serveur MCP et l'utilisent avec n'importe quel framework compatible. DSPy supporte ça nativement. Tu n'as pas besoin d'écrire des classes d'adapter complexes pour intégrer ces tools externes dans tes programmes DSPy. On croit souvent à tort que DSPy gère lui-même les connexions serveur sous-jacentes vers ces tools. Ce n'est pas le cas. DSPy s'appuie entièrement sur le package Python officiel mcp pour gérer le réseau et établir la connexion. DSPy intervient uniquement à la toute fin pour convertir l'objet tool MCP actif vers un format de tool DSPy natif. Pour voir comment ça marche, regardons comment connecter un serveur de tools local à un agent DSPy. D'abord, tu as besoin d'un serveur MCP qui tourne. Dans ton script Python, tu importes la classe des paramètres du serveur depuis le package MCP. Si tu fais tourner un process local, tu définis les paramètres serveur standard IO et tu pointes vers ton exécutable serveur. Sinon, si tes tools sont sur un serveur distant, tu configures une connexion HTTP client. Ces deux méthodes définissent comment ton application va parler au fournisseur de tools. Ensuite, tu utilises la library MCP pour ouvrir une session client. À l'intérieur de ce context de session, tu initialises la connexion. À ce stade, DSPy est encore complètement hors jeu. Tu demandes à la session MCP active de lister ses tools disponibles. Le serveur répond avec une liste d'objets tools. Chaque objet contient le nom du tool, une description de ce qu'il fait, et les arguments d'entrée attendus. Maintenant, tu fais le pont. C'est là que ça devient intéressant. Pour chaque tool renvoyé par le serveur, tu appelles la méthode from mcp tool sur la classe de base DSPy Tool. Tu passes à cette méthode deux arguments spécifiques : l'objet tool brut, et la session client active. Cette simple commande lit le schema fourni par le serveur MCP et le wrap instantanément dans une interface compatible. Tu as maintenant une liste de tools DSPy natifs prête à l'emploi. Enfin, tu passes cette liste de tools fraîchement convertie à un agent. Tu initialises un module ReAct, et tu lui passes ton array de tools DSPy. Quand tu lances l'agent, il peut maintenant appeler les tools MCP externes de manière transparente. Les arguments circulent depuis le module ReAct, à travers le wrapper DSPy converti, sur la session client MCP jusqu'au serveur, et le résultat revient pour informer la prochaine étape de raisonnement. La vraie puissance de cette intégration, c'est le découplage. Tes modules DSPy peuvent accéder de manière sécurisée aux bases de données d'entreprise ou aux systèmes de fichiers locaux avec zéro code de wrapper custom, tout en garantissant que ce même serveur de tools reste complètement utilisable par des frameworks totalement différents. Merci d'avoir écouté, et happy coding à tous !
15

Ensembles et Méta-optimisation

3m 15s

Poussez DSPy dans ses retranchements. L'épisode final couvre les transformations de programmes via dspy.Ensemble et le méta-optimizer expérimental BetterTogether, qui combine le réglage de prompts avec le finetuning des poids pour des performances maximales.

Télécharger
Salut, c'est Alex de DEV STORIES DOT EU. Apprendre DSPy, épisode 15 sur 15. Que se passe-t-il quand tu combines l'optimisation bayésienne de prompt avec le weight fine-tuning en deep learning ? Tu arrêtes de traiter le prompt engineering et le model training comme des étapes isolées, et tu commences à les voir comme un pipeline continu. C'est là que tu atteins la pointe de l'AI engineering automatisé, en t'appuyant sur les Ensembles et la Meta-Optimization. Il faut qu'on clarifie un truc tout de suite. Quand tu entends le mot ensemble, tu penses probablement au fait de requêter cinq foundation models différents en même temps. Dans DSPy, un ensemble, c'est complètement autre chose. Ici, un ensemble signifie faire tourner plusieurs programmes optimisés sur le même language model sous-jacent. Ça combine différentes structures de prompt et différentes reasoning traces pour agréger leurs outputs. La logique ici est super simple. Pendant un run d'optimisation profonde, différentes configurations découvrent souvent des reasoning paths distincts, mais tout aussi valides, pour arriver à la bonne réponse. Disons que tu viens de lancer l'optimizer MIPROv2. Il évalue des centaines de configurations et garde un historique des plus performantes. Au lieu de choisir le seul programme avec le meilleur score et de jeter le reste, tu extrais le top cinq des programmes candidats. Tu les passes dans la transformation DSPy Ensemble. Quand un nouvel input arrive, l'ensemble exécute les cinq programmes. Il agrège leurs outputs, généralement via un majority voting, et renvoie une réponse finale ultra robuste. En gros, tu scales ton compute au moment de l'inference pour garantir un résultat de meilleure qualité. Faire tourner un ensemble de cinq programmes sur un énorme foundation model te donne une précision incroyable, mais c'est cher et lent. C'est là que les meta-optimizers entrent en jeu. Un meta-optimizer gère l'exécution d'autres optimizers, en les séquençant pour cumuler leurs bénéfices. Le meilleur exemple dans DSPy, c'est BetterTogether. BetterTogether empile les améliorations de manière systématique. Il te permet de prendre la capacité de reasoning massive de ton ensemble et de la distiller dans un modèle rapide et fine-tuné. D'abord, tu configures BetterTogether pour utiliser l'optimisation de prompt afin de générer des reasoning traces d'une qualité exceptionnelle à partir de ton ensemble lourd. Ensuite, il passe automatiquement ces traces à un weight optimizer. Le weight optimizer utilise ces données pour fine-tuner les paramètres d'un student model beaucoup plus petit et moins cher. Enfin, BetterTogether peut lancer un deuxième round d'optimisation de prompt, en adaptant cette fois-ci les instructions spécifiquement aux nouveaux weights du student model. Tu passes donc de l'optimisation de prompt, à l'optimisation de weights, pour revenir à l'optimisation de prompt. L'output est un modèle rapide et ultra spécialisé qui a capturé les divers reasoning paths de l'ensemble d'origine, sans le coût d'inference massif. Empiler les techniques d'optimisation de façon séquentielle, c'est comme ça que tu fais le pont entre un reasoning lourd et coûteux, et une inference rapide et production-ready. Ça nous amène à la fin de la série. Je t'encourage vivement à explorer la documentation officielle de DSPy, à essayer de construire ces pipelines hands-on, ou à visiter devstories dot eu pour suggérer les prochains sujets que tu veux voir abordés. Merci d'avoir écouté, et happy coding tout le monde !