Aracılığıyla paylaş


Özel Ajanlar

Microsoft Agent Framework, sınıfından AIAgent devralarak ve gerekli yöntemleri uygulayarak özel aracılar oluşturulmasını destekler.

Bu makale, kullanıcı girişini büyük harfle tekrar eden basit bir özelleştirilmiş ajan nasıl oluşturulacağını gösterir. Çoğu durumda kendi aracınızı oluşturmak için yapay zeka hizmetiyle daha karmaşık mantık ve tümleştirme gerekir.

Başlangıç Yapmak

Projenize gerekli NuGet paketlerini ekleyin.

dotnet add package Microsoft.Agents.AI.Abstractions --prerelease

Özel Aracı Oluşturma

Ajan İş Parçacığı

Özel bir temsilci oluşturmak için, ileti geçmişi ve temsilcinin sürdürmesi gereken diğer tüm durumlar dahil olmak üzere, tek bir konuşmanın durumunu izlemek için kullanılan bir iş parçacığına da ihtiyacınız vardır.

Başlamayı kolaylaştırmak için, yaygın iş parçacığı depolama mekanizmalarını uygulayan çeşitli temel sınıflardan devir alabilirsiniz.

  1. InMemoryAgentThread - sohbet geçmişini bellekte depolar ve JSON'a seri hale getirilebilir.
  2. ServiceIdAgentThread - herhangi bir sohbet geçmişi depolamaz, ancak bir kimliği sohbet geçmişinin harici olarak depolanabileceği yazışmayla ilişkilendirmenize olanak tanır.

Bu örnekte, özel iş parçacığı için temel sınıf olarak InMemoryAgentThread öğesini kullanacaksınız.

internal sealed class CustomAgentThread : InMemoryAgentThread
{
    internal CustomAgentThread() : base() { }
    internal CustomAgentThread(JsonElement serializedThreadState, JsonSerializerOptions? jsonSerializerOptions = null)
        : base(serializedThreadState, jsonSerializerOptions) { }
}

Agent sınıfı

Ardından, AIAgent sınıfından türeterek aracı sınıfının kendisini oluşturun.

internal sealed class UpperCaseParrotAgent : AIAgent
{
}

Konuları oluşturma

İş parçacıkları her zaman aracı sınıfındaki iki fabrika yöntemiyle oluşturulur. Bu, aracının iş parçacıklarının nasıl oluşturulduğunu ve seri durumdan çıkarıldığını denetlemesine olanak tanır. Bu nedenle aracılar, oluşturulduğunda iş parçacığına gereken ek durumları veya davranışları ekleyebilir.

İki yöntemin uygulanması gerekir:

    public override AgentThread GetNewThread() => new CustomAgentThread();

    public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
        => new CustomAgentThread(serializedThread, jsonSerializerOptions);

Temel ajan mantığı

Aracının temel mantığı, tüm giriş iletilerini almak, metinlerini büyük harfe dönüştürmek ve bunları yanıt iletileri olarak döndürmektir.

Bu mantığı içerecek şekilde aşağıdaki yöntemi ekleyin. Giriş iletilerinin çeşitli yönlerinin geçerli yanıt iletileri olması için değiştirilmesi gerektiğinden, giriş iletileri kopyalanır. Örneğin, rolün Assistant olarak değiştirilmesi gerekir.

    private static IEnumerable<ChatMessage> CloneAndToUpperCase(IEnumerable<ChatMessage> messages, string agentName) => messages.Select(x =>
        {
            var messageClone = x.Clone();
            messageClone.Role = ChatRole.Assistant;
            messageClone.MessageId = Guid.NewGuid().ToString();
            messageClone.AuthorName = agentName;
            messageClone.Contents = x.Contents.Select(c => c is TextContent tc ? new TextContent(tc.Text.ToUpperInvariant())
            {
                AdditionalProperties = tc.AdditionalProperties,
                Annotations = tc.Annotations,
                RawRepresentation = tc.RawRepresentation
            } : c).ToList();
            return messageClone;
        });

