Dela via


Utforska den semantiska kerneln AzureAIAgent

Viktigt!

Den här funktionen är i den experimentella fasen. Funktioner i det här skedet är under utveckling och kan komma att ändras innan de går vidare till förhandsversionen eller lanseringsfasen.

Tips/Råd

Detaljerad API-dokumentation som rör den här diskussionen finns på:

Tips/Råd

Detaljerad API-dokumentation som rör den här diskussionen finns på:

Funktionen är för närvarande inte tillgänglig i Java.

Vad är en AzureAIAgent?

En AzureAIAgent är en specialiserad agent inom semantisk kernelramverk, utformad för att tillhandahålla avancerade konversationsfunktioner med sömlös verktygsintegrering. Det automatiserar verktygsanrop, vilket eliminerar behovet av manuell parsning och anrop. Agenten hanterar också konversationshistoriken på ett säkert sätt med hjälp av trådar, vilket minskar kostnaderna för att underhålla tillstånd. Dessutom stöder AzureAIAgent en mängd olika inbyggda verktyg, inklusive filhämtning, kodkörning och datainteraktion via Bing, Azure AI Search, Azure Functions och OpenAPI.

Om du vill använda en AzureAIAgentmåste ett Azure AI Foundry-projekt användas. Följande artiklar innehåller en översikt över Azure AI Foundry, hur du skapar och konfigurerar ett projekt och agenttjänsten:

Förbereda din utvecklingsmiljö

Om du vill fortsätta med att utveckla en AzureAIAgentkonfigurerar du utvecklingsmiljön med lämpliga paket.

Lägg till Microsoft.SemanticKernel.Agents.AzureAI-paketet i projektet:

dotnet add package Microsoft.SemanticKernel.Agents.AzureAI --prerelease

Du kanske också vill ta med Azure.Identity-paketet:

dotnet add package Azure.Identity

Installera semantic-kernel-paketet:

pip install semantic-kernel

Funktionen är för närvarande inte tillgänglig i Java.

Konfigurera AI-projektklienten

För att först få åtkomst till en AzureAIAgent måste du skapa en klient som är konfigurerad för ett specifikt Foundry-projekt, och det vanligaste sättet att göra detta är genom att ange projektslutpunkten (Azure AI Foundry SDK: Komma igång med projekt).

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

Ändra .env-filen i rotkatalogen så att den inkluderar:

AZURE_AI_AGENT_ENDPOINT = "<example-endpoint>"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "<example-model-deployment-name>"

När konfigurationen har definierats kan klienten skapas:

from semantic_kernel.agents import AzureAIAgent

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds) as client,
):
    # Your operational code here

Den underliggande endpoint hämtas av Pydantic-inställningarna om de är konfigurerade. Annars kan du uttryckligen skicka in den till create_client() metoden:

from semantic_kernel.agents import AzureAIAgent

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds, endpoint="<your-endpoint>") as client,
):
    # Your operational code here

Funktionen är för närvarande inte tillgänglig i Java.

Skapa en AzureAIAgent

Om du vill skapa en AzureAIAgentbörjar du med att konfigurera och initiera Foundry-projektet via Azure Agent-tjänsten och sedan integrera det med semantisk kernel:

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

// 1. Define an agent on the Azure AI agent service
PersistentAgent definition = await agentsClient.Administration.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>");

// 2. Create a Semantic Kernel agent based on the agent definition
AzureAIAgent agent = new(definition, agentsClient);
from azure.identity.aio import DefaultAzureCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds) as client,
):
    # 1. Define an agent on the Azure AI agent service
    agent_definition = await client.agents.create_agent(
        model=AzureAIAgentSettings().model_deployment_name,
        name="<name>",
        instructions="<instructions>",
    )

    # 2. Create a Semantic Kernel agent based on the agent definition
    agent = AzureAIAgent(
        client=client,
        definition=agent_definition,
    )

Funktionen är för närvarande inte tillgänglig i Java.

Interagera med en AzureAIAgent

Interaktion med AzureAIAgent är enkelt. Agenten underhåller konversationshistoriken automatiskt med hjälp av en tråd.

Detaljerna i Azure AI Agent-tråden abstraheras bort via klassen Microsoft.SemanticKernel.Agents.AzureAI.AzureAIAgentThread, som är en implementering av Microsoft.SemanticKernel.Agents.AgentThread.

Viktigt!

Observera att Azure AI Agents SDK har PersistentAgentThread klassen . Det bör inte förväxlas med Microsoft.SemanticKernel.Agents.AgentThread, vilket är den vanliga semantiska kernelagentabstraktionen för alla trådtyper.

