0Pricing
AI Engineering Academy · Leçon

La boucle d’exécution du code

Concevez la boucle écrire-exécuter-observer : l’agent génère du code, un exécuteur isolé l’exécute, stdout et stderr sont capturés puis renvoyés comme observations, et l’agent corrige les erreurs.

La boucle d’exécution du code est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.

Agents programmant : écrire et exécuter du code

Un agent d’exécution de code est un type particulier d’agent d’IA qui résout des problèmes en écrivant du code, en l’exécutant, en observant le résultat, puis en recommençant jusqu’à ce que la tâche soit terminée. Contrairement aux agents qui utilisent uniquement des outils prédéfinis, les agents programmant créent de nouveaux outils de calcul à la volée. Ils sont ainsi extrêmement flexibles : toute tâche qui peut être programmée peut être tentée par un agent programmant.

La boucle écrire-exécuter-observer

Le cœur d’un agent d’exécution de code est une boucle en trois étapes : Écrire — le LLM génère du code Python pour résoudre l’étape actuelle de la tâche. Exécuter — le code est exécuté dans un environnement isolé et stdout/stderr sont capturés. Observer — le résultat de l’exécution est renvoyé au LLM sous la forme d’une nouvelle observation, qu’il utilise pour décider de ce qu’il doit écrire ensuite. Cette boucle se poursuit jusqu’à la fin de la tâche ou jusqu’à ce qu’une limite d’itérations soit atteinte.

def code_execution_loop(task: str, max_iterations=10):
    messages = [
        {'role': 'system', 'content': 'You are a Python coding agent. Write code to solve tasks step by step.'},
        {'role': 'user', 'content': task}
    ]
    
    for i in range(max_iterations):
        # WRITE: LLM generates code
        response = llm.complete(messages)
        code = extract_code_block(response)
        
        if not code:
            return response  # LLM gave a final answer without code
        
        # EXECUTE: run the code
        output, error = execute_safely(code)
        
        # OBSERVE: feed output back
        observation = f'Output:\n{output}' if not error else f'Error:\n{error}'
        messages.append({'role': 'assistant', 'content': response})
        messages.append({'role': 'user', 'content': observation})
    
    return 'Max iterations reached'

Extraire des blocs de code de la sortie du LLM

Les LLM encadrent généralement le code généré dans des blocs de code Markdown délimités : ```python ... ```. Votre boucle d’exécution doit extraire le code de ces blocs de manière fiable avant de l’exécuter. Utilisez une expression rationnelle ou un analyseur simple pour trouver les blocs délimités et gérer les cas particuliers comme les accents graves imbriqués, plusieurs blocs de code dans une seule réponse ou du code sans indicateur de langage.

import re

def extract_code_block(response: str) -> str | None:
    # Match ```python ... ``` or ``` ... ```
    pattern = r'```(?:python)?\n(.*?)```'
    matches = re.findall(pattern, response, re.DOTALL)
    if not matches:
        return None
    # Return the LAST code block (often the most complete version)
    return matches[-1].strip()

# Test
sample_response = '''I will calculate the sum:\n\n```python\nnumbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))\n```'''
code = extract_code_block(sample_response)
print(repr(code))  # 'numbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))'

Capturer stdout et stderr

Lors de l’exécution de code généré par un agent, vous devez capturer à la fois stdout (la sortie normale) et stderr (les messages d’erreur et les traces d’exécution) afin de les renvoyer au LLM. Le module subprocess de Python constitue l’approche la plus simple : exécutez le code dans un processus distinct et capturez les deux flux. Définissez un délai d’expiration pour empêcher du code bloqué de paralyser l’agent.

import subprocess
import tempfile
import os

def execute_code(code: str, timeout_seconds=30) -> tuple[str, str]:
    # Write code to a temp file
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(code)
        tmp_path = f.name
    
    try:
        result = subprocess.run(
            ['python', tmp_path],
            capture_output=True,
            text=True,
            timeout=timeout_seconds
        )
        stdout = result.stdout[:5000]  # cap output length
        stderr = result.stderr[:2000]  # cap error length
        return stdout, stderr
    except subprocess.TimeoutExpired:
        return '', f'TimeoutError: code exceeded {timeout_seconds}s limit'
    finally:
        os.unlink(tmp_path)  # always clean up temp file

