#
Construire des agents qui utilisent du code

Les agents à code sont le type d’agent par défaut dans `smolagents`. Ils génèrent des appels d’outils Python pour effectuer des actions, obtenant des représentations d’actions qui sont efficaces, expressives et précises.

Leur approche simplifiée réduit le nombre d’actions requises, simplifie les opérations complexes et permet la réutilisation de fonctions de code existantes. `smolagents` fournit un framework léger pour construire de tels agents en environ 1 000 lignes de code.

Graphique issu du papier Executable Code Actions Elicit Better LLM Agents

> Si vous voulez en savoir plus sur pourquoi les agents à code sont efficaces, consultez ce guide de la documentation smolagents.

##
Pourquoi les agents à code ?

Dans un processus d’agent multi-étapes, le LLM écrit et exécute des actions, impliquant généralement des appels d’outils externes. Les approches traditionnelles utilisent un format JSON pour spécifier les noms d’outils et les arguments sous forme de chaînes, que le système doit analyser pour déterminer quel outil exécuter.

Cependant, la recherche montre que les LLM d’appel d’outils fonctionnent plus efficacement avec du code directement. C’est un principe fondamental de `smolagents`, comme le montre le diagramme ci-dessus issu de Executable Code Actions Elicit Better LLM Agents.

Écrire des actions en code plutôt qu’en JSON offre plusieurs avantages clés :

- Composabilité : Combiner et réutiliser facilement des actions
- Gestion d’objets : Travailler directement avec des structures complexes comme des images
- Généralité : Exprimer toute tâche computationnellement possible
- Naturel pour les LLM : Du code de haute qualité est déjà présent dans les données d’entraînement des LLM

##
Comment fonctionne un agent à code ?

Le diagramme ci-dessus illustre comment `CodeAgent.run()` fonctionne, suivant le framework ReAct que nous avons mentionné dans l’Unité 1. L’abstraction principale pour les agents dans `smolagents` est un `MultiStepAgent` qui sert de bloc de construction principal. Comme nous le verrons dans un exemple ci-dessous, `CodeAgent` est un type spécial de `MultiStepAgent`.

Un `CodeAgent` effectue des actions à travers un cycle d’étapes (avec les variables existantes et les connaissances étant incorporées dans le contexte de l’agent) qui est conservé dans un journal d’exécution :

1. Le prompt système est stocké dans un `SystemPromptStep` et la requête utilisateur est enregistrée dans un `TaskStep`.

2. Ensuite, la boucle while suivante est exécutée :

   2.1 La méthode `agent.write_memory_to_messages()` écrit les logs de l’agent dans une liste de messages de chat lisibles par le LLM.

   2.2 Ces messages sont envoyés à un `Model` qui génère une complétion.

   2.3 La complétion est analysée pour extraire l’action, qui, dans notre cas, devrait être un extrait de code puisque nous travaillons avec un `CodeAgent`.

   2.4 L’action est exécutée.

   2.5 Les résultats sont enregistrés en mémoire dans un `ActionStep`.

À la fin de chaque étape, si l’agent inclut des appels de fonction (dans `agent.step_callback`), ils sont exécutés.

##
Voyons quelques exemples

> Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab.

Alfred planifie une fête au manoir de la famille Wayne et a besoin de votre aide pour s’assurer que tout se passe bien. Pour l’aider, nous appliquerons ce que nous avons appris sur le fonctionnement d’un `CodeAgent` multi-étapes.

Si vous n’avez pas encore installé `smolagents`, vous pouvez le faire en exécutant la commande suivante :

    pip install smolagents -U

Connectons-nous également au Hub d’Hugging Face pour avoir accès à l’API d’inférence Serverless.

    from huggingface_hub import login

    login()

###
Sélectionner une playlist pour la fête en utilisant smolagents

La musique est un élément essentiel d’une fête réussie ! Alfred a besoin d’aide pour sélectionner la playlist. Heureusement, `smolagents` nous couvre ! Nous pouvons construire un agent capable de rechercher sur le web en utilisant DuckDuckGo. Pour donner à l’accès à cet outil l’agent, nous l’incluons dans la liste des outils lors de la création de l’agent.

Pour le modèle, nous nous appuierons sur `InferenceClientModel`, qui fournit l’accès à l’API d’inférence Serverless d’Hugging Face. Le modèle par défaut est `"Qwen/Qwen2.5-Coder-32B-Instruct"`, qui est performant et disponible pour une inférence rapide, mais vous pouvez sélectionner depuis le Hub n’importe quel modèle compatible.