AzureAIAgent stöder för närvarande endast trådar av typen AzureAIAgentThread.

AzureAIAgentThread agentThread = new(agent.Client);
try
{
    ChatMessageContent message = new(AuthorRole.User, "<your user input>");
    await foreach (ChatMessageContent response in agent.InvokeAsync(message, agentThread))
    {
        Console.WriteLine(response.Content);
    }
}
finally
{
    await agentThread.DeleteAsync();
    await agent.Client.DeleteAgentAsync(agent.Id);
}

Detaljerna i Azure AI Agent-tråden abstraheras bort via klassen AzureAIAgentThread, som är en implementering av AgentThread.

USER_INPUTS = ["Hello", "What's your name?"]

thread: AzureAIAgentThread = AzureAIAgentThread()

try:
    for user_input in USER_INPUTS:
        response = await agent.get_response(messages=user_inputs, thread=thread)
        print(response)
        thread = response.thread
finally:
    await thread.delete() if thread else None

Du kan också anropa en agent som:

for user_input in USER_INPUTS:
    async for content in agent.invoke(messages=user_input, thread=thread):
        print(content.content)
        thread = response.thread

Du kan också skicka en lista med meddelanden till metoderna get_response(...), invoke(...)eller invoke_stream(...):

USER_INPUTS = ["Hello", "What's your name?"]

thread: AzureAIAgentThread = AzureAIAgentThread()

try:
    for user_input in USER_INPUTS:
        response = await agent.get_response(messages=USER_INPUTS, thread=thread)
        print(response)
        thread = response.thread
finally:
    await thread.delete() if thread else None

En agent kan också generera ett strömmat svar:

ChatMessageContent message = new(AuthorRole.User, "<your user input>");
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
{
    Console.Write(response.Content);
}
for user_input in USER_INPUTS:
    await agent.add_chat_message(thread_id=thread.id, message=user_input)
    async for content in agent.invoke_stream(thread_id=thread.id):
        print(content.content, end="", flush=True)

Funktionen är för närvarande inte tillgänglig i Java.

Använda insticksprogram med en AzureAIAgent

Semantisk kernel har stöd för att utöka en AzureAIAgent med anpassade plugin-program för förbättrade funktioner:

KernelPlugin plugin = KernelPluginFactory.CreateFromType<YourPlugin>();
PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

PersistentAgent definition = await agentsClient.Administration.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>");

AzureAIAgent agent = new(definition, agentsClient, plugins: [plugin]);
from semantic_kernel.functions import kernel_function

class SamplePlugin:
    @kernel_function(description="Provides sample data.")
    def get_data(self) -> str:
        return "Sample data"

async with (
        DefaultAzureCredential() as creds,
        AzureAIAgent.create_client(credential=creds) as client,
    ):
        agent_definition = await client.agents.create_agent(
            model=AzureAIAgentSettings().model_deployment_name,
        )

        agent = AzureAIAgent(
            client=client,
            definition=agent_definition,
            plugins=[SamplePlugin()]
        )

Funktionen är för närvarande inte tillgänglig i Java.

Avancerade funktioner

En AzureAIAgent kan använda avancerade verktyg som:

Kodtolkare

Med kodtolk kan agenterna skriva och köra Python-kod i en miljö för körning i begränsat läge (Azure AI Agent Service Code Interpreter).

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

PersistentAgent definition = await agentsClient.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>",
    tools: [new CodeInterpreterToolDefinition()],
    toolResources:
        new()
        {
            CodeInterpreter = new()
            {
                FileIds = { ... },
            }
        }));

AzureAIAgent agent = new(definition, agentsClient);
from azure.ai.agents.models import CodeInterpreterTool

async with (
        DefaultAzureCredential() as creds,
        AzureAIAgent.create_client(credential=creds) as client,
    ):
        code_interpreter = CodeInterpreterTool()
        agent_definition = await client.agents.create_agent(
            model=ai_agent_settings.model_deployment_name,
            tools=code_interpreter.definitions,
            tool_resources=code_interpreter.resources,
        )

Funktionen är för närvarande inte tillgänglig i Java.

Filsökning förser agenter med kunskap från utanför dess modell (Azure AI Agent Service File Search Tool).

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

PersistentAgent definition = await agentsClient.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>",
    tools: [new FileSearchToolDefinition()],
    toolResources:
        new()
        {
            FileSearch = new()
            {
                VectorStoreIds = { ... },
            }
        });

