Partilhar via


Como fazer: OpenAIAssistantAgent pesquisa de arquivos

Importante

Este recurso está na fase de candidato a lançamento. Os recursos neste estágio estão quase completos e geralmente estáveis, embora possam passar por pequenos refinamentos ou otimizações antes de atingir a disponibilidade geral total.

Descrição geral

Neste exemplo, exploraremos como usar a ferramenta de pesquisa de arquivos de um OpenAIAssistantAgent para concluir tarefas de compreensão. A abordagem será passo a passo, garantindo clareza e precisão ao longo de todo o processo. Como parte da tarefa, o agente fornecerá citações de documentos na resposta.

O streaming será usado para entregar as respostas do agente. Isso fornecerá atualizações em tempo real à medida que a tarefa progride.

Introdução

Antes de prosseguir com a codificação de funcionalidades, verifique se o ambiente de desenvolvimento está totalmente configurado.

Para adicionar dependências de pacote a partir da linha de comando, use o dotnet comando:

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
dotnet add package Microsoft.SemanticKernel.Agents.OpenAI --prerelease

Se estiver gerenciando pacotes NuGet no Visual Studio, verifique se Include prerelease está marcado.

O ficheiro de projeto (.csproj) deve conter as seguintes PackageReference definições:

  <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" Version="<latest>" />
    <PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" Version="<latest>" />
  </ItemGroup>

O Agent Framework é experimental e requer supressão de aviso. Isso pode ser abordado como uma propriedade no arquivo de projeto (.csproj):

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

Além disso, copie o conteúdo de domínio público dos , e do projeto Semantic Kernel. Adicione esses arquivos na pasta do projeto e configure para copiá-los para o diretório de saída:

  <ItemGroup>
    <None Include="Grimms-The-King-of-the-Golden-Mountain.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Include="Grimms-The-Water-of-Life.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Include="Grimms-The-White-Snake.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

Comece criando uma pasta que armazenará seu script (.py arquivo) e os recursos de exemplo. Inclua as seguintes importações na parte superior do arquivo .py :

import asyncio
import os

from semantic_kernel.agents.open_ai import AzureAssistantAgent
from semantic_kernel.contents import StreamingAnnotationContent

Além disso, copie o conteúdo de domínio público Grimms-The-King-of-the-Golden-Mountain.txt, Grimms-The-Water-of-Life.txt e Grimms-The-White-Snake.txt do Projeto Semantic KernelLearnResources. Adicione esses arquivos na pasta do projeto.

Os agentes estão atualmente indisponíveis em Java.

Configuração

Este exemplo requer definição de configuração para se conectar a serviços remotos. Você precisará definir configurações para OpenAI ou Azure OpenAI.

# 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" "https://lightspeed-team-shared-openai-eastus.openai.azure.com/"
dotnet user-secrets set "AzureOpenAISettings:ChatModelDeployment" "gpt-4o"

A classe a seguir é usada em todos os exemplos de agente. Certifique-se de incluí-lo em seu projeto para garantir a funcionalidade adequada. Esta classe serve como um componente fundamental para os exemplos que se seguem.

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 maneira mais rápida de começar com a configuração adequada para executar o código de exemplo é criar um .env arquivo na raiz do seu projeto (onde o script é executado).

Configure as configurações seguintes no seu ficheiro .env para Azure OpenAI ou o OpenAI.

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

")

Os Assistentes do Azure exigem uma versão de API de pelo menos 2024-05-01-preview. À medida que novos recursos são introduzidos, as versões da API são atualizadas de acordo. No momento em que este artigo foi escrito, a versão mais recente é 2025-01-01-preview. Para obter os detalhes de controle de versão mais atualizados, consulte o ciclo de vida de pré-visualização da API Azure OpenAI.

Uma vez configuradas, as respetivas classes de serviço de IA pegarão as variáveis necessárias e as usarão durante a instanciação.

Os agentes estão atualmente indisponíveis em Java.

Codificação

O processo de codificação para este exemplo envolve:

  1. Configuração - Inicializando as configurações e o plug-in.
  2. Definição de Agente - Crie o _Chat_CompletionAgent com instruções padronizadas e plug-in.
  3. The Chat Loop - Escreva o loop que impulsiona a interação usuário/agente.

