Maison >développement back-end >Tutoriel Python >Construire un chatbot avec Semantic Kernel - Part Plugins

Construire un chatbot avec Semantic Kernel - Part Plugins

Linda Hamilton
Linda Hamiltonoriginal
2024-12-06 07:33:15621parcourir

Dans notre chapitre précédent, nous avons passé en revue certains des concepts de base du noyau sémantique, pour terminer avec un agent fonctionnel capable de répondre à des questions génériques, mais avec un ton et un objectif prédéfinis en utilisant les instructions.

Dans ce deuxième chapitre, nous ajouterons des compétences spécifiques à notre Bibliothécaire en utilisant des Plugins.

Qu'est-ce qu'un plugin ?

Un Plugin est un ensemble de fonctions exposées aux services d'IA. Les plugins encapsulent des fonctionnalités, permettant à l'assistant d'effectuer des actions qui ne font pas partie de son comportement natif.

Par exemple, avec les plugins, nous pourrions permettre à l'assistant de récupérer certaines données d'une API ou d'une base de données. De plus, l'assistant peut effectuer certaines actions au nom de l'utilisateur, généralement via des API. De plus, l'assistant serait capable de mettre à jour certaines parties de l'interface utilisateur à l'aide d'un plugin.

Comme je l'ai mentionné précédemment, un plugin est composé de différentes fonctions. Chaque fonction est définie principalement par :

  • Description : le but de la fonction et quand elle doit être invoquée. Cela aidera le modèle à décider quand l'appeler comme nous le verrons dans la section appel de fonction.
  • Variables d'entrée : utilisées pour paramétrer la fonction afin qu'elle puisse être réutilisable.

Semantic Kernel prend en charge différents types de plugins. Dans cet article, nous nous concentrerons sur deux d'entre eux : Prompt Plugin et Native Plugin.

Plugin d'invite

Un Prompt Plugin est essentiellement une invite spécifique à invoquer dans des circonstances concrètes. Dans un scénario typique, nous pourrions avoir une Invite système complexe, dans laquelle nous définissons le ton, l'objectif et le comportement général de notre agent. Cependant, il est possible que nous souhaitions que l'agent effectue des actions concrètes pour lesquelles nous devons définir des restrictions et des règles spécifiques. Dans ce cas, nous essaierions d'éviter que l'Invite système atteigne l'infini afin de réduire les hallucinations et de garder la réponse du modèle pertinente et contrôlée. C'est un cas parfait pour un Plugin d'invite :

  1. Invite système :ton, objectif et comportement général.
  2. Invite de résumé : comprenant des règles et des restrictions sur la façon de faire un résumé. Par exemple, il ne doit pas dépasser deux paragraphes.

Un Prompt Plugin est défini par deux fichiers :

  • config.json : fichier de configuration comprenant la description, les variables et les paramètres d'exécution :
{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}
  • skprompt.txt : contenu de l'invite en texte brut. Les variables du fichier de configuration sont accessibles en utilisant la syntaxe {{$parameter_1}}.

Pour ajouter un Prompt Plugin dans le noyau, il suffit de spécifier le dossier. Par exemple, si nous avons la structure de dossiers /plugins/plugin_name/skprompt.txt, le plugin est enregistré comme suit :

{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}

Plugin natif

Un Plugin Natif permet au modèle d'invoquer du code natif (python, C# ou Java). Un plugin est représenté comme une classe, où n'importe quelle fonction peut être définie comme invocable depuis l'agent à l'aide d'annotations. Le développeur doit fournir quelques informations au modèle avec les annotations : nom, description et arguments.

Pour définir un Plugin Natif il faut seulement créer la classe et ajouter les annotations correspondantes :

self.kernel.add_plugin(parent_directory="./plugins", plugin_name="plugin_name")

Pour ajouter un Plugin natif dans le noyau, nous devons créer une nouvelle instance de la classe :

from datetime import datetime
from typing import Annotated
from semantic_kernel.functions.kernel_function_decorator import kernel_function

class MyFormatterPlugin():

    @kernel_function(name='format_current_date', description='Call to format current date to specific strftime format') # Define the function as invokable
    def formate_current_date(
        self,
        strftime_format: Annotated[str, 'Format, must follow strftime syntax'] # Describe the arguments
    ) -> Annotated[str, 'Current date on the specified format']: # Describe the return value
    return datetime.today().strftime(strftime_format)

Appel de fonction

L'appel de fonction, ou planification, dans le noyau sémantique est un moyen pour le modèle d'invoquer une fonction enregistrée dans le noyau.

Pour chaque message utilisateur, le modèle crée un plan pour décider comment répondre. Premièrement, il utilise l'historique des discussions et les informations de la fonction pour décider quelle fonction, le cas échéant, doit être appelée. Une fois invoqué, il ajoute le résultat de la fonction à l'historique et décide si elle a terminé la tâche à partir du message de l'utilisateur ou si elle nécessite plus d'étapes. S'il n'est pas terminé, il recommence depuis la première étape jusqu'à ce qu'il ait terminé la tâche ou qu'il ait besoin de l'aide de l'utilisateur.

Grâce à cette boucle, le modèle peut concaténer des appels à différentes fonctions. Par exemple, nous pourrions avoir une fonction qui renvoie un user_session (y compris l'identifiant de l'utilisateur) et une autre qui nécessite un current_user_id comme argument. Le modèle fera un plan dans lequel il appellera la première fonction pour récupérer la session utilisateur, analysera la réponse et utilisera l'id_utilisateur comme argument pour la deuxième fonction.