AzureAIAgent agent = new(definition, agentsClient);
from azure.ai.agents.models import FileSearchTool

async with (
        DefaultAzureCredential() as creds,
        AzureAIAgent.create_client(credential=creds) as client,
    ):
        file_search = FileSearchTool(vector_store_ids=[vector_store.id])
        agent_definition = await client.agents.create_agent(
            model=ai_agent_settings.model_deployment_name,
            tools=file_search.definitions,
            tool_resources=file_search.resources,
        )

Funktionen är för närvarande inte tillgänglig i Java.

OpenAPI-integrering

Ansluter din agent till ett externt API (Använda Azure AI Agent Service med OpenAPI-angivna verktyg).

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

string apiJsonSpecification = ...; // An Open API JSON specification

PersistentAgent definition = await agentsClient.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>",
    tools: [
        new OpenApiToolDefinition(
            "<api name>", 
            "<api description>", 
            BinaryData.FromString(apiJsonSpecification), 
            new OpenApiAnonymousAuthDetails())
    ]
);

AzureAIAgent agent = new(definition, agentsClient);
from azure.ai.agents.models import OpenApiTool, OpenApiAnonymousAuthDetails

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds) as client,
):
    openapi_spec_file_path = "sample/filepath/..."
    with open(os.path.join(openapi_spec_file_path, "spec_one.json")) as file_one:
        openapi_spec_one = json.loads(file_one.read())
    with open(os.path.join(openapi_spec_file_path, "spec_two.json")) as file_two:
        openapi_spec_two = json.loads(file_two.read())

    # Note that connection or managed identity auth setup requires additional setup in Azure
    auth = OpenApiAnonymousAuthDetails()
    openapi_tool_one = OpenApiTool(
        name="<name>",
        spec=openapi_spec_one,
        description="<description>",
        auth=auth,
    )
    openapi_tool_two = OpenApiTool(
        name="<name>",
        spec=openapi_spec_two,
        description="<description>",
        auth=auth,
    )

    agent_definition = await client.agents.create_agent(
        model=ai_agent_settings.model_deployment_name,
        tools=openapi_tool_one.definitions + openapi_tool_two.definitions,
    )

Funktionen är för närvarande inte tillgänglig i Java.

AzureAI-sökintegration

Använd ett befintligt Azure AI Search-index med din agent (Använd ett befintligt Azure AI Search-index).

PersistentAgentsClient client = AzureAIAgent.CreateAgentsClient("<your endpoint>", new AzureCliCredential());

PersistentAgent definition = await agentsClient.CreateAgentAsync(
    "<name of the the model used by the agent>",
    name: "<agent name>",
    description: "<agent description>",
    instructions: "<agent instructions>",
    tools: [new AzureAISearchToolDefinition()],
    toolResources: new()
    {
        AzureAISearch = new()
        {
            IndexList = { new AISearchIndexResource("<your connection id>", "<your index name>") }
        }
    });

AzureAIAgent agent = new(definition, agentsClient);
from azure.ai.agents.models import AzureAISearchTool, ConnectionType

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds) as client,
):
    conn_list = await client.connections.list()

    ai_search_conn_id = ""
    for conn in conn_list:
        if conn.connection_type == ConnectionType.AZURE_AI_SEARCH:
            ai_search_conn_id = conn.id
            break

    ai_search = AzureAISearchTool(
        index_connection_id=ai_search_conn_id, 
        index_name=AZURE_AI_SEARCH_INDEX_NAME,
    )

    agent_definition = await client.agents.create_agent(
        model=ai_agent_settings.model_deployment_name,
        instructions="Answer questions using your index.",
        tools=ai_search.definitions,
        tool_resources=ai_search.resources,
        headers={"x-ms-enable-preview": "true"},
    )

Funktionen är för närvarande inte tillgänglig i Java.

Grundläggning i Bing

Exempel kommer snart.

from azure.ai.agents.models import BingGroundingTool
from azure.identity.aio import DefaultAzureCredential

from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings

async with (
    DefaultAzureCredential() as creds,
    AzureAIAgent.create_client(credential=creds) as client,
):
    # 1. Enter your Bing Grounding Connection Name
    bing_connection = await client.connections.get(connection_name="<your-bing-grounding-connection-name>")
    conn_id = bing_connection.id

    # 2. Initialize agent bing tool and add the connection id
    bing_grounding = BingGroundingTool(connection_id=conn_id)

    # 3. Create an agent with Bing grounding on the Azure AI agent service
    agent_definition = await client.agents.create_agent(
        name="BingGroundingAgent",
        instructions="Use the Bing grounding tool to answer the user's question.",
        model=AzureAIAgentSettings().model_deployment_name,
        tools=bing_grounding.definitions,
    )

    # 4. Create a Semantic Kernel agent for the Azure AI agent
    agent = AzureAIAgent(
        client=client,
        definition=agent_definition,
    )

