探索语义内核 OpenAIAssistantAgent

重要

单代理功能(如 OpenAIAssistantAgent)处于候选发布阶段。 这些功能几乎完整且通常是稳定的,尽管这些功能在正式发布之前可能会进行细微的改进或优化。

小窍门

有关此讨论的详细 API 文档在以下位置提供:

小窍门

有关此讨论的详细 API 文档在以下位置提供:

功能当前在 Java 中不可用。

什么是助手?

OpenAI 助手 API 是专为更高级和交互式 AI 功能设计的专用界面,使开发人员能够创建个性化的多步骤面向任务的代理。 与专注于简单聊天交换的聊天完成 API 不同,助手 API 允许动态、目标驱动的交互与代码解释器和文件搜索等其他功能交互。

准备您的开发环境

若要继续开发 OpenAIAssistantAgent,请使用相应的包配置开发环境。

Microsoft.SemanticKernel.Agents.OpenAI 包添加到项目:

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

您可能还希望包括 Azure.Identity 包:

dotnet add package Azure.Identity

安装 semantic-kernel 包:

pip install semantic-kernel

功能当前在 Java 中不可用。

创建一个 OpenAIAssistantAgent

创建OpenAIAssistant需要先创建一个客户端,以便能够与远程服务进行通信。

AssistantClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(...).GetAssistantClient();
Assistant assistant =
    await client.CreateAssistantAsync(
        "<model name>",
        "<agent name>",
        instructions: "<agent instructions>");
OpenAIAssistantAgent agent = new(assistant, client);
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent, OpenAIAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings, OpenAISettings

# Set up the client and model using Azure OpenAI Resources
client = AzureAssistantAgent.create_client()

# Define the assistant definition
definition = await client.beta.assistants.create(
    model=AzureOpenAISettings().chat_deployment_name,
    instructions="<instructions>",
    name="<agent name>",
)

# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
    client=client,
    definition=definition,
)

# or

# Set up the client and model using OpenAI Resources
client = OpenAIAssistantAgent.create_client()

# Define the assistant definition
definition = await client.beta.assistants.create(
    model=OpenAISettings().chat_model_id,
    instructions="<instructions>",
    name="<agent name>",
)

# Create the OpenAIAssistantAgent instance using the client and the assistant definition
agent = OpenAIAssistantAgent(
    client=client,
    definition=definition,
)

功能当前在 Java 中不可用。

检索一个OpenAIAssistantAgent

创建后,可以通过其标识符访问助手的标识。 此标识符可用于从已存在的助手定义创建 OpenAIAssistantAgent

对于 .NET,代理标识符通过由任何代理定义的属性以 string 的形式公开。

AssistantClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(...).GetAssistantClient();
Assistant assistant = await client.GetAssistantAsync("<assistant id>");
OpenAIAssistantAgent agent = new(assistant, client);
# Using Azure OpenAI Resources

# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client()

# Create the assistant definition
definition = await client.beta.assistants.create(
    model=AzureOpenAISettings().chat_deployment_name,
    name="<agent name>",
    instructions="<instructions>",
)

# Store the assistant ID
assistant_id = definition.id

# Retrieve the assistant definition from the server based on the assistant ID
new_asst_definition = await client.beta.assistants.retrieve(assistant_id)

# Create the AzureAssistantAgent instance using the client and the assistant definition
agent = AzureAssistantAgent(
    client=client,
    definition=new_asst_definition,
)

功能当前在 Java 中不可用。

使用 OpenAIAssistantAgent

与助手 API 的所有方面一样,对话会远程存储。 每个会话称为主题,并通过唯一标识符string进行标识。 您与 OpenAIAssistantAgent 的互动关联至此特定线程标识符。 助理 API 线程的具体细节通过 OpenAIAssistantAgentThread 类进行了抽象化,该类是 AgentThread 的实现。

OpenAIAssistantAgent 目前仅支持类型为 OpenAIAssistantAgentThread的线程。

无需指定 OpenAIAssistantAgent即可调用 AgentThread,以启动新线程,新的 AgentThread 将作为响应的一部分返回。


// Define agent
OpenAIAssistantAgent agent = ...;
AgentThread? agentThread = null;

// Generate the agent response(s)
await foreach (AgentResponseItem<ChatMessageContent> response in agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, "<user input>")))
{
  // Process agent response(s)...
  agentThread = response.Thread;
}

// Delete the thread if no longer needed
if (agentThread is not null)
{
    await agentThread.DeleteAsync();
}

您还可以使用您创建的 OpenAIAssistantAgent 来调用 AgentThread

// Define agent
OpenAIAssistantAgent agent = ...;

// Create a thread with some custom metadata.
AgentThread agentThread = new OpenAIAssistantAgentThread(client, metadata: myMetadata);

// Generate the agent response(s)
await foreach (ChatMessageContent response in agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, "<user input>"), agentThread))
{
  // Process agent response(s)...
}

// Delete the thread when it is no longer needed
await agentThread.DeleteAsync();

您还可以创建一个通过对话编号恢复早期对话的 OpenAIAssistantAgentThread

// Create a thread with an existing thread id.
AgentThread agentThread = new OpenAIAssistantAgentThread(client, "existing-thread-id");
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent

# Define agent
openai_agent = await ...

# Create a thread for the agent conversation
thread: AssistantAgentThread = None

# Generate the agent response(s)
async for response in agent.invoke(messages="user input", thread=thread):
  # process agent response(s)...
  thread = response.thread

# Delete the thread when it is no longer needed
await thread.delete() if thread else None

功能当前在 Java 中不可用。

删除 OpenAIAssistantAgent

由于助手的定义是远程存储的,因此如果未删除,它将保留。
可以直接使用客户端执行删除助理定义。

注意:在删除代理实例后尝试使用代理实例将导致服务异常。

对于 .NET,通过任何代理定义的string属性来公开代理标识符Agent.Id

AssistantClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(...).GetAssistantClient();
await client.DeleteAssistantAsync("<assistant id>");
await client.beta.assistants.delete(agent.id)

功能当前在 Java 中不可用。

使用 OpenAIAssistantAgent 处理中间消息

语义内核 OpenAIAssistantAgent 旨在调用满足用户查询或问题的代理。 在调用期间,代理可以执行工具来派生最终答案。 若要访问在此过程中生成的中间消息,调用方可以提供一个回调函数来处理FunctionCallContentFunctionResultContent的实例。

即将推出 OpenAIAssistantAgent 回调文档。

on_intermediate_messageagent.invoke(...)中配置agent.invoke_stream(...)回调函数允许调用方在制定代理最终响应的过程中接收生成的中间消息。

import asyncio
from typing import Annotated

from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FunctionCallContent, FunctionResultContent
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():
    # Create the client using Azure OpenAI resources and configuration
    client = AzureAssistantAgent.create_client()

    # Define the assistant definition
    definition = await client.beta.assistants.create(
        model=AzureOpenAISettings().chat_deployment_name,
        name="Host",
        instructions="Answer questions about the menu.",
    )

    # Create the AzureAssistantAgent instance using the client and the assistant definition and the defined plugin
    agent = AzureAssistantAgent(
        client=client,
        definition=definition,
        plugins=[MenuPlugin()],
    )

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

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

    try:
        for user_input in user_inputs:
            print(f"# {AuthorRole.USER}: '{user_input}'")
            async for response in agent.invoke(
                messages=user_input,
                thread=thread,
                on_intermediate_message=handle_intermediate_steps,
            ):
                print(f"# {response.role}: {response}")
                thread = response.thread
    finally:
        await thread.delete() if thread else None
        await client.beta.assistants.delete(assistant_id=agent.id)


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

下面演示了代理调用过程的示例输出:

AuthorRole.USER: 'Hello'
AuthorRole.ASSISTANT: Hello! How can I assist you today?
AuthorRole.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
AuthorRole.ASSISTANT: The special soup is Clam Chowder. Would you like to know more about the specials or 
    anything else?
AuthorRole.USER: 'What is the special drink?'
AuthorRole.ASSISTANT: The special drink is Chai Tea. If you have any more questions, feel free to ask!
AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
AuthorRole.ASSISTANT: The Chai Tea is priced at $9.99. If there's anything else you'd like to know, 
    just let me know!
AuthorRole.USER: 'Thank you'
AuthorRole.ASSISTANT: You're welcome! If you have any more questions or need further assistance, feel free to 
    ask. Enjoy your day!

功能当前在 Java 中不可用。

声明性规范

即将推出有关使用声明式规格的文档。

重要

此功能处于实验阶段。 此阶段的功能正在开发中,在升级到预览阶段或候选发布阶段之前可能会更改。

OpenAIAssistantAgent 支持从 YAML 声明性规范中进行实例化。 声明性方法允许在单个可审核文档中定义代理的属性、说明、模型配置、工具和其他选项。 这使得代理组合可移植且易于跨环境进行管理。

注释

声明性 YAML 中列出的任何工具、函数或插件都必须在构造时可供代理使用。 对于基于内核的插件,这意味着必须在内核中注册它们。 对于代码解释器或文件搜索等内置工具,必须提供正确的配置和凭据。 代理加载程序不会从头开始创建函数。 如果缺少所需的组件,代理创建将失败。

如何使用声明性规范

本部分概述了关键原则,并提供概念示例的链接,这些示例显示了每种工具类型的完整代码,而不是枚举每个可能的 YAML 配置。 请参阅以下概念示例,了解具有声明性规范的 OpenAIAssistantAgent 端到端实现:

AzureAssistantAgent 样品:

OpenAIAssistantAgent 样品:

示例:从 YAML 创建 AzureAIAgent

最小 YAML 声明性规范可能如下所示:

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

有关如何连接代理的详细信息,请参阅上面的完整代码示例。

要点

  • 声明性规范允许在 YAML 中定义代理结构、工具和行为。
  • 必须在运行时注册或访问所有引用的工具和插件。
  • 必应、文件搜索和代码解释器等内置工具需要适当的配置和凭据(通常通过环境变量或显式参数)。
  • 有关全面的示例,请参阅提供的示例链接,这些链接演示了实际方案,包括插件注册、Azure 标识配置和高级工具使用。

此功能不可用。

操作说明

如需了解 OpenAIAssistantAgent 的端到端示例,请参阅:

后续步骤