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.
Importante
Questa funzionalità si trova nella fase sperimentale. Le funzionalità in questa fase sono in fase di sviluppo e soggette a cambiamenti prima di passare alla fase di anteprima o alla versione candidata al rilascio.
Informazioni generali
In questo esempio verrà illustrato come usare AgentGroupChat
per coordinare la collaborazione di due agenti diversi che lavorano per esaminare e riscrivere il contenuto fornito dall'utente. A ogni agente viene assegnato un ruolo distinto:
- Revisore: rivede e fornisce orientamento allo scrittore.
- Writer: aggiorna il contenuto utente in base all'input del revisore.
L'approccio verrà suddiviso passo dopo passo per mettere in evidenza le parti chiave del processo di codifica.
Come iniziare
Prima di procedere con la codifica delle funzionalità, assicurati che l'ambiente di sviluppo sia completamente allestito e configurato.
Suggerimento
Questo esempio usa un file di testo facoltativo come parte dell'elaborazione. Se si vuole usarlo, è possibile scaricarlo qui. Posiziona il file nella cartella di lavoro del codice.
Per iniziare, creare un progetto console. Includere quindi i seguenti riferimenti ai pacchetti per garantire che tutte le dipendenze necessarie siano disponibili.
Per aggiungere le dipendenze dei pacchetti dalla riga di comando, usare il dotnet
comando :
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Binder
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables
dotnet add package Microsoft.SemanticKernel.Connectors.AzureOpenAI
dotnet add package Microsoft.SemanticKernel.Agents.Core --prerelease
Se si gestiscono pacchetti NuGet in Visual Studio, verificare che
Include prerelease
sia selezionata.
Il file di progetto (.csproj
) deve contenere le definizioni seguenti PackageReference
:
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="<stable>" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="<stable>" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="<stable>" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="<stable>" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="<stable>" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" Version="<latest>" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureOpenAI" Version="<latest>" />
</ItemGroup>
Il Agent Framework
è sperimentale e richiede l'eliminazione degli avvisi. Ciò può essere risolto come proprietà nel file di progetto (.csproj
):
<PropertyGroup>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
</PropertyGroup>
Suggerimento
Questo esempio usa un file di testo facoltativo come parte dell'elaborazione. Se si vuole usarlo, è possibile scaricarlo qui. Posiziona il file nella cartella di lavoro del codice.
Per iniziare, installare il pacchetto Python del kernel semantico.
pip install semantic-kernel
Aggiungere quindi le importazioni necessarie.
import asyncio
import os
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import (
KernelFunctionSelectionStrategy,
KernelFunctionTerminationStrategy,
)
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistoryTruncationReducer
from semantic_kernel.functions import KernelFunctionFromPrompt
Funzionalità attualmente non disponibile in Java.
Configurazione
Questo esempio richiede l'impostazione di configurazione per connettersi ai servizi remoti. Sarà necessario definire le impostazioni per OpenAI o Azure OpenAI.
# OpenAI
dotnet user-secrets set "OpenAISettings:ApiKey" "<api-key>"
dotnet user-secrets set "OpenAISettings:ChatModel" "gpt-4o"
# Azure OpenAI
dotnet user-secrets set "AzureOpenAISettings:ApiKey" "<api-key>" # Not required if using token-credential
dotnet user-secrets set "AzureOpenAISettings:Endpoint" "<model-endpoint>"
dotnet user-secrets set "AzureOpenAISettings:ChatModelDeployment" "gpt-4o"
La classe seguente viene usata in tutti gli esempi di Agent. Assicurarsi di includerlo nel progetto per garantire una funzionalità appropriata. Questa classe funge da componente di base per gli esempi seguenti.
using System.Reflection;
using Microsoft.Extensions.Configuration;
namespace AgentsSample;
public class Settings
{
private readonly IConfigurationRoot configRoot;
private AzureOpenAISettings azureOpenAI;
private OpenAISettings openAI;
public AzureOpenAISettings AzureOpenAI => this.azureOpenAI ??= this.GetSettings<Settings.AzureOpenAISettings>();
public OpenAISettings OpenAI => this.openAI ??= this.GetSettings<Settings.OpenAISettings>();
public class OpenAISettings
{
public string ChatModel { get; set; } = string.Empty;
public string ApiKey { get; set; } = string.Empty;
}
public class AzureOpenAISettings
{
public string ChatModelDeployment { get; set; } = string.Empty;
public string Endpoint { get; set; } = string.Empty;
public string ApiKey { get; set; } = string.Empty;
}
public TSettings GetSettings<TSettings>() =>
this.configRoot.GetRequiredSection(typeof(TSettings).Name).Get<TSettings>()!;
public Settings()
{
this.configRoot =
new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddUserSecrets(Assembly.GetExecutingAssembly(), optional: true)
.Build();
}
}
Il modo più rapido per iniziare a usare la configurazione corretta per eseguire il codice di esempio consiste nel creare un .env
file nella radice del progetto (dove viene eseguito lo script). L'esempio richiede che siano disponibili risorse Azure OpenAI o OpenAI.
Configurare le impostazioni seguenti nel .env
file per Azure OpenAI o OpenAI:
AZURE_OPENAI_API_KEY="..."
AZURE_OPENAI_ENDPOINT="https://<resource-name>.openai.azure.com/"
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME="..."
AZURE_OPENAI_API_VERSION="..."
OPENAI_API_KEY="sk-..."
OPENAI_ORG_ID=""
OPENAI_CHAT_MODEL_ID=""
Dopo la configurazione, le rispettive classi di servizi di intelligenza artificiale rileveranno le variabili necessarie e le useranno durante la creazione di istanze.
Funzionalità attualmente non disponibile in Java.
Scrittura del codice
Il processo di codifica per questo esempio prevede:
- Installazione : inizializzazione delle impostazioni e del plug-in.
-
Agent
Definizione - Creare le due istanze diChatCompletionAgent
(Reviewer e Writer). -
Definizione della chat: creare la
AgentGroupChat
e le strategie associate. - Ciclo chat - Scrivere il ciclo che determina l'interazione utente/agente.
Il codice di esempio completo viene fornito nella sezione Finale . Fare riferimento a questa sezione per l'implementazione completa.
Configurazione
Prima di creare qualsiasi ChatCompletionAgent
, è necessario inizializzare le impostazioni di configurazione, i plug-in e Kernel
.
Creare un'istanza della classe Settings
a cui si fa riferimento nella sezione Configurazione precedente.
Settings settings = new();
Funzionalità attualmente non disponibile in Java.
Inizializza ora un'istanza Kernel
con un IChatCompletionService
.
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
settings.AzureOpenAI.ChatModelDeployment,
settings.AzureOpenAI.Endpoint,
new AzureCliCredential());
Kernel kernel = builder.Build();
Inizializzare l'oggetto kernel:
kernel = Kernel()
Funzionalità attualmente non disponibile in Java.
Creiamo anche una seconda istanza Kernel
tramite clonazione e aggiungiamo un plug-in che consentirà alla revisione di inserire contenuto aggiornato nella clip-board.
Kernel toolKernel = kernel.Clone();
toolKernel.Plugins.AddFromType<ClipboardAccess>();
Funzionalità attualmente non disponibile in Java.
Il plug-in Appunti può essere considerato parte dell'esempio.
private sealed class ClipboardAccess
{
[KernelFunction]
[Description("Copies the provided content to the clipboard.")]
public static void SetClipboard(string content)
{
if (string.IsNullOrWhiteSpace(content))
{
return;
}
using Process clipProcess = Process.Start(
new ProcessStartInfo
{
FileName = "clip",
RedirectStandardInput = true,
UseShellExecute = false,
});
clipProcess.StandardInput.Write(content);
clipProcess.StandardInput.Close();
}
}
Funzionalità attualmente non disponibile in Java.
Definizione agente
Si dichiarino ora i nomi degli agenti come const
in modo che possano essere referenziati nelle strategie di AgentGroupChat
:
const string ReviewerName = "Reviewer";
const string WriterName = "Writer";
I nomi degli agenti verranno dichiarati come "Revisore" e "Scrittore".
REVIEWER_NAME = "Reviewer"
COPYWRITER_NAME = "Writer"
Funzionalità attualmente non disponibile in Java.
La definizione dell'agente revisore utilizza il modello esplorato in Guida pratica: Agente di completamento chat.
In questo caso, il revisore ha il ruolo di rispondere all'input dell'utente, fornendo la direzione all'agente writer e verificando il risultato dell'agente writer .
ChatCompletionAgent agentReviewer =
new()
{
Name = ReviewerName,
Instructions =
"""
Your responsibility is to review and identify how to improve user provided content.
If the user has providing input or direction for content already provided, specify how to address this input.
Never directly perform the correction or provide example.
Once the content has been updated in a subsequent response, you will review the content again until satisfactory.
Always copy satisfactory content to the clipboard using available tools and inform user.
RULES:
- Only identify suggestions that are specific and actionable.
- Verify previous suggestions have been addressed.
- Never repeat previous suggestions.
""",
Kernel = toolKernel,
Arguments =
new KernelArguments(
new AzureOpenAIPromptExecutionSettings()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
})
};
agent_reviewer = ChatCompletionAgent(
kernel=kernel,
name=REVIEWER_NAME,
instructions="""
Your responsibility is to review and identify how to improve user provided content.
If the user has provided input or direction for content already provided, specify how to address this input.
Never directly perform the correction or provide an example.
Once the content has been updated in a subsequent response, review it again until it is satisfactory.
RULES:
- Only identify suggestions that are specific and actionable.
- Verify previous suggestions have been addressed.
- Never repeat previous suggestions.
""",
)
Funzionalità attualmente non disponibile in Java.
L'agente writer è simile, ma non richiede la specifica delle impostazioni di esecuzione perché non è configurato con un plug-in.
Qui a Writer viene assegnata un'attività a scopo singolo, seguire la direzione e riscrivere il contenuto.
ChatCompletionAgent agentWriter =
new()
{
Name = WriterName,
Instructions =
"""
Your sole responsibility is to rewrite content according to review suggestions.
- Always apply all review direction.
- Always revise the content in its entirety without explanation.
- Never address the user.
""",
Kernel = kernel,
};
L'agente writer è simile. Viene dato un compito specifico, seguire le istruzioni e riscrivere il contenuto.
agent_writer = ChatCompletionAgent(
kernel=kernel,
name=WRITER_NAME,
instructions="""
Your sole responsibility is to rewrite content according to review suggestions.
- Always apply all review directions.
- Always revise the content in its entirety without explanation.
- Never address the user.
""",
)
Funzionalità attualmente non disponibile in Java.
Definizione chat
Per definire l'AgentGroupChat
è necessario prendere in considerazione le strategie per selezionare il turno di Agent
e determinare quando uscire dal ciclo chat. Per entrambe queste considerazioni, definiremo una Kernel Prompt Function.
Il primo a riflettere sulla selezione Agent
:
L'uso di AgentGroupChat.CreatePromptFunctionForStrategy
fornisce un meccanismo pratico per evitare la codifica HTML del parametro del messaggio .
KernelFunction selectionFunction =
AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Examine the provided RESPONSE and choose the next participant.
State only the name of the chosen participant without explanation.
Never choose the participant named in the RESPONSE.
Choose only from these participants:
- {{{ReviewerName}}}
- {{{WriterName}}}
Always follow these rules when choosing the next participant:
- If RESPONSE is user input, it is {{{ReviewerName}}}'s turn.
- If RESPONSE is by {{{ReviewerName}}}, it is {{{WriterName}}}'s turn.
- If RESPONSE is by {{{WriterName}}}, it is {{{ReviewerName}}}'s turn.
RESPONSE:
{{$lastmessage}}
""",
safeParameterNames: "lastmessage");
selection_function = KernelFunctionFromPrompt(
function_name="selection",
prompt=f"""
Examine the provided RESPONSE and choose the next participant.
State only the name of the chosen participant without explanation.
Never choose the participant named in the RESPONSE.
Choose only from these participants:
- {REVIEWER_NAME}
- {WRITER_NAME}
Rules:
- If RESPONSE is user input, it is {REVIEWER_NAME}'s turn.
- If RESPONSE is by {REVIEWER_NAME}, it is {WRITER_NAME}'s turn.
- If RESPONSE is by {WRITER_NAME}, it is {REVIEWER_NAME}'s turn.
RESPONSE:
{{{{$lastmessage}}}}
"""
)
Funzionalità attualmente non disponibile in Java.
Il secondo valuterà quando uscire dal ciclo chat :
const string TerminationToken = "yes";
KernelFunction terminationFunction =
AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Examine the RESPONSE and determine whether the content has been deemed satisfactory.
If content is satisfactory, respond with a single word without explanation: {{{TerminationToken}}}.
If specific suggestions are being provided, it is not satisfactory.
If no correction is suggested, it is satisfactory.
RESPONSE:
{{$lastmessage}}
""",
safeParameterNames: "lastmessage");
termination_keyword = "yes"
termination_function = KernelFunctionFromPrompt(
function_name="termination",
prompt=f"""
Examine the RESPONSE and determine whether the content has been deemed satisfactory.
If the content is satisfactory, respond with a single word without explanation: {termination_keyword}.
If specific suggestions are being provided, it is not satisfactory.
If no correction is suggested, it is satisfactory.
RESPONSE:
{{{{$lastmessage}}}}
"""
)
Funzionalità attualmente non disponibile in Java.
Entrambe queste strategie richiederanno solo la conoscenza del messaggio di chat più recente. In questo modo si riduce l'utilizzo dei token e si migliorano le prestazioni:
ChatHistoryTruncationReducer historyReducer = new(1);
history_reducer = ChatHistoryTruncationReducer(target_count=1)
Funzionalità attualmente non disponibile in Java.
Finalmente siamo pronti a riunire tutto nella definizione di AgentGroupChat
.
La creazione AgentGroupChat
prevede:
- Includere entrambi gli agenti nel costruttore.
- Definire un
KernelFunctionSelectionStrategy
utilizzando le istanze precedentemente definiteKernelFunction
eKernel
. - Definire un
KernelFunctionTerminationStrategy
utilizzando le istanze precedentemente definiteKernelFunction
eKernel
.
Si noti che ogni strategia è responsabile dell'analisi del KernelFunction
risultato.
AgentGroupChat chat =
new(agentReviewer, agentWriter)
{
ExecutionSettings = new AgentGroupChatSettings
{
SelectionStrategy =
new KernelFunctionSelectionStrategy(selectionFunction, kernel)
{
// Always start with the editor agent.
InitialAgent = agentReviewer,
// Save tokens by only including the final response
HistoryReducer = historyReducer,
// The prompt variable name for the history argument.
HistoryVariableName = "lastmessage",
// Returns the entire result value as a string.
ResultParser = (result) => result.GetValue<string>() ?? agentReviewer.Name
},
TerminationStrategy =
new KernelFunctionTerminationStrategy(terminationFunction, kernel)
{
// Only evaluate for editor's response
Agents = [agentReviewer],
// Save tokens by only including the final response
HistoryReducer = historyReducer,
// The prompt variable name for the history argument.
HistoryVariableName = "lastmessage",
// Limit total number of turns
MaximumIterations = 12,
// Customer result parser to determine if the response is "yes"
ResultParser = (result) => result.GetValue<string>()?.Contains(TerminationToken, StringComparison.OrdinalIgnoreCase) ?? false
}
}
};
Console.WriteLine("Ready!");
La creazione AgentGroupChat
prevede:
- Includere entrambi gli agenti nel costruttore.
- Definire un
KernelFunctionSelectionStrategy
utilizzando le istanze precedentemente definiteKernelFunction
eKernel
. - Definire un
KernelFunctionTerminationStrategy
utilizzando le istanze precedentemente definiteKernelFunction
eKernel
.
Si noti che ogni strategia è responsabile dell'analisi del KernelFunction
risultato.
chat = AgentGroupChat(
agents=[agent_reviewer, agent_writer],
selection_strategy=KernelFunctionSelectionStrategy(
initial_agent=agent_reviewer,
function=selection_function,
kernel=kernel,
result_parser=lambda result: str(result.value[0]).strip() if result.value[0] is not None else WRITER_NAME,
history_variable_name="lastmessage",
history_reducer=history_reducer,
),
termination_strategy=KernelFunctionTerminationStrategy(
agents=[agent_reviewer],
function=termination_function,
kernel=kernel,
result_parser=lambda result: termination_keyword in str(result.value[0]).lower(),
history_variable_name="lastmessage",
maximum_iterations=10,
history_reducer=history_reducer,
),
)
Il lastmessage
history_variable_name
corrisponde al KernelFunctionSelectionStrategy
e alla richiesta di KernelFunctionTerminationStrategy
definita in precedenza. Questo è il percorso in cui viene inserito l'ultimo messaggio durante il rendering del prompt.
Funzionalità attualmente non disponibile in Java.
Il Ciclo Chat
Infine, è possibile coordinare l'interazione tra l'utente e il AgentGroupChat
. Per iniziare, creare un ciclo vuoto.
Nota: a differenza degli altri esempi, non viene gestita alcuna cronologia o thread esterno.
AgentGroupChat
gestisce internamente la cronologia delle conversazioni.
bool isComplete = false;
do
{
} while (!isComplete);
is_complete: bool = False
while not is_complete:
# operational logic
Funzionalità attualmente non disponibile in Java.
Ora catturiamo l'input dell'utente all'interno del ciclo precedente. In questo caso:
- L'input vuoto verrà ignorato
- Il termine
EXIT
segnalerà che la conversazione è stata completata - Il termine
RESET
cancella la cronologiaAgentGroupChat
- Qualsiasi termine che inizia con
@
verrà considerato come un percorso di file il cui contenuto verrà fornito come input - L'input valido verrà aggiunto al
AgentGroupChat
come messaggio di utente.
Console.WriteLine();
Console.Write("> ");
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
continue;
}
input = input.Trim();
if (input.Equals("EXIT", StringComparison.OrdinalIgnoreCase))
{
isComplete = true;
break;
}
if (input.Equals("RESET", StringComparison.OrdinalIgnoreCase))
{
await chat.ResetAsync();
Console.WriteLine("[Conversation has been reset]");
continue;
}
if (input.StartsWith("@", StringComparison.Ordinal) && input.Length > 1)
{
string filePath = input.Substring(1);
try
{
if (!File.Exists(filePath))
{
Console.WriteLine($"Unable to access file: {filePath}");
continue;
}
input = File.ReadAllText(filePath);
}
catch (Exception)
{
Console.WriteLine($"Unable to access file: {filePath}");
continue;
}
}
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, input));
Ora catturiamo l'input dell'utente all'interno del ciclo precedente. In questo caso:
- L'input vuoto verrà ignorato.
- Il termine
exit
segnalerà che la conversazione è stata completata. - Il termine
reset
cancella la cronologiaAgentGroupChat
. - Qualsiasi termine che inizia con
@
verrà considerato come un percorso di file il cui contenuto verrà fornito come input. - L'input valido verrà aggiunto al
AgentGroupChat
come messaggio di utente.
La logica dell'operazione all'interno del ciclo while è simile alla seguente:
print()
user_input = input("User > ").strip()
if not user_input:
continue
if user_input.lower() == "exit":
is_complete = True
break
if user_input.lower() == "reset":
await chat.reset()
print("[Conversation has been reset]")
continue
# Try to grab files from the script's current directory
if user_input.startswith("@") and len(user_input) > 1:
file_name = user_input[1:]
script_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(script_dir, file_name)
try:
if not os.path.exists(file_path):
print(f"Unable to access file: {file_path}")
continue
with open(file_path, "r", encoding="utf-8") as file:
user_input = file.read()
except Exception:
print(f"Unable to access file: {file_path}")
continue
# Add the current user_input to the chat
await chat.add_chat_message(message=user_input)
Funzionalità attualmente non disponibile in Java.
Per avviare la collaborazione Agent
in risposta all'input dell'utente e visualizzare le risposte Agent
, richiamare il AgentGroupChat
; tuttavia, assicurarsi di reimpostare lo stato Completamento da qualsiasi chiamata precedente.
Nota: gli errori del servizio vengono rilevati e visualizzati per evitare l'arresto anomalo del ciclo di conversazione.
chat.IsComplete = false;
try
{
await foreach (ChatMessageContent response in chat.InvokeAsync())
{
Console.WriteLine();
Console.WriteLine($"{response.AuthorName.ToUpperInvariant()}:{Environment.NewLine}{response.Content}");
}
}
catch (HttpOperationException exception)
{
Console.WriteLine(exception.Message);
if (exception.InnerException != null)
{
Console.WriteLine(exception.InnerException.Message);
if (exception.InnerException.Data.Count > 0)
{
Console.WriteLine(JsonSerializer.Serialize(exception.InnerException.Data, new JsonSerializerOptions() { WriteIndented = true }));
}
}
}
try:
async for response in chat.invoke():
if response is None or not response.name:
continue
print()
print(f"# {response.name.upper()}:\n{response.content}")
except Exception as e:
print(f"Error during chat invocation: {e}")
# Reset the chat's complete flag for the new conversation round.
chat.is_complete = False
Funzionalità attualmente non disponibile in Java.
Finale
Combinando tutti i passaggi, otteniamo il codice finale per questo esempio. Di seguito è riportata l'implementazione completa.
Provare a usare questi input suggeriti:
- Ciao
- {"message: "ciao mondo"}
- {"message": "ciao mondo"}
- Semantic Kernel (SK) è un SDK open source che consente agli sviluppatori di creare e orchestrare flussi di lavoro di intelligenza artificiale complessi che coinvolgono l'elaborazione del linguaggio naturale (NLP) e i modelli di Machine Learning. Offre una piattaforma flessibile per l'integrazione di funzionalità di intelligenza artificiale come la ricerca semantica, il riepilogo del testo e i sistemi di dialogo nelle applicazioni. Con SK è possibile combinare facilmente diversi servizi e modelli di intelligenza artificiale, definire le relazioni e orchestrare le interazioni tra di esse.
- trasforma questo in due paragrafi
- Grazie
- @.\SuffragioFemminile.txt
- Va bene, ma è adatto per il mio professore universitario?
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Chat;
using Microsoft.SemanticKernel.Agents.History;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
namespace AgentsSample;
public static class Program
{
public static async Task Main()
{
// Load configuration from environment variables or user secrets.
Settings settings = new();
Console.WriteLine("Creating kernel...");
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
settings.AzureOpenAI.ChatModelDeployment,
settings.AzureOpenAI.Endpoint,
new AzureCliCredential());
Kernel kernel = builder.Build();
Kernel toolKernel = kernel.Clone();
toolKernel.Plugins.AddFromType<ClipboardAccess>();
Console.WriteLine("Defining agents...");
const string ReviewerName = "Reviewer";
const string WriterName = "Writer";
ChatCompletionAgent agentReviewer =
new()
{
Name = ReviewerName,
Instructions =
"""
Your responsibility is to review and identify how to improve user provided content.
If the user has providing input or direction for content already provided, specify how to address this input.
Never directly perform the correction or provide example.
Once the content has been updated in a subsequent response, you will review the content again until satisfactory.
Always copy satisfactory content to the clipboard using available tools and inform user.
RULES:
- Only identify suggestions that are specific and actionable.
- Verify previous suggestions have been addressed.
- Never repeat previous suggestions.
""",
Kernel = toolKernel,
Arguments = new KernelArguments(new AzureOpenAIPromptExecutionSettings() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() })
};
ChatCompletionAgent agentWriter =
new()
{
Name = WriterName,
Instructions =
"""
Your sole responsibility is to rewrite content according to review suggestions.
- Always apply all review direction.
- Always revise the content in its entirety without explanation.
- Never address the user.
""",
Kernel = kernel,
};
KernelFunction selectionFunction =
AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Examine the provided RESPONSE and choose the next participant.
State only the name of the chosen participant without explanation.
Never choose the participant named in the RESPONSE.
Choose only from these participants:
- {{{ReviewerName}}}
- {{{WriterName}}}
Always follow these rules when choosing the next participant:
- If RESPONSE is user input, it is {{{ReviewerName}}}'s turn.
- If RESPONSE is by {{{ReviewerName}}}, it is {{{WriterName}}}'s turn.
- If RESPONSE is by {{{WriterName}}}, it is {{{ReviewerName}}}'s turn.
RESPONSE:
{{$lastmessage}}
""",
safeParameterNames: "lastmessage");
const string TerminationToken = "yes";
KernelFunction terminationFunction =
AgentGroupChat.CreatePromptFunctionForStrategy(
$$$"""
Examine the RESPONSE and determine whether the content has been deemed satisfactory.
If content is satisfactory, respond with a single word without explanation: {{{TerminationToken}}}.
If specific suggestions are being provided, it is not satisfactory.
If no correction is suggested, it is satisfactory.
RESPONSE:
{{$lastmessage}}
""",
safeParameterNames: "lastmessage");
ChatHistoryTruncationReducer historyReducer = new(1);
AgentGroupChat chat =
new(agentReviewer, agentWriter)
{
ExecutionSettings = new AgentGroupChatSettings
{
SelectionStrategy =
new KernelFunctionSelectionStrategy(selectionFunction, kernel)
{
// Always start with the editor agent.
InitialAgent = agentReviewer,
// Save tokens by only including the final response
HistoryReducer = historyReducer,
// The prompt variable name for the history argument.
HistoryVariableName = "lastmessage",
// Returns the entire result value as a string.
ResultParser = (result) => result.GetValue<string>() ?? agentReviewer.Name
},
TerminationStrategy =
new KernelFunctionTerminationStrategy(terminationFunction, kernel)
{
// Only evaluate for editor's response
Agents = [agentReviewer],
// Save tokens by only including the final response
HistoryReducer = historyReducer,
// The prompt variable name for the history argument.
HistoryVariableName = "lastmessage",
// Limit total number of turns
MaximumIterations = 12,
// Customer result parser to determine if the response is "yes"
ResultParser = (result) => result.GetValue<string>()?.Contains(TerminationToken, StringComparison.OrdinalIgnoreCase) ?? false
}
}
};
Console.WriteLine("Ready!");
bool isComplete = false;
do
{
Console.WriteLine();
Console.Write("> ");
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
continue;
}
input = input.Trim();
if (input.Equals("EXIT", StringComparison.OrdinalIgnoreCase))
{
isComplete = true;
break;
}
if (input.Equals("RESET", StringComparison.OrdinalIgnoreCase))
{
await chat.ResetAsync();
Console.WriteLine("[Conversation has been reset]");
continue;
}
if (input.StartsWith("@", StringComparison.Ordinal) && input.Length > 1)
{
string filePath = input.Substring(1);
try
{
if (!File.Exists(filePath))
{
Console.WriteLine($"Unable to access file: {filePath}");
continue;
}
input = File.ReadAllText(filePath);
}
catch (Exception)
{
Console.WriteLine($"Unable to access file: {filePath}");
continue;
}
}
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, input));
chat.IsComplete = false;
try
{
await foreach (ChatMessageContent response in chat.InvokeAsync())
{
Console.WriteLine();
Console.WriteLine($"{response.AuthorName.ToUpperInvariant()}:{Environment.NewLine}{response.Content}");
}
}
catch (HttpOperationException exception)
{
Console.WriteLine(exception.Message);
if (exception.InnerException != null)
{
Console.WriteLine(exception.InnerException.Message);
if (exception.InnerException.Data.Count > 0)
{
Console.WriteLine(JsonSerializer.Serialize(exception.InnerException.Data, new JsonSerializerOptions() { WriteIndented = true }));
}
}
}
} while (!isComplete);
}
private sealed class ClipboardAccess
{
[KernelFunction]
[Description("Copies the provided content to the clipboard.")]
public static void SetClipboard(string content)
{
if (string.IsNullOrWhiteSpace(content))
{
return;
}
using Process clipProcess = Process.Start(
new ProcessStartInfo
{
FileName = "clip",
RedirectStandardInput = true,
UseShellExecute = false,
});
clipProcess.StandardInput.Write(content);
clipProcess.StandardInput.Close();
}
}
}
Riunire tutti i passaggi, è ora disponibile il codice finale per questo esempio. Di seguito è illustrata l'implementazione completa.
È possibile provare a usare uno degli input suggeriti. Quando inizia la chat dell'agente, gli agenti scambiano messaggi per diverse iterazioni fino a quando l'agente revisore non è soddisfatto del lavoro del copywriter. Il ciclo while
garantisce che la conversazione continui, anche se la chat viene inizialmente considerata completa, reimpostando il flag is_complete
su False
.
- I Rozes sono rossi, violaz sono blu.
- Semantic Kernel (SK) è un SDK open source che consente agli sviluppatori di creare e orchestrare flussi di lavoro di intelligenza artificiale complessi che coinvolgono l'elaborazione del linguaggio naturale (NLP) e i modelli di Machine Learning. Offre una piattaforma flessibile per l'integrazione di funzionalità di intelligenza artificiale come la ricerca semantica, il riepilogo del testo e i sistemi di dialogo nelle applicazioni. Con SK è possibile combinare facilmente diversi servizi e modelli di intelligenza artificiale, definire le relazioni e orchestrare le interazioni tra di esse.
- Creare questi due paragrafi
- Grazie
- @WomensSuffrage.txt
- Va bene, ma è pronto per il mio professore universitario?
Suggerimento
È possibile fare riferimento a qualsiasi file specificando @<file_path_to_file>
. Per fare riferimento al testo "WomensSuffrage" riportato sopra, scaricalo da qui e posizionalo nella tua directory di lavoro corrente. È quindi possibile farvi riferimento con @WomensSuffrage.txt
.
import asyncio
import os
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import (
KernelFunctionSelectionStrategy,
KernelFunctionTerminationStrategy,
)
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistoryTruncationReducer
from semantic_kernel.functions import KernelFunctionFromPrompt
"""
The following sample demonstrates how to create a simple,
agent group chat that utilizes a Reviewer Chat Completion
Agent along with a Writer Chat Completion Agent to
complete a user's task.
"""
# Define agent names
REVIEWER_NAME = "Reviewer"
WRITER_NAME = "Writer"
def create_kernel() -> Kernel:
"""Creates a Kernel instance with an Azure OpenAI ChatCompletion service."""
kernel = Kernel()
kernel.add_service(service=AzureChatCompletion())
return kernel
async def main():
# Create a single kernel instance for all agents.
kernel = create_kernel()
# Create ChatCompletionAgents using the same kernel.
agent_reviewer = ChatCompletionAgent(
kernel=kernel,
name=REVIEWER_NAME,
instructions="""
Your responsibility is to review and identify how to improve user provided content.
If the user has provided input or direction for content already provided, specify how to address this input.
Never directly perform the correction or provide an example.
Once the content has been updated in a subsequent response, review it again until it is satisfactory.
RULES:
- Only identify suggestions that are specific and actionable.
- Verify previous suggestions have been addressed.
- Never repeat previous suggestions.
""",
)
agent_writer = ChatCompletionAgent(
kernel=kernel,
name=WRITER_NAME,
instructions="""
Your sole responsibility is to rewrite content according to review suggestions.
- Always apply all review directions.
- Always revise the content in its entirety without explanation.
- Never address the user.
""",
)
# Define a selection function to determine which agent should take the next turn.
selection_function = KernelFunctionFromPrompt(
function_name="selection",
prompt=f"""
Examine the provided RESPONSE and choose the next participant.
State only the name of the chosen participant without explanation.
Never choose the participant named in the RESPONSE.
Choose only from these participants:
- {REVIEWER_NAME}
- {WRITER_NAME}
Rules:
- If RESPONSE is user input, it is {REVIEWER_NAME}'s turn.
- If RESPONSE is by {REVIEWER_NAME}, it is {WRITER_NAME}'s turn.
- If RESPONSE is by {WRITER_NAME}, it is {REVIEWER_NAME}'s turn.
RESPONSE:
{{{{$lastmessage}}}}
""",
)
# Define a termination function where the reviewer signals completion with "yes".
termination_keyword = "yes"
termination_function = KernelFunctionFromPrompt(
function_name="termination",
prompt=f"""
Examine the RESPONSE and determine whether the content has been deemed satisfactory.
If the content is satisfactory, respond with a single word without explanation: {termination_keyword}.
If specific suggestions are being provided, it is not satisfactory.
If no correction is suggested, it is satisfactory.
RESPONSE:
{{{{$lastmessage}}}}
""",
)
history_reducer = ChatHistoryTruncationReducer(target_count=5)
# Create the AgentGroupChat with selection and termination strategies.
chat = AgentGroupChat(
agents=[agent_reviewer, agent_writer],
selection_strategy=KernelFunctionSelectionStrategy(
initial_agent=agent_reviewer,
function=selection_function,
kernel=kernel,
result_parser=lambda result: str(result.value[0]).strip() if result.value[0] is not None else WRITER_NAME,
history_variable_name="lastmessage",
history_reducer=history_reducer,
),
termination_strategy=KernelFunctionTerminationStrategy(
agents=[agent_reviewer],
function=termination_function,
kernel=kernel,
result_parser=lambda result: termination_keyword in str(result.value[0]).lower(),
history_variable_name="lastmessage",
maximum_iterations=10,
history_reducer=history_reducer,
),
)
print(
"Ready! Type your input, or 'exit' to quit, 'reset' to restart the conversation. "
"You may pass in a file path using @<path_to_file>."
)
is_complete = False
while not is_complete:
print()
user_input = input("User > ").strip()
if not user_input:
continue
if user_input.lower() == "exit":
is_complete = True
break
if user_input.lower() == "reset":
await chat.reset()
print("[Conversation has been reset]")
continue
# Try to grab files from the script's current directory
if user_input.startswith("@") and len(user_input) > 1:
file_name = user_input[1:]
script_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(script_dir, file_name)
try:
if not os.path.exists(file_path):
print(f"Unable to access file: {file_path}")
continue
with open(file_path, "r", encoding="utf-8") as file:
user_input = file.read()
except Exception:
print(f"Unable to access file: {file_path}")
continue
# Add the current user_input to the chat
await chat.add_chat_message(message=user_input)
try:
async for response in chat.invoke():
if response is None or not response.name:
continue
print()
print(f"# {response.name.upper()}:\n{response.content}")
except Exception as e:
print(f"Error during chat invocation: {e}")
# Reset the chat's complete flag for the new conversation round.
chat.is_complete = False
if __name__ == "__main__":
asyncio.run(main())
È possibile trovare il codice completo , come illustrato in precedenza, nel repository.
Funzionalità attualmente non disponibile in Java.