Exécuter un agent est assez simple :

    from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel

    agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel())

    agent.run("Recherche les meilleures recommandations musicales pour une fête au manoir des Wayne.")

Lorsque vous exécutez cet exemple, la sortie affichera une trace des étapes du workflow en cours d’exécution. Elle affichera également le code Python correspondant avec le message :

     ─ Executing parsed code: ────────────────────────────────────────────────────────────────────────────────────────
      results = web_search(query="best music for a Batman party")
      print(results)
     ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Après quelques étapes, vous verrez la playlist générée qu’Alfred peut utiliser pour la fête ! 🎵

###
Utiliser un outil personnalisé pour préparer le menu

Maintenant que nous avons sélectionné une playlist, nous devons organiser le menu pour les invités. Encore une fois, Alfred peut tirer parti de `smolagents` pour le faire. Ici, nous utilisons le décorateur `@tool` pour définir une fonction personnalisée qui agit comme un outil. Nous couvrirons la création d’outils plus en détail plus tard, donc pour l’instant, nous pouvons simplement exécuter le code.

Comme vous pouvez le voir dans l’exemple ci-dessous, nous allons créer un outil en utilisant le décorateur `@tool` et l’inclure dans la liste `tools`.

    from smolagents import CodeAgent, tool, InferenceClientModel

    # Outil pour suggérer un menu basé sur l'occasion
    @tool
    def suggest_menu(occasion: str) -> str:
        """
        Suggère un menu basé sur l'occasion.
        Args:
            occasion (str): Le type d'occasion pour la fête. Les valeurs autorisées sont :
                            - "casual": Menu pour une fête décontractée.
                            - "formal": Menu pour une fête formelle.
                            - "superhero": Menu pour une fête de super-héros.
                            - "custom": Menu personnalisé.
        """
        if occasion == "casual":
            return "Pizza, collations et boissons."
        elif occasion == "formal":
            return "Dîner 3 services avec vin et dessert."
        elif occasion == "superhero":
            return "Buffet avec nourriture énergétique et saine."
        else:
            return "Menu personnalisé pour le majordome."

    # Alfred, le majordome, préparant le menu pour la fête
    agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel())

    # Préparer le menu pour la fête
    agent.run("Prépare un menu formel pour la fête.")

L’agent s’exécutera pendant quelques étapes jusqu’à trouver la réponse. Préciser les valeurs autorisées dans la docstring aide à diriger l’agent vers les valeurs d’argument `occasion` qui existent et limite les hallucinations.

Le menu est prêt ! 🥗

###
Utiliser des imports Python à l’intérieur de l’agent

Nous avons la playlist et le menu prêts, mais nous devons vérifier un dernier détail crucial : le temps de préparation !

Alfred doit calculer quand tout serait prêt s’il commençait à préparer maintenant, au cas où ils auraient besoin de l’aide d’autres super-héros.

`smolagents` est spécialisé dans les agents qui écrivent et exécutent des extraits de code Python, offrant une exécution sécurisée.

En effet, l’exécution du code a des mesures de sécurité strictes : les imports en dehors d’une liste sûre prédéfinie sont bloqués par défaut. Cependant, vous pouvez autoriser des imports supplémentaires en les passant sous forme de chaînes dans `additional_authorized_imports`. Pour plus de détails sur l’exécution sécurisée du code, consultez le guide officiel.

Lors de la création de l’agent, nous utiliserons `additional_authorized_imports` pour permettre l’importation du module `datetime`.

    from smolagents import CodeAgent, InferenceClientModel
    import numpy as np
    import time
    import datetime

    agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime'])

    agent.run(
        """
        Alfred doit se préparer pour la fête. Voici les tâches :
        1. Préparer les boissons - 30 minutes
        2. Décorer le manoir - 60 minutes
        3. Mettre en place le menu - 45 minutes
        4. Préparer la musique et la playlist - 45 minutes

        Si nous commençons maintenant, à quelle heure la fête sera-t-elle prête ?
        """
    )

Ces exemples ne sont que le début de ce que vous pouvez faire avec les agents à code, et nous commençons déjà à voir leur utilité pour préparer la fête. Vous pouvez en apprendre davantage sur la façon de construire de tels agents dans la documentation de `smolagents`.