O código de exemplo completo é fornecido na seção Final . Consulte essa seção para obter a implementação completa.

Configuração

Antes de criar um OpenAIAssistantAgent, verifique se as definições de configuração estão disponíveis e prepare os recursos do arquivo.

Instancie a Settings classe referenciada na seção Configuração anterior. Use as configurações para também criar um AzureOpenAIClient que será usado para a definição do agente, bem como para carregar arquivos e criar um VectorStore.

Settings settings = new();

AzureOpenAIClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));

O método de classe setup_resources() no Agente Assistente trata de criar o cliente e retorná-lo e o modelo a ser usado com base na configuração desejada. As configurações Pydantic são usadas para carregar variáveis de ambiente, primeiro a partir destas ou do arquivo .env. Pode-se optar por api_key, api_version, deployment_name ou endpoint, que terá prioridade sobre quaisquer variáveis de ambiente configuradas.

# Create the client using Azure OpenAI resources and configuration
client, model = AzureAssistantAgent.setup_resources()

Os agentes estão atualmente indisponíveis em Java.

Agora crie um _Vetor Store vazio para usar com a ferramenta de pesquisa de arquivos:

Use o AzureOpenAIClient para aceder a um VectorStoreClient e criar um VectorStore.

Console.WriteLine("Creating store...");
VectorStoreClient storeClient = client.GetVectorStoreClient();
CreateVectorStoreOperation operation = await storeClient.CreateVectorStoreAsync(waitUntilCompleted: true);
string storeId = operation.VectorStoreId;
def get_filepath_for_filename(filename: str) -> str:
    base_directory = os.path.join(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
        "resources",
    )
    return os.path.join(base_directory, filename)

# Upload the files to the client
file_ids: list[str] = []
for path in [get_filepath_for_filename(filename) for filename in filenames]:
    with open(path, "rb") as file:
        file = await client.files.create(file=file, purpose="assistants")
        file_ids.append(file.id)

# Get the file search tool and resources
file_search_tools, file_search_tool_resources = AzureAssistantAgent.configure_file_search_tool(file_ids=file_ids)

Os agentes estão atualmente indisponíveis em Java.

Vamos declarar os três arquivos de conteúdo descritos na seção Configuração anterior:

private static readonly string[] _fileNames =
    [
        "Grimms-The-King-of-the-Golden-Mountain.txt",
        "Grimms-The-Water-of-Life.txt",
        "Grimms-The-White-Snake.txt",
    ];
filenames = [
    "Grimms-The-King-of-the-Golden-Mountain.txt",
    "Grimms-The-Water-of-Life.txt",
    "Grimms-The-White-Snake.txt",
]

Os agentes estão atualmente indisponíveis em Java.

Agora, carregue esses arquivos e adicione-os ao Vector Store usando os clientes criados anteriormente VectorStoreClient para carregar cada arquivo com um OpenAIFileClient e adicioná-lo ao Vector Store, preservando as Referências de Arquivo resultantes.

Dictionary<string, OpenAIFile> fileReferences = [];

Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = client.GetOpenAIFileClient();
foreach (string fileName in _fileNames)
{
    OpenAIFile fileInfo = await fileClient.UploadFileAsync(fileName, FileUploadPurpose.Assistants);
    await storeClient.AddFileToVectorStoreAsync(storeId, fileInfo.Id, waitUntilCompleted: true);
    fileReferences.Add(fileInfo.Id, fileInfo);
}

Os agentes estão atualmente indisponíveis em Java.

Definição do agente

Estamos agora prontos para instanciar um OpenAIAssistantAgent. O agente é configurado com seu modelo de destino, Instruções e a ferramenta de Pesquisa de Arquivos habilitada. Além disso, associamos explicitamente o Vetor Store à ferramenta de Pesquisa deFicheiros.

Utilizaremos o AzureOpenAIClient novamente como parte da criação do OpenAIAssistantAgent:

Console.WriteLine("Defining assistant...");
Assistant assistant =
    await assistantClient.CreateAssistantAsync(
        settings.AzureOpenAI.ChatModelDeployment,
        name: "SampleAssistantAgent",
        instructions:
                """
                The document store contains the text of fictional stories.
                Always analyze the document store to provide an answer to the user's question.
                Never rely on your knowledge of stories not included in the document store.
                Always format response using markdown.
                """,
        enableFileSearch: true,
        vectorStoreId: storeId);

