Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Avvertimento
Il framework del processo del kernel semantico è ancora in fase di sviluppo e sperimentale, ed è soggetto a modifiche.
Panoramica
Nelle sezioni precedenti è stato creato un processo per automatizzare la creazione della documentazione per il nuovo prodotto. Ora il nostro processo può generare documentazione specifica per il prodotto e garantisce che soddisfi i nostri standard di qualità attraverso un ciclo di revisione e correzione. In questa sezione si migliorerà di nuovo su tale processo richiedendo a un utente di approvare o rifiutare la documentazione prima della pubblicazione. La flessibilità del framework di processo implica che esistono diversi modi per eseguire questa operazione, ma in questo esempio verrà illustrata l'integrazione con un sistema pubub esterno per richiedere l'approvazione.
Rendere la pubblicazione in attesa di approvazione
La prima modifica da apportare al processo consiste nel fare in modo che il passaggio di pubblicazione attenda l'approvazione prima di pubblicare la documentazione. Un'opzione consiste semplicemente nell'aggiungere un secondo parametro per l'approvazione alla funzione PublishDocumentation nel PublishDocumentationStep. Questa operazione funziona perché un kernelFunction in un passaggio verrà richiamato solo quando sono stati forniti tutti i relativi parametri obbligatori.
// 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;
}
}
Il supporto per il comportamento del processo Python "human-in-the-loop" sarà presto disponibile.
Con il codice precedente, la funzione PublishDocumentation nel PublishDocumentationStep verrà richiamata solo quando la documentazione generata è stata inviata al parametro document e il risultato dell'approvazione è stato inviato al parametro userApproval.
È ora possibile riutilizzare la logica esistente del ProofreadStep passaggio per generare un evento al sistema pubsub esterno che informerà il responsabile dell'approvazione umano che c'è una nuova richiesta.
// 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);
}
...
}
Poiché desideriamo pubblicare la documentazione appena generata quando viene approvata dall'agente di revisione, i documenti approvati verranno messi in coda per la pubblicazione. Inoltre, un essere umano riceverà una notifica tramite il nostro sistema pubsub esterno con un aggiornamento sul documento più recente. Si aggiornerà ora il flusso di processo in modo che corrisponda a questa nuova progettazione.
Il supporto per il comportamento del processo Python "human-in-the-loop" sarà presto disponibile.
// 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;
Infine, deve essere fornita un'implementazione dell'interfaccia IExternalKernelProcessMessageChannel perché viene usata internamente dal nuovo ProxyStep. Questa interfaccia viene usata per generare messaggi esternamente. L'implementazione di questa interfaccia dipenderà dal sistema esterno in uso. In questo esempio si userà un client personalizzato creato per inviare messaggi a un sistema pubub esterno.
// 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();
}
}
}
Infine, per consentire al processo ProxyStep di usare l'implementazione IExternalKernelProcessMessageChannel , in questo caso MyCloudEventClient, è necessario inviarlo tramite pipe correttamente.
Quando si usa il runtime locale, la classe implementata può essere passata quando si richiama StartAsync sulla 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)
Quando si utilizza Dapr Runtime, è necessario eseguire la configurazione tramite l'inserimento delle dipendenze nella configurazione del programma del progetto.
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>();
Il supporto per il comportamento del processo Python "human-in-the-loop" sarà presto disponibile.
Sono state apportate due modifiche al flusso di processo:
- Aggiunta di un evento di input denominato
HumanApprovalResponseche verrà indirizzato al parametrouserApprovaldel passaggiodocsPublishStep. - Poiché KernelFunction in
docsPublishStepora include due parametri, è necessario aggiornare la route esistente per specificare il nome del parametro didocument.
Eseguire il processo come in precedenza e notare che questa volta quando il correttore di correzione approva la documentazione generata e lo invia al parametro document del passaggio docPublishStep, il passaggio non viene più richiamato perché è in attesa del parametro userApproval. A questo punto il processo diventa inattivo perché non sono disponibili passaggi pronti per essere richiamati e la chiamata effettuata per avviare il processo restituisce. Il processo rimarrà in questo stato di attesa fino a quando l'"umano nel ciclo" non interviene per approvare o rifiutare la richiesta di pubblicazione. Una volta che questo è successo e il risultato è stato comunicato al programma, è possibile riavviare il processo con il risultato.
// Restart the process with approval for publishing the documentation.
await process.StartAsync(kernel, new KernelProcessEvent { Id = "UserApprovedDocument", Data = true });
Il supporto per il comportamento del processo Python "human-in-the-loop" sarà presto disponibile.
Quando il processo verrà avviato nuovamente con il UserApprovedDocument riprenderà da dove era stato interrotto e verrà richiamato il docsPublishStep con userApproval impostato su true, e la nostra documentazione verrà pubblicata. Se viene avviato nuovamente con l'evento UserRejectedDocument , il processo avvierà la ApplySuggestions funzione nel docsGenerationStep passaggio e il processo continuerà come prima.
Il processo è ora completo e abbiamo aggiunto con successo un passaggio umano al processo. Il processo può ora essere usato per generare la documentazione per il prodotto, la correzione e pubblicarla dopo l'approvazione da parte di un essere umano.