En résumé, `smolagents` se spécialise dans les agents qui écrivent et exécutent des extraits de code Python, offrant une exécution sécurisée. Il supporte à la fois les modèles de langage locaux et basés sur API, le rendant adaptable à divers environnements de développement.

###
Partager notre agent préparateur de fête personnalisé sur le Hub

Ne serait-il pas incroyable de partager notre propre agent Alfred avec le reste du monde ? En faisant cela, n’importe qui peut facilement télécharger et utiliser l’agent directement depuis le Hub, apportant l’ultime planificateur de fête de Gotham à portée de main ! Faisons-le ! 🎉

La bibliothèque `smolagents` rend cela possible en vous permettant de partager un agent complet avec la communauté et de télécharger ceux des autres pour une utilisation immédiate. C’est aussi simple que ce qui suit :

    # Changez pour votre nom d'utilisateur et nom de dépôt
    agent.push_to_hub('sergiopaniego/AlfredAgent')

Pour télécharger à nouveau l’agent, utilisez le code ci-dessous :

    # Changez pour votre nom d'utilisateur et nom de dépôt
    alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True)

    alfred_agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'")

Ce qui est également excitant, c’est que les agents partagés sont directement disponibles en tant que Spaces, vous permettant d’interagir avec eux en temps réel. Vous pouvez explorer d’autres agents ici.

Par exemple, l’AlfredAgent est disponible ici. Vous pouvez l’essayer directement ci-dessous :

Vous vous demandez peut-être comment Alfred a construit un tel agent en utilisant `smolagents` ? En intégrant plusieurs outils, il peut générer un agent comme suit. Ne vous inquiétez pas des outils pour l’instant, car nous aurons une section dédiée plus tard dans cette unité pour explorer cela en détail :

    from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool

    @tool
    def suggest_menu(occasion: str) -> str:
        """
        Suggère un menu basé sur l'occasion.
        Args:
            occasion: Le type d'occasion pour la fête.
        """
        if occasion == "casual":
            return "Pizza, collations et boissons."
        elif occasion == "formal":
            return "Dîner 3 services avec vin et dessert."
        elif occasion == "superhero":
            return "Buffet avec nourriture énergétique et saine."
        else:
            return "Menu personnalisé pour le majordome."

    @tool
    def catering_service_tool(query: str) -> str:
        """
        Cet outil renvoie le service de restauration le mieux noté à Gotham City.

        Args:
            query: Un terme de recherche pour trouver des services de restauration.
        """
        # Exemple de liste de services de restauration et leurs notes
        services = {
            "Gotham Catering Co.": 4.9,
            "Wayne Manor Catering": 4.8,
            "Gotham City Events": 4.7,
        }

        # Trouver le service de restauration le mieux noté (simuler le filtrage de requête de recherche)
        best_service = max(services, key=services.get)

        return best_service

    class SuperheroPartyThemeTool(Tool):
        name = "superhero_party_theme_generator"
        description = """
        Cet outil suggère des idées créatives de fête sur le thème des super-héros basées sur une catégorie.
        Il renvoie une idée de thème de fête unique."""

        inputs = {
            "category": {
                "type": "string",
                "description": "Le type de fête de super-héros (par ex., 'héros classiques', 'mascarade de méchants', 'Gotham futuriste').",
            }
        }

        output_type = "string"

        def forward(self, category: str):
            themes = {
                "classic heroes": "Gala de la Justice League : Les invités viennent habillés comme leurs héros DC préférés avec des cocktails thématiques comme 'Le Punch Kryptonite'.",
                "villain masquerade": "Bal des Voyous de Gotham : Une mascarade mystérieuse où les invités s'habillent en méchants classiques de Batman.",
                "futuristic Gotham": "Nuit Neo-Gotham : Une fête de style cyberpunk inspirée de Batman Beyond, avec des décorations néon et des gadgets futuristes."
            }

            return themes.get(category.lower(), "Idée de fête thématique non trouvée. Essayez 'héros classiques', 'mascarade de méchants', ou 'Gotham futuriste'.")

    # Alfred, le majordome, préparant le menu pour la fête
    agent = CodeAgent(
        tools=[
            DuckDuckGoSearchTool(),
            VisitWebpageTool(),
            suggest_menu,
            catering_service_tool,
            SuperheroPartyThemeTool(),
    	FinalAnswerTool()
        ],
        model=InferenceClientModel(),
        max_steps=10,
        verbosity_level=2
    )

    agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'")