Gérer intelligemment les erreurs

Lorsque le code produit une erreur, le message d’erreur (trace d’exécution, type d’exception, numéro de ligne) est renvoyé au LLM sous forme d’observation. Le LLM analyse alors l’erreur et écrit du code corrigé. Pour l’aider à déboguer efficacement, incluez le texte exact de l’erreur dans l’observation, incluez la ligne de code à l’origine de l’erreur et demandez explicitement au LLM de la corriger avant de réessayer.

def format_error_observation(code: str, error: str) -> str:
    lines = code.split('\n')
    
    # Extract line number from traceback if available
    line_match = re.search(r'line (\d+)', error)
    error_context = ''
    if line_match:
        line_num = int(line_match.group(1))
        if 1 <= line_num <= len(lines):
            error_context = f'\nFailing line: {lines[line_num - 1].strip()}'
    
    return f'''Execution failed with error:{error_context}\n\n{error}\n\nPlease analyze the error and write corrected code.'''

# Usage in loop
output, err = execute_code(code)
if err:
    observation = format_error_observation(code, err)
else:
    observation = f'Output:\n{output}\n\nContinue with the next step or provide the final answer.'

Détecter la fin d’une tâche

La boucle d’exécution de code doit savoir quand s’arrêter. Les signaux courants de fin comprennent : le LLM renvoie une réponse sans bloc de code (uniquement une réponse en langage naturel), le LLM écrit un marqueur spécial comme # TASK_COMPLETE, le code produit un fichier de sortie que l’agent devait créer, ou une fonction de validation confirme que la sortie respecte les critères de réussite. Implémentez toujours une limite d’itérations comme solution de secours.

COMPLETION_MARKERS = ['TASK COMPLETE', 'FINAL ANSWER:', 'DONE:']

def is_task_complete(response: str, code: str | None, output: str, success_fn=None) -> bool:
    # Check for explicit completion markers
    for marker in COMPLETION_MARKERS:
        if marker in response.upper():
            return True
    
    # No code generated - LLM is done
    if code is None:
        return True
    
    # Custom success function (e.g., check output file exists)
    if success_fn and success_fn(output):
        return True
    
    return False

# Example success function
def report_was_generated(output: str) -> bool:
    import os
    return os.path.exists('analysis_report.pdf')

Transmettre des données entre les itérations

L’un des défis des boucles d’exécution de code est la persistance de l’état entre les itérations. Chaque bloc de code s’exécute dans un nouveau processus Python ; les variables définies lors d’une itération ne sont donc pas disponibles lors de la suivante. Parmi les solutions figurent l’écriture des données intermédiaires dans des fichiers, l’utilisation d’un processus persistant auquel le code est transmis au moyen de exec(), ou l’instruction explicite au LLM de redéfinir les variables nécessaires au début de chaque bloc de code.

# Strategy 1: Save to files between iterations
# Iteration 1: LLM writes
'''
import pandas as pd
df = pd.read_csv('data.csv')
df_cleaned = df.dropna()
df_cleaned.to_parquet('cleaned.parquet')  # save for next iteration
print('Cleaned rows:', len(df_cleaned))
'''

# Iteration 2: LLM reads previous output
'''
import pandas as pd
df = pd.read_parquet('cleaned.parquet')  # reload from file
result = df.groupby('category').sum()
result.to_csv('result.csv')
print(result.head())
'''

Structurer l’invite système

L’invite système d’un agent d’exécution de code doit apprendre au LLM à utiliser efficacement la boucle. Les éléments essentiels à inclure sont les suivants : comment écrire des blocs de code Python exécutables, comment vérifier les résultats intermédiaires avant de poursuivre, comment signaler la fin d’une tâche, quelles bibliothèques sont disponibles dans l’environnement isolé et quels chemins de fichiers l’agent est autorisé à lire et à modifier.

