
Aller au-delà de la fenêtre contextuelle : les modèles de langage récursifs en action
le contexte est vraiment tout. La qualité des résultats d’un LLM est étroitement liée à la qualité et à la quantité d’informations que vous fournissez. Dans la pratique, de nombreux cas d’utilisation réels s’accompagnent de contextes massifs : génération de code sur de grandes bases de code, interrogation de systèmes de connaissances complexes ou même de longues discussions sinueuses lors de la recherche de la destination de vacances idéale (nous y sommes tous passés).
Malheureusement, les LLM ne peuvent fonctionner efficacement qu’avec un contexte limité. Et il ne s’agit pas seulement des limites strictes de la fenêtre contextuelle, surtout maintenant que les modèles frontières prennent en charge des centaines de milliers, voire des millions, de jetons. Et ces limites continuent de croître. Le plus grand défi est un phénomène connu sous le nom de pourriture du contexteoù les performances du modèle se dégradent à mesure que la longueur du contexte augmente.
Cet effet est clairement démontré dans l’article « RÈGLE : Quelle est la taille réelle du contexte de vos modèles de langage à contexte long ? » par Hsieh et al. Les auteurs présentent RULER, une nouvelle référence pour évaluer les performances dans un contexte long, et testent une gamme de modèles. Les résultats montrent une tendance cohérente : à mesure que la longueur du contexte augmente, les performances diminuent considérablement dans tous les modèles. Dans de nombreux cas, la longueur effective du contexte (où les performances restent comparables à celles de Llama 2–7B) ne représente qu’environ 50 % de la fenêtre de contexte annoncée, voire moins.

Dans leur récent article « Modèles de langage récursifs », Zhang et coll. proposent une approche prometteuse pour résoudre le problème de la pourriture du contexte. Dans cet article, j’aimerais examiner de plus près cette idée et explorer comment elle fonctionne dans la pratique, en tirant parti de la prise en charge récemment ajoutée par DSPy pour cette stratégie d’inférence.
Modèles de langage récursifs
Les modèles de langage récursifs (RLM) ont été introduits pour remédier à la dégradation des performances à mesure que la longueur du contexte augmente et pour permettre aux LLM de fonctionner avec des contextes très volumineux (jusqu’à deux ordres de grandeur au-delà de la fenêtre de contexte native du modèle). Cela devient de plus en plus important à mesure que nous adoptons les LLM pour les tâches impliquant le traitement de centaines de millions de jetons.
Il existe déjà plusieurs approches pour gérer les tâches à long terme. Le plus courant (quelque chose que vous avez probablement rencontré lors de l’utilisation d’agents de code comme Cursor) est résumé du contexte. Dans cette configuration, la conversation ou le contexte de travail est résumé à plusieurs reprises une fois qu’il approche de la limite de contexte du modèle. Dans la pratique, cependant, cela échoue souvent : des détails importants et des nuances subtiles des étapes précédentes ont tendance à se perdre à mesure que le modèle « oublie » les anciennes informations pour faire place à de nouveaux jetons.
Les modèles de langage récursifs adoptent une approche différente et étonnamment élégante. Au lieu de transmettre l’intégralité de l’invite au LLM à chaque fois, l’invite est traitée comme un ensemble de variables disponibles dans un environnement Python REPL (Read-Eval-Print Loop). Le modèle est équipé d’outils qui lui permettent d’inspecter ces variables ou de s’invoquer de manière récursive sur des fragments sélectionnés par programme.

En d’autres termes, les RLM encouragent le LLM à écrire du code qui construit ses propres sous-tâches, puis à résoudre ces sous-tâches en s’appelant de manière récursive. Cela déplace le fardeau de tout regrouper dans une seule invite vers une structuration du problème de manière à ce que le modèle puisse naviguer de manière plus fiable dans de grands contextes.
Les auteurs ont évalué leur approche sur plusieurs tâches à long terme, dans lesquelles les RLM ont fourni d’excellents résultats sur les modèles GPT-5 et Qwen-3.

Les résultats semblent extrêmement prometteurs. Les RLM (avec ou sans sous-appels) surpassent systématiquement les autres approches dans toutes les tâches. Voyons comment cela fonctionne en pratique.
Utiliser RLM en pratique
Un scénario courant dans lequel le contexte long brille vraiment est celui de répondre à des questions sur une vaste base de connaissances. C’est donc exactement ce que nous allons essayer ici. J’ai pris tous les articles que j’ai publiés sur Towards Data Science et les ai chargés dans un seul fichier Markdown. Étonnamment, cela représente près de 1,5 Mo de texte. Espérons que cela suffise pour que le modèle puisse creuser.
Heureusement, DSPy a récemment introduit une implémentation de l’approche d’inférence des modèles de langage récursifs. Cela signifie que nous n’avons pas besoin de construire quoi que ce soit nous-mêmes ; nous avons juste besoin de DSPy version 3.1.2 ou plus récente.
pip install dspy --upgrade
Commençons par charger l’ensemble de données.
with open('articles.md', 'r') as f:
articles = f.read()
Vérifions ensuite combien de jetons il contient.
import anthropic
client = anthropic.Anthropic(api_key=config['ANTHROPIC_API_KEY'])
# Count tokens for messages
token_count = client.messages.count_tokens(
model="claude-sonnet-4-5",
messages=[
{"role": "user", "content": articles}
]
)
print(f"Input tokens: {token_count.input_tokens}")
# Input tokens: 386768
Il y a près de 400 000 tokens dans notre contexte. Claude Sonnet 4.5 prend en charge une fenêtre contextuelle de 200 Ko, il n’est donc pas possible de traiter l’intégralité de l’ensemble de données en une seule invite. C’est exactement là que RLM devient utile.
Pour utiliser DSPy, nous devons d’abord configurer le modèle de langage. Comme indiqué précédemment, RLM s’appuie sur le code pour interagir avec l’invite, il fonctionne donc mieux avec les modèles dotés de fortes capacités de codage. Pour cette raison, j’utiliserai Claude dans cet exemple, car il est connu pour ses bonnes performances sur les tâches liées au code.
lm = dspy.LM('anthropic/claude-sonnet-4-5', api_key=config['ANTHROPIC_API_KEY'])
dspy.configure(lm=lm)
Ensuite, nous initialisons le RLM en spécifiant sa signature. Dans ce cas d’utilisation, je transmets l’ensemble complet des articles avec une question et j’attends du modèle qu’il extraie les tendances clés et les renvoie sous forme de liste de chaînes.
rlm = dspy.RLM('articles, question -> trends: list[str]')
Ici, j’utilise Claude Sonnet 4.5 à la fois pour le modèle principal et les sous-appels récursifs. DSPy vous permet également d’utiliser un modèle plus petit pour les sous-appels via le
sub_lmparamètre, ce qui peut aider à réduire les coûts.
Nous pouvons maintenant exécuter le RLM et accéder au trends champ dans la sortie.
output = rlm(
articles = articles,
question = '''What were the main AI trends of 2025 based on provided
articles? Pay attention to the content not only the titles.'''
)
print('\n'.join(output.trends))
# Agentic AI and Autonomous Systems: Self-reflection patterns, iterative improvement through feedback loops (Self-Refine, Reflexion, CRITIC), and LLMs as reasoning engines that can autonomously plan and execute tasks
# Multi-Agent AI Systems: Evolution from single agents to collaborative teams of specialized agents with distinct roles, using frameworks like LangGraph, CrewAI, and AutoGen for orchestration
# Context Engineering and RAG: Moving beyond static prompting to dynamic retrieval-augmented generation (RAG), adaptive memory systems, and self-improving contexts that learn from experience without retraining
# Standardization Protocols: Emergence of Model Context Protocol (MCP) for standardizing LLM-tool integrations and Agent Communication Protocol (ACP) for inter-agent communication, reducing integration complexity
# Tool-Using LLMs and Function Calling: LLMs equipped with ability to invoke external tools, execute SQL queries, browse web, and interact with APIs through structured function calling mechanisms
# Production-Ready AI Frameworks: Mature ecosystem including LangGraph, DSPy, LangChain, NeMo Agent Toolkit, CrewAI, and AutoGen, focused on moving from prototype to production with built-in observability
# LLM Evaluation and Observability: LLM-as-judge evaluation patterns, comprehensive metrics frameworks (Ragas, DeepEval, Evidently), trajectory evaluation, and continuous monitoring as essential production infrastructure
# Programming Over Prompting: Shift toward declarative, code-based AI development with frameworks like DSPy and configuration-driven approaches (YAML-based) replacing prompt engineering
# Framework Interoperability: Tools designed to integrate across multiple frameworks rather than create silos, enabling composable AI architectures that leverage best features from different ecosystems
# Local and Cost-Effective LLM Deployment: Running smaller efficient models locally (Llama, Ollama) to reduce API costs and enable experimentation, with focus on cost-quality-latency tradeoffs
# SQL Agents and Data Analysis Automation: LLM agents specialized in data analysis tasks, generating and executing SQL queries, with applications in replacing or augmenting traditional data analyst workflows
# Production Quality and Accuracy Enhancement: Techniques for improving LLM accuracy including chain-of-thought reasoning, structured outputs through function calling, and iterative refinement for business-critical applications
L’exécution a duré environ trois minutes et le résultat a été un résumé étonnamment plausible des thèmes principaux de mes articles. Cependant, nous ne sommes pas ici pour connaître les tendances elles-mêmes. La question la plus intéressante est de savoir comment RLM a réussi à faire cela en premier lieu. Alors creusons plus profondément.
RLM sous le capot
Naturellement, la partie la plus fascinante est de comprendre ce qui se passe réellement sous le capot.
Mise en œuvre du RLM
Comme indiqué précédemment, l’idée clé derrière les modèles de langage récursifs est que les contextes longs sont traités comme faisant partie d’un environnement externe, plutôt que d’être introduits directement dans le modèle comme une seule invite. Au lieu de cela, le LLM écrit du code Python pour inspecter, décomposer et appeler de manière récursive des sous-LLM sur des extraits de données plus petits.
À un niveau élevé, la mise en œuvre présente quelques caractéristiques essentielles :
- Il utilise un Python REPL (Read – Eval – Print Loop) en bac à sable qui permet au LLM d’explorer de grands contextes via l’exécution de code.
- Le LLM fonctionne dans une boucle agent familière : il écrit du code Python, observe le résultat, puis décide quoi faire ensuite.
- Il peut effectuer des sous-appels récursifs (s’appelant effectivement lui-même) à l’aide d’outils tels que
llm_query()etllm_query_batched()pour analyser sémantiquement des morceaux plus petits. - Une fois que le modèle est satisfait du résultat, il finalise le processus en appelant
SUBMIT()avec la sortie.
Invites
Pour vraiment comprendre comment cela fonctionne, je trouve utile d’inspecter les messages réels envoyés vers et depuis le LLM. DSPy facilite cela avec la commande suivante.
# Inspect the raw LLM calls - shows the actual prompts sent to the model
dspy.inspect_history(n=39)
Cela nous donne une visibilité complète sur ce qui a été partagé avec le modèle à chaque étape.
Commençons par le message système. Il définit les variables d’entrée disponibles pour le modèle (telles que spécifiées dans la signature RLM) et répertorie les fonctions que le modèle peut appeler, telles que printles appels LLM récursifs et les utilitaires de bibliothèque standard.
Notamment, le module RLM vous permet également d’exposer des fonctions personnalisées au Python REPL via le
toolsparamètre lors de l’initialisation du RLM. Dans cet exemple, je me suis uniquement appuyé sur les fonctions par défaut, mais dans des configurations plus avancées, cela peut constituer un point d’extension puissant.
Your input fields are:
1. `variables_info` (str): Metadata about the variables available in the REPL
2. `repl_history` (REPLHistory): Previous REPL code executions and their outputs
3. `iteration` (str): Current iteration number (1-indexed) out of max_iterations
Your output fields are:
1. `reasoning` (str): Think step-by-step: what do you know? What remains? Plan your next action.
2. `code` (str): Python code to execute.
All interactions will be structured in the following way, with the appropriate values filled in.
[[ ## variables_info ## ]]
{variables_info}
[[ ## repl_history ## ]]
{repl_history}
[[ ## iteration ## ]]
{iteration}
[[ ## reasoning ## ]]
{reasoning}
[[ ## code ## ]]
{code}
[[ ## completed ## ]]
In adhering to this structure, your objective is:
Given the fields `articles`, `question`, produce the fields `trends`.
You are tasked with producing the following outputs given the inputs `articles`, `question`:
- {trends} # note: the value you produce must adhere to the JSON schema: {"type": "array", "items": {"type": "string"}}
You have access to a Python REPL environment. Write Python code and it will be executed. You will see the output, then write more code based on what you learned. This is an iterative process.
Available:
- Variables: `articles`, `question` (your input data)
- `llm_query(prompt)` - query a sub-LLM (~500K char capacity) for semantic analysis
- `llm_query_batched(prompts)` - query multiple prompts concurrently (much faster for multiple queries)
- `print()` - ALWAYS print to see results
- `SUBMIT(trends)` - submit final output when done
- Standard libraries: re, json, collections, math, etc.
IMPORTANT: This is ITERATIVE. Each code block you write will execute, you'll see the output, then you decide what to do next. Do NOT try to solve everything in one step.
1. EXPLORE FIRST - Look at your data before processing it. Print samples, check types/lengths, understand the structure.
2. ITERATE - Write small code snippets, observe outputs, then decide next steps. State persists between iterations.
3. VERIFY BEFORE SUBMITTING - If results seem wrong (zeros, empty, unexpected), reconsider your approach.
4. USE llm_query FOR SEMANTICS - String matching finds WHERE things are; llm_query understands WHAT things mean.
5. MINIMIZE RETYPING (INPUTS & OUTPUTS) - When values are long, precise, or error-prone (IDs, numbers, code, quotes), re-access them via variables and parse/compute in code instead of retyping. Use small, targeted prints to sanity-check, but avoid manual copying when variables can carry the exact value.
6. SUBMIT ONLY AFTER SEEING OUTPUTS - SUBMIT ends the current run immediately. If you need to inspect printed output, run it in one step, review the result, then call SUBMIT in a later step.
You have max 50 sub-LLM calls. When done, call SUBMIT() with your output.
Jetons également un coup d’œil au premier message utilisateur envoyé au LLM. Cela donne au modèle un aperçu des variables d’entrée : leurs types, leurs longueurs (afin que le modèle sache combien de choses il peut lire en même temps) et un aperçu du contenu pour comprendre la structure.
[[ ## variables_info ## ]]
[1] «««
Variable: `articles` (access it in your code)
Type: str
Total length: 1,392,921 characters
Preview:
```
---
title: "Agentic AI from First Principles: Reflection"
date: "2025-10-24T12:00:00-05:00"
category: "Agentic AI"
read_time: "21 min read"
url: "https://towardsdatascience.com/agentic-ai-from-first-principles-reflection/"
---
Arthur C. Clarke's Third Law says that "*any sufficiently advanced technology is indistinguishable from magic*". That's exactly how a lot of today's AI frameworks feel. Tools like GitHub Copilot, Claude Desktop, OpenAI Operator, and Perplexity Comet are automating everyda...
```
»»»
[2] «««
Variable: `question` (access it in your code)
Type: str
Total length: 114 characters
Preview:
```
What were the main AI trends of 2025 based on provided articles? Pay attention to the content not only the titles.
```
»»»
[3] «««
Variable: `verbose` (access it in your code)
Type: bool
Total length: 4 characters
Preview:
```
True
```
»»»
[[ ## repl_history ## ]]
You have not interacted with the REPL environment yet.
[[ ## iteration ## ]]
1/20
Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## code ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
Voici la réponse initiale du modèle conforme au format spécifié dans le message utilisateur.
[[ ## reasoning ## ]]
I need to analyze articles to identify main AI trends of 2025. Let me start by exploring the data:
1. First, I'll examine the structure and content of the `articles` variable to understand what I'm working with
2. I'll need to look at multiple articles, not just titles, to understand the actual content
3. Then I'll use semantic analysis (llm_query) to extract and identify trends
4. Finally, I'll compile the trends into a list
Let me start by exploring the articles data to see its structure and get a sense of what's available.
[[ ## code ## ]]
# First, let's understand the structure of the articles
print("Type of articles:", type(articles))
print("\nLength of articles:", len(articles))
print("\n" + "="*80)
print("First 2000 characters:")
print(articles[:2000])
print("\n" + "="*80)
# Let's see if we can identify the structure - looks like articles are separated
# Let's try to split and count them
article_separator = "---\ntitle:"
article_parts = articles.split(article_separator)
print(f"\nNumber of article parts found: {len(article_parts)}")
print(f"First part length: {len(article_parts[0])} (likely empty or header)")
print(f"Second part length: {len(article_parts[1]) if len(article_parts) > 1 else 0}")
[[ ## completed ## ]]
Les journaux bruts nous ont donné une solide compréhension de la façon dont le LLM interagit avec l’environnement sous le capot. Examinons ensuite la trajectoire suivie par le LLM pour atteindre son résultat final.
Trajectoire
Pour une vue structurée de la trajectoire, nous pouvons inspecter output.trajectory. Cela donne accès à chaque étape du raisonnement du modèle, au code qu’il génère et aux résultats qui en résultent. Essentiellement, il fournit une vue complète de toutes les interactions REPL.
# Examine the full trajectory - this shows all REPL interactions
for i, step in enumerate(output.trajectory):
print(f"\n{'='*60}")
print(f"STEP {i+1}")
print(f"{'='*60}")
print(f"\n📝 REASONING:\n{step['reasoning']}")
print(f"\n💻 CODE:\n{step['code']}")
print(f"\n📤 OUTPUT:\n{step['output'][:1000]}{'...' if len(step['output']) > 1000 else ''}")
Vous pouvez également retrouver le journal complet sur GitHub.
L’examen de la trajectoire nous aide à comprendre les principaux modèles utilisés par le LLM pour résoudre le problème. Dans ce cas, il a fallu 13 étapes pour parvenir à la réponse finale.
La première étape, comme prévu, consistait à explorer articles variable : examiner sa structure et avoir une idée des données disponibles. Cette exploration initiale prépare le terrain pour tous les raisonnements et sous-appels ultérieurs.
# First, let's understand the structure of the articles
print("Type of articles:", type(articles))
print("\nLength of articles:", len(articles))
print("\n" + "="*80)
print("First 2000 characters:")
print(articles[:2000])
print("\n" + "="*80)
# Let's see if we can identify the structure - looks like articles are separated
# Let's try to split and count them
article_separator = "---\ntitle:"
article_parts = articles.split(article_separator)
print(f"\nNumber of article parts found: {len(article_parts)}")
print(f"First part length: {len(article_parts[0])} (likely empty or header)")
print(f"Second part length: {len(article_parts[1]) if len(article_parts) > 1 else 0}")
Ensuite, le LLM s’est rendu compte qu’il y avait 40 articles au total, chacun séparé par ---\ntitle:et que chaque article contenait des champs de métadonnées comme title, date, category, read_timeet urlsuivi du contenu principal. Le simple fait d’identifier cette structure à partir d’un fichier texte de 1,5 Mo constitue déjà une réussite significative.
S’appuyant sur cette compréhension, le LLM a ensuite analysé les articles et généré un résumé des titres des articles et des thèmes principaux.
# Parse articles into structured format
import re
# Split by the article separator
raw_articles = articles.split("---\ntitle:")
# Process each article (skip the first empty element)
parsed_articles = []
for i, raw_article in enumerate(raw_articles[1:], 1): # Skip first empty element
# Add back the "title:" that was removed by split
raw_article = "title:" + raw_article
# Extract metadata using regex
title_match = re.search(r'title:\s*"([^"]*)"', raw_article)
date_match = re.search(r'date:\s*"([^"]*)"', raw_article)
category_match = re.search(r'category:\s*"([^"]*)"', raw_article)
# Find where content starts (after the second "---")
content_start = raw_article.find("---", 10) # Skip the first part
content = raw_article[content_start+3:].strip() if content_start != -1 else ""
parsed_articles.append({
'index': i,
'title': title_match.group(1) if title_match else "Unknown",
'date': date_match.group(1) if date_match else "Unknown",
'category': category_match.group(1) if category_match else "Unknown",
'content': content,
'content_length': len(content)
})
print(f"Successfully parsed {len(parsed_articles)} articles\n")
print("="*80)
print("Sample of articles (titles and categories):")
print("="*80)
for i, article in enumerate(parsed_articles[:10], 1):
print(f"{i}. [{article['category']}] {article['title']}")
print(f" Content length: {article['content_length']} chars")
print()
Après avoir analysé les articles, le LLM a décidé de se concentrer exclusivement sur le contenu lié à l’IA, puisque la question portait spécifiquement sur les tendances de l’IA.
# Let's focus on AI-related articles (AI, Agentic AI, LLM Applications, ChatGPT categories)
# and sample strategically to understand content-based trends
ai_related = [a for a in parsed_articles if a['category'] in [
'Artificial Intelligence', 'Agentic AI', 'LLM Applications', 'ChatGPT', 'Deep Learning'
]]
Ensuite, le LLM a identifié les articles clés sur lesquels il souhaitait se concentrer. Il s’agissait d’une sélection subjective basée sur la pertinence et le contenu. Pour les analyser en détail, il a utilisé des sous-appels récursifs, traitant chaque article par programme.
Pour gérer efficacement la charge de travail, le LLM a divisé les articles en deux lots et les a traités séquentiellement. Pour chaque article, le contenu a également été tronqué aux 15 000 premiers caractères. Cette stratégie a permis au modèle de gérer un grand volume de texte sans dépasser sa fenêtre contextuelle, tout en capturant les informations les plus importantes de chaque article.
# Create prompts to extract AI trends from article content
# I'll include a substantial portion of each article's content for analysis
prompts_batch1 = []
for i, article in enumerate(selected_for_analysis[:8]): # First batch of 8
# Take first ~15K chars of content to stay within LLM limits while getting substance
content_sample = article['content'][:15000]
prompt = f"""Analyze this article about AI from 2025 and identify the main AI trends, technologies, methodologies, or concepts it discusses.
Article Title: {article['title']}
Article Content (excerpt):
{content_sample}
Based on the content above, list the key AI trends, technologies, or concepts discussed in this article. Focus on:
- New frameworks, tools, or methodologies mentioned
- Emerging patterns in AI development (e.g., agentic AI, multi-agent systems)
- Important techniques or approaches
- Production/deployment considerations
Provide a concise list of 3-5 main trends/concepts from this article."""
prompts_batch1.append(prompt)
print(f"Created {len(prompts_batch1)} prompts for first batch")
print("\nProcessing first batch of articles...")
# Query the first batch
results_batch1 = llm_query_batched(prompts_batch1)
print(f"\nReceived {len(results_batch1)} results")
print("\nResults from first batch:")
print("="*80)
for i, (article, result) in enumerate(zip(selected_for_analysis[:8], results_batch1), 1):
print(f"\n{i}. {article['title']}")
print("-"*80)
print(result)
print()
Enfin, le LLM a examiné une fois de plus la liste complète des articles, identifié des sujets pertinents supplémentaires et les a traités de la même manière à l’aide de sous-appels récursifs. Une fois toutes les informations récupérées, il a synthétisé les résultats dans le trends_2025 variable (une liste de chaînes représentant les principales tendances de l’IA) et l’a soumis comme réponse finale.
##### STEP 12 #####
# Now let me synthesize all findings into comprehensive AI trends
# I'll review all the results and create a structured summary
print("SYNTHESIZING ALL FINDINGS FROM 20 ANALYZED ARTICLES")
print("="*80)
print("\nBased on deep content analysis of 20 AI-focused articles from 2025,")
print("here are the main AI trends identified:\n")
# Compile the comprehensive list of trends
trends_2025 = [
"Agentic AI and Autonomous Systems: Self-reflection patterns, iterative improvement through feedback loops (Self-Refine, Reflexion, CRITIC), and LLMs as reasoning engines that can autonomously plan and execute tasks",
"Multi-Agent AI Systems: Evolution from single agents to collaborative teams of specialized agents with distinct roles, using frameworks like LangGraph, CrewAI, and AutoGen for orchestration",
"Context Engineering and RAG: Moving beyond static prompting to dynamic retrieval-augmented generation (RAG), adaptive memory systems, and self-improving contexts that learn from experience without retraining",
"Standardization Protocols: Emergence of Model Context Protocol (MCP) for standardizing LLM-tool integrations and Agent Communication Protocol (ACP) for inter-agent communication, reducing integration complexity",
"Tool-Using LLMs and Function Calling: LLMs equipped with ability to invoke external tools, execute SQL queries, browse web, and interact with APIs through structured function calling mechanisms",
"Production-Ready AI Frameworks: Mature ecosystem including LangGraph, DSPy, LangChain, NeMo Agent Toolkit, CrewAI, and AutoGen, focused on moving from prototype to production with built-in observability",
"LLM Evaluation and Observability: LLM-as-judge evaluation patterns, comprehensive metrics frameworks (Ragas, DeepEval, Evidently), trajectory evaluation, and continuous monitoring as essential production infrastructure",
"Programming Over Prompting: Shift toward declarative, code-based AI development with frameworks like DSPy and configuration-driven approaches (YAML-based) replacing prompt engineering",
"Framework Interoperability: Tools designed to integrate across multiple frameworks rather than create silos, enabling composable AI architectures that leverage best features from different ecosystems",
"Local and Cost-Effective LLM Deployment: Running smaller efficient models locally (Llama, Ollama) to reduce API costs and enable experimentation, with focus on cost-quality-latency tradeoffs",
"SQL Agents and Data Analysis Automation: LLM agents specialized in data analysis tasks, generating and executing SQL queries, with applications in replacing or augmenting traditional data analyst workflows",
"Production Quality and Accuracy Enhancement: Techniques for improving LLM accuracy including chain-of-thought reasoning, structured outputs through function calling, and iterative refinement for business-critical applications"
]
print("MAIN AI TRENDS OF 2025:")
print("="*80)
for i, trend in enumerate(trends_2025, 1):
print(f"\n{i}. {trend}")
print("\n" + "="*80)
print(f"\nTotal trends identified: {len(trends_2025)}")
print("\nThese trends are based on content analysis of articles covering:")
print("- Agentic AI systems and design patterns")
print("- Multi-agent architectures and frameworks")
print("- Production deployment and evaluation")
print("- Emerging protocols and standardization")
print("- Tool use and external system integration")
print("- Cost-effective and accurate LLM applications")
##### STEP 13 #####
# Submit the final list of AI trends from 2025
SUBMIT(trends_2025)
Nous pouvons voir que le modèle était assez créatif : il comprenait la structure de notre contenu, analysait les articles et utilisait des appels récursifs pour traiter chacun individuellement. Il y avait cependant une lacune importante dans cette analyse. Il a complètement négligé le filtrage par année, même si les métadonnées de chaque article contenaient clairement la date de publication.
Pour répondre à ce problème, j’ai réitéré la demande, en soulignant cette fois l’importance du filtrage pour 2025, afin de garantir que le modèle se concentre uniquement sur les articles de cette année-là.
output2 = rlm(
articles = articles,
question = '''What were the main AI trends of 2025 based on provided
articles? Pay attention to the content not only the titles.
Don\'t forget to filter by year, this information is present in
metadata for each article.'''
)
Cette fois, le modèle a pris en compte l’année et a effectué une analyse plus sophistiquée, en utilisant des expressions régulières pour extraire la date de publication de chaque article.
import re
from datetime import datetime
# Split articles by the separator "---" at the beginning of metadata blocks
# The pattern is: --- followed by metadata, followed by --- followed by content
article_blocks = re.split(r'\n---\n', articles)
print(f"Total article blocks found: {len(article_blocks)}")
print("\n" + "="*80)
# Let's examine the structure - articles seem to start with "---\ntitle:"
# Let me try a different approach - find all articles by their metadata pattern
article_pattern = r'---\ntitle: "(.*?)"\ndate: "(.*?)"\ncategory: "(.*?)"\nread_time: "(.*?)"\nurl: "(.*?)"\n---\n(.*?)(?=\n---\ntitle:|$)'
matches = re.findall(article_pattern, articles, re.DOTALL)
print(f"Articles found with regex: {len(matches)}")
if len(matches) > 0:
print("\nFirst article metadata:")
print(f" Title: {matches[0][0]}")
print(f" Date: {matches[0][1]}")
print(f" Category: {matches[0][2]}")
print(f" Content preview (first 200 chars): {matches[0][5][:200]}")
Ensuite, il a filtré les articles par année et identifié 13 articles de 2025.
# Parse articles and filter for 2025
articles_2025 = []
for match in matches:
title, date_str, category, read_time, url, content = match
# Extract year from date string (format: "2025-10-24T12:00:00-05:00")
year = date_str.split('-')[0]
if year == "2025":
articles_2025.append({
'title': title,
'date': date_str,
'category': category,
'content': content.strip()
})
print(f"Total articles: {len(matches)}")
print(f"Articles from 2025: {len(articles_2025)}")
print("\n" + "="*80)
print("2025 Articles:")
print("="*80)
for i, article in enumerate(articles_2025, 1):
print(f"\n{i}. {article['title']}")
print(f" Date: {article['date']}")
print(f" Category: {article['category']}")
print(f" Content length: {len(article['content'])} chars")
Ensuite, il a analysé ces 13 articles à l’aide de sous-appels récursifs et a produit une liste mise à jour des tendances. Cette fois, la tâche s’est déroulée correctement. Comme pour de nombreux autres exemples, il souligne l’importance de poser des questions claires et explicites et de préciser les critères et les actions que nous souhaitons que le modèle suive.
Agentic AI and Multi-Agent Systems: Building autonomous AI agents capable of multi-step reasoning, tool use, planning, and reflection, often with multiple specialized agents collaborating on complex tasks
Code Agents: AI agents that execute tool calls using actual code (Python) instead of JSON-based tool calling, enabling dynamic function creation and achieving higher success rates with fewer steps
Model Context Protocol (MCP): Anthropic's standardization protocol for connecting AI applications to external tools and data sources, reducing integration complexity from M*N to M+N and enabling reusable, framework-agnostic components
Agent Communication Protocol (ACP): Emerging open protocol under the Linux Foundation for standardizing communication between AI agents via RESTful APIs, enabling interoperability across different frameworks
Reflection and Self-Refinement Patterns: LLMs reviewing and improving their own outputs through iterative feedback loops, including self-feedback, verbal reinforcement learning, and tool-interactive critiquing, achieving 10-30% accuracy improvements
Framework Ecosystem Proliferation: Multiple competing frameworks including LangGraph, smolagents, CrewAI, DSPy, and NeMo Agent Toolkit, with growing emphasis on interoperability and declarative configuration approaches
Production-Ready LLM Infrastructure: Moving beyond prototypes to address 'day 2' problems like API exposure, observability, monitoring, evaluation frameworks, and deployment at scale
Parameter-Efficient Fine-Tuning (PEFT) and LoRA: Techniques for customizing LLMs by updating only small subsets of parameters, enabling task-specific optimization while reducing computational costs and enabling on-premises deployment
Advanced Fine-Tuning with Memory Experts: Lamini's Mixture of Memory Experts (MoME) using ~1 million LoRA adapters for near-perfect factual accuracy (95%) with zero loss on specific information
Shift from Prompting to Programming Paradigm: Frameworks like DSPy treating LLM tasks as modular programming rather than manual prompt crafting, with structured signatures and reusable components
LLM Evaluation and Quality Assurance: Comprehensive evaluation frameworks (Evidently, DeepEval, MLFlow, LangSmith) for testing, monitoring, and ensuring reliability in production, especially for regulated industries
RAG (Retrieval-Augmented Generation): Providing relevant context and knowledge bases to enhance LLM precision and enable specialized capabilities in agents
Tool Use and Orchestration: AI systems dynamically selecting and executing tools from multiple sources, with standardized tool definitions and safety controls
YAML-Based Declarative Configuration: Defining LLM workflows, models, and agent behavior through configuration files rather than purely code-based implementations
Interpretable AI and Rule-Based Systems: Using decision trees, extracted rules, and transparent models as alternatives to black-box approaches for compliance, explainability, and rapid deployment in regulated industries
Résumé
Il est temps de conclure et de réfléchir à ce que nous avons appris. Dans cet article, nous avons exploré RLM (Recursive Language Models) — une nouvelle stratégie d’inférence qui permet aux LLM de gérer des contextes jusqu’à deux ordres de grandeur plus grands que leur fenêtre de contexte standard, tout en atténuant le problème de pourriture du contexte.
Je suis vraiment fasciné par cette approche. L’article propose une méthode simple mais élégante pour traiter les invites comme des variables dans un environnement Python, qui me rappelle mon framework agent préféré, smolagents de HuggingFace. Je pense que cette méthode est particulièrement efficace car les LLM ont été formés sur tellement de code que la programmation leur semble être un langage natif. Utiliser le code comme interface de raisonnement et de récursivité est à la fois pratique et puissant.
Dans l’ensemble, les modèles de langage récursifs offrent un moyen pratique et élégant de repousser les limites de la longueur du contexte, rendant les LLM plus capables de gérer des tâches complexes et à grande échelle. Cependant, des instructions claires et des conseils réfléchis restent essentiels pour obtenir les meilleurs résultats.
Merci d’avoir lu. J’espère que cet article a été instructif. Rappelez-vous le conseil d’Einstein : « L’important est de ne pas cesser de remettre en question. La curiosité a sa propre raison d’exister. » Puisse votre curiosité vous conduire à votre prochaine grande découverte.
Référence
Cet article est basé sur l’article de Zhang et al., « Modèles de langage récursifs »publié le 31 décembre 2025.



