Aracılığıyla paylaş


Nasıl Yapılır: Aracı Grubu Sohbeti kullanarak Aracı İşbirliğini Koordine Etme

Önemli

Bu arşivlenmiş bir belgedir.

Önemli

Bu özellik deneysel aşamadadır ancak artık desteklenmemektedir. Bunun yerine Grup Sohbeti Düzenlemesi'ne ve AgentChat'ten Grup Sohbeti Düzenleme'ye geçiş kılavuzuna bakın.

Genel Bakış

Bu örnekte, kullanıcı tarafından sağlanan içeriği gözden geçirmek ve yeniden yazmak için çalışan iki farklı aracının işbirliğini koordine etmek için AgentGroupChat nasıl kullanılacağını keşfedeceğiz. Her bir aracıya birbirinden farklı bir rol atanır.

  • Gözden Geçiren: Yazarı gözden geçirir ve yönlendirir.
  • Yazan: Kullanıcı içeriğini Gözden Geçiren girişlerine göre güncelleştirir.

Bu yaklaşım, kodlama sürecinin önemli bölümlerini vurgulamak için adım adım ayrıntılı bir şekilde ele alınacaktır.

Başlangıç Yapmak

Özellik kodlamaya devam etmeden önce geliştirme ortamınızın tam olarak ayarlandığından ve yapılandırıldığından emin olun.

Tavsiye

Bu örnek, işlemenin bir parçası olarak isteğe bağlı bir metin dosyası kullanır. Kullanmak isterseniz, buradanindirebilirsiniz. Dosyayı kod çalışma dizininize yerleştirin.

Konsol projesi oluşturarak başlayın. Ardından, gerekli tüm bağımlılıkların kullanılabilir olduğundan emin olmak için aşağıdaki paket başvurularını ekleyin.

Komut satırından paket bağımlılıkları eklemek için komutunu dotnet kullanın:

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

Visual Studio'da NuGet paketlerini yönetiyorsanız, Include prerelease işaretli olduğundan emin olun.

Proje dosyası (.csproj) aşağıdaki PackageReference tanımları içermelidir:

  <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 deneyseldir ve uyarı gizleme gerektirir. Bu, proje dosyasında (.csproj) bir özellik olarak ele alınabilir:

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

Tavsiye

Bu örnek, işlemenin bir parçası olarak isteğe bağlı bir metin dosyası kullanır. Kullanmak isterseniz, buradanindirebilirsiniz. Dosyayı kod çalışma dizininize yerleştirin.

Semantik Çekirdek Python paketini yükleyerek başlayın.

pip install semantic-kernel

Ardından gerekli importları ekleyin.

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

Özellik şu anda Java'da kullanılamıyor.

Konfigürasyon

Bu örnek, uzak hizmetlere bağlanmak için yapılandırma ayarı gerektirir. OpenAI veya Azure OpenAI ayarlarını tanımlamanız gerekir.

# 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şağıdaki sınıf tüm Agent örneklerinde kullanılır. Düzgün işlevsellik sağlamak için bunu projenize eklediğinizden emin olun. Bu sınıf, aşağıdaki örnekler için temel bir bileşen olarak hizmet eder.

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

Örnek kodu çalıştırmak için uygun yapılandırmayı kullanmaya başlamanın en hızlı yolu, projenizin kökünde (betiğinizin çalıştırıldığı) bir .env dosya oluşturmaktır. Örnek, Azure OpenAI veya OpenAI kaynaklarının kullanılabilir olmasını gerektirir.

Azure OpenAI veya OpenAI için dosyanızda .env aşağıdaki ayarları yapılandırı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=""

Yapılandırıldıktan sonra ilgili yapay zeka hizmet sınıfları gerekli değişkenleri alır ve örnekleme sırasında kullanır.

Özellik şu anda Java'da kullanılamıyor.

Kodlama

Bu örnek için kodlama işlemi şunları içerir:

  1. Kurulum - Ayarları ve eklentiyi başlatma.
  2. Agent Tanım - İki ChatCompletionAgent örneği oluşturun (Gözden Geçirici ve Yazar).
  3. Sohbet Tanımı - AgentGroupChat ve ilişkili stratejileri oluşturun.
  4. Sohbet Döngüsü - Kullanıcı/aracı etkileşimini yönlendiren döngüleri yazın.

Örnek kodun tamamı Final bölümünde verilmiştir. Tam uygulama için bu bölüme bakın.

Kurulum

herhangi bir ChatCompletionAgentoluşturulmadan önce yapılandırma ayarları, eklentiler ve Kernel başlatılmalıdır.

Settings Önceki Yapılandırma bölümünde başvurulan sınıfın örneğini oluşturun.

Settings settings = new();

Özellik şu anda Java'da kullanılamıyor.

Şimdi bir Kernel örneğini bir IChatCompletionService ile başlatın.

