Útmutató: Az ügynökök együttműködésének koordinálása ügynökcsoportos csevegéssel

Fontos

Ez egy archivált dokumentum.

Fontos

Ez a funkció a kísérleti fázisban van, de már nem tart fenn. Csere esetén tekintse meg a Csoportos csevegés vezénylését és a migrálási útmutatót az AgentChatből a csoportos csevegés vezénylésére.

Áttekintés

Ebben a mintában bemutatjuk, hogyan használhatjuk a AgentGroupChat a felhasználó által megadott tartalom áttekintésén és átírásán dolgozó két különböző ügynök együttműködésének összehangolására. Minden ügynökhöz külön szerepkör van hozzárendelve:

  • Véleményező: Vélemények és útmutatást ad az Írónak.
  • Író: Frissíti a felhasználói tartalmat a véleményező bemenete alapján.

A megközelítés lépésről lépésre bontva lesz, hogy a kódolási folyamat főbb részeit jól megvilágítsa.

Első lépések

A funkciókódolás előtt győződjön meg arról, hogy a fejlesztési környezet teljesen be van állítva és konfigurálva van.

Jótanács

Ez a minta egy opcionális szövegfájlt használ a feldolgozás részeként. Ha használni szeretné, letöltheti itt. Helyezze a fájlt a kód munkakönyvtárába.

Először hozzon létre egy konzolprojektet. Ezután adja meg a következő csomaghivatkozásokat, hogy az összes szükséges függőség elérhető legyen.

Ha csomagfüggőségeket szeretne hozzáadni a parancssorból, használja a dotnet következő parancsot:

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

Ha NuGet-csomagokat kezel a Visual Studióban, ellenőrizze, hogy Include prerelease van-e bejelölve.

A projektfájlnak (.csproj) a következő PackageReference definíciókat kell tartalmaznia:

  <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>

A Agent Framework kísérleti jellegű, és figyelmeztetések elnyomását igényli. Ez megadható a projektfájl tulajdonságaként (.csproj).

  <PropertyGroup>
    <NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
  </PropertyGroup>

Jótanács

Ez a minta egy opcionális szövegfájlt használ a feldolgozás részeként. Ha használni szeretné, letöltheti itt. Helyezze a fájlt a kód munkakönyvtárába.

Először telepítse a Szemantic Kernel Python-csomagot.

pip install semantic-kernel

Ezután adja hozzá a szükséges importot.

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

A funkció jelenleg nem érhető el a Javában.

Konfiguráció

Ez a minta konfigurációs beállítást igényel a távoli szolgáltatásokhoz való csatlakozáshoz. Meg kell adnia az OpenAI vagy az Azure OpenAI beállításait.

# 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"

A rendszer az alábbi osztályt használja az összes ügynök-példában. A megfelelő működés érdekében mindenképpen vegye fel a projektbe. Ez az osztály alapvető összetevőként szolgál az alábbi példákhoz.

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();
    }
}

A mintakód futtatásához szükséges megfelelő konfiguráció használatának leggyorsabb módja egy .env fájl létrehozása a projekt gyökerénél (ahol a szkript fut). A minta használatához elérhető Azure OpenAI- vagy OpenAI-erőforrásokra van szükség.

Állítsa be a következő beállításokat az .env fájlban, akár az Azure OpenAI, akár az OpenAI esetén:

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=""

A konfigurálás után a megfelelő AI-szolgáltatásosztályok felveszik a szükséges változókat, és a példányosítás során használják őket.

A funkció jelenleg nem érhető el a Javában.

Kódolás

A minta kódolási folyamata a következőket foglalja magában:

  1. Beállítás – Beállítások inicializálása és a beépülő modul.
  2. Agent Definíció – Készítse el a két ChatCompletionAgent példányt (Véleményező és Író).
  3. beszélgetés meghatározás – Hozd létre a AgentGroupChat és a kapcsolódó stratégiákat.
  4. A csevegési hurok – Írja meg a felhasználói/ügynöki interakciót hajtó hurkot.

A teljes példakód az Utolsó szakaszban található. A teljes megvalósításhoz tekintse meg ezt a szakaszt.

Beállítás

Mielőtt bármilyen ChatCompletionAgent-t létrehoznánk, inicializálni kell a konfigurációs beállításokat, a beépülő modulokat és a Kernel-et.

Példányosítsa a Settings osztályt, amelyre az előző Konfiguráció szakasz hivatkozik.

Settings settings = new();

A funkció jelenleg nem érhető el a Javában.

Most kezdje el egy Kernel példány inicializálását egy IChatCompletionService segítségével.

IKernelBuilder builder = Kernel.CreateBuilder();

builder.AddAzureOpenAIChatCompletion(
	settings.AzureOpenAI.ChatModelDeployment,
	settings.AzureOpenAI.Endpoint,
	new AzureCliCredential());

Kernel kernel = builder.Build();

