Implémentation d'un Agent IA de Zéro sans Framework

Nous allons explorer la mise en place d'un Agent Intelligence Artificielle (IA) à partir de zéro, en révélant les mécanismes fondamentaux et essentiels qui se cachent derrière les concepts d'agents.

Bien que les frameworks d'agents puissent sembler complexes, leur logique centrale est en réalité remarquablement simple, au point de paraître presque élémentaire. Dans cet article, nous allons implémenter un agent IA en utilisant uniquement Python et l'API d'OpenAI.

Méthode ReAct

Nous utiliserons la méthode ReAct (Reason - Act) pour construire notre agent IA. ReAct signifie "Raisonner - Agir".

Le processus peut être résumé comme suit :

  • • L'utilisateur pose une question
  • • L'IA analyse la question et réfléchit à une approche
  • • L'agent appelle des outils pour agir
  • • L'agent observe les résultats de ses actions
  • • Si la question est résolue, le processus se termine
  • • Sinon, l'agent réitère le processus de raisonnement jusqu'à résolution complète

La méthode ReAct, combinée à des instructions précises et à divers outils, constitue la base d'écosystèmes complexes comme LangChain, l'un des frameworks open source les plus connus dans ce domaine.

Mise en pratique

Commençons par importer les bibliothèques nécessaires :

import openai
import re
import httpx
import os
from dotenv import load_dotenv
import json

_ = load_dotenv()
from openai import OpenAI

Initialisons le client OpenAI :

client_ia = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

Vérifions rapidement le fonctionnement de base du modèle :

reponse = client_ia.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "Bonjour, comment allez-vous ?"}]
)
print(reponse.choices[0].message.content)

Classe de Base pour l'Agent

Implémentons maintenant une classe de base pour notre agent. Cette classe servira de fondation pour tous nos agents futurs :

class AssistantIntelligent:
    def __init__(self, instruction_systeme=""):
        self.instruction_systeme = instruction_systeme
        self.historique_messages = []
        if self.instruction_systeme:
            self.historique_messages.append({"role": "system", "content": self.instruction_systeme})

    def __call__(self, message_utilisateur):
        self.historique_messages.append({"role": "user", "content": message_utilisateur})
        resultat = self.executer_tache()
        self.historique_messages.append({"role": "assistant", "content": resultat})
        return resultat

    def executer_tache(self):
        completion = client_ia.chat.completions.create(
                        model="gpt-4", 
                        temperature=0,
                        messages=self.historique_messages)
        return completion.choices[0].message.content

Nous utilisons ici le modèle GPT-4 pour obtenir des raisonnements plus précis.

Définition des Instructions

Établissosn maintenant les instructions qui guideront notre agent dans son processus de réflexion et d'action :

instruction_principale = """
Vous opérez dans un cycle de réflexion, d'action, d'observation et de réponse.
À la fin de chaque cycle, vous devez fournir une réponse finale.

Utilisez la réflexion pour analyser la question posée et planifier votre approche.
Utilisez l'action pour exécuter une des fonctions disponibles disponibles.
Après chaque action, attendez le résultat de votre observation.

Les fonctions disponibles sont :

calculatrice:
Exemple: calculatrice: 15 * 4 / 2
Exécute un calcul mathématique et retourne le résultat en utilisant la syntaxe Python

poids_moyen_chien:
Exemple: poids_moyen_chien: Labrador Retriever
Retourne le poids moyen d'une race de chien spécifiée

Exemple de conversation:

Question: Quel est le poids moyen d'un Beagle?
Réflexion: Je devrais utiliser la fonction poids_moyen_chien pour obtenir cette information
Action: poids_moyen_chien: Beagle
Observation: Un Beagle pèse en moyenne 15 kg

Réponse finale: Un Beagle pèse en moyenne 15 kg
""".strip()

Création des Fonctions d'Action

Pour que notre agent puisse interagir avec le monde réel, nous devons lui fournir des fonctions d'acsion. Définissons deux fonctions de base :

def effectuer_calcul(expression):
    """Exécute un calcul mathématique et retourne le résultat"""
    try:
        return eval(expression)
    except:
        return "Erreur dans le calcul"

def poids_moyen_race_chien(race):
    """Retourne le poids moyen d'une race de chien spécifique"""
    donnees_races = {
        "Écossais Terrier": "20 lbs",
        "Border Collie": "37 lbs",
        "Caniche Toy": "7 lbs",
        "Berger Allemand": "70 lbs",
        "Bulldog": "51 lbs",
        "Labrador": "65 lbs"
    }
    return donnees_races.get(race, "Un chien moyen pèse 50 lbs")

