# Installation de Semantic Kernel (si nécessaire)
# Vérification de la version installée
from semantic_kernel import __version__
print(f"Semantic Kernel version : {__version__}")Semantic Kernel version : 1.42.0
Navigation : Index | 02-Functions >>
A la fin de ce notebook, vous saurez : 1. Installer et configurer Semantic Kernel pour Python 2. Comprendre le rôle du Kernel comme orchestrateur central 3. Ajouter des services LLM (OpenAI, Azure, Hugging Face) 4. Charger et utiliser des plugins (prompts templates) 5. Créer des fonctions sémantiques inline 6. Gerer un chat conversationnel avec historique
.env configure| Section | Contenu | Concepts cles |
|---|---|---|
| 1 | Installation | pip install semantic-kernel |
| 2 | Configuration | .env, Kernel, Services |
| 3 | Premier Kernel | Initialisation, service LLM |
| 4 | Plugins | Chargement depuis fichiers |
| 5 | Fonctions inline | Prompts dynamiques |
| 6 | Chat | Historique, KernelArguments |
Qu’est-ce que Semantic Kernel ? Un SDK Microsoft open-source pour integrer des LLMs dans vos applications. Il orchestre les appels aux modèles, gere les plugins, et permet de créer des agents intelligents.
Semantic Kernel version : 1.42.0
Dans cette cellule, nous allons importer les modules principaux.
import os
import json
from dotenv import load_dotenv
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.connectors.ai.open_ai import OpenAIChatPromptExecutionSettings
from semantic_kernel.functions import KernelArguments # Correction de l'import
from semantic_kernel.prompt_template import PromptTemplateConfig
from semantic_kernel.prompt_template.input_variable import InputVariable
print("Imports OK : Kernel, OpenAIChatCompletion, KernelArguments, PromptTemplateConfig, InputVariable")Imports OK : Kernel, OpenAIChatCompletion, KernelArguments, PromptTemplateConfig, InputVariable
.env ou JSONLe fichier de configuration .env doit contenir les clés nécessaires pour accéder aux services OpenAI/Azure OpenAI.
💡 Vérifiez que vous avez bien créé un fichier .env dans le même dossier que ce notebook avec ces valeurs :
GLOBAL_LLM_SERVICE="OpenAI"
OPENAI_API_KEY="sk-..."
OPENAI_CHAT_MODEL_ID="gpt-5-mini"
👉 Nous allons maintenant charger ces paramètres en Python :
# Chargement du fichier .env
load_dotenv()
# Récupération des clés API et du modèle
llm_service = os.getenv("GLOBAL_LLM_SERVICE", "OpenAI")
api_key = os.getenv("OPENAI_API_KEY")
model_id = os.getenv("OPENAI_CHAT_MODEL_ID", "gpt-5-mini")
# Vérification
print(f"Service sélectionné : {llm_service}")
print(f"Modèle utilisé : {model_id}")Service sélectionné : OpenAI
Modèle utilisé : gpt-5.2
Les deux cellules précédentes ont respectivement charge les variables d’environnement et instancie le Kernel Semantic Kernel. Ces deux étapes sont preconditionnees l’une par l’autre :
| Étape | Action | Résultat |
|---|---|---|
Lecture .env |
load_dotenv() + os.getenv() |
Recuperation de la cle API et du modèle |
| Initialisation Kernel | Kernel() |
Orchestrateur central pret a recevoir des services |
Le Kernel est actuellement “nu” : il ne possede pas encore de service LLM. La cellule suivante va verifier la connectivite avec l’API OpenAI avant d’ajouter le service ChatCompletion au Kernel.
import os
from dotenv import load_dotenv
from openai import AsyncOpenAI
import asyncio
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
# Récupère la valeur du .env et nettoie les espaces
base_url_from_env = os.getenv("OPENAI_BASE_URL", "").strip()
# Détermine explicitement l'URL finale
if base_url_from_env:
final_base_url = base_url_from_env
print(f"Utilisation de l'URL du .env : {final_base_url}")
else:
final_base_url = "https://api.openai.com/v1" # <<< URL par défaut explicite
print(f"Utilisation de l'URL par défaut : {final_base_url}")
model_id = os.getenv("OPENAI_CHAT_MODEL_ID", "gpt-5-mini")
print(f"Utilisation du modèle : {model_id}")
print(f"Clé API utilisée : {'Oui' if api_key else 'Non'}")
async def test_connection():
try:
if not api_key:
print("ERREUR : Clé API non définie.")
return
# Utilise final_base_url déterminé ci-dessus
client = AsyncOpenAI(api_key=api_key, base_url=final_base_url)
response = await client.chat.completions.create(
model=model_id,
messages=[{"role": "user", "content": "Say hello!"}],
timeout=20
)
print("Connexion réussie !")
print("Réponse :", response.choices[0].message.content)
except Exception as e:
print(f"ERREUR lors du test de connexion : {type(e).__name__} - {e}")
import traceback
traceback.print_exc()
# Exécuter le test
await test_connection()Utilisation de l'URL par défaut : https://api.openai.com/v1
Utilisation du modèle : gpt-5.2
Clé API utilisée : Oui
Connexion réussie !
Réponse : Hello!
Nous devons connecter notre Kernel à un service de Chat Completion.
Pour cet exemple, nous allons utiliser OpenAI. Si vous préférez Azure OpenAI, adaptez le code en conséquence (voir la documentation).
La configuration se fait via l’ajout d’un service au Kernel.
Assurez-vous que votre fichier .env contient votre clé API.
Service OpenAI ajouté au Kernel.
Configuration effectuée : Ajout du service OpenAI au Kernel avec l’identifiant “default”.
| Aspect | Détail | Signification |
|---|---|---|
| Service ID | “default” | Identifiant unique pour référencer ce service lors des invocations |
| Type | OpenAIChatCompletion | Service de complétion chat (vs embedding, image, etc.) |
| Configuration automatique | Via .env | api_key et model_id chargés depuis les variables d’environnement |
| Flexibilité | Multi-services possibles | Un Kernel peut avoir plusieurs services (OpenAI, Azure, Ollama, etc.) |
Points clés :
Note technique : La méthode
add_service()enregistre le service dans le registre interne du Kernel. Lors d’une invocation, le Kernel sélectionne automatiquement le service approprié basé sur leservice_idou utilise le service par défaut.
Semantic Kernel permet de charger des prompt plugins stockés sur disque.
Dans cet exemple, nous chargerons le plugin “FunPlugin” qui contient, par exemple, une fonction pour générer une blague.
Les fichiers du plugin (le prompt et sa configuration) sont stockés dans le répertoire prompt_template_samples/.
Nous allons charger ce plugin et invoquer la fonction “Joke” pour générer une blague sur un sujet donné.
# Chemin correct vers les plugins
plugins_directory = "./prompt_template_samples/"
# Vérifier si le dossier du plugin existe avant de charger
if os.path.exists(os.path.join(plugins_directory, "FunPlugin")):
fun_plugin = kernel.add_plugin(parent_directory=plugins_directory, plugin_name="FunPlugin")
joke_function = fun_plugin["Joke"]
print("Plugin chargé avec succès.")
else:
print("⚠️ Le plugin FunPlugin est introuvable. Vérifiez le chemin et assurez-vous qu'il est bien présent.")
# Invoquer la fonction pour générer une blague sur un thème donné
# Pour ce faire, nous utilisons des KernelArguments (ici, seul l'input est nécessaire)
from semantic_kernel.functions import KernelArguments
print(joke_function)
# Exemple : générer une blague sur "time travel to dinosaur age" avec un style "super silly"
joke_response = await kernel.invoke(joke_function, KernelArguments(input="time travel to dinosaur age", style="super silly"))
print("Blague générée :", joke_response)Plugin chargé avec succès.
metadata=KernelFunctionMetadata(name='Joke', plugin_name='FunPlugin', description='Generate a funny joke', parameters=[KernelParameterMetadata(name='input', description='Joke subject', default_value='', type_='', is_required=True, type_object=None, schema_data={'type': 'object', 'description': 'Joke subject'}, include_in_function_choices=True), KernelParameterMetadata(name='style', description='Give a hint about the desired joke style', default_value='', type_='', is_required=True, type_object=None, schema_data={'type': 'object', 'description': 'Give a hint about the desired joke style'}, include_in_function_choices=True)], is_prompt=True, is_asynchronous=True, return_parameter=KernelParameterMetadata(name='return', description='The completion result', default_value=None, type_='FunctionResult', is_required=True, type_object=None, schema_data=None, include_in_function_choices=True), additional_properties=None) invocation_duration_histogram=<opentelemetry.metrics._internal.instrument._ProxyHistogram object at 0x0000023B5E2E4190> streaming_duration_histogram=<opentelemetry.metrics._internal.instrument._ProxyHistogram object at 0x0000023B5CCE2780> prompt_template=KernelPromptTemplate(prompt_template_config=PromptTemplateConfig(name='Joke', description='Generate a funny joke', template="WRITE EXACTLY ONE JOKE or HUMOROUS STORY ABOUT THE TOPIC BELOW\n\nJOKE MUST BE:\n- G RATED\n- WORKPLACE/FAMILY SAFE\nNO SEXISM, RACISM OR OTHER BIAS/BIGOTRY\nAVOID Daddy's jokes and puns, be funny, be deep, provocative, for real !\n\nBE CREATIVE AND FUNNY. I WANT TO LAUGH.\nIncorporate the style suggestion, if provided: {{$style}}\n+++++\n\n{{$input}}\n+++++\n", template_format='semantic-kernel', input_variables=[InputVariable(name='input', description='Joke subject', default='', is_required=True, json_schema='', allow_dangerously_set_content=False), InputVariable(name='style', description='Give a hint about the desired joke style', default='', is_required=True, json_schema='', allow_dangerously_set_content=False)], allow_dangerously_set_content=False, execution_settings={'default': PromptExecutionSettings(service_id=None, extension_data={}, function_choice_behavior=None)}), allow_dangerously_set_content=False) prompt_execution_settings={'default': PromptExecutionSettings(service_id=None, extension_data={}, function_choice_behavior=None)}
Blague générée : I built my time machine at the kitchen table because that’s where all serious science happens in my family. My sister kept walking by, seeing wires everywhere, and asking the same question: “Is it safe?”
I told her, “It’s safer than my search history.”
The plan was simple: jump back to the dinosaur age, take one photo, come back, finally silence the group chat that keeps saying, “If time travel is real, why hasn’t anyone visited us?” I even packed responsibly: granola bars, a first-aid kit, and a tiny notebook labeled IMPORTANT DISCOVERIES, like I was about to change history instead of immediately forgetting why I walked into a room.
I hit the button.
Reality folded like a cheap lawn chair.
And I landed in the dinosaur age with the confidence of someone who has never had to make eye contact with a creature that could treat them like a snack-sized opinion.
It was beautiful. Huge ferns. A sky so clear it looked like someone had just wiped the lens. The air had this warm, swampy smell that made me understand, spiritually, why people invented deodorant.
Then the ground started doing that thing where it decides to become a drum.
Thump. Thump. Thump.
I turned slowly, like a person who has watched documentaries and still learned nothing.
Behind me: a T. rex.
Not “movie monster” scary. Worse. Real-life scary. Like a forklift with teeth, standing there with the calm authority of something that has never been asked to “circle back” or “touch base.”
It looked at me.
I looked at it.
My brain offered exactly one plan: “Act natural.”
So I stood up straighter, nodded politely, and did what any reasonable adult does when confronted by an apex predator: I pulled out my notebook and pretended I was here for research.
The T. rex took a step closer.
I raised a hand like I was directing traffic. “Hi. Hello. Great to meet you. I’m just here to—”
It lowered its head and sniffed me.
And in that moment I realized something profound: I had packed granola bars.
I slowly reached into my bag, took one out, unwrapped it with the careful reverence of someone defusing a bomb, and held it out like an offering to the gods of poor planning.
The T. rex stared at the granola bar.
Then it opened its mouth.
And instead of roaring or trying to eat me, it did something I was not prepared for.
It sneezed.
Not a cute little sneeze. A prehistoric sneeze. A sneeze with weather in it. A sneeze that arrived with its own wind advisory.
I was instantly coated in dinosaur mucus—warm, swampy, existentially discouraging dinosaur mucus. My notebook slapped shut in my hand like it was quitting.
The T. rex blinked, looked mildly offended—like *I* had startled *it*—and then wandered off with the energy of someone who just coughed in a meeting and decided to retire.
I stood there, dripping, trying to process the fact that I had time-traveled across millions of years and my first contact with the distant past was… being sneezed on by history.
Then I heard a new sound.
A chorus of smaller thumps.
I turned and saw a line of little dinosaurs—raptors, I think—peeking out from behind the ferns. They weren’t charging. They were… watching. Their heads tilted in sync like a committee.
One stepped forward, stared at the granola bar still in my hand, and made a noise that sounded exactly like a tiny judgmental cough.
And suddenly it hit me.
I wasn’t in danger.
I was being evaluated.
By dinosaurs.
Like I was at some ancient reptile networking event and I had shown up wearing the wrong badge.
I offered the granola bar again.
The raptor sniffed it, took the tiniest bite, and immediately spit it out with theatrical disgust. Another one tried. Same reaction. The whole group began making these annoyed little chirps, like: *What is this? Why is it dry? Why does it taste like disappointment and responsibility?*
Then one of them hopped closer, looked me dead in the eye, and—no joke—pushed the granola bar back toward me with its snout, like a waiter returning a meal.
And I understood, completely and spiritually, that I had been rejected by dinosaurs for my snack choices.
I did the only dignified thing left.
I bowed.
“I respect your feedback,” I said, because apparently my survival strategy is “customer service voice.” “We will take this under advisement.”
The raptors, satisfied that they had delivered their critique, lost interest and dispersed into the ferns like a tiny, scaly review panel moving on to destroy another product.
I stood there, covered in T. rex sneeze, holding my rejected granola bar, and for the first time I thought, with total clarity: *If I stay here, I will become an extremely humiliating footnote.*
So I sprinted back to my time machine.
Which, because I built it on the kitchen table, required me to kick it twice for it to start.
I hit the return button.
Reality folded again.
I landed back in my kitchen, dripping, hair stuck to my forehead, smelling like I had wrestled a swamp.
My sister walked in, took one look at me, and said, very calmly, “So. Was it safe?”
I looked her in the eye and said, “I have traveled through time and been reviewed negatively by dinosaurs.”
She paused. “Did you at least get a photo?”
I pulled out my phone.
It was open to the camera.
It had one picture.
A perfect, crystal-clear, high-resolution shot of my thumb covering the lens.
And, faintly in the background, the T. rex mid-sneeze, looking like it was about to end my whole era.
My sister stared at it for a long time and finally said, “So… you went back sixty-five million years… to get slimed and take a thumb picture.”
I nodded.
She nodded back, like she was updating her internal file on me.
Then she said, “Next time, bring something better than granola.”
And that’s how I learned the most humbling truth of time travel:
You can rewrite history, but you cannot impress a dinosaur with a snack that tastes like office morale.
Objectif : Créer une fonction sémantique qui analyse le sentiment d’un texte et retourne un résultat structure avec le sentiment dominant, un score de confiance et une justification courte.
L’analyse de sentiment est un cas d’usage classique des LLMs. Vous allez créer une fonction qui prend un texte en entree et retourne une analyse structuree (positif/negatif/neutre + score).
Indices : - # Étape 1 : Ecrire un template qui demande au LLM d’analyser le sentiment et de formater la reponse - # Étape 2 : Specifier le format de sortie attendu dans le prompt (ex: “SENTIMENT: positif | CONFIANCE: 0.8 | RAISON: …”) - # Étape 3 : Tester avec 3 textes de sentiments différents - # Indice : Demander explicitement un format structure dans le prompt force le LLM a etre consistent
# Exercice 3 : Analyseur de sentiment
sentiment_prompt = """
# TODO etudiant : ecrire le template d'analyse de sentiment
# Le template doit utiliser {{$input}} et demander un format structure
Analyse le sentiment.
"""
# TODO etudiant : configurer le PromptTemplateConfig
sentiment_config = PromptTemplateConfig(
template=sentiment_prompt,
name="sentiment",
template_format="semantic-kernel",
input_variables=[
InputVariable(name="input", description="Texte a analyser", is_required=True),
],
)
# TODO etudiant : ajouter au kernel et tester
# sentiment_function = kernel.add_function(
# function_name="sentiment",
# plugin_name="sentimentPlugin",
# prompt_template_config=sentiment_config
# )
# Textes de test avec sentiments differents
test_texts = [
"J'adore ce nouveau framework ! Il est incroyablement bien concu et facile a utiliser.",
"Le service etait tres decevant. Je ne recommande pas du tout ce produit.",
"La reunion d'hier a dure 2 heures. Nous avons discute du budget pour le prochain trimestre.",
]
# TODO etudiant : decommentez apres implementation
# for text in test_texts:
# result = await kernel.invoke(sentiment_function, KernelArguments(input=text))
# print(f"Texte : {text[:60]}...")
# print(f"Analyse : {result}\n")
print("Exercice a completer : implementez le template et testez les 3 textes")Exercice a completer : implementez le template et testez les 3 textes
Sortie obtenue : Blague générée sur le voyage dans le temps à l’ère des dinosaures avec style “super silly”.
| Aspect | Valeur | Signification |
|---|---|---|
| Plugin | FunPlugin | Collection de fonctions liées (Joke, Story, etc.) |
| Fonction | Joke | Prompt template avec variables {input} et {style} |
| Variables d’entrée | input=“time travel…”, style=“super silly” | Paramètres injectés dans le template |
| Configuration prompt | Aucune dans config.json (execution_settings vide) |
Ni max_tokens ni temperature ne sont fixés par le plugin — la génération utilise les réglages par défaut du service (visible dans la sortie : extension_data={}) |
| Format de sortie | Texte libre (blague) | Le LLM génère du contenu non structuré |
Architecture d’un Prompt Template :
┌─────────────────────────────────────────────┐
│ FunPlugin/Joke/ │
│ ┌────────────────────────────────────────┐ │
│ │ skprompt.txt (template) │ │
│ │ "Write a joke about `{$input}` │ │
│ │ with style `{$style}`" │ │
│ └────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────┐ │
│ │ config.json (exécution settings) │ │
│ │ { execution_settings: {} } │ │
│ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
↓
kernel.invoke(joke_function, args)
↓
Prompt rempli → Service LLM → Résultat
Points clés :
skprompt.txt et config.json{$nom} - Syntaxe Semantic Kernel pour les placeholdersKernelFunctionMetadata décrit la fonction (nom, paramètres, description)Avantage des plugins : Séparation du code Python et des prompts. Les prompts peuvent être modifiés par des non-développeurs (prompt engineers) sans toucher au code.
Le plugin (template skprompt.txt + reglages config.json) est invoque par le kernel, qui remplit le prompt, appelle le service LLM et renvoie le résultat.
flowchart TD
subgraph P["FunPlugin/Joke/"]
T["skprompt.txt (template)"]
C["config.json (exécution settings)"]
end
P --> I["kernel.invoke(joke_function, args)"]
I --> F["Prompt rempli"]
F --> L["Service LLM"]
L --> Res["Résultat"]
Outre l’utilisation de plugins stockés sur disque, il est possible de définir des fonctions sémantiques directement dans votre code Python.
Cette approche est particulièrement utile pour : - Générer dynamiquement des prompts en fonction du contexte - Prototyper rapidement des idées sans créer de fichiers séparés
Dans cet exemple, nous allons créer une fonction qui résume un texte donné en quelques mots (TL;DR).
from semantic_kernel.connectors.ai.open_ai import OpenAIChatPromptExecutionSettings
from semantic_kernel.prompt_template import PromptTemplateConfig
from semantic_kernel.prompt_template.input_variable import InputVariable
# Définition du prompt
tldr_prompt = """
{{$input}}
Donne-moi un résumé en 5 mots ou moins.
"""
# Configuration de l'exécution (temperature non supportée par les modèles de raisonnement)
execution_settings = OpenAIChatPromptExecutionSettings(
service_id="default",
ai_model_id=model_id,
)
# Configuration du prompt template
tldr_template_config = PromptTemplateConfig(
template=tldr_prompt,
name="tldr",
template_format="semantic-kernel",
input_variables=[InputVariable(name="input", description="Texte à résumer", is_required=True)],
execution_settings=execution_settings,
)
# Ajout de la fonction au Kernel
tldr_function = kernel.add_function(function_name="tldrFunction", plugin_name="tldrPlugin", prompt_template_config=tldr_template_config)
# Exécution de la fonction
async def run_tldr():
input_text = "Demo était une poétesse grecque ancienne connue pour un unique poème gravé sur le Colosse de Memnon."
tldr_summary = await kernel.invoke(tldr_function, KernelArguments(input=input_text))
print("Résumé (TL;DR) :", tldr_summary)
# Lancer la fonction
await run_tldr()Résumé (TL;DR) : Poétesse grecque, poème sur Memnon.
Objectif : Créer une fonction sémantique qui genere des titres creatifs pour un article, et experimenter avec le paramètre temperature pour observer son impact sur la creativite.
La temperature est le paramètre le plus important pour contrôler le comportement d’un LLM : 0 = déterministe, 1 = creatif, 2 = très aleatoire. Vous allez créer un générateur de titres et tester plusieurs valeurs de temperature.
Indices : - # Étape 1 : Créer un template qui genere 3 propositions de titre pour un article donne - # Étape 2 : Configurer les execution_settings avec temperature variable - # Étape 3 : Tester avec temperature 0.0, 0.5 et 1.5 et comparer les résultats - # Indice : OpenAIChatPromptExecutionSettings(service_id="default", temperature=0.0) pour le contrôle
# Exercice 2 : Generateur de titres avec temperature variable
title_prompt = """
# TODO etudiant : ecrire un template qui genere 3 propositions de titre
# pour l'article decrit dans {{$input}}
Genere des titres.
"""
# TODO etudiant : creer une fonction pour chaque niveau de temperature
async def generate_titles_with_temperature(article_topic: str, temperature: float) -> str:
"""
Genere des titres avec une temperature donnee.
# Etape 1 : Creer les execution_settings avec la temperature specifiee
# Etape 2 : Configurer le PromptTemplateConfig avec ces settings
# Etape 3 : Invoquer la fonction et retourner le resultat
# Indice : Creez une nouvelle fonction pour chaque temperature
# car les execution_settings sont lies a la fonction
"""
# TODO etudiant : implementer la generation avec temperature
return "Exercice a completer" # TODO etudiant : retourner les titres generes
# Test avec differentes temperatures
topic = "L'impact de l'intelligence artificielle sur l'education superieure"
# TODO etudiant : decommentez apres implementation
# for temp in [0.0, 0.5, 1.5]:
# print(f"\n--- Temperature : {temp} ---")
# titles = await generate_titles_with_temperature(topic, temp)
# print(titles)
print("Exercice a completer : testez differentes valeurs de temperature")Exercice a completer : testez differentes valeurs de temperature
Sortie obtenue : Résumé (TL;DR) : Poétesse grecque, poème sur Memnon.
| Aspect | Valeur | Signification |
|---|---|---|
| Méthode de définition | Inline (dans le code) | Pas de fichiers externes, tout défini en Python |
| Template | String Python avec {$input} |
Prompt défini directement dans une variable |
| Configuration | PromptTemplateConfig | Metadata + exécution settings embarqués |
| Avantage | Dynamique et flexible | Permet de générer des prompts programmatiquement |
| Température | 0.7 | Équilibre entre créativité et cohérence |
Comparaison Plugin vs Inline :
| Critère | Plugin (fichiers) | Fonction Inline |
|---|---|---|
| Modification | Par prompt engineers | Par développeurs |
| Versioning | Git + fichiers séparés | Code source uniquement |
| Réutilisation | Facile (import plugin) | Requiert copier-coller |
| Génération dynamique | Difficile | Très facile |
| Maintenance | Prompts centralisés | Dispersés dans le code |
Cas d’usage idéaux pour inline :
Points clés :
Best practice : Utilisez les plugins pour les prompts stables et réutilisables, et les fonctions inline pour l’expérimentation et les cas dynamiques.
Semantic Kernel offre également la possibilité de créer des interactions de type chatbot.
Nous allons configurer une fonction de chat qui utilise des Kernel Arguments pour conserver l’historique de la conversation.
L’objectif est de simuler une conversation où l’utilisateur envoie un message, le bot y répond, et l’historique est mis à jour à chaque échange.
from semantic_kernel.contents import ChatHistory
# Initialiser l'historique
chat_history = ChatHistory()
chat_history.add_system_message("Vous êtes un chatbot utile et vous fournissez des recommandations de livres.")
# Définition du prompt de chat
chat_prompt = """
{{$history}}
User: {{$user_input}}
ChatBot:
"""
# Configuration de l'exécution (temperature non supportée par les modèles de raisonnement)
chat_exec_settings = OpenAIChatPromptExecutionSettings(
service_id="default",
ai_model_id=model_id,
)
# Configuration du chat template
chat_template_config = PromptTemplateConfig(
template=chat_prompt,
name="chat",
template_format="semantic-kernel",
input_variables=[
InputVariable(name="user_input", description="Message de l'utilisateur", is_required=True),
InputVariable(name="history", description="Historique de la conversation", is_required=True),
],
execution_settings=chat_exec_settings,
)
# Ajout au Kernel
chat_function = kernel.add_function(function_name="chat", plugin_name="chatPlugin", prompt_template_config=chat_template_config)
# Fonction asynchrone pour le chat
async def chat(input_text: str):
print(f"Utilisateur : {input_text}")
response = await kernel.invoke(chat_function, KernelArguments(
user_input=input_text,
history=str(chat_history),
allow_dangerously_set_content=True
))
print(f"ChatBot : {response}")
chat_history.add_user_message(input_text)
chat_history.add_assistant_message(str(response))
# Exécution des exemples
await chat("Salut, je cherche des suggestions de livres sur la philosophie antique.")
await chat("Peux-tu m'en recommander quelques-uns ?")Utilisateur : Salut, je cherche des suggestions de livres sur la philosophie antique.
ChatBot : Voici quelques excellentes suggestions de livres (en français) pour découvrir et approfondir la philosophie antique, selon différents niveaux :
## Pour débuter (clair et accessible)
- **Pierre Hadot — *Qu’est-ce que la philosophie antique ?***
Une très bonne porte d’entrée : la philosophie comme “manière de vivre”, avec des repères historiques.
- **Jean-François Pradeau (dir.) — *Histoire de la philosophie* (tome sur l’Antiquité, selon l’édition)**
Vue d’ensemble structurée, utile pour se situer (présocratiques, Socrate, Platon, Aristote, écoles hellénistiques).
## Les grands textes (indispensables)
- **Platon — *Apologie de Socrate*, *Criton*, *Phédon***
Idéal pour comprendre Socrate, la justice, la mort, et la naissance de la philosophie morale.
- **Aristote — *Éthique à Nicomaque***
Un classique sur la vertu, le bonheur (eudaimonia) et la vie bonne.
- **Épictète — *Manuel* (et *Entretiens* si vous voulez aller plus loin)**
Stoïcisme très concret, orienté pratique.
- **Marc Aurèle — *Pensées pour moi-même***
Stoïcisme introspectif, accessible, souvent très actuel.
- **Épicure — *Lettre à Ménécée* (et *Maximes capitales*)**
Texte bref et central pour comprendre l’éthique épicurienne.
- **Lucrèce — *De la nature (De rerum natura)***
Épicurisme en poésie : fascinant, plus exigeant, mais majeur.
- **Sénèque — *Lettres à Lucilius* (sélections possibles)**
Une entrée très riche dans le stoïcisme romain.
## Pour approfondir (commentaires et interprétations)
- **Pierre Hadot — *La Citadelle intérieure*** (sur Marc Aurèle)
Superbe analyse du stoïcisme comme exercice spirituel.
- **Michel Onfray — *L’Antiquité* (dans sa contre-histoire, selon volumes)**
Accessible et stimulant (plus “interprétation” que manuel académique).
## Si vous aimez les présocratiques
- **Jean-Paul Dumont — *Les Présocratiques*** (selon édition/anthologie)
Pour découvrir Héraclite, Parménide, etc., avec fragments et explications.
Si vous me dites :
1) votre niveau (débutant / déjà lu Platon-Aristote),
2) ce qui vous attire le plus (éthique, politique, métaphysique, stoïcisme/épicurisme),
3) si vous préférez **textes originaux** ou **essais explicatifs**,
je peux vous proposer une liste plus ciblée (5–8 titres) avec un ordre de lecture.
Utilisateur : Peux-tu m'en recommander quelques-uns ?
ChatBot : Oui — voici une petite sélection (8 titres) très solides pour commencer et progresser, avec un bon équilibre entre **textes** et **livres d’introduction** :
1) **Pierre Hadot — *Qu’est-ce que la philosophie antique ?***
Le meilleur point d’entrée : comprend les écoles (stoïciens, épicuriens, sceptiques…) et l’idée de la philosophie comme art de vivre.
2) **Platon — *Apologie de Socrate* (souvent avec *Criton*)**
Court, captivant, central pour comprendre Socrate, la justice et la naissance de la démarche philosophique.
3) **Aristote — *Éthique à Nicomaque***
Un grand classique sur le bonheur, la vertu, le choix, et la “vie bonne” (un peu plus dense, mais incontournable).
4) **Épictète — *Manuel* (Enchiridion)**
Stoïcisme très pratique, facile à lire par fragments, et immédiatement applicable.
5) **Marc Aurèle — *Pensées pour moi-même***
Notes personnelles d’un empereur stoïcien : introspectif, très accessible, souvent étonnamment actuel.
6) **Épicure — *Lettre à Ménécée* + *Maximes capitales***
Très court : parfait pour comprendre rapidement l’épicurisme (désir, plaisir, peur de la mort, tranquillité).
7) **Sénèque — *Lettres à Lucilius* (en sélection)**
Le stoïcisme “romain” en lettres : concret, moral, parfois très beau.
8) **Pierre Hadot — *La Citadelle intérieure*** (sur Marc Aurèle)
Pour approfondir : un excellent guide de lecture et une interprétation forte des exercices spirituels stoïciens.
Si tu me dis ce que tu préfères (plutôt **stoïcisme**, **Platon/Aristote**, ou une **vue d’ensemble**) et ton niveau, je te propose un **ordre de lecture sur 4–6 semaines** avec 5–6 titres max.
Objectif : Créer une fonction sémantique inline qui traduit un texte dans une langue cible specifiee, en utilisant PromptTemplateConfig et KernelArguments.
Vous avez vu comment créer des fonctions sémantiques inline (TLDR) et comment passer des arguments dynamiques (KernelArguments). Vous allez maintenant combiner ces deux concepts pour créer un traducteur configurable.
Indices : - # Étape 1 : Définir un template avec deux variables {$input} (texte) et {$language} (langue cible) - # Étape 2 : Configurer PromptTemplateConfig avec les InputVariable correspondants - # Étape 3 : Invoquer la fonction avec différentes langues cibles (espagnol, allemand, japonais) - # Indice : Inspirez-vous du template TLDR mais ajoutez la variable {$language}
# Exercice 1 : Traducteur multilingue
translate_prompt = """
# TODO etudiant : ecrire le template de prompt avec {{$input}} et {{$language}}
Traduis le texte suivant.
"""
# TODO etudiant : configurer PromptTemplateConfig avec les bonnes input_variables
translate_config = PromptTemplateConfig(
template=translate_prompt,
name="translate",
template_format="semantic-kernel",
input_variables=[
# TODO etudiant : ajouter InputVariable pour "input" et "language"
],
)
# TODO etudiant : ajouter la fonction au kernel
# translate_function = kernel.add_function(
# function_name="translate",
# plugin_name="translatePlugin",
# prompt_template_config=translate_config
# )
# Test (decommentez apres implementation)
# test_text = "Semantic Kernel est un SDK pour integrer des LLMs dans vos applications."
# for lang in ["espagnol", "allemand", "japonais"]:
# result = await kernel.invoke(
# translate_function,
# KernelArguments(input=test_text, language=lang)
# )
# print(f"{lang} : {result}")
print("Exercice a completer : implementez le template, la config et l'invocation")Exercice a completer : implementez le template, la config et l'invocation
Sortie obtenue : Conversation multi-tours avec recommandations de livres sur la philosophie antique.
| Aspect | Valeur | Signification |
|---|---|---|
| Historique | ChatHistory() | Structure pour conserver tous les messages échangés |
| Message système | “Vous êtes un chatbot…” | Définit le rôle et le comportement du bot |
| Messages utilisateur | add_user_message() | Ajoutés après chaque tour de conversation |
| Messages assistant | add_assistant_message() | Ajoutés après chaque réponse du LLM |
| Injection dans prompt | {$history} |
L’historique complet est passé à chaque invocation |
Architecture du Chat avec Historique :
┌─────────────────────────────────────────────────┐
│ ChatHistory (état persistant) │
│ ┌───────────────────────────────────────────┐ │
│ │ [System] "Vous êtes un chatbot..." │ │
│ │ [User] "Salut, je cherche..." │ │
│ │ [Assistant] "Salut ! La philosophie..." │ │
│ │ [User] "Peux-tu m'en recommander..." │ │
│ │ [Assistant] "Bien sûr ! Voici..." │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
↓ À chaque tour
Prompt: `{$history}` + `{$user_input}`
↓
Service LLM (avec contexte complet)
↓
Réponse → Ajoutée à l'historique
Flux de conversation :
| Tour | Entrée utilisateur | Historique passé au LLM | Action |
|---|---|---|---|
| 1 | “Salut, je cherche…” | [System] | Réponse + ajout user/assistant à historique |
| 2 | “Peux-tu m’en recommander…” | [System] + [U1] + [A1] | Réponse avec contexte du tour 1 |
| 3+ | Messages suivants | [System] + tous les tours précédents | Contexte cumulatif |
Points clés :
Limitations et solutions :
| Problème | Impact | Solution |
|---|---|---|
| Contexte trop long | Dépassement max_tokens | Implémenter sliding window (garder N derniers messages) |
| Coût API croissant | Chaque tour envoie tout l’historique | Utiliser summarization ou compression |
| Perte de focus | Le bot peut dériver du sujet initial | Ré-injecter le message système périodiquement |
Note technique : ChatHistory peut être sérialisé/désérialisé pour persister les conversations entre sessions (ex: sauvegarder en JSON ou base de données).
| Concept | Description | Code cle |
|---|---|---|
| Kernel | Orchestrateur central SK | Kernel() |
| Service | Connexion LLM | kernel.add_service(OpenAIChatCompletion(...)) |
| Plugin | Collection de fonctions | kernel.add_plugin(parent_directory=..., plugin_name=...) |
| Fonction sémantique | Prompt template execute | kernel.add_function(prompt_template_config=...) |
| KernelArguments | Paramètres dynamiques | KernelArguments(input=..., style=...) |
| ChatHistory | Historique conversation | ChatHistory() + add_user_message() |
| Notebook suivant | Contenu |
|---|---|
| 02-Functions | Function Calling moderne, Memory, Groundedness |
| 03-Agents | ChatCompletionAgent, AgentGroupChat |
Navigation : Index | 02-Functions >>