A kernelobjektum inicializálása:

kernel = Kernel()

A funkció jelenleg nem érhető el a Javában.

Hozzunk létre egy második Kernel-példányt is klónozási keresztül, és adjunk hozzá egy beépülő modult, amely lehetővé teszi, hogy a felülvizsgálat frissített tartalmat helyezzen el a vágólapon.

Kernel toolKernel = kernel.Clone();
toolKernel.Plugins.AddFromType<ClipboardAccess>();

A funkció jelenleg nem érhető el a Javában.

A vágólap plugin a minta részeként definiálható.

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();
    }
}

A funkció jelenleg nem érhető el a Javában.

Ügynökdefiníció

Deklaráljuk az ügynökneveket const, hogy hivatkozni lehessen rájuk AgentGroupChat stratégiákban:

const string ReviewerName = "Reviewer";
const string WriterName = "Writer";

Az ügynök nevét "Véleményező" és "Író" néven deklaráljuk.

REVIEWER_NAME = "Reviewer"
COPYWRITER_NAME = "Writer"

A funkció jelenleg nem érhető el a Javában.

A Véleményező ügynök meghatározása az Útmutató: Csevegés-befejező ügynök során feltárt mintát használja.

Itt a véleményezőnek az a feladata, hogy válaszoljon a felhasználói bemenetre, irányt adjon az Íróügynöknek , és ellenőrizze az Íróügynök eredményét.

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.
""",
)

A funkció jelenleg nem érhető el a Javában.

Az Íróügynök hasonló, de nem követeli meg a végrehajtási beállítások specifikációját, mivel nincs beépülő modullal konfigurálva.

Itt az Író egy egycélú feladatot kap, kövesse az irányt, és írja át a tartalmat.

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,
    };

Az Író ügynök hasonló. Egy célfeladatot kap, követi az irányt, és újraírja a tartalmat.

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.
""",
    )

A funkció jelenleg nem érhető el a Javában.

A csevegés meghatározása

A AgentGroupChat meghatározásához figyelembe kell venni a Agent forduló kiválasztására vonatkozó stratégiákat, és meg kell határozni, hogy mikor kell kilépni a csevegési ciklusból. Mindkét szempont esetében meghatározunk egy kernel-parancssori függvényt.

Az első, aki átgondolja a Agent kiválasztását:

A AgentGroupChat.CreatePromptFunctionForStrategy használata kényelmes mechanizmust biztosít az üzenetparaméter HTML-kódolás elkerüléséhez.

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}}}}
"""
)

A funkció jelenleg nem érhető el a Javában.

A második kiértékeli, hogy mikor lépjen ki a csevegési ciklusból:

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}}}}
"""
)

A funkció jelenleg nem érhető el a Javában.

Mindkét stratégia csak a legutóbbi csevegőüzenet ismeretét igényli. Ez csökkenti a tokenek használatát, és javítja a teljesítményt.

ChatHistoryTruncationReducer historyReducer = new(1);
history_reducer = ChatHistoryTruncationReducer(target_count=1)

A funkció jelenleg nem érhető el a Javában.

Végül készen állunk arra, hogy mindent összehozzuk a AgentGroupChat definíciónkban.

A AgentGroupChat létrehozása a következőkből áll:

  1. Mindkét ügynököt vegyük bele a konstruktorba.
  2. Határozzon meg egy KernelFunctionSelectionStrategy a korábban definiált KernelFunction és Kernel példányok használatával.
  3. Határozzon meg egy KernelFunctionTerminationStrategy a korábban definiált KernelFunction és Kernel példányok használatával.

Figyelje meg, hogy minden stratégia felelős az eredmény elemzéséért 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!");

A AgentGroupChat létrehozása a következőkből áll:

  1. Mindkét ügynököt vegyük bele a konstruktorba.
  2. Határozzon meg egy KernelFunctionSelectionStrategy a korábban definiált KernelFunction és Kernel példányok használatával.
  3. Határozzon meg egy KernelFunctionTerminationStrategy a korábban definiált KernelFunction és Kernel példányok használatával.

Figyelje meg, hogy minden stratégia felelős az eredmény elemzéséért 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,
    ),
)

A lastmessagehistory_variable_name megfelel a fent definiált KernelFunctionSelectionStrategy és KernelFunctionTerminationStrategy kérésnek. Itt helyezik el az utolsó üzenetet az előugró ablak megjelenítésekor.

A funkció jelenleg nem érhető el a Javában.

A Beszélgetés ciklus

Végre össze tudjuk hangolni a felhasználó és a AgentGroupChatközötti interakciót. Először hozzon létre egy üres hurkot.

Megjegyzés: A többi példával ellentétben nincs külső előzmény vagy szál kezelése. AgentGroupChat belsőleg kezeli a beszélgetési előzményeket.

bool isComplete = false;
do
{

} while (!isComplete);
is_complete: bool = False
while not is_complete:
    # operational logic