Aracı çalıştırma yöntemleri

Son olarak, aracıyı çalıştırmak için kullanılan iki temel yöntemi uygulamanız gerekir: biri akış dışı ve biri akış için.

Her iki yöntem için de bir iş parçacığının sağlandığından emin olmanız ve sağlanmadıysa yeni bir iş parçacığı oluşturmanız gerekir. Ardından iş parçacığı, NotifyThreadOfNewMessagesAsync çağrılarak yeni iletilerle güncellenebilir. Bunu yapmazsanız, kullanıcı aracıyla çoklu tur konuşması yapamaz ve her oturum yeni bir etkileşim olacaktır.

    public override async Task<AgentRunResponse> RunAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
    {
        thread ??= this.GetNewThread();
        List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.DisplayName).ToList();
        await NotifyThreadOfNewMessagesAsync(thread, messages.Concat(responseMessages), cancellationToken);
        return new AgentRunResponse
        {
            AgentId = this.Id,
            ResponseId = Guid.NewGuid().ToString(),
            Messages = responseMessages
        };
    }

    public override async IAsyncEnumerable<AgentRunResponseUpdate> RunStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        thread ??= this.GetNewThread();
        List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.DisplayName).ToList();
        await NotifyThreadOfNewMessagesAsync(thread, messages.Concat(responseMessages), cancellationToken);
        foreach (var message in responseMessages)
        {
            yield return new AgentRunResponseUpdate
            {
                AgentId = this.Id,
                AuthorName = this.DisplayName,
                Role = ChatRole.Assistant,
                Contents = message.Contents,
                ResponseId = Guid.NewGuid().ToString(),
                MessageId = Guid.NewGuid().ToString()
            };
        }
    }

Ajanı Kullanma

Yöntemlerin AIAgent tümü doğru uygulanırsa, aracı standart bir AIAgent olur ve standart aracı işlemlerini destekler.

Aracıları çalıştırma ve aracılarla etkileşim kurma hakkında daha fazla bilgi için bkz. Aracı kullanmaya başlama öğreticileri.

Microsoft Agent Framework, sınıfından BaseAgent devralarak ve gerekli yöntemleri uygulayarak özel aracılar oluşturulmasını destekler.

Bu belgede, ön ek ile kullanıcı girişini geri döndüren basit bir özel aracı oluşturma gösterilmektedir. Çoğu durumda kendi aracınızı oluşturmak için yapay zeka hizmetiyle daha karmaşık mantık ve tümleştirme gerekir.

Başlangıç Yapmak

Projenize gerekli Python paketlerini ekleyin.

pip install agent-framework-core --pre

Özelleştirilmiş Temsilci Oluşturma

Aracı Protokolü

Çerçeve, tüm aracıların AgentProtocol uygulaması gereken arabirimi tanımlayan protokolü sağlar. Özel aracılar bu protokolü doğrudan uygulayabilir veya kolaylık sağlamak için sınıfını BaseAgent genişletebilir.

from agent_framework import AgentProtocol, AgentRunResponse, AgentRunResponseUpdate, AgentThread, ChatMessage
from collections.abc import AsyncIterable
from typing import Any

class MyCustomAgent(AgentProtocol):
    """A custom agent that implements the AgentProtocol directly."""

    @property
    def id(self) -> str:
        """Returns the ID of the agent."""
        ...

    async def run(
        self,
        messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
        *,
        thread: AgentThread | None = None,
        **kwargs: Any,
    ) -> AgentRunResponse:
        """Execute the agent and return a complete response."""
        ...

    def run_stream(
        self,
        messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
        *,
        thread: AgentThread | None = None,
        **kwargs: Any,
    ) -> AsyncIterable[AgentRunResponseUpdate]:
        """Execute the agent and yield streaming response updates."""
        ...

BaseAgent kullanma

Önerilen yaklaşım, ortak işlevsellik sağlayan ve uygulamayı basitleştiren sınıfını genişletmektir BaseAgent :