// Create agent
OpenAIAssistantAgent agent = new(assistant, assistantClient);
# Create the assistant definition
definition = await client.beta.assistants.create(
    model=model,
    instructions="""
        The document store contains the text of fictional stories.
        Always analyze the document store to provide an answer to the user's question.
        Never rely on your knowledge of stories not included in the document store.
        Always format response using markdown.
        """,
    name="SampleAssistantAgent",
    tools=file_search_tools,
    tool_resources=file_search_tool_resources,
)

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

Os agentes estão atualmente indisponíveis em Java.

O Loop do Chat

Finalmente, somos capazes de coordenar a interação entre o usuário e o Agent. Comece criando um Thread Assistente para manter o estado da conversa e criando um loop vazio.

Vamos também garantir que os recursos sejam removidos no final da execução para minimizar cobranças desnecessárias.

Console.WriteLine("Creating thread...");
AssistantThread thread = await assistantClient.CreateThreadAsync();

Console.WriteLine("Ready!");

try
{
    bool isComplete = false;
    do
    {
        // Processing occurs here
    } while (!isComplete);
}
finally
{
    Console.WriteLine();
    Console.WriteLine("Cleaning-up...");
    await Task.WhenAll(
        [
            assistantClient.DeleteThreadAsync(thread.Id),
            assistantClient.DeleteAssistantAsync(assistant.Id),
            storeClient.DeleteVectorStoreAsync(storeId),
            ..fileReferences.Select(fileReference => fileClient.DeleteFileAsync(fileReference.Key))
        ]);
}
print("Creating thread...")
thread_id = await agent.create_thread()

try:
    is_complete: bool = False
    while not is_complete:
        # Processing occurs here

finally:
    print("Cleaning up resources...")
    if agent is not None:
        [await agent.delete_file(file_id) for file_id in agent.file_search_file_ids]
        await agent.delete_thread(thread_id)
        await agent.delete()

Os agentes estão atualmente indisponíveis em Java.

Agora vamos capturar a entrada do usuário dentro do loop anterior. Neste caso, a entrada vazia será ignorada e o termo EXIT sinalizará que a conversa está concluída. Uma entrada válida será adicionada ao fio do Assistente como uma mensagem de utilizador .

Console.WriteLine();
Console.Write("> ");
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
    continue;
}
if (input.Trim().Equals("EXIT", StringComparison.OrdinalIgnoreCase))
{
    isComplete = true;
    break;
}

await agent.AddChatMessageAsync(thread.Id, new ChatMessageContent(AuthorRole.User, input));
Console.WriteLine();
user_input = input("User:> ")
if not user_input:
    continue

if user_input.lower() == "exit":
    is_complete = True
    break

await agent.add_chat_message(
    thread_id=thread_id, message=ChatMessageContent(role=AuthorRole.USER, content=user_input)
)

Os agentes estão atualmente indisponíveis em Java.

Antes de invocar a resposta Agent, vamos adicionar um método auxiliar para reformatar os colchetes de anotação unicode para colchetes ANSI.

private static string ReplaceUnicodeBrackets(this string content) =>
    content?.Replace('【', '[').Replace('】', ']');
# No special handling required.

Os agentes estão atualmente indisponíveis em Java.

Para gerar uma resposta Agent à entrada do usuário, invoque o agente especificando o Assistant Thread. Neste exemplo, escolhemos uma resposta transmitida em fluxo e capturamos todas as Anotações de Citação associadas para exibição no final do ciclo de resposta. Observe que cada parte transmitida está sendo reformatada usando o método auxiliar anterior.

List<StreamingAnnotationContent> footnotes = [];
await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(thread.Id))
{
    // Capture annotations for footnotes
    footnotes.AddRange(chunk.Items.OfType<StreamingAnnotationContent>());

    // Render chunk with replacements for unicode brackets.
    Console.Write(chunk.Content.ReplaceUnicodeBrackets());
}

Console.WriteLine();

// Render footnotes for captured annotations.
if (footnotes.Count > 0)
{
    Console.WriteLine();
    foreach (StreamingAnnotationContent footnote in footnotes)
    {
        Console.WriteLine($"#{footnote.Quote.ReplaceUnicodeBrackets()} - {fileReferences[footnote.FileId!].Filename} (Index: {footnote.StartIndex} - {footnote.EndIndex})");
    }
}
footnotes: list[StreamingAnnotationContent] = []
async for response in agent.invoke_stream(thread_id=thread_id):
    footnotes.extend([item for item in response.items if isinstance(item, StreamingAnnotationContent)])

    print(f"{response.content}", end="", flush=True)

print()

if len(footnotes) > 0:
    for footnote in footnotes:
        print(
            f"\n`{footnote.quote}` => {footnote.file_id} "
            f"(Index: {footnote.start_index} - {footnote.end_index})"
        )

Os agentes estão atualmente indisponíveis em Java.

Final

Juntando todas as etapas, temos o código final para este exemplo. A implementação completa é fornecida abaixo.

Tente usar estas entradas sugeridas.

  1. Qual é a contagem de parágrafos para cada uma das histórias?
  2. Crie uma tabela que identifique o protagonista e antagonista de cada história.
  3. Qual é a moral em A Serpente Branca?
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.VectorStores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AgentsSample;

public static class Program
{
    private static readonly string[] _fileNames =
        [
            "Grimms-The-King-of-the-Golden-Mountain.txt",
            "Grimms-The-Water-of-Life.txt",
            "Grimms-The-White-Snake.txt",
        ];

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    public static async Task Main()
    {
        // Load configuration from environment variables or user secrets.
        Settings settings = new();

        // Initialize the clients
        AzureOpenAIClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));
        //OpenAIClient client = OpenAIAssistantAgent.CreateOpenAIClient(new ApiKeyCredential(settings.OpenAI.ApiKey)));
        AssistantClient assistantClient = client.GetAssistantClient();
        OpenAIFileClient fileClient = client.GetOpenAIFileClient();
        VectorStoreClient storeClient = client.GetVectorStoreClient();

        // Create the vector store
        Console.WriteLine("Creating store...");
        CreateVectorStoreOperation operation = await storeClient.CreateVectorStoreAsync(waitUntilCompleted: true);
        string storeId = operation.VectorStoreId;

        // Upload files and retain file references.
        Console.WriteLine("Uploading files...");
        Dictionary<string, OpenAIFile> fileReferences = [];
        foreach (string fileName in _fileNames)
        {
            OpenAIFile fileInfo = await fileClient.UploadFileAsync(fileName, FileUploadPurpose.Assistants);
            await storeClient.AddFileToVectorStoreAsync(storeId, fileInfo.Id, waitUntilCompleted: true);
            fileReferences.Add(fileInfo.Id, fileInfo);
        }

        // Define assistant
        Console.WriteLine("Defining assistant...");
        Assistant assistant =
            await assistantClient.CreateAssistantAsync(
                settings.AzureOpenAI.ChatModelDeployment,
                name: "SampleAssistantAgent",
                instructions:
                        """
                        The document store contains the text of fictional stories.
                        Always analyze the document store to provide an answer to the user's question.
                        Never rely on your knowledge of stories not included in the document store.
                        Always format response using markdown.
                        """,
                enableFileSearch: true,
                vectorStoreId: storeId);

        // Create agent
        OpenAIAssistantAgent agent = new(assistant, assistantClient);

        // Create the conversation thread
        Console.WriteLine("Creating thread...");
        AssistantThread thread = await assistantClient.CreateThreadAsync();

        Console.WriteLine("Ready!");

        try
        {
            bool isComplete = false;
            do
            {
                Console.WriteLine();
                Console.Write("> ");
                string input = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(input))
                {
                    continue;
                }
                if (input.Trim().Equals("EXIT", StringComparison.OrdinalIgnoreCase))
                {
                    isComplete = true;
                    break;
                }

                await agent.AddChatMessageAsync(thread.Id, new ChatMessageContent(AuthorRole.User, input));
                Console.WriteLine();

                List<StreamingAnnotationContent> footnotes = [];
                await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(thread.Id))
                {
                    // Capture annotations for footnotes
                    footnotes.AddRange(chunk.Items.OfType<StreamingAnnotationContent>());

                    // Render chunk with replacements for unicode brackets.
                    Console.Write(chunk.Content.ReplaceUnicodeBrackets());
                }

                Console.WriteLine();

                // Render footnotes for captured annotations.
                if (footnotes.Count > 0)
                {
                    Console.WriteLine();
                    foreach (StreamingAnnotationContent footnote in footnotes)
                    {
                        Console.WriteLine($"#{footnote.Quote.ReplaceUnicodeBrackets()} - {fileReferences[footnote.FileId!].Filename} (Index: {footnote.StartIndex} - {footnote.EndIndex})");
                    }
                }
            } while (!isComplete);
        }
        finally
        {
            Console.WriteLine();
            Console.WriteLine("Cleaning-up...");
            await Task.WhenAll(
                [
                    assistantClient.DeleteThreadAsync(thread.Id),
                    assistantClient.DeleteAssistantAsync(assistant.Id),
                    storeClient.DeleteVectorStoreAsync(storeId),
                    ..fileReferences.Select(fileReference => fileClient.DeleteFileAsync(fileReference.Key))
                ]);
        }
    }

    private static string ReplaceUnicodeBrackets(this string content) =>
        content?.Replace('【', '[').Replace('】', ']');
}
import asyncio
import os

