A la fin de ce notebook, vous saurez : 1. Comprendre la différence entre Plugins, Agents et Processes 2. Créer des Steps (étapes) de workflow 3. Orchestrer des étapes avec ProcessBuilder 4. Gerer l’etat entre les étapes 5. Implementer des conditions et branchements
Prerequis
Python 3.10+
Notebooks 01-05 completes
Cle API OpenAI configuree (.env)
Duree estimee : 40 minutes
Sommaire
Section
Contenu
Concepts cles
1
Introduction
Plugins vs Agents vs Processes
2
Architecture
Steps, State, Events
3
ProcessBuilder
Creation de workflow
4
Gestion d’etat
Passage de données
5
Conditions
Branchements dynamiques
6
Cas d’usage
Validation de contenu
7
Conclusion
Resume, exercices
Process Framework : Introduit en preview dans SK 1.x, GA prevu Q2 2026. Ce framework permet d’orchestrer des workflows complexes avec gestion d’etat, checkpoints, et human-in-the-loop. Ideal pour les pipelines multi-étapes.
# Installation et configurationimport osfrom dotenv import load_dotenvfrom semantic_kernel import Kernelfrom semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAIChatPromptExecutionSettings# Chargement du fichier .envload_dotenv()# Configuration : le Kernel necessite une cle API OpenAIapi_key = os.getenv("OPENAI_API_KEY")if api_key: kernel = Kernel() kernel.add_service(OpenAIChatCompletion(service_id="default"))print("Process Framework - Kernel initialise (cle API detectee)")else: kernel =Noneprint("Process Framework - Kernel non initialise (OPENAI_API_KEY absente)")# Settings par defaut pour les appels chat (utilises plus loin dans le notebook)default_settings = OpenAIChatPromptExecutionSettings()
Process Framework - Kernel initialise (cle API detectee)
Interprétation : Configuration du kernel
Sortie obtenue : Kernel SK configuré avec service OpenAI
Aspect
Valeur
Signification
Service
OpenAIChatCompletion
Modèle de chat (GPT-3.5/4)
Service ID
“default”
Identifiant pour multi-services
Settings
OpenAIChatPromptExecutionSettings
Configuration réutilisable
Points clés : 1. Le kernel est le point d’entrée central de SK 2. add_service() permet de configurer plusieurs modèles (OpenAI, Azure, Anthropic) 3. Les settings par défaut évitent de répéter la config à chaque appel (requis SK 1.39+) 4. Le service_id permet de gérer plusieurs modèles simultanément
Note technique : SK 1.39+ rend les settings obligatoires pour get_chat_message_contents(). Avant, ils étaient optionnels.
1. Introduction : Plugins vs Agents vs Processes
SK offre trois niveaux d’abstraction pour structurer votre code IA :
Niveau
Abstraction
Granularite
Exemple
Plugin
Fonction
Atomique
summarize_text()
Agent
Entite autonome
Tâche
“Resume ce document”
Process
Workflow
Pipeline
Generate -> Review -> Publish
Quand utiliser quoi ?
Le tableau ci-dessous préserve la comparaison originale sans inventer un flux entre les trois niveaux :
Complexité croissante
Plugin
Agent
Process
Responsabilité
Fonction
Autonome
Pipeline
État
Stateless
Stateful
État partagé et checkpoints
Composition
Simple
Tools
Multi-step
Invocation
call()
invoke()
run()
Indicateurs pour utiliser un Process : - Pipeline avec plusieurs étapes séquentielles/paralleles - Besoin de checkpoints (reprise après echec) - Human-in-the-loop (approbation humaine) - Etat partage entre étapes - Conditions de branchement complexes
La même architecture, rendue sous forme de graphe : un Process encapsule un State partagé, une chaîne de Step (Generate → Review → Publish) et un bus d’Events qui déclenche le passage d’une étape à la suivante.
flowchart TB
subgraph PROCESS["PROCESS · conteneur du workflow"]
direction TB
STATE["STATE<br/>données partagées entre étapes"]
S1["STEP · Generate"] --> S2["STEP · Review"] --> S3["STEP · Publish"]
EV["EVENTS<br/>déclencheurs entre étapes"]
STATE -.->|lit / écrit| S1
STATE -.->|lit / écrit| S2
STATE -.->|lit / écrit| S3
S1 -.->|émet| EV
S2 -.->|émet| EV
S3 -.->|émet| EV
end
classDef state fill:#cfe2ff,stroke:#084298,color:#052c65
classDef step fill:#d1e7dd,stroke:#0f5132,color:#052e16
classDef event fill:#fff3cd,stroke:#b8860b,color:#5c4400
class STATE state
class S1,S2,S3 step
class EV event
Lecture. Le Process est le conteneur ; le State est la mémoire partagée que chaque Step lit et met à jour ; les Events sont les déclencheurs qui font avancer le pipeline Generate → Review → Publish. C’est cette séparation état / étapes / événements qui permet à un workflow d’être repris après un point de contrôle (checkpoint).
3. Creation de Steps
Les Steps sont les briques de base des processes.
from dataclasses import dataclassfrom typing import Optionalfrom semantic_kernel.contents import ChatHistory# Definition de l'etat du process@dataclassclass ContentState:"""Etat partage entre les etapes du workflow.""" topic: str draft_content: Optional[str] =None review_feedback: Optional[str] =None is_approved: bool=False final_content: Optional[str] =None# Step 1: Generation de contenuasyncdef generate_content_step(state: ContentState, kernel: Kernel) -> ContentState:"""Genere un brouillon de contenu."""print(f"[Step 1] Generation du contenu sur: {state.topic}") chat_service = kernel.get_service(service_id="default") history = ChatHistory() history.add_user_message(f"Ecris un paragraphe court sur: {state.topic}")# SK 1.39+: settings requis response =await chat_service.get_chat_message_contents( chat_history=history, settings=default_settings ) state.draft_content =str(response[0])print(f"[Step 1] Brouillon genere: {len(state.draft_content)} caracteres")return state# Step 2: Review du contenuasyncdef review_content_step(state: ContentState, kernel: Kernel) -> ContentState:"""Evalue la qualite du contenu."""print(f"[Step 2] Review du contenu") chat_service = kernel.get_service(service_id="default") history = ChatHistory() history.add_user_message(f"""Evalue ce contenu et reponds par 'APPROVED' si c'est bon, sinon donne des suggestions:{state.draft_content}""" )# SK 1.39+: settings requis response =await chat_service.get_chat_message_contents( chat_history=history, settings=default_settings ) state.review_feedback =str(response[0]) state.is_approved ="approved"in state.review_feedback.lower()print(f"[Step 2] Approuve: {state.is_approved}")return state# Step 3: Publicationasyncdef publish_content_step(state: ContentState) -> ContentState:"""Publie le contenu final."""print(f"[Step 3] Publication du contenu")if state.is_approved: state.final_content = state.draft_contentprint(f"[Step 3] Contenu publie avec succes!")else:print(f"[Step 3] Contenu rejete - necessite revision")return stateprint("Steps definis: generate, review, publish")
Steps definis: generate, review, publish
Exercice 1 : Step de traduction multilingue
Le pipeline generate -> review -> publish peut etre enrichi avec une étape de traduction pour produire du contenu dans plusieurs langues.
Objectif : Implementer une fonction translate_content_step() qui traduit le contenu genere vers une langue cible.
Indices : - # Étape 1 : Ajouter un champ translated_content et target_language au ContentState - # Étape 2 : Utiliser le service LLM pour traduire draft_content vers la langue cible - # Étape 3 : Adapter le pipeline pour generer, traduire, puis reviewer la traduction - # Indice : Specifier explicitement le contexte de traduction dans le prompt (“traduis en anglais en preservant le ton et le style”)
@dataclassclass MultilingualContentState:"""Etat etendu pour le pipeline multilingue.""" topic: str target_language: str="en" draft_content: str=None translated_content: str=None# TODO etudiant : ajoutez ce champ is_approved: bool=Falseasyncdef translate_content_step(state: MultilingualContentState, kernel: Kernel) -> MultilingualContentState:"""TODO etudiant : Traduire le contenu vers la langue cible. Args: state: Etat avec draft_content et target_language kernel: Kernel SK avec service LLM Returns: Etat mis a jour avec translated_content """# TODO etudiant : utiliser le service LLM pour traduirereturnNone# Test :# state = MultilingualContentState(topic="L'IA en France", target_language="en", draft_content="L'intelligence artificielle transforme...")# result = await translate_content_step(state, kernel)# print(f"Traduction: {result.translated_content[:100]}...")print("Exercice a completer")
Points clés : 1. State pattern : Chaque step reçoit et retourne l’état complet (ContentState) 2. Immutabilité partielle : L’objet state est muté in-place (Python dataclass mutable) 3. Async/await : Les steps sont async pour supporter les appels réseau (LLM) 4. Separation of concerns : Chaque step a une responsabilité unique (SRP)
Note technique : SK 1.39+ requiert settings dans get_chat_message_contents(). Les versions précédentes acceptaient settings=None.
# Execution manuelle du pipelineasyncdef run_content_pipeline(topic: str, kernel: Kernel) -> ContentState:"""Execute le pipeline de validation de contenu."""# Initialiser l'etat state = ContentState(topic=topic)# Etape 1: Generation state =await generate_content_step(state, kernel)# Etape 2: Review state =await review_content_step(state, kernel)# Etape 3: Publication (conditionnelle) state =await publish_content_step(state)return state# Test du pipelineresult =await run_content_pipeline("Les avantages de Semantic Kernel", kernel)print("\n"+"="*60)print("RESULTAT DU PIPELINE")print("="*60)print(f"Topic: {result.topic}")print(f"Approuve: {result.is_approved}")print(f"Contenu final: {'Oui'if result.final_content else'Non'}")
[Step 1] Generation du contenu sur: Les avantages de Semantic Kernel
[Step 1] Brouillon genere: 672 caracteres
[Step 2] Review du contenu
[Step 2] Approuve: True
[Step 3] Publication du contenu
[Step 3] Contenu publie avec succes!
============================================================
RESULTAT DU PIPELINE
============================================================
Topic: Les avantages de Semantic Kernel
Approuve: True
Contenu final: Oui
Interprétation : Exécution du pipeline
Sortie obtenue : Contenu généré, reviewé et publié avec succès
Métrique
Valeur
Explication
Caractères générés
~1039
Paragraphe court produit par GPT
Approbation
True
Review automatique positive
Étapes exécutées
3/3
Pipeline complet sans échec
Temps estimé
~5-10s
2 appels LLM + logique
Points clés : 1. Pipeline séquentiel : Les steps s’exécutent dans l’ordre défini 2. État partagé : state est passé entre les fonctions (pas de base de données) 3. Exécution conditionnelle : publish_step vérifie is_approved avant publication 4. Traçabilité : Les print() permettent d’observer le flux d’exécution
Pattern observé : Generate → Review → Publish (workflow classique de production de contenu)
Note technique : Ce pipeline est stateless entre exécutions. Pour persister l’état (checkpoints), utiliser Dapr State Store ou un stockage externe.
4. Process avec itérations
Un pattern courant : iterer jusqu’a ce qu’une condition soit remplie.
asyncdef run_iterative_pipeline( topic: str, kernel: Kernel, max_iterations: int=3) -> ContentState:"""Pipeline avec boucle de revision.""" state = ContentState(topic=topic)for iteration inrange(max_iterations):print(f"\n--- Iteration {iteration +1}/{max_iterations} ---")# Generation (ou revision)if iteration ==0: state =await generate_content_step(state, kernel)else:# Reviser en tenant compte du feedback state =await revise_content_step(state, kernel)# Review state =await review_content_step(state, kernel)# Condition de sortieif state.is_approved:print(f"\n[SUCCESS] Contenu approuve apres {iteration +1} iteration(s)")break# Publication state =await publish_content_step(state)return stateasyncdef revise_content_step(state: ContentState, kernel: Kernel) -> ContentState:"""Revise le contenu selon le feedback."""print(f"[Step R] Revision du contenu") chat_service = kernel.get_service(service_id="default") history = ChatHistory() history.add_user_message(f"""Revise ce contenu en tenant compte du feedback: CONTENU ORIGINAL:{state.draft_content} FEEDBACK:{state.review_feedback} Produis une version amelioree.""" )# SK 1.39+: settings requis response =await chat_service.get_chat_message_contents( chat_history=history, settings=default_settings ) state.draft_content =str(response[0])print(f"[Step R] Contenu revise")return state# Test du pipeline iteratifresult =await run_iterative_pipeline("L'importance du RAG en IA", kernel, max_iterations=3)print("\n"+"="*60)print(f"Resultat final: {'PUBLIE'if result.final_content else'NON PUBLIE'}")
--- Iteration 1/3 ---
[Step 1] Generation du contenu sur: L'importance du RAG en IA
[Step 1] Brouillon genere: 644 caracteres
[Step 2] Review du contenu
[Step 2] Approuve: True
[SUCCESS] Contenu approuve apres 1 iteration(s)
[Step 3] Publication du contenu
[Step 3] Contenu publie avec succes!
============================================================
Resultat final: PUBLIE
Exercice 2 : Collecteur de metriques de pipeline
En production, il est crucial de mesurer les performances de chaque étape d’un pipeline (temps, cout, taux de succes).
Objectif : Implementer une classe PipelineMetrics qui collecte les metriques d’exécution d’un workflow.
Indices : - # Étape 1 : Enregistrer le temps de debut et fin de chaque step avec time.time() - # Étape 2 : Compter les appels LLM et estimer le cout (GPT-4o: ~$2.50/1M input tokens) - # Étape 3 : Produire un rapport avec le temps total, le taux de succes par step et le cout estime - # Indice : Utiliser un decorator ou un contexte (__enter__/__exit__) pour mesurer automatiquement chaque step
import time as time_moduleclass PipelineMetrics:"""TODO etudiant : Collecteur de metriques pour un pipeline de steps. """def__init__(self):# TODO etudiant : initialiser les structures de stockagepassdef start_step(self, step_name: str) ->None:"""TODO etudiant : Debuter la mesure pour une etape."""passdef end_step(self, step_name: str, success: bool=True, tokens_used: int=0) ->None:"""TODO etudiant : Terminer la mesure et enregistrer les metriques."""passdef get_report(self) ->dict:"""TODO etudiant : Retourner un rapport de metriques."""returnNone# Test :# metrics = PipelineMetrics()# metrics.start_step("generate")# # ... appel LLM ...# metrics.end_step("generate", success=True, tokens_used=500)# report = metrics.get_report()# print(f"Temps total: {report['total_time_seconds']:.2f}s")# print(f"Cout estime: ${report['estimated_cost']:.4f}")print("Exercice a completer")
Exercice a completer
Interprétation : Pipeline itératif avec révision
Sortie obtenue : Contenu approuvé après 1 itération
Métrique
Valeur
Signification
Itérations max
3
Budget de révisions autorisées
Itérations réelles
1
Contenu approuvé du premier coup
Steps exécutés
Generate → Review → Publish
Pas besoin de révision
Appels LLM
2
Generate + Review (pas de Revise)
Points clés : 1. Boucle de feedback : Le pipeline peut itérer jusqu’à approbation 2. Early exit : break dès que is_approved == True (économise des appels LLM) 3. Step conditionnel : revise_content_step n’est appelé qu’à partir de l’itération 2 4. Budget de tokens : Limiter max_iterations pour éviter les coûts incontrôlés
Note technique : Pour des itérations complexes, LangGraph offre des primitives dédiées (cycles, checkpoints). SK Process est plus adapté aux workflows linéaires avec branchements simples.
5. Pattern avec Human-in-the-Loop (conceptuel)
Le Process Framework permet d’integrer des points d’approbation humaine.
# Simulation d'approbation humaineasyncdef human_approval_step(state: ContentState) -> ContentState:"""Demande une approbation humaine (simule)."""print(f"\n[HUMAN] Contenu a approuver:")print("-"*40)print(state.draft_content[:200] +"..."iflen(state.draft_content) >200else state.draft_content)print("-"*40)# En production, ceci serait un webhook, email, ou UI# Ici on simule une approbation automatiqueprint("[HUMAN] Approbation simulee...") state.is_approved =Truereturn state# Pipeline avec approbation humaineasyncdef run_human_in_loop_pipeline(topic: str, kernel: Kernel) -> ContentState:"""Pipeline avec point d'approbation humaine.""" state = ContentState(topic=topic)# Generation state =await generate_content_step(state, kernel)# Review automatique state =await review_content_step(state, kernel)# Point d'arret pour approbation humaineifnot state.is_approved:print("\n[PROCESS] Review automatique negative - demande approbation humaine") state =await human_approval_step(state)# Publication state =await publish_content_step(state)return state# Testresult =await run_human_in_loop_pipeline("Les limites des LLMs", kernel)print(f"\nContenu final publie: {'Oui'if result.final_content else'Non'}")
[Step 1] Generation du contenu sur: Les limites des LLMs
[Step 1] Brouillon genere: 753 caracteres
[Step 2] Review du contenu
[Step 2] Approuve: True
[Step 3] Publication du contenu
[Step 3] Contenu publie avec succes!
Contenu final publie: Oui
Exercice 3 : Constructeur de workflow dynamique
Les workflows de production sont souvent dynamiques : le nombre d’étapes et les conditions changent selon le contenu.
Objectif : Implementer une classe WorkflowBuilder qui permet de construire un pipeline dynamiquement.
Indices : - # Étape 1 : Créer une classe avec une méthode add_step(name, function) et add_condition(step_name, condition_fn) - # Étape 2 : Implementer run(initial_state) qui execute les steps en sequence, en verifiant les conditions - # Étape 3 : Ajouter une méthode get_execution_plan() qui retourne l’ordre d’exécution prevu - # Indice : Stocker les steps dans une liste ordonnee et les conditions dans un dict indexe par nom de step
class WorkflowBuilder:"""TODO etudiant : Constructeur de pipeline dynamique. """def__init__(self):# TODO etudiant : initialiser _steps et _conditionspassdef add_step(self, name: str, step_fn) ->'WorkflowBuilder':"""TODO etudiant : Ajouter une etape au workflow."""returnNonedef add_condition(self, step_name: str, condition_fn) ->'WorkflowBuilder':"""TODO etudiant : Ajouter une condition avant une etape."""returnNonedef get_execution_plan(self) ->list:"""TODO etudiant : Retourner le plan d'execution prevu."""returnNoneasyncdef run(self, initial_state) ->object:"""TODO etudiant : Executer le pipeline dynamiquement."""returnNone# Test :# builder = WorkflowBuilder()# builder.add_step("generate", generate_content_step)# builder.add_step("review", review_content_step)# builder.add_condition("review", lambda state: state.draft_content is not None)# print(builder.get_execution_plan())print("Exercice a completer")
Exercice a completer
Interprétation : Human-in-the-Loop
Sortie obtenue : Pipeline avec point d’approbation humaine (simulé)
Composant
Implémentation
Équivalent production
human_approval_step
Fonction simulée
Webhook, email, UI dashboard
Trigger
if not state.is_approved
Après échec de review auto
Timeout
Aucun (simulation)
Délai d’attente configurable
Notification
Print
Slack, Teams, email
Points clés : 1. Breakpoint asynchrone : Le process attend une action externe 2. Deux niveaux de validation : Review auto (LLM) + Review humaine (fallback) 3. Stateful : L’état doit être persisté si le workflow attend des heures/jours 4. Reprise après pause : Nécessite un système de checkpoints (Dapr, base de données)
Architecture pour production :
┌──────────┐ ┌──────────┐ ┌────────────┐
│ Generate │───>│ Review │───>│ If not OK │
└──────────┘ └──────────┘ └─────┬──────┘
│
v
┌─────────────────┐
│ Send webhook │
│ Wait for event │ <- Humain approuve
└────────┬────────┘
│
v
┌─────────────────┐
│ Publish │
└─────────────────┘
Note technique : SK Process Framework (preview) n’a pas encore de primitive dédiée pour human-in-the-loop. Utiliser Dapr Workflows pour cette fonctionnalité en production.
Le même flux, rendu sous forme de graphe avec le branchement conditionnel explicite :
flowchart TD
G["Generate"] --> R["Review · LLM auto"]
R --> D{"Review OK ?"}
D -->|oui| P["Publish"]
D -->|non| W["Send webhook<br/>Wait for event"]
W -->|humain approuve| P
classDef step fill:#d1e7dd,stroke:#0f5132,color:#052e16
classDef decision fill:#fff3cd,stroke:#b8860b,color:#5c4400
classDef human fill:#f8d7da,stroke:#842029,color:#2c0b0e
class G,R,P step
class D decision
class W human
Lecture. Tant que la revue automatique échoue, le process bascule sur un breakpoint asynchrone : il émet un webhook et attend un événement externe (l’approbation humaine) avant de publier. En production, cet état d’attente doit être persisté (Dapr, Temporal, file + base) pour survivre à une pause de plusieurs heures.
6. Comparaison avec alternatives
Framework
Forces
Cas d’usage
SK Process
Integration SK native, Dapr support
Workflows IA simples
LangGraph
Graphes complexes, cycles
Multi-agent sophistique
Prefect/Airflow
Scheduling, monitoring
Data pipelines
Temporal
Durabilite, versioning
Workflows long-running
AutoGen Flows
Multi-agent natif
Conversations complexes
Quand utiliser SK Process Framework ?
OUI
NON
Déjà dans l’ecosysteme SK
Besoins de scheduling avance
Pipelines lineaires simples
Graphes avec cycles complexes
Human-in-the-loop basique
Monitoring entreprise
Prototypage rapide
Production critique
Conclusion
Resume des concepts
Concept
Description
Code cle
Process
Workflow orchestre
Conteneur de steps
Step
Étape d’exécution
Fonction async
State
Données partagees
Dataclass mutable
Condition
Branchement
if state.is_approved:
Itération
Boucle jusqu’a succes
for i in range(max):
Points cles a retenir
Plugins < Agents < Processes - Choisir le bon niveau d’abstraction
L’etat lie les étapes - Dataclass partagee entre steps
Les conditions permettent le branchement - Logique metier dans l’etat
Human-in-the-loop est essentiel - Points d’arret pour approbation