Building a chatbot with Semantic Kernel - Part Plugins

Dans le noyau sémantique, nous devons dire à l'agent d'utiliser l'appel de fonction. Cela se fait en définissant des paramètres d'exécution avec le comportement de choix de fonction comme automatique :

self.kernel.add_plugin(MyFormatterPlugin(), plugin_name="my_formatter_plugin")

Il est important de souligner que plus les descriptions sont détaillées, plus de jetons sont utilisés, donc cela coûte plus cher. Il est essentiel de trouver un équilibre entre de bonnes descriptions détaillées et les jetons utilisés.

Plugins pour notre bibliothécaire

Maintenant que ce qu'est une fonction et son objectif est clair, voyons comment nous pouvons en tirer le meilleur parti pour notre agent Bibliothécaire.

À des fins d'apprentissage, nous définirons un Plugin natif et un Plugin d'invite :

  • Plugin de référentiel de livres : il s'agit d'un Plugin natif permettant de récupérer des livres d'un référentiel.

  • Plugin de création de poèmes : c'est un Plugin d'invite pour créer un poème à partir de la première phrase d'un livre.

Plugin de dépôt de livres

Nous utilisons l'API Open Library pour récupérer les informations des livres. Le plugin renvoie les 5 meilleurs résultats de la recherche, y compris le titre, l'auteur et la première phrase du livre.

Plus précisément, nous utilisons le point de terminaison suivant pour récupérer les informations : https://openlibrary.org/search.json?q={user-query}&fields=key,title,author_name,first_sentence&limit=5.

Tout d'abord, nous définissons le BookModel qui représente un livre dans notre système :

{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}

Et maintenant, c'est l'heure de la réception. Nous utilisons une description claire de la fonction et de l'argument. Dans ce cas, nous utilisons un objet complexe comme réponse, mais le modèle est capable de l'utiliser plus tard pour d'autres réponses.

self.kernel.add_plugin(parent_directory="./plugins", plugin_name="plugin_name")

Enfin, on peut ajouter ce plugin au Kernel :

from datetime import datetime
from typing import Annotated
from semantic_kernel.functions.kernel_function_decorator import kernel_function

class MyFormatterPlugin():

    @kernel_function(name='format_current_date', description='Call to format current date to specific strftime format') # Define the function as invokable
    def formate_current_date(
        self,
        strftime_format: Annotated[str, 'Format, must follow strftime syntax'] # Describe the arguments
    ) -> Annotated[str, 'Current date on the specified format']: # Describe the return value
    return datetime.today().strftime(strftime_format)

Plugin de création de poèmes

Nous définirons ce plugin comme un Prompt Plugin avec quelques restrictions spécifiques. Voici à quoi ressemblent l'invite et sa configuration :

/plugins/poem-plugin/poem-creator/config.json :

self.kernel.add_plugin(MyFormatterPlugin(), plugin_name="my_formatter_plugin")

/plugins/poem-plugin/poem-creator/skprompt.txt :

# Create the settings
settings = AzureChatPromptExecutionSettings()

# Set the behavior as automatic
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

# Pass the settings to the agent
self.agent = ChatCompletionAgent(
    service_id='chat_completion',
    kernel=self.kernel,
    name='Assistant',
    instructions="The prompt",
    execution_settings=settings
)

Il est simple d'ajouter le plugin au noyau :

class BookModel(TypedDict):
    author: str
    title: str
    first_sentence: str

Bonnes pratiques

Quelques suggestions basées sur la littérature existante et ma propre expérience :

  • Utilisez la syntaxe Python pour décrire votre fonction même en .NET ou Java. Les modèles sont généralement plus compétents sur Python en raison des données entraînées ?
  • Gardez les fonctions concentrées, en particulier les descriptions. Une fonction, un objectif. N'essayez pas de créer une fonction qui fait trop de choses, cela serait contre-productif ?
  • Des arguments simples et un faible nombre d'entre eux. Plus ils sont simples et peu nombreux, plus l'appel des modèles vers les fonctions sera fiable ?
  • Si vous avez de nombreuses fonctions, examinez attentivement les descriptions pour vous assurer qu'il n'y a pas de conflits potentiels qui pourraient confondre le modèle ?
  • Demandez à un modèle (via chatgpt ou similaire) des commentaires sur les descriptions des fonctions. Ils sont généralement assez doués pour trouver des améliorations. D'ailleurs, cela s'applique également au développement d'invites en général ❓
  • Testez, testez et testez. Surtout dans les cas de logiciels d'entreprise, la fiabilité est la clé. Assurez-vous que le modèle est capable d'appeler les fonctions attendues avec les informations que vous leur avez fournies via annotation ?

Résumé

Dans ce chapitre, nous avons amélioré notre agent bibliothécaire avec certaines compétences spécifiques en utilisant les plugins et la planification du noyau sémantique.

Vous vous souvenez que tout le code est déjà disponible sur mon dépôt GitHub ? PyChatbot pour le noyau sémantique.

Dans le prochain chapitre, nous inclurons quelques fonctionnalités dans le chat pour inspecter en temps réel comment notre modèle appelle et interagit avec nos plugins en créant un Inspecteur.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn