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.
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 :
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.
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 :
Un Prompt Plugin est défini par deux fichiers :
{ "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": "" } ] }
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": "" } ] }
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)
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.
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.
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.
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)
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
Quelques suggestions basées sur la littérature existante et ma propre expérience :
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!