from semantic_kernel.agents.open_ai import AzureAssistantAgent
from semantic_kernel.contents import StreamingAnnotationContent

"""
The following sample demonstrates how to create a simple,
OpenAI assistant agent that utilizes the vector store
to answer questions based on the uploaded documents.
"""


def get_filepath_for_filename(filename: str) -> str:
    base_directory = os.path.join(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
        "resources",
    )
    return os.path.join(base_directory, filename)


filenames = [
    "Grimms-The-King-of-the-Golden-Mountain.txt",
    "Grimms-The-Water-of-Life.txt",
    "Grimms-The-White-Snake.txt",
]


async def main():
    # Create the client using Azure OpenAI resources and configuration
    client, model = AzureAssistantAgent.setup_resources()

    # Upload the files to the client
    file_ids: list[str] = []
    for path in [get_filepath_for_filename(filename) for filename in filenames]:
        with open(path, "rb") as file:
            file = await client.files.create(file=file, purpose="assistants")
            file_ids.append(file.id)

    vector_store = await client.beta.vector_stores.create(
        name="assistant_search",
        file_ids=file_ids,
    )

    # Get the file search tool and resources
    file_search_tools, file_search_tool_resources = AzureAssistantAgent.configure_file_search_tool(
        vector_store_ids=vector_store.id
    )

    # Create the assistant definition
    definition = await client.beta.assistants.create(
        model=model,
        instructions="""
            The document store contains the text of fictional stories.
            Always analyze the document store to provide an answer to the user's question.
            Never rely on your knowledge of stories not included in the document store.
            Always format response using markdown.
            """,
        name="SampleAssistantAgent",
        tools=file_search_tools,
        tool_resources=file_search_tool_resources,
    )

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

    print("Creating thread...")
    thread = await client.beta.threads.create()

    try:
        is_complete: bool = False
        while not is_complete:
            user_input = input("User:> ")
            if not user_input:
                continue

            if user_input.lower() == "exit":
                is_complete = True
                break

            await agent.add_chat_message(thread_id=thread.id, message=user_input)

            footnotes: list[StreamingAnnotationContent] = []
            async for response in agent.invoke_stream(thread_id=thread.id):
                footnotes.extend([item for item in response.items if isinstance(item, StreamingAnnotationContent)])

                print(f"{response.content}", end="", flush=True)

            print()

            if len(footnotes) > 0:
                for footnote in footnotes:
                    print(
                        f"\n`{footnote.quote}` => {footnote.file_id} "
                        f"(Index: {footnote.start_index} - {footnote.end_index})"
                    )

    finally:
        print("\nCleaning up resources...")
        [await client.files.delete(file_id) for file_id in file_ids]
        await client.beta.threads.delete(thread.id)
        await client.beta.assistants.delete(agent.id)


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

Você pode encontrar o código de completo, como mostrado acima, em nosso repositório.

Os agentes estão atualmente indisponíveis em Java.