actions_connues = {
    "calculatrice": effectuer_calcul,
    "poids_moyen_chien": poids_moyen_race_chien
}

Premier Test de l'Agent

Testons notre agent avec une question simple :

assistant = AssistantIntelligent(instruction_principale)
resultat = assistant("Quel est le poids d'un Caniche Toy?")
print(resultat)

L'agent devrait produrie une réponse structurée comme suit :

Réflexion: Je dois utiliser la fonction poids_moyen_chien pour obtenir le poids moyen d'un Caniche Toy
Action: poids_moyen_chien: Caniche Toy
Observation: Un Caniche Toy pèse en moyenne 7 lbs

Nous pouvons maintenant vérifier manuellement le résultat :

resultat_verification = poids_moyen_race_chien("Caniche Toy")
print(resultat_verification)

Ce qui devrait afficher :

Un Caniche Toy pèse en moyenne 7 lbs

Ensuite, nous transmettons cette observation à notre agent :

prochaine_question = "Observation: {}".format(resultat_verification)
assistant(prochaine_question)

Le dernier message de l'historique devrait contenir :

{'role': 'assistant',
  'content': 'Réponse finale: Un Caniche Toy pèse en moyenne 7 lbs'}

Automatisation du Processus

Pour rendre notre agent véritablement autonome, nous devons automatiser l'exécution des fonctions détectées dans ses réponses. Implémentons un mécanisme de boucle avec une expression régulière pour détecter et exécuter les actions :

expression_action = re.compile('^Action: (\w+): (.*)$')

def interroger_agent(question, max_tours=5):
    i = 0
    assistant = AssistantIntelligent(instruction_principale)
    prochaine_question = question
    while i < max_tours:
        i += 1
        resultat = assistant(prochaine_question)
        print("Réponse de l'agent:", resultat)
        
        actions_detectees = [
            expression_action.match(reponse) 
            for reponse in resultat.split('\n') 
            if expression_action.match(reponse)
        ]
        
        if actions_detectees:
            # Une action à exécuter a été détectée
            action, entree_action = actions_detectees[0].groups()
            if action not in actions_connues:
                raise Exception("Action inconnue: {}: {}".format(action, entree_action))
            
            print(" -- Exécution de l'action: {} {}".format(action, entree_action))
            observation = actions_connues[action](entree_action)
            print("Observation:", observation)
            prochaine_question = "Observation: {}".format(observation)
        else:
            # Plus d'actions à exécuter, le processus est terminé
            return assistant.historique_messages[-1]['content']

Testons maintenant notre agent avec une question plus complexe :

question = "J'ai deux chiens, un Border Collie et un Écossais Terrier. Quel est leur poids combiné?"
interroger_agent(question)

Le résultat devrait ressembler à ceci :

Réflexion: Je dois trouver le poids moyen du Border Collie et de l'Écossais Terrier, puis additionner ces deux valeurs.
Action: poids_moyen_chien: Border Collie
Observation: Un Border Collie pèse en moyenne 37 lbs
Réflexion: Maintenant je dois trouver le poids moyen de l'Écossais Terrier.
Action: poids_moyen_chien: Écossais Terrier
Observation: Un Écossais Terrier pèse en moyenne 20 lbs
Réflexion: Je connais maintenant les poids moyens des deux races. Je vais les additionner pour obtenir le poids total.
Action: calculatrice: 37 + 20
Observation: 57
Réponse finale: Le poids combiné d'un Border Collie et d'un Écossais Terrier est de 57 lbs.

Applications Potentielles

Bien que cet exemple semble simple, il démontre les principes fondamentaux qui peuvent être étendus pour créer des agents IA beaucoup plus sophistiqués et utiles :

  • • Intégration d'API météorologiques pour créer un assistant météo
  • • Connexion à des bases de données personnelles pour générer des rapports automatiques
  • • Utilisation d'API cartographiques pour obtenir des informations sur le trafic
  • • Contrôle d'appareils IoT domotiques via des commandes vocales naturelles

Essentiellement, presque toute fonctionnalité programmable peut être enveloppée dans une interface de langage naturel grâce aux grands modèles de langage, créant ainsi des agents IA capables de comprendre et d'exécuter des instructions complexes.

Étiquettes: IA Python OpenAI React AssistantIntelligent

Publié le 6 juin à 23h48