Comme vous pouvez le voir, nous avons créé un `CodeAgent` avec plusieurs outils qui améliorent la fonctionnalité de l’agent, le transformant en l’ultime planificateur de fête prêt à partager avec la communauté ! 🎉

Maintenant, c’est à votre tour : construisez votre propre agent et partagez-le avec la communauté en utilisant les connaissances que nous venons d’apprendre ! 🕵️‍♂️💡

> Si vous souhaitez partager votre projet d’agent, créez un Space et taguez agents-course sur le Hub. Nous serions ravis de voir ce que vous avez créé !

###
Inspecter notre agent préparateur de fête avec OpenTelemetry et Langfuse 📡

Alors qu’Alfred peaufine l’agent, il se lasse de déboguer ses exécutions. Les agents, par nature, sont imprévisibles et difficiles à inspecter. Mais comme il vise à construire l’ultime agent préparateur de fête et à le déployer en production, il a besoin d’une traçabilité robuste pour la surveillance et l’analyse futures.

Encore une fois, `smolagents` vient à la rescousse ! Il adopte la norme OpenTelemetry pour instrumenter les exécutions d’agents, permettant une inspection et une journalisation transparentes. Avec l’aide de Langfuse et du `SmolagentsInstrumentor`, Alfred peut facilement suivre et analyser le comportement de son agent.

La configuration est simple !

D’abord, nous devons installer les dépendances nécessaires :

    pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents langfuse

Ensuite, Alfred a déjà créé un compte sur Langfuse et a ses clés API prêtes. Si vous ne l’avez pas encore fait, vous pouvez vous inscrire à Langfuse Cloud ici ou explorer des alternatives.

Une fois que vous avez vos clés API, elles doivent être correctement configurées comme suit :

    import os

    # Obtenez les clés pour votre projet depuis la page des paramètres du projet : https://cloud.langfuse.com
    os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..."
    os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..."
    os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 Région UE
    # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 Région US

Avec les variables d’environnement définies, nous pouvons maintenant initialiser le client Langfuse. `get_client()` initialise le client Langfuse en utilisant les identifiants fournis dans les variables d’environnement.

    from langfuse import get_client

    langfuse = get_client()

    # Vérifier la connexion
    if langfuse.auth_check():
        print("Le client Langfuse est authentifié et prêt !")
    else:
        print("L'authentification a échoué. Veuillez vérifier vos identifiants et l'hôte.")

Enfin, Alfred est prêt à initialiser le `SmolagentsInstrumentor` et commencer à suivre les performances de son agent.

    from openinference.instrumentation.smolagents import SmolagentsInstrumentor

    SmolagentsInstrumentor().instrument()

Alfred est maintenant connecté 🔌 ! Les exécutions de `smolagents` sont enregistrées dans Langfuse, lui donnant une visibilité complète sur le comportement de l’agent. Avec cette configuration, il est prêt à revisiter les exécutions précédentes et à affiner encore plus son agent préparateur de fête.

> Pour en savoir plus sur le traçage de vos agents et l’utilisation des données collectées pour évaluer leurs performances, consultez l’Unité Bonus 2.

    from smolagents import CodeAgent, InferenceClientModel

    agent = CodeAgent(tools=[], model=InferenceClientModel())
    alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True)
    alfred_agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'")

Alfred peut maintenant accéder aux logs ici pour les relire et les analyser.

> En fait, une erreur mineure s’est produite lors de l’exécution. Pouvez-vous la repérer dans les logs ? Essayez de suivre comment l’agent la gère et renvoie quand même une réponse valide. Voici le lien direct vers l’erreur si vous voulez vérifier votre réponse. Bien sûr, l’erreur a été corrigée entre-temps, plus de détails peuvent être trouvés dans cette issue.

Pendant ce temps, la playlist suggérée crée l’ambiance parfaite pour les préparatifs de la fête. Cool, non ? 🎶

Maintenant que nous avons créé notre premier Code Agent, apprenons comment nous pouvons créer des Tool Calling Agents, le deuxième type d’agent disponible dans `smolagents`.

##
Ressources

- Blog smolagents - Introduction à smolagents et aux interactions de code
- smolagents : Construire de bons agents - Meilleures pratiques pour des agents fiables
- Construire des agents efficaces - Anthropic - Principes de conception d’agents
- Partager des exécutions avec OpenTelemetry - Détails sur la façon de configurer OpenTelemetry pour suivre vos agents.

Update on GitHub