A funkció jelenleg nem érhető el a Javában.

Most rögzítsük a felhasználói bemenetet az előző ciklusban. Ebben az esetben:

  • Az üres bemenet figyelmen kívül lesz hagyva
  • A kifejezés EXIT jelzi, hogy a beszélgetés befejeződött
  • A RESET kifejezés törli a AgentGroupChat előzményeit
  • Minden olyan kifejezés, amely a következővel @ kezdődik, fájlútvonalként lesz kezelve, amelynek tartalma bemenetként lesz megadva
  • Az érvényes bemenet a(z) AgentGroupChat-hoz Felhasználói üzenetként hozzá lesz adva.
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));

Most rögzítsük a felhasználói bemenetet az előző ciklusban. Ebben az esetben:

  • Az üres bemenet figyelmen kívül lesz hagyva.
  • A exit kifejezés jelzi, hogy a beszélgetés befejeződött.
  • A reset kifejezés törli a AgentGroupChat előzményeit.
  • A @ kezdődő kifejezések fájlútvonalként lesznek kezelve, amelynek tartalma bemenetként lesz megadva.
  • Az érvényes bemenet a(z) AgentGroupChat-hoz Felhasználói üzenetként hozzá lesz adva.

A while cikluson belüli műveleti logika a következőképpen néz ki:

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)

A funkció jelenleg nem érhető el a Javában.

A Agent együttműködés felhasználói bemenetre adott válaszként történő elindításához és a Agent válaszok megjelenítéséhez hívja meg a AgentGroupChat; először azonban mindenképpen állítsa vissza a Befejezési állapotot bármely korábbi meghívásból.

Megjegyzés: A szolgáltatáshibákat elkapják és megjelenítik a beszélgetési ciklus összeomlásának elkerülése érdekében.

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

A funkció jelenleg nem érhető el a Javában.

Végső

Ha összehozzuk az összes lépést, megkapjuk a végleges kódot ehhez a példához. A teljes megvalósítást alább találja.

Próbálja meg használni a következő javasolt bemeneteket:

  1. Szia
  2. {"message: "helló világ"}
  3. {"message": "helló világ"}
  4. A Szemantic Kernel (SK) egy nyílt forráskódú SDK, amely lehetővé teszi a fejlesztők számára a természetes nyelvi feldolgozást (NLP) és gépi tanulási modelleket tartalmazó összetett AI-munkafolyamatok létrehozását és vezénylésére. Rugalmas platformot biztosít az olyan AI-képességek integrálásához, mint a szemantikai keresés, a szövegösszesítés és a párbeszédrendszerek az alkalmazásokba. Az SK-val egyszerűen kombinálhatja a különböző AI-szolgáltatásokat és modelleket, meghatározhatja azok kapcsolatait, és vezényelheti az interakciókat közöttük.
  5. alakítsd két bekezdéssé
  6. köszönöm
  7. @.\WomensSuffrage.txt
  8. Jó, de készen áll a főiskolai tanárom számára?
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();
        }
    }
}

Az összes lépést összehozva most már megvan a példa végleges kódja. A teljes megvalósítás alább látható.

A javasolt bemenetek egyikével próbálkozhat. Az ügynök csevegésének kezdetekor az ügynökök több iterációra cserélik az üzeneteket, amíg a véleményező ügynök meg nem elégedett a szövegíró munkájával. A while hurok biztosítja, hogy a beszélgetés folytatódjon, még akkor is, ha a csevegés kezdetben befejezettnek tekinthető, a is_complete jelzőt False-re állítva vissza.

  1. Rozes piros, lila kék.
  2. A Szemantic Kernel (SK) egy nyílt forráskódú SDK, amely lehetővé teszi a fejlesztők számára a természetes nyelvi feldolgozást (NLP) és gépi tanulási modelleket tartalmazó összetett AI-munkafolyamatok létrehozását és vezénylésére. Rugalmas platformot biztosít az olyan AI-képességek integrálásához, mint a szemantikai keresés, a szövegösszesítés és a párbeszédrendszerek az alkalmazásokba. Az SK-val egyszerűen kombinálhatja a különböző AI-szolgáltatásokat és modelleket, meghatározhatja azok kapcsolatait, és vezényelheti az interakciókat közöttük.
  3. Tedd ezt két bekezdéssé
  4. köszönöm
  5. @WomensSuffrage.txt
  6. Jó, de megfelel a főiskolai professzorom elvárásainak?

Jótanács

Bármely fájlra hivatkozhat a @<file_path_to_file>megadásával. Ha a fent említett "WomensSuffrage" szövegre szeretne hivatkozni, töltse le innen, és helyezze az aktuális munka könyvtárába. Ezután hivatkozhat rá a(z) @WomensSuffrage.txt-ként.

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())

A teljes kóda fent látható módon az adattárunkban található.

A funkció jelenleg nem érhető el a Javában.