IKernelBuilder builder = Kernel.CreateBuilder();

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

Kernel kernel = builder.Build();

Çekirdek nesnesini başlatın:

kernel = Kernel()

Özellik şu anda Java'da kullanılamıyor.

Şimdi Kernel aracılığıyla ikinci bir örneği oluşturalım ve gözden geçirmenin güncelleştirilmiş içeriği panoya yerleştirmesini sağlayacak bir eklenti ekleyelim.

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

Özellik şu anda Java'da kullanılamıyor.

Clipboard eklentisi, örnek uygulamanın bir parçası olarak tanımlanabilir.

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

Özellik şu anda Java'da kullanılamıyor.

Ajan Tanımı

Aracı adlarını const olarak bildirelim, böylece AgentGroupChat stratejilerde bunlara başvurulabilir:

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

Etken adlarını "Gözden Geçiren" ve "Yazar" olarak bildireceğiz.

REVIEWER_NAME = "Reviewer"
COPYWRITER_NAME = "Writer"

Özellik şu anda Java'da kullanılamıyor.

Reviewer aracısını tanımlamak, Nasıl Yapılır: Sohbet Tamamlama Aracısı'nda incelenen deseni kullanır.

Burada Gözden Geçiren'e kullanıcı girişine yanıt verme, Yazıcı aracısına yön sağlama ve Yazıcı aracısının sonucunu doğrulama rolü verilir.

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

Özellik şu anda Java'da kullanılamıyor.

Yazıcı aracısı benzerdir, ancak eklentiyle yapılandırılmadığından Yürütme Ayarları belirtimini gerektirmez.

Burada Yazara tek amaçlı bir görev verilir: yönergeleri takip edin ve içeriği yeniden yazın.

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

Yazar aracısı benzerdir. Belirli bir görev verilir, talimatları izleyin ve içeriği yeniden yazın.

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

Özellik şu anda Java'da kullanılamıyor.

Sohbet Tanımı

AgentGroupChat tanımlamak için Agent dönüşü seçme ve Sohbet döngüsünden ne zaman çıkılması gerektiğini belirleme stratejilerinin dikkate alınması gerekir. Bu konuların her ikisi için de bir Çekirdek İstemi İşlevi tanımlayacağız.

Agent seçimi üzerine düşünen ilk kişi

AgentGroupChat.CreatePromptFunctionForStrategy kullanmak, ileti parametresi HTML kodlamasını önlemek için kullanışlı bir mekanizma sağlar.

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

Özellik şu anda Java'da kullanılamıyor.

İkincisi, Sohbet döngüsünden ne zaman çıkılacağını değerlendirir:

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

Özellik şu anda Java'da kullanılamıyor.

Bu Stratejilerin her ikisi de yalnızca en son Sohbet iletisi hakkında bilgi gerektirir. Bu, belirteç kullanımını azaltır ve performansı geliştirmeye yardımcı olur:

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

Özellik şu anda Java'da kullanılamıyor.

Son olarak AgentGroupChat tanımımızda her şeyi bir araya getirmeye hazırız.

Oluşturma AgentGroupChat şunları içerir:

  1. Constructor fonksiyonuna her iki etmeni de ekleyin.
  2. Önceden tanımlanmış KernelFunctionSelectionStrategy ve KernelFunction örneğini kullanarak bir Kernel tanımlayın.
  3. Önceden tanımlanmış KernelFunctionTerminationStrategy ve KernelFunction örneğini kullanarak bir Kernel tanımlayın.

Her stratejinin KernelFunction sonucunu ayrıştırmaktan sorumlu olduğuna dikkat edin.

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!");

Oluşturma AgentGroupChat şunları içerir:

  1. Constructor fonksiyonuna her iki etmeni de ekleyin.
  2. Önceden tanımlanmış KernelFunctionSelectionStrategy ve KernelFunction örneğini kullanarak bir Kernel tanımlayın.
  3. Önceden tanımlanmış KernelFunctionTerminationStrategy ve KernelFunction örneğini kullanarak bir Kernel tanımlayın.

Her stratejinin KernelFunction sonucunu ayrıştırmaktan sorumlu olduğuna dikkat edin.

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, yukarıda tanımlanan KernelFunctionSelectionStrategy ve KernelFunctionTerminationStrategy istemine karşılık gelir. Bu, istem sunulurken son iletinin yerleştirildiği yerdir.

Özellik şu anda Java'da kullanılamıyor.

Sohbet Döngüsü

Sonunda kullanıcı ile AgentGroupChatarasındaki etkileşimi koordine edebiliyoruz. Boş bir döngü oluşturarak başlayın.

Not: Diğer örneklerden farklı olarak, hiçbir dış geçmiş veya iş parçacığı yönetilmemiştir. AgentGroupChat konuşma geçmişini dahili olarak yönetir.