CODE_AGENT_SYSTEM_PROMPT = '''
You are a Python code execution agent. Solve tasks by writing and running code.

Rules:
1. Write ALL code inside ```python ... ``` blocks.
2. Write small, testable code blocks - do not try to do everything in one block.
3. When you see execution output, analyze it and decide whether to continue or fix errors.
4. Available libraries: pandas, numpy, matplotlib, requests, json, os, pathlib.
5. You can read/write files only in /workspace/ directory.
6. When the task is fully complete, say TASK COMPLETE and summarize the result.
7. If you are stuck after 3 attempts at the same error, say ESCALATE and explain the problem.
'''

Troncature de la sortie et gestion des jetons

Le code généré par un agent peut produire des sorties considérables : affichages de DataFrame, longues listes, journaux détaillés. Renvoyer l’intégralité de la sortie au LLM gaspille des jetons et peut dépasser la fenêtre de contexte. Veillez toujours à tronquer la sortie de l’exécution avant de l’ajouter à la conversation. Une bonne valeur par défaut est de 2 000 à 5 000 caractères, accompagnés d’une note indiquant que la sortie a été tronquée afin que le LLM sache qu’il peut rester des éléments à explorer.

MAX_OUTPUT_CHARS = 3000

def format_observation(stdout: str, stderr: str) -> str:
    if stderr:
        # Errors take priority - show full error
        return f'Error:\n{stderr[:MAX_OUTPUT_CHARS]}'
    
    if len(stdout) > MAX_OUTPUT_CHARS:
        truncated = stdout[:MAX_OUTPUT_CHARS]
        remaining = len(stdout) - MAX_OUTPUT_CHARS
        return f'{truncated}\n... [output truncated, {remaining} more characters]'
    
    return f'Output:\n{stdout}' if stdout else 'Code executed successfully (no output)'

La boucle de code en pratique

Un véritable agent d’exécution de code destiné à l’analyse de données peut effectuer 5 à 15 itérations pour charger un CSV, en explorer la structure, nettoyer les données, calculer des statistiques, générer un graphique et produire un rapport récapitulatif. Chaque itération s’appuie sur la précédente, le LLM adaptant son approche en fonction des valeurs et des formes réelles des données découvertes lors de l’exécution. Cette adaptation dynamique rend les agents programmant particulièrement puissants pour les tâches exploratoires.

Considérations de sécurité dans les boucles de code

Exécuter du code généré par un LLM sur votre infrastructure représente un risque de sécurité important. N’exécutez jamais le code d’un agent sans l’isoler dans un environnement sécurisé. Le LLM peut générer par inadvertance (ou à la suite d’une injection d’invite) du code qui supprime des fichiers, exfiltre des données, envoie des requêtes réseau à des services externes ou épuise les ressources du système. Exécutez toujours ce code dans un environnement isolé avec des limites strictes de ressources, des restrictions réseau et des limites d’accès au système de fichiers.

Vérification rapide

Vérifiez votre compréhension de la boucle d’exécution de code présentée dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que la boucle écrire-exécuter-observer est le modèle central des agents d’exécution de code ; que stdout et stderr issus de l’exécution sont renvoyés sous forme d’observations qui orientent la prochaine génération de code du LLM ; et que la troncature de la sortie ainsi que les limites d’itérations sont des mécanismes de sécurité essentiels. Nous allons maintenant explorer l’isolation de l’exécution de code avec Docker et RestrictedPython.

Questions Fréquemment Posées

La leçon « La boucle d’exécution du code » est-elle gratuite ?

Oui — le texte complet de « La boucle d’exécution du code » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « La boucle d’exécution du code » ?

Concevez la boucle écrire-exécuter-observer : l’agent génère du code, un exécuteur isolé l’exécute, stdout et stderr sont capturés puis renvoyés comme observations, et l’agent corrige les erreurs. Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?

Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « La boucle d’exécution du code » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?

Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. La boucle d’exécution du code
  2. Isoler l’exécution avec Docker et RestrictedPython
  3. Gérer l’état entre les étapes d’exécution
  4. Créer un agent d’analyse de données
← Retour à AI Engineering Academy