När du använder Bing Grounding-verktyget kommer den FunctionCallContent som skickas till on_intermediate_message-återanropet att ha dess funktionsnamn inställt på "bing_grounding". När processen ChatMessageContent.items är klar kommer listan att inkludera antingen AnnotationContent eller StreamingAnnotationContent, beroende på om anropet är standard eller strömmande. Dessa anteckningsobjekt innehåller information om länkarna som agenten besökte under svaret, ungefär som informationen i FunctionCallContent.

Mer information finns i följande konceptexempel:

Funktionen är för närvarande inte tillgänglig i Java.

Hämtar en befintlig AzureAIAgent

En befintlig agent kan hämtas och återanvändas genom att ange dess assistent-ID:

PersistentAgent definition = await agentsClient.Administration.GetAgentAsync("<your agent id>");
AzureAIAgent agent = new(definition, agentsClient);
agent_definition = await client.agents.get_agent(assistant_id="your-agent-id")
agent = AzureAIAgent(client=client, definition=agent_definition)

Funktionen är för närvarande inte tillgänglig i Java.

Ta bort en AzureAIAgent

Agenter och deras associerade trådar kan tas bort när de inte längre behövs:

await agentThread.DeleteAsync();
await agentsClient.Administration.DeleteAgentAsync(agent.Id);
await client.agents.delete_thread(thread.id)
await client.agents.delete_agent(agent.id)

Om du arbetar med ett vektorlager eller filer kan de också tas bort:

await agentsClient.VectorStores.DeleteVectorStoreAsync("<your store id>");
await agentsClient.Files.DeleteFileAsync("<your file id>");
await client.agents.files.delete(file_id=file.id)
await client.agents.vector_stores.delete(vector_store_id=vector_store.id)

Funktionen är för närvarande inte tillgänglig i Java.

Mer information om filsökningsverktyget beskrivs i artikeln om Azure AI Agent Service-filsökningsverktyget.

Så här gör du

Praktiska exempel på hur du använder en AzureAIAgentfinns i våra kodexempel på GitHub:

Funktionen är för närvarande inte tillgänglig i Java.

Hantera mellanliggande meddelanden med en AzureAIAgent

Semantisk kärna AzureAIAgent är utformad för att anropa en agent som besvarar användarens frågor eller förfrågningar. Under anropet kan agenten köra verktyg för att härleda det slutliga svaret. För att få åtkomst till mellanliggande meddelanden som skapas under den här processen kan anropare tillhandahålla en återanropsfunktion som hanterar instanser av FunctionCallContent eller FunctionResultContent.

Dokumentationen för återanrop för AzureAIAgent kommer snart.

Genom att konfigurera återanropet on_intermediate_message inom agent.invoke(...) eller agent.invoke_stream(...) kan anroparen ta emot mellanliggande meddelanden som genererats under processen med att formulera agentens slutliga svar.

import asyncio
from typing import Annotated

from azure.identity.aio import DefaultAzureCredential

from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.functions import kernel_function


# Define a sample plugin for the sample
class MenuPlugin:
    """A sample Menu Plugin used for the concept sample."""

    @kernel_function(description="Provides a list of specials from the menu.")
    def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
        return """
        Special Soup: Clam Chowder
        Special Salad: Cobb Salad
        Special Drink: Chai Tea
        """

    @kernel_function(description="Provides the price of the requested menu item.")
    def get_item_price(
        self, menu_item: Annotated[str, "The name of the menu item."]
    ) -> Annotated[str, "Returns the price of the menu item."]:
        return "$9.99"


# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
    for item in message.items or []:
        if isinstance(item, FunctionResultContent):
            print(f"Function Result:> {item.result} for function: {item.name}")
        elif isinstance(item, FunctionCallContent):
            print(f"Function Call:> {item.name} with arguments: {item.arguments}")
        else:
            print(f"{item}")


