Tu suis la course aux modèles IA ?
Chaque sortie (GPT, Claude, Gemini, Mistral…) décryptée le soir même, en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisis ton rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Modèles de Langage de Grande Taille
Les Modèles de Langage Récursifs (RLMs) sont en train de dominer tous les benchmarks de long contexte actuellement. Cet article explore ce que sont les RLMs, pourquoi ils réussissent si bien et comment ils se distinguent des conceptions d'agents existantes.
Étude de Cas
J'ai passé une bonne partie du mois dernier à implémenter des RLMs, à exécuter des benchmarks et à produire une vidéo tutorielle de 50 minutes à ce sujet. Au cours de ce processus, j'ai répondu à plus de 100 questions sur YouTube et X concernant les RLMs. Cet article résume ce que j'ai appris en répondant à ces questions et les nuances spécifiques des RLMs qui m'ont fait dire "eureka !"
La principale raison pour laquelle les RLMs semblent inaccessibles à beaucoup de gens est que certaines idées sont en réalité assez contre-intuitives par rapport aux méthodes existantes (comme ReAct, CodeAct, ou les sous-agents). La meilleure façon de comprendre les RLMs est d'abord de saisir où ces autres méthodes échouent et de réaliser la pièce manquante dans les harnais agentiques : l'idée de passer le contexte par référence, au lieu de le répliquer.
Expériences
Parmi toutes les expériences compliquées que j'ai menées, la plus éclairante a été celle où j'ai demandé à un RLM de :
- "Générer 50 noms de fruits et compter le nombre de R dans chacun, retourner sous forme de dictionnaire."
Une variation plus avancée (appelons-la Problème 2) était :
- "Générer un dictionnaire de différentes catégories : fruits, pays, animaux. Pour chaque catégorie, générer 50 noms et compter le nombre de R dans chacun, retourner sous forme de dictionnaire imbriqué."
Pour le problème 1, la sortie attendue est quelque chose comme :
{"strawberry": 3, "berry": 2, ... "grape": 1}
Et pour le problème 2, cela ressemble à :
"fruits": {"strawberry": 3, "berry": 2, ... "grape": 1, ...},
"countries": {"united states of america": 1, "russia": 1, ...},
"animals": {"kangaroo": 1, "tiger": 1, ... "deer": 1, ...}
Bien que cela puisse sembler trivial, la manière dont un RLM résout ce problème est fondamentalement différente des autres architectures comme ReAct ou CodeAct. Comprendre comment chaque méthode aborde ce problème ludique est essentiel pour apprécier la beauté des RLMs.
Le Paysage Agentique
Génération Directe
La première méthode est la génération directe. Le LLM "réfléchit" à la demande de l'utilisateur et génère de manière autorégressive un dictionnaire.
Problèmes avec cette approche :
- Le LLM n'a aucun moyen de vérifier s'il est mathématiquement correct.
- Le LLM sera probablement incorrect car, fondamentalement, le comptage d'alphabets n'est pas un problème de "prédiction du prochain mot".
- Les chances d'hallucination ou d'erreurs sont extrêmement élevées, même si le LLM sous-jacent est intelligent.
ReAct (Raisonnement et Action)
ReAct est une boucle de raisonnement et d'action où le LLM réfléchit d'abord au problème (chaîne de pensée) puis génère un appel d'outil. Dans le prompt système, nous passons une liste de "noms de fonctions" et des instructions sur la façon de les appeler.
Par exemple, vous pourriez donner un outil simple au LLM qui est juste :
def count_alphabets_in_word(word: string, alphabet: string) -> int
Avec cette idée, l'agent ReAct pourra :
- Générer une liste de noms de fruits.
- Utiliser l'outil pour passer chaque nom de fruit et recevoir l'entier de sortie.
- À partir de sa mémoire de sortie, reconstruire le dictionnaire des fruits et leur compte, puis retourner.
Le suivi d'une telle transaction ressemblerait à ceci :
Générer un dictionnaire avec 50 fruits et le nombre de 'r' dans chacun
<think> 50 noms de fruits sont : strawberry, berry, grape, ... </think>
count_alphabets_in_word("strawberry", "r")
# Tool_Out (exécute notre fonction)
count_alphabets_in_word("berry", "r") ## Appel d'outil exécuté !
# Tool_Out (exécute notre fonction)
<think> J'ai maintenant tout ce dont j'ai besoin dans mon historique de messages,
construisons ce dictionnaire </think>
{ "strawberry": 3, "berry": 2, .... }
Vous voyez quels sont les problèmes, n'est-ce pas ? D'abord, vous devez définir une fonction count_alphabet_in_r à l'avance pour ce cas d'utilisation spécifique. Si vous ne définissez pas de fonction, l'agent revient simplement à l'ancienne méthode (c'est-à-dire la génération directe des comptes d'alphabets) !
Cela garantit que le LLM a une idée de ce que devrait être la sortie, mais le LLM doit toujours générer les tokens un par un à partir de son historique de messages.
CodeAct
CodeAct permet au LLM d'écrire du code et de l'exécuter. Cela signifie que vous (l'humain) n'avez plus besoin d'écrire des outils exacts. Vous pouvez simplement donner au LLM la capacité d'écrire n'importe quel code Python et de l'exécuter dans un environnement terminal isolé, lire les résultats et générer la sortie.
Cela se déroulera comme suit :
Générer un dictionnaire avec 50 fruits et le nombre de 'r' dans chacun
<think> D'accord, écrivons un peu de code python pour cela. </think>
fruits = [ 'strawberry', 'berry', 'grape', .... ]
count_r = { k: sum(1 for c in fruit if c == 'r') for k, f in fruits }
print("Nombre de fruits : ", len(fruits)) print("Comptes : " , count_r) '
# Sortie d'outil (Sortie du terminal)
Nombre de fruits : 50
Les comptes sont : {"strawberry": 3, "berry": 2 ....}
<think> D'accord, j'ai lu la sortie du terminal,
laissons-moi l'écrire à nouveau pour retourner la sortie </think>
{ "strawberry": 3, "berry": 2, .... }
Règles de Base pour ReAct vs CodeAct
- Utilisez ReAct lorsque vous travaillez sur des produits étroits et que vous savez exactement quels outils l'IA doit utiliser pour résoudre un problème.
- Utilisez CodeAct lorsque le domaine est général.
Sous-agents
Les architectures de sous-agents sont assez simples. Il y a un agent principal, et il peut lancer de plus petits agents pour effectuer des sous-tâches. Chaque sous-agent est également un agent CodeAct qui exécute les tâches qui lui sont assignées et retourne la sortie à l'agent principal.
Le principal avantage de l'architecture de sous-agents est que l'agent principal ne souffre pas de la dégradation du contexte puisqu'il n'a pas besoin de se soucier du fonctionnement interne des sous-agents. C'est une boîte noire complète.
Nous avons déjà vu que l'architecture de sous-agents résoudra facilement le Problème 1 avec num_subagent = 0 (CodeAct classique), voyons donc comment cela fonctionnera sur le Problème 2.
Générer un dictionnaire de différentes catégories : fruits, pays, animaux. Pour chaque catégorie, générer 50 noms. Et compter le nombre de R dans chacun, retourner sous forme de dictionnaire imbriqué
<think> Appelons quelques sous-agents et divisons les tâches entre eux </think>
call_subagent("Retourner un dictionnaire de 50 noms de fruits et le nombre de r dans chacun")
# Sous-agent (Un nouveau module code-act)
{"strawberry": 3, "berry": 2 ....}
call_subagent("Retourner un dictionnaire de 50 noms de pays et le nombre de r dans chacun")
{"france": 1, "russia": 1 ....}
call_subagent("Retourner un dictionnaire de 50 noms d'animaux et le nombre de r dans chacun")
{"kangaroo": 1, "deer": 1 ....}
<think> J'ai des réponses de tous les sous-agents, maintenant je vais écrire le JSON final </think>
"fruits": { "strawberry": 3, "berry": 2, .... },
"countries": { "france": 1, "russia": 1 .... },
"animals": { "kangaroo": 1, "deer": 1 .... }
Nous avons fait beaucoup de progrès. CodeAct + Sous-agents peuvent écrire du code arbitraire pour des choses arbitraires, mais ils doivent toujours :
- LIRE l'intégralité du prompt utilisateur dans leur fenêtre de contexte.
- LIRE l'intégralité de la sortie des sous-agents dans leur fenêtre de contexte.
- ÉCRIRE de manière autorégressive.


