Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Avertissement
L’infrastructure de processus de noyau sémantique est expérimentale, toujours en cours de développement et est susceptible de changer.
Aperçu
Dans les sections précédentes, nous avons créé un processus pour nous aider à automatiser la création de la documentation pour notre nouveau produit. Notre processus peut maintenant générer de la documentation spécifique à notre produit et s’assurer qu’il répond à notre barre de qualité en l’exécutant via un cycle de vérification et de modification. Dans cette section, nous allons améliorer à nouveau ce processus en demandant à un humain d’approuver ou de rejeter la documentation avant sa publication. La flexibilité du cadre de processus signifie qu’il existe plusieurs façons de procéder, mais dans cet exemple, nous allons démontrer l’intégration avec un système pubsub externe pour demander l’approbation.
Faire en sorte que la publication attende l'approbation
La première modification que nous devons apporter au processus consiste à faire en sorte que l’étape de publication attende l’approbation avant de publier la documentation. Une option consiste simplement à ajouter un deuxième paramètre pour l’approbation à la fonction PublishDocumentation dans la PublishDocumentationStep. Cela fonctionne, car un KernelFunction dans une étape n’est appelé que lorsque tous ses paramètres requis ont été fournis.
// A process step to publish documentation
public class PublishDocumentationStep : KernelProcessStep
{
[KernelFunction]
public DocumentInfo PublishDocumentation(DocumentInfo document, bool userApproval) // added the userApproval parameter
{
// Only publish the documentation if it has been approved
if (userApproval)
{
// For example purposes we just write the generated docs to the console
Console.WriteLine($"[{nameof(PublishDocumentationStep)}]:\tPublishing product documentation approved by user: \n{document.Title}\n{document.Content}");
}
return document;
}
}
La prise en charge du comportement de processus de l’homme dans la boucle Python est bientôt disponible.
Avec le code ci-dessus, la fonction PublishDocumentation dans l'PublishDocumentationStep est appelée uniquement lorsque la documentation générée a été envoyée au paramètre document et que le résultat de l’approbation a été envoyé au paramètre userApproval.
Nous pouvons maintenant réutiliser la logique existante d’étape ProofreadStep pour émettre un événement à notre système pubsub externe qui informera l’approbateur humain qu’il existe une nouvelle demande.
// A process step to publish documentation
public class ProofReadDocumentationStep : KernelProcessStep
{
...
if (formattedResponse.MeetsExpectations)
{
// Events that are getting piped to steps that will be resumed, like PublishDocumentationStep.OnPublishDocumentation
// require events to be marked as public so they are persisted and restored correctly
await context.EmitEventAsync("DocumentationApproved", data: document, visibility: KernelProcessEventVisibility.Public);
}
...
}
Étant donné que nous voulons publier la documentation nouvellement générée lorsqu’elle est approuvée par l’agent de vérification linguistique, les documents approuvés sont mis en file d’attente à l’étape de publication. En outre, une personne sera avertie par le biais de notre système externe de publication/souscription avec une mise à jour sur le dernier document. Nous allons mettre à jour le flux de processus pour qu’il corresponde à cette nouvelle conception.
La prise en charge du comportement de processus de l’homme dans la boucle Python est bientôt disponible.
// Create the process builder
ProcessBuilder processBuilder = new("DocumentationGeneration");
// Add the steps
var infoGatheringStep = processBuilder.AddStepFromType<GatherProductInfoStep>();
var docsGenerationStep = processBuilder.AddStepFromType<GenerateDocumentationStepV2>();
var docsProofreadStep = processBuilder.AddStepFromType<ProofreadStep>();
var docsPublishStep = processBuilder.AddStepFromType<PublishDocumentationStep>();
// internal component that allows emitting SK events externally, a list of topic names
// is needed to link them to existing SK events
var proxyStep = processBuilder.AddProxyStep(["RequestUserReview", "PublishDocumentation"]);
// Orchestrate the events
processBuilder
.OnInputEvent("StartDocumentGeneration")
.SendEventTo(new(infoGatheringStep));
processBuilder
.OnInputEvent("UserRejectedDocument")
.SendEventTo(new(docsGenerationStep, functionName: "ApplySuggestions"));
// When external human approval event comes in, route it to the 'isApproved' parameter of the docsPublishStep
processBuilder
.OnInputEvent("UserApprovedDocument")
.SendEventTo(new(docsPublishStep, parameterName: "userApproval"));
// Hooking up the rest of the process steps
infoGatheringStep
.OnFunctionResult()
.SendEventTo(new(docsGenerationStep, functionName: "GenerateDocumentation"));
docsGenerationStep
.OnEvent("DocumentationGenerated")
.SendEventTo(new(docsProofreadStep));
docsProofreadStep
.OnEvent("DocumentationRejected")
.SendEventTo(new(docsGenerationStep, functionName: "ApplySuggestions"));
// When the proofreader approves the documentation, send it to the 'document' parameter of the docsPublishStep
// Additionally, the generated document is emitted externally for user approval using the pre-configured proxyStep
docsProofreadStep
.OnEvent("DocumentationApproved")
// [NEW] addition to emit messages externally
.EmitExternalEvent(proxyStep, "RequestUserReview") // Hooking up existing "DocumentationApproved" to external topic "RequestUserReview"
.SendEventTo(new(docsPublishStep, parameterName: "document"));
// When event is approved by user, it gets published externally too
docsPublishStep
.OnFunctionResult()
// [NEW] addition to emit messages externally
.EmitExternalEvent(proxyStep, "PublishDocumentation");
var process = processBuilder.Build();
return process;
Enfin, une implémentation de l’interface IExternalKernelProcessMessageChannel doit être fournie, car elle est utilisée en interne par le nouveau ProxyStep. Cette interface est utilisée pour émettre des messages en externe. L’implémentation de cette interface dépend du système externe que vous utilisez. Dans cet exemple, nous allons utiliser un client personnalisé que nous avons créé pour envoyer des messages à un système pubsub externe.
// Example of potential custom IExternalKernelProcessMessageChannel implementation
public class MyCloudEventClient : IExternalKernelProcessMessageChannel
{
private MyCustomClient? _customClient;
// Example of an implementation for the process
public async Task EmitExternalEventAsync(string externalTopicEvent, KernelProcessProxyMessage message)
{
// logic used for emitting messages externally.
// Since all topics are received here potentially
// some if else/switch logic is needed to map correctly topics with external APIs/endpoints.
if (this._customClient != null)
{
switch (externalTopicEvent)
{
case "RequestUserReview":
var requestDocument = message.EventData.ToObject() as DocumentInfo;
// As an example only invoking a sample of a custom client with a different endpoint/api route
this._customClient.InvokeAsync("REQUEST_USER_REVIEW", requestDocument);
return;
case "PublishDocumentation":
var publishedDocument = message.EventData.ToObject() as DocumentInfo;
// As an example only invoking a sample of a custom client with a different endpoint/api route
this._customClient.InvokeAsync("PUBLISH_DOC_EXTERNALLY", publishedDocument);
return;
}
}
}
public async ValueTask Initialize()
{
// logic needed to initialize proxy step, can be used to initialize custom client
this._customClient = new MyCustomClient("http://localhost:8080");
this._customClient.Initialize();
}
public async ValueTask Uninitialize()
{
// Cleanup to be executed when proxy step is uninitialized
if (this._customClient != null)
{
await this._customClient.ShutdownAsync();
}
}
}
Enfin, pour permettre au processus ProxyStep d’utiliser l’implémentation IExternalKernelProcessMessageChannel , dans ce cas MyCloudEventClient, nous devons le diriger correctement.
Lors de l'utilisation du runtime local, la classe implémentée peut être passée lorsqu'on invoque StartAsync sur la classe KernelProcess.
KernelProcess process;
IExternalKernelProcessMessageChannel myExternalMessageChannel = new MyCloudEventClient();
// Start the process with the external message channel
await process.StartAsync(kernel, new KernelProcessEvent
{
Id = inputEvent,
Data = input,
},
myExternalMessageChannel)
Lorsque vous utilisez Dapr Runtime, la plomberie doit être effectuée via l’injection de dépendances lors de la configuration du programme du projet.
var builder = WebApplication.CreateBuilder(args);
...
// depending on the application a singleton or scoped service can be used
// Injecting SK Process custom client IExternalKernelProcessMessageChannel implementation
builder.Services.AddSingleton<IExternalKernelProcessMessageChannel, MyCloudEventClient>();
La prise en charge du comportement de processus de l’homme dans la boucle Python est bientôt disponible.
Deux modifications ont été apportées au flux de processus :
- Ajout d’un événement d’entrée nommé
HumanApprovalResponsequi sera routé vers le paramètreuserApprovalde l’étape dedocsPublishStep. - Étant donné que KernelFunction dans
docsPublishStepa maintenant deux paramètres, nous devons mettre à jour l’itinéraire existant pour spécifier le nom de paramètre dedocument.
Exécutez le processus comme vous l’avez fait précédemment et notez que cette fois lorsque le lecteur de vérification approuve la documentation générée et l’envoie au paramètre document de l’étape docPublishStep, l’étape n’est plus appelée, car elle attend le paramètre userApproval. À ce stade, le processus est inactif, car aucune étape n’est prête à être appelée et l’appel que nous avons effectué pour démarrer le processus retourne. Le processus restera dans cet état inactif jusqu’à ce que notre humain dans le processus intervienne pour approuver ou rejeter la demande de publication. Une fois que cela s’est produit et que le résultat a été communiqué à notre programme, nous pouvons redémarrer le processus avec le résultat.
// Restart the process with approval for publishing the documentation.
await process.StartAsync(kernel, new KernelProcessEvent { Id = "UserApprovedDocument", Data = true });
La prise en charge du comportement de processus de l’homme dans la boucle Python est bientôt disponible.
Lorsque le processus est redémarré avec le UserApprovedDocument, il reprendra là où il s'était arrêté et invoquera le docsPublishStep avec userApproval réglé sur true, et notre documentation sera publiée. S’il est redémarché avec l’événement UserRejectedDocument , le processus lance la ApplySuggestions fonction à l’étape docsGenerationStep et le processus continue comme avant.
Le processus est maintenant terminé et nous avons ajouté une étape avec intervention humaine à notre démarche. Le processus peut maintenant être utilisé pour générer de la documentation pour notre produit, le lire et le publier une fois qu’il a été approuvé par un humain.