async def main() -> None:
    ai_agent_settings = AzureAIAgentSettings()

    async with (
        DefaultAzureCredential() as creds,
        AzureAIAgent.create_client(credential=creds, endpoint=ai_agent_settings.endpoint) as client,
    ):
        AGENT_NAME = "Host"
        AGENT_INSTRUCTIONS = "Answer questions about the menu."

        # Create agent definition
        agent_definition = await client.agents.create_agent(
            model=ai_agent_settings.deployment_name,
            name=AGENT_NAME,
            instructions=AGENT_INSTRUCTIONS,
        )

        # Create the AzureAI Agent
        agent = AzureAIAgent(
            client=client,
            definition=agent_definition,
            plugins=[MenuPlugin()],  # add the sample plugin to the agent
        )

        # Create a thread for the agent
        # If no thread is provided, a new thread will be
        # created and returned with the initial response
        thread: AzureAIAgentThread = None

        user_inputs = [
            "Hello",
            "What is the special soup?",
            "How much does that cost?",
            "Thank you",
        ]

        try:
            for user_input in user_inputs:
                print(f"# User: '{user_input}'")
                async for response in agent.invoke(
                    messages=user_input,
                    thread=thread,
                    on_intermediate_message=handle_intermediate_steps,
                ):
                    print(f"# Agent: {response}")
                    thread = response.thread
        finally:
            # Cleanup: Delete the thread and agent
            await thread.delete() if thread else None
            await client.agents.delete_agent(agent.id)


if __name__ == "__main__":
    asyncio.run(main())

Följande visar exempelutdata från agentanropsprocessen:

User: 'Hello'
Agent: Hi there! How can I assist you today?
User: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:> 
        Special Soup: Clam Chowder
        Special Salad: Cobb Salad
        Special Drink: Chai Tea
        for function: MenuPlugin-get_specials
Agent: The special soup is Clam Chowder. Would you like to know anything else about the menu?
User: 'How much does that cost?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
Agent: The Clam Chowder costs $9.99. Let me know if you would like assistance with anything else!
User: 'Thank you'
Agent: You're welcome! Enjoy your meal! 😊

Funktionen är för närvarande inte tillgänglig i Java.

Deklarativ specifikation

Dokumentationen om hur du använder deklarativa specifikationer kommer snart.

Viktigt!

Den här funktionen är i den experimentella fasen. Funktioner i det här skedet är under utveckling och kan komma att ändras innan de går vidare till förhandsversionen eller lanseringsfasen.

AzureAIAgent Stöder instansiering från en YAML-deklarativ specifikation. Med den deklarativa metoden kan du definiera agentens egenskaper, instruktioner, modellkonfiguration, verktyg och andra alternativ i ett enda, granskningsbart dokument. Detta gör agentsammansättningen portabel och lätthanterad i olika miljöer.

Anmärkning

Alla verktyg, funktioner eller plugin-program som anges i deklarativ YAML måste vara tillgängliga för agenten vid byggtiden. För kernelbaserade plugin-program innebär det att de måste vara registrerade i kerneln. För inbyggda verktyg som Bing Grounding, File Search eller OpenAPI-verktyg måste rätt konfiguration och autentiseringsuppgifter anges. Agentinläsaren skapar inte funktioner helt från grunden. Om en nödvändig komponent saknas misslyckas agentskapandet.

Så här använder du deklarativ specifikation

I stället för att räkna upp alla möjliga YAML-konfigurationer beskriver det här avsnittet nyckelprinciperna och innehåller länkar till konceptexempel som visar fullständig kod för varje verktygstyp. Se dessa konceptexempel för implementeringar från slutpunkt till slutpunkt för en AzureAIAgent med deklarativa specifikationer:

Exempel: Skapa en AzureAIAgent från YAML

En minimal YAML-deklarativ specifikation kan se ut så här:

type: foundry_agent
name: MyAgent
instructions: Respond politely to the user's questions.
model:
  id: ${AzureAI:ChatModelId}
tools:
  - id: MenuPlugin.get_specials
    type: function
  - id: MenuPlugin.get_item_price
    type: function

Mer information om hur du kopplar agenten finns i de fullständiga kodexemplen ovan.

Huvudpunkter

  • Deklarativa specifikationer gör det möjligt att definiera agentstruktur, verktyg och beteende i YAML.
  • Alla refererade verktyg och plugins måste vara registrerade eller tillgängliga under körning.
  • Inbyggda verktyg som Bing, Filsökning och kodtolk kräver korrekt konfiguration och autentiseringsuppgifter (ofta via miljövariabler eller explicita argument).
  • Omfattande exempel finns i de exempellänkar som visar praktiska scenarier, inklusive registrering av plugin-program, Azure-identitetskonfiguration och avancerad verktygsanvändning.

Den här funktionen är inte tillgänglig.

Nästa steg