bool isComplete = false;
do
{

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

Özellik şu anda Java'da kullanılamıyor.

Şimdi önceki döngüde kullanıcı girişini yakalayalım. Bu durumda:

  • Boş girişler dikkate alınmayacak
  • Terim EXIT , konuşmanın tamamlandığını bildirir
  • RESET terimi AgentGroupChat geçmişini temizler
  • ile @ başlayan tüm terimler, içeriği giriş olarak sağlanacak olan bir dosya yolu olarak değerlendirilir
  • Geçerli giriş, AgentGroupChat'a, Kullanıcı iletisi olarak eklenir.
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));

Şimdi önceki döngüde kullanıcı girişini yakalayalım. Bu durumda:

  • Boş girişler göz ardı edilecektir.
  • exit terimi konuşmanın tamamlandığını gösterir.
  • reset terimi AgentGroupChat geçmişini temizler.
  • @ ile başlayan tüm terimler, içeriği giriş olarak sağlanacak bir dosya yolu olarak değerlendirilir.
  • Geçerli giriş, AgentGroupChat'a, Kullanıcı iletisi olarak eklenir.

while döngüsünün içindeki işlem mantığı şöyle görünür:

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)

Özellik şu anda Java'da kullanılamıyor.

Kullanıcı girişine yanıt olarak Agent işbirliğini başlatmak ve Agent yanıtlarını görüntülemek için AgentGroupChatçağırın; ancak, önce Tamamlama durumunu önceki çağrılardan sıfırladığınızdan emin olun.

Not: Konuşma döngüsünün çökmesini önlemek için hizmet hataları yakalanıyor ve görüntüleniyor.

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

Özellik şu anda Java'da kullanılamıyor.

Nihai

Tüm adımları bir araya getirdiğimizde, bu örneğin son koduna sahibiz. Uygulamanın tamamı aşağıda verilmiştir.

Şu önerilen girişleri kullanmayı deneyin:

  1. Merhaba
  2. {"message: "merhaba dünya"}
  3. {"message": "merhaba dünya"}
  4. Semantik Çekirdek (SK), geliştiricilerin doğal dil işleme (NLP) ve makine öğrenmesi modelleri içeren karmaşık yapay zeka iş akışları oluşturmasını ve düzenlemesini sağlayan bir açık kaynak SDK'dır. Anlamsal arama, metin özetleme ve diyalog sistemleri gibi yapay zeka özelliklerini uygulamalarla tümleştirmek için esnek bir platform sağlar. SK ile farklı yapay zeka hizmetlerini ve modellerini kolayca birleştirebilir, bunların ilişkilerini tanımlayabilir ve aralarındaki etkileşimleri düzenleyebilirsiniz.
  5. Bu metni iki paragrafa bölün.
  6. Teşekkür ederim
  7. @.\WomensSuffrage.txt
  8. İyi, ama üniversite profesörüm için hazır mı?
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();
        }
    }
}

Tüm adımları bir araya getirdiğimizde artık bu örneğin son koduna sahibiz. Uygulamanın tamamı aşağıda gösterilmiştir.

Önerilen girişlerden birini kullanmayı deneyebilirsiniz. Temsilci sohbeti başladığında, temsilciler, gözden geçiren temsilci metin yazarının çalışmalarından memnun kalana kadar birkaç tur boyunca iletişim alışverişi yapacaktır. while döngüsü, sohbet başlangıçta tamamlandı olarak kabul edilse bile is_complete bayrağını Falseolarak sıfırlayarak konuşmanın devam etmesini sağlar.

  1. Roze'lar kırmızı, menekşe mavi.
  2. Semantik Çekirdek (SK), geliştiricilerin doğal dil işleme (NLP) ve makine öğrenmesi modelleri içeren karmaşık yapay zeka iş akışları oluşturmasını ve düzenlemesini sağlayan bir açık kaynak SDK'dır. Anlamsal arama, metin özetleme ve diyalog sistemleri gibi yapay zeka özelliklerini uygulamalarla tümleştirmek için esnek bir platform sağlar. SK ile farklı yapay zeka hizmetlerini ve modellerini kolayca birleştirebilir, bunların ilişkilerini tanımlayabilir ve aralarındaki etkileşimleri düzenleyebilirsiniz.
  3. Bu iki paragrafı oluşturun
  4. Teşekkür ederim
  5. @WomensSuffrage.txt
  6. İyi ama üniversite profesörüm için hazır mı?

Tavsiye

@<file_path_to_file>sağlayarak herhangi bir dosyaya erişim sağlayabilirsiniz. Yukarıdaki "WomensSuffrage" metnine başvurmak için buradan indirip geçerli çalışma dizininize yerleştirin. Daha sonra @WomensSuffrage.txtile atıfta bulunabilirsiniz.

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

Yukarıda belirtildiği gibi tam kodu'i depomuzda bulabilirsiniz.

Özellik şu anda Java'da kullanılamıyor.