from agent_framework import (
    BaseAgent,
    AgentRunResponse,
    AgentRunResponseUpdate,
    AgentThread,
    ChatMessage,
    Role,
    TextContent,
)
from collections.abc import AsyncIterable
from typing import Any


class EchoAgent(BaseAgent):
    """A simple custom agent that echoes user messages with a prefix."""

    echo_prefix: str = "Echo: "

    def __init__(
        self,
        *,
        name: str | None = None,
        description: str | None = None,
        echo_prefix: str = "Echo: ",
        **kwargs: Any,
    ) -> None:
        """Initialize the EchoAgent.

        Args:
            name: The name of the agent.
            description: The description of the agent.
            echo_prefix: The prefix to add to echoed messages.
            **kwargs: Additional keyword arguments passed to BaseAgent.
        """
        super().__init__(
            name=name,
            description=description,
            echo_prefix=echo_prefix,
            **kwargs,
        )

    async def run(
        self,
        messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
        *,
        thread: AgentThread | None = None,
        **kwargs: Any,
    ) -> AgentRunResponse:
        """Execute the agent and return a complete response.

        Args:
            messages: The message(s) to process.
            thread: The conversation thread (optional).
            **kwargs: Additional keyword arguments.

        Returns:
            An AgentRunResponse containing the agent's reply.
        """
        # Normalize input messages to a list
        normalized_messages = self._normalize_messages(messages)

        if not normalized_messages:
            response_message = ChatMessage(
                role=Role.ASSISTANT,
                contents=[TextContent(text="Hello! I'm a custom echo agent. Send me a message and I'll echo it back.")],
            )
        else:
            # For simplicity, echo the last user message
            last_message = normalized_messages[-1]
            if last_message.text:
                echo_text = f"{self.echo_prefix}{last_message.text}"
            else:
                echo_text = f"{self.echo_prefix}[Non-text message received]"

            response_message = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=echo_text)])

        # Notify the thread of new messages if provided
        if thread is not None:
            await self._notify_thread_of_new_messages(thread, normalized_messages, response_message)

        return AgentRunResponse(messages=[response_message])

    async def run_stream(
        self,
        messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
        *,
        thread: AgentThread | None = None,
        **kwargs: Any,
    ) -> AsyncIterable[AgentRunResponseUpdate]:
        """Execute the agent and yield streaming response updates.

        Args:
            messages: The message(s) to process.
            thread: The conversation thread (optional).
            **kwargs: Additional keyword arguments.

        Yields:
            AgentRunResponseUpdate objects containing chunks of the response.
        """
        # Normalize input messages to a list
        normalized_messages = self._normalize_messages(messages)

        if not normalized_messages:
            response_text = "Hello! I'm a custom echo agent. Send me a message and I'll echo it back."
        else:
            # For simplicity, echo the last user message
            last_message = normalized_messages[-1]
            if last_message.text:
                response_text = f"{self.echo_prefix}{last_message.text}"
            else:
                response_text = f"{self.echo_prefix}[Non-text message received]"

        # Simulate streaming by yielding the response word by word
        words = response_text.split()
        for i, word in enumerate(words):
            # Add space before word except for the first one
            chunk_text = f" {word}" if i > 0 else word

            yield AgentRunResponseUpdate(
                contents=[TextContent(text=chunk_text)],
                role=Role.ASSISTANT,
            )

            # Small delay to simulate streaming
            await asyncio.sleep(0.1)

        # Notify the thread of the complete response if provided
        if thread is not None:
            complete_response = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)])
            await self._notify_thread_of_new_messages(thread, normalized_messages, complete_response)

Ajanı Kullanma

Aracı yöntemlerinin tümü doğru şekilde uygulanırsa, ajan tüm standart ajan işlevlerini destekler.

Aracıları çalıştırma ve aracılarla etkileşim kurma hakkında daha fazla bilgi için bkz. Aracı kullanmaya başlama öğreticileri.

Sonraki Adımlar