Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Důležité
Toto je archivovaný dokument.
Důležité
Tato funkce je v experimentální fázi, ale už není zachována. Náhradu najdete v orchestraci skupinového chatu a v průvodci migrací migrace z AgentChatu na orchestraci skupinového chatu.
Přehled
V této ukázce prozkoumáme, jak pomocí AgentGroupChat koordinovat spolupráci dvou různých agentů, kteří pracují na kontrole a přepsání obsahu poskytnutého uživatelem. Každému agentovi je přiřazena samostatná role:
- Kontrolor: Prohlíží a poskytuje směr autorovi.
- Zapisovač: Aktualizuje uživatelský obsah na základě vstupu revidujících.
Tento přístup bude rozdělen krok za krokem, aby zdůraznil klíčové části procesu kódování.
Začínáme
Než budete pokračovat v kódování funkcí, ujistěte se, že je vaše vývojové prostředí plně nastavené a nakonfigurované.
Návod
Tato ukázka používá volitelný textový soubor jako součást zpracování. Pokud ho chcete použít, můžete si ho stáhnout zde. Umístěte soubor do pracovního adresáře kódu.
Začněte vytvořením projektu konzoly. Pak zahrňte následující odkazy na balíčky, abyste zajistili, že jsou k dispozici všechny požadované závislosti.
Pokud chcete přidat závislosti balíčků z příkazového řádku, použijte tento dotnet příkaz:
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
Pokud spravujete balíčky NuGet v sadě Visual Studio, ujistěte se, že je zaškrtnuté
Include prerelease.
Soubor projektu (.csproj) by měl obsahovat následující PackageReference definice:
<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>
Agent Framework je experimentální a vyžaduje potlačení upozornění. To se může vyřešit jako vlastnost v souboru projektu (.csproj):
<PropertyGroup>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
</PropertyGroup>
Návod
Tato ukázka používá volitelný textový soubor jako součást zpracování. Pokud ho chcete použít, můžete si ho stáhnout zde. Umístěte soubor do pracovního adresáře kódu.
Začněte instalací balíčku Semantic Kernel pro Python.
pip install semantic-kernel
Dále přidejte požadované importy.
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
Funkce aktuálně není dostupná v Javě.
Konfigurace
Tato ukázka vyžaduje nastavení konfigurace pro připojení ke vzdáleným službám. Budete muset definovat nastavení pro OpenAI nebo 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"
Následující třída se používá ve všech příkladech agenta. Nezapomeňte ho zahrnout do projektu, abyste zajistili správné funkce. Tato třída slouží jako základní komponenta pro následující příklady.
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();
}
}
Nejrychlejší způsob, jak začít se správnou konfigurací pro spuštění ukázkového kódu, je vytvořit .env soubor v kořenovém adresáři projektu (kde se spouští váš skript). Ukázkový příklad vyžaduje, abyste měli k dispozici prostředky Azure OpenAI nebo OpenAI.
V souboru .env nakonfigurujte následující nastavení pro Azure OpenAI nebo 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=""
Po nakonfigurování příslušné třídy služeb AI vyberou požadované proměnné a použijí je při instanciaci.
Funkce aktuálně není dostupná v Javě.
Kódování
Proces kódování pro tuto ukázku zahrnuje:
- Nastavení – Inicializace nastavení a modulu plug-in.
-
Agentdefinice – vytvořte dvě instanceChatCompletionAgent(Recenzent a Autor). -
Definice chatu – Vytvořte
AgentGroupChata přidružené strategie. - Smyčka chatu – napište smyčku, která řídí interakci uživatele / agenta.
Úplný ukázkový kód je k dispozici v části Konečný . Kompletní implementaci najdete v této části.
Nastavení
Před vytvořením jakéhokoli ChatCompletionAgent je nutné inicializovat nastavení konfigurace, pluginy a Kernel.
Vytvořte instanci třídy Settings, na kterou bylo odkazováno v předchozí části Konfigurace.
Settings settings = new();
Funkce aktuálně není dostupná v Javě.
Nyní inicializujte instanci Kernel pomocí IChatCompletionService.
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
settings.AzureOpenAI.ChatModelDeployment,
settings.AzureOpenAI.Endpoint,
new AzureCliCredential());
Kernel kernel = builder.Build();
Inicializace objektu jádra:
kernel = Kernel()
Funkce aktuálně není dostupná v Javě.
Vytvoříme také druhou instanci Kernel prostřednictvím klonování a přidáme modul plug-in, který umožní kontrole umístit aktualizovaný obsah na výřez.
Kernel toolKernel = kernel.Clone();
toolKernel.Plugins.AddFromType<ClipboardAccess>();
Funkce aktuálně není dostupná v Javě.
Plug-in Schránka může být určen jako součást ukázky.
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();
}
}
Funkce aktuálně není dostupná v Javě.
Definice agenta
Pojďme deklarovat názvy agentů jako const, aby se na tyto názvy mohly odkazovat ve strategiích AgentGroupChat:
const string ReviewerName = "Reviewer";
const string WriterName = "Writer";
Názvy agentů deklarujeme jako Revidující a Zapisovatel.
REVIEWER_NAME = "Reviewer"
COPYWRITER_NAME = "Writer"
Funkce aktuálně není dostupná v Javě.
Definování agenta Recenzenta používá vzor prozkoumaný v Návodu: Agent pro dokončování chatu.
Revidující zde má roli reagovat na vstupy uživatele, poskytnout směr pro agenta Writer a ověřit výsledek agenta 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.
""",
)
Funkce aktuálně není dostupná v Javě.
Agent Writer je podobný, ale nevyžaduje specifikaci nastavení spuštění, protože není nakonfigurovaný s modulem plug-in.
Zde je spisovatel přidělen jednoúčelový úkol, má dodržovat pokyny a přepsat obsah.
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,
};
Agent Writer je podobný. Má přidělený jeden jednoúčelový úkol, následujte pokyny a přepište obsah.
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.
""",
)
Funkce aktuálně není dostupná v Javě.
Definice chatu
Definování AgentGroupChat vyžaduje zvážení strategií pro výběr Agent směru a určení, kdy ukončit smyčku chatu . Pro obě tyto aspekty definujeme funkci Příkazového řádku jádra.
První, kdo uvažuje o výběru Agent:
Použití AgentGroupChat.CreatePromptFunctionForStrategy poskytuje pohodlný mechanismus, který zabraňuje kódování HTML parametru zprávy.
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}}}}
"""
)
Funkce aktuálně není dostupná v Javě.
Druhá bude vyhodnocovat, kdy ukončit smyčku Chatu:
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}}}}
"""
)
Funkce aktuálně není dostupná v Javě.
Obě tyto strategie budou vyžadovat pouze znalost nejnovější chatové zprávy. Tím se sníží využití tokenů a zlepší se výkon:
ChatHistoryTruncationReducer historyReducer = new(1);
history_reducer = ChatHistoryTruncationReducer(target_count=1)
Funkce aktuálně není dostupná v Javě.
Nakonec jsme připraveni spojit všechno v naší definici AgentGroupChat.
Vytváření AgentGroupChat zahrnuje:
- Do konstruktoru zahrňte oba agenty.
- Definujte
KernelFunctionSelectionStrategypomocí dříve definované instanceKernelFunctionaKernel. - Definujte
KernelFunctionTerminationStrategypomocí dříve definované instanceKernelFunctionaKernel.
Všimněte si, že každá strategie zodpovídá za analýzu výsledku KernelFunction .
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!");
Vytváření AgentGroupChat zahrnuje:
- Do konstruktoru zahrňte oba agenty.
- Definujte
KernelFunctionSelectionStrategypomocí dříve definované instanceKernelFunctionaKernel. - Definujte
KernelFunctionTerminationStrategypomocí dříve definované instanceKernelFunctionaKernel.
Všimněte si, že každá strategie zodpovídá za analýzu výsledku KernelFunction .
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,
),
)
lastmessage
history_variable_name odpovídá KernelFunctionSelectionStrategy a výzvě KernelFunctionTerminationStrategy, která byla definována výše. Tady se při zobrazování výzvy umístí poslední zpráva.
Funkce aktuálně není dostupná v Javě.
Smyčka Chatu
Nakonec můžeme koordinovat interakci mezi uživatelem a AgentGroupChat. Začněte vytvořením prázdné smyčky.
Poznámka: Na rozdíl od ostatních příkladů se nespravuje žádná externí historie ani vlákno .
AgentGroupChatspravuje historii konverzací interně.
bool isComplete = false;
do
{
} while (!isComplete);
is_complete: bool = False
while not is_complete:
# operational logic
Funkce aktuálně není dostupná v Javě.
Teď zachytáme vstup uživatele v rámci předchozí smyčky. V tomto případě:
- Prázdný vstup bude ignorován.
- Termín
EXITbude signalizovat, že se konverzace dokončila. - Termín
RESETvymaže historiiAgentGroupChat. - Jakýkoli termín začínající
@se bude považovat za cestu k souboru, jejíž obsah bude poskytován jako vstup. - Platný vstup bude přidán do
AgentGroupChatjako zpráva uživatele .
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));
Teď zachytáme vstup uživatele v rámci předchozí smyčky. V tomto případě:
- Prázdný vstup bude ignorován.
- Termín
exitsignalizují, že konverzace je dokončená. - Termín
resetvymaže historiiAgentGroupChat. - Jakýkoli termín začínající
@se bude považovat za cestu k souboru, jejíž obsah bude poskytován jako vstup. - Platný vstup bude přidán do
AgentGroupChatjako zpráva uživatele .
Logika operace uvnitř smyčky While vypadá takto:
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)
Funkce aktuálně není dostupná v Javě.
Chcete-li zahájit spolupráci Agent v reakci na vstup uživatele a zobrazit odpovědi Agent, vyvolejte AgentGroupChat; nejprve však nezapomeňte resetovat stav Dokončení v rámci z jakéhokoli předchozího spuštění.
Poznámka: Chyby služby jsou zachycovány a zobrazovány, aby nedošlo ke zhroucení smyčky konverzace.
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
Funkce aktuálně není dostupná v Javě.
Finále
Spojte všechny kroky dohromady, máme pro tento příklad konečný kód. Kompletní implementace je uvedená níže.
Zkuste použít tyto navrhované vstupy:
- Ahoj
- {"message: "hello world"}
- {"message": "ahoj světe"}
- Sémantické jádro (SK) je opensourcová sada SDK, která vývojářům umožňuje vytvářet a orchestrovat složité pracovní postupy AI, které zahrnují zpracování přirozeného jazyka (NLP) a modely strojového učení. Poskytuje flexibilní platformu pro integraci funkcí umělé inteligence, jako je sémantické vyhledávání, shrnutí textu a dialogové systémy do aplikací. Pomocí SKU můžete snadno kombinovat různé služby a modely AI, definovat jejich vztahy a orchestrovat interakce mezi nimi.
- udělat z toho dva odstavce
- Děkuju
- @.\WomensSuffrage.txt
- je to dobré, ale je to připravené pro mého profesora na vysoké škole?
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();
}
}
}
Spojte všechny kroky dohromady, teď máme konečný kód pro tento příklad. Kompletní implementace je znázorněna níže.
Můžete zkusit použít jeden z navrhovaných vstupů. Jakmile začne chat s agentem, agenti si budou vyměňovat zprávy v několika iteracích, dokud nebude revidující agent spokojen s prací copywritera. Smyčka while zajistí pokračování konverzace resetováním příznaku is_complete na False, i když se chat zpočátku považuje za dokončený.
- Růže jsou červené, fialky jsou modré.
- Sémantické jádro (SK) je opensourcová sada SDK, která vývojářům umožňuje vytvářet a orchestrovat složité pracovní postupy AI, které zahrnují zpracování přirozeného jazyka (NLP) a modely strojového učení. Poskytuje flexibilní platformu pro integraci funkcí umělé inteligence, jako je sémantické vyhledávání, shrnutí textu a dialogové systémy do aplikací. Pomocí SKU můžete snadno kombinovat různé služby a modely AI, definovat jejich vztahy a orchestrovat interakce mezi nimi.
- Udělejte z toho dva odstavce
- Děkuju
- @WomensSuffrage.txt
- Je to dobré, ale je to připravené pro mého profesora na vysoké škole?
Návod
Můžete odkazovat na libovolný soubor zadáním @<file_path_to_file>. Pokud chcete odkazovat na text "WomensSuffrage" uvedený výše, stáhněte si ho zde a umístěte ho do aktuálního pracovního adresáře. Pak na něj můžete odkazovat pomocí @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())
Úplný kód , jak je znázorněno výše, najdete v našem úložišti.
Funkce aktuálně není dostupná v Javě.