次の方法で共有


ハウツー: OpenAIAssistantAgent コードインタープリターを使う方法

重要

この機能はリリース候補段階にあります。 この段階の機能はほぼ完全で一般的に安定していますが、完全な一般提供に到達する前に、小さな改良や最適化が行われる可能性があります。

概要

このサンプルでは、 OpenAIAssistantAgent のコード インタープリター ツールを使用してデータ分析タスクを完了する方法について説明します。 このアプローチは、コーディング プロセスの重要な部分を明るくするために、段階的に分割されます。 タスクの一環として、エージェントは画像とテキストの両方の応答を生成します。 これにより、定量分析を実行する場合のこのツールの汎用性が示されます。

ストリーミングは、エージェントの応答を配信するために使用されます。 これにより、タスクの進行に合ったリアルタイムの更新が提供されます。

はじめに

機能のコーディングに進む前に、開発環境が完全に設定および構成されていることを確認してください。

まず、コンソール プロジェクトを作成します。 次に、次のパッケージ参照を含め、必要なすべての依存関係を使用できるようにします。

コマンド ラインからパッケージの依存関係を追加するには、 dotnet コマンドを使用します。

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

重要

Visual Studio で NuGet パッケージを管理する場合は、 Include prerelease がオンになっていることを確認します。

プロジェクト ファイル (.csproj) には、次の PackageReference 定義が含まれている必要があります。

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

Agent Framework は試験段階であり、警告の抑制が必要です。 これは、プロジェクト ファイル内のプロパティとして対処できます (.csproj)。

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

さらに、PopulationByAdmin1.csvからPopulationByCountry.csvLearnResourcesデータ ファイルをコピーします。 これらのファイルをプロジェクト フォルダーに追加し、出力ディレクトリにコピーするように構成します。

  <ItemGroup>
    <None Include="PopulationByAdmin1.csv">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Include="PopulationByCountry.csv">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

まず、スクリプト (.py ファイル) とサンプル リソースを保持するフォルダーを作成します。 .py ファイルの先頭に次のインポートを含めます。

import asyncio
import os

from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.contents import StreamingFileReferenceContent

さらに、PopulationByAdmin1.csvからPopulationByCountry.csvおよびlearn_resources/resourcesデータ ファイルをコピーします。 これらのファイルを作業ディレクトリに追加します。

機能は現在 Java では使用できません。

構成

このサンプルでは、リモート サービスに接続するための構成設定が必要です。 OpenAI または 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" "<model-endpoint>"
dotnet user-secrets set "AzureOpenAISettings:ChatModelDeployment" "gpt-4o"

次のクラスは、すべてのエージェントの例で使用されます。 適切な機能を確保するには、必ずプロジェクトに含めるようにしてください。 このクラスは、次の例の基本コンポーネントとして機能します。

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

サンプル コードを実行するための適切な構成を開始する最も簡単な方法は、プロジェクトのルート (スクリプトが実行されている場所) に .env ファイルを作成することです。

Azure OpenAI または OpenAI の .env ファイルで次の設定を構成します。

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

ヒント

Azure Assistants には、少なくとも 2024-05-01-preview の API バージョンが必要です。 新機能が導入されると、それに応じて API バージョンが更新されます。 この執筆時点では、最新バージョンは 2025-01-01-preview です。 最新のバージョン管理の詳細については、Azure OpenAI API プレビュー ライフサイクルを参照してください。

構成が完了すると、それぞれの AI サービス クラスが必要な変数を取得し、インスタンス化中にそれらを使用します。

機能は現在 Java では使用できません。

コーディング

このサンプルのコーディング プロセスには、次のものが含まれます。

  1. セットアップ - 設定とプラグインの初期化。
  2. エージェント定義 - テンプレート化された命令とプラグインを使用して_OpenAI_AssistantAgentを作成します。
  3. チャット ループ - ユーザー/エージェントの対話を促進するループを記述します。

完全なコード例については、「 Final 」セクションを参照してください。 完全な実装については、そのセクションを参照してください。

セットアップ

OpenAIAssistantAgentを作成する前に、構成設定が使用可能であることを確認し、ファイル リソースを準備します。

前の Settings セクションで参照されている クラスをインスタンス化します。 設定を利用して、AzureOpenAIClientおよびファイルアップロードに使用されるも作成します。

Settings settings = new();

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

機能は現在 Java では使用できません。

AzureOpenAIClientを使用してOpenAIFileClientにアクセスし、前の Configuration セクションで説明した 2 つのデータ ファイルをアップロードし、最終的なクリーンアップのために File Reference を保持します。

Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = client.GetOpenAIFileClient();
OpenAIFile fileDataCountryDetail = await fileClient.UploadFileAsync("PopulationByAdmin1.csv", FileUploadPurpose.Assistants);
OpenAIFile fileDataCountryList = await fileClient.UploadFileAsync("PopulationByCountry.csv", FileUploadPurpose.Assistants);

AzureAssistantAgent または OpenAIAssistantAgentを作成する前に、構成設定が使用可能であることを確認し、ファイル リソースを準備します。

ヒント

ファイルの場所によっては、ファイル パスの調整が必要になる場合があります。

# Let's form the file paths that we will use as part of file upload
csv_file_path_1 = os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
    "resources",
    "PopulationByAdmin1.csv",
)

csv_file_path_2 = os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
    "resources",
    "PopulationByCountry.csv",
)
# 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 [csv_file_path_1, csv_file_path_2]:
    with open(path, "rb") as file:
        file = await client.files.create(file=file, purpose="assistants")
        file_ids.append(file.id)

# Get the code interpreter tool and resources
code_interpreter_tools, code_interpreter_tool_resources = AzureAssistantAgent.configure_code_interpreter_tool(
    file_ids=file_ids
)

# Create the assistant definition
definition = await client.beta.assistants.create(
    model=model,
    instructions="""
        Analyze the available data to provide an answer to the user's question.
        Always format response using markdown.
        Always include a numerical index that starts at 1 for any lists or tables.
        Always sort lists in ascending order.
        """,
    name="SampleAssistantAgent",
    tools=code_interpreter_tools,
    tool_resources=code_interpreter_tool_resources,
)

最初に、クライアントとモデルを取得するために Azure OpenAI リソースを設定します。 次に、クライアントの Files API を使用して、指定したパスから CSV ファイルをアップロードします。 次に、アップロードされたファイル ID を使用して code_interpreter_tool を構成します。これらの ID は、モデル、指示、名前と共に作成時にアシスタントにリンクされます。

機能は現在 Java では使用できません。

エージェント定義

これで、最初にアシスタント定義を作成して、OpenAIAssistantAgent をインスタンス化する準備ができました。 アシスタントは、ターゲット モデル、命令、および Code インタープリター ツールを有効にして構成されます。 さらに、2 つのデータ ファイルを Code インタープリター ツールに明示的に関連付けます。

Console.WriteLine("Defining agent...");
AssistantClient assistantClient = client.GetAssistantClient();
        Assistant assistant =
            await assistantClient.CreateAssistantAsync(
                settings.AzureOpenAI.ChatModelDeployment,
                name: "SampleAssistantAgent",
                instructions:
                        """
                        Analyze the available data to provide an answer to the user's question.
                        Always format response using markdown.
                        Always include a numerical index that starts at 1 for any lists or tables.
                        Always sort lists in ascending order.
                        """,
                enableCodeInterpreter: true,
                codeInterpreterFileIds: [fileDataCountryList.Id, fileDataCountryDetail.Id]);

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

これで、AzureAssistantAgentをインスタンス化する準備ができました。 エージェントは、クライアントとアシスタントの定義で構成されます。

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

機能は現在 Java では使用できません。

チャット ループ

最後に、ユーザーと Agentの間の相互作用を調整できます。 まず、会話状態を維持するための AgentThread を作成し、空のループを作成します。

また、不要な料金を最小限に抑えるために、実行の終了時にリソースが削除されるようにしましょう。

Console.WriteLine("Creating thread...");
AssistantAgentThread agentThread = new();

Console.WriteLine("Ready!");

try
{
    bool isComplete = false;
    List<string> fileIds = [];
    do
    {

    } while (!isComplete);
}
finally
{
    Console.WriteLine();
    Console.WriteLine("Cleaning-up...");
    await Task.WhenAll(
        [
            agentThread.DeleteAsync(),
            assistantClient.DeleteAssistantAsync(assistant.Id),
            fileClient.DeleteFileAsync(fileDataCountryList.Id),
            fileClient.DeleteFileAsync(fileDataCountryDetail.Id),
        ]);
}
thread: AssistantAgentThread = None

try:
    is_complete: bool = False
    file_ids: list[str] = []
    while not is_complete:
        # agent interaction logic here
finally:
    print("\nCleaning up resources...")
    [await client.files.delete(file_id) for file_id in file_ids]
    await thread.delete() if thread else None
    await client.beta.assistants.delete(agent.id)

機能は現在 Java では使用できません。

次に、前のループ内でユーザー入力をキャプチャしてみましょう。 この場合、空の入力は無視され、 EXIT という用語は会話が完了したことを通知します。

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

var message = 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

機能は現在 Java では使用できません。

Agent 応答を呼び出す前に、いくつかのヘルパー メソッドを追加して、Agentによって生成される可能性のあるファイルをダウンロードしてみましょう。

ここでは、システム定義の一時ディレクトリにファイル コンテンツを配置し、システム定義ビューアー アプリケーションを起動します。

private static async Task DownloadResponseImageAsync(OpenAIFileClient client, ICollection<string> fileIds)
{
    if (fileIds.Count > 0)
    {
        Console.WriteLine();
        foreach (string fileId in fileIds)
        {
            await DownloadFileContentAsync(client, fileId, launchViewer: true);
        }
    }
}

private static async Task DownloadFileContentAsync(OpenAIFileClient client, string fileId, bool launchViewer = false)
{
    OpenAIFile fileInfo = client.GetFile(fileId);
    if (fileInfo.Purpose == FilePurpose.AssistantsOutput)
    {
        string filePath =
            Path.Combine(
                Path.GetTempPath(),
                Path.GetFileName(Path.ChangeExtension(fileInfo.Filename, ".png")));

        BinaryData content = await client.DownloadFileAsync(fileId);
        await using FileStream fileStream = new(filePath, FileMode.CreateNew);
        await content.ToStream().CopyToAsync(fileStream);
        Console.WriteLine($"File saved to: {filePath}.");

        if (launchViewer)
        {
            Process.Start(
                new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    Arguments = $"/C start {filePath}"
                });
        }
    }
}
import os

async def download_file_content(agent, file_id: str):
    try:
        # Fetch the content of the file using the provided method
        response_content = await agent.client.files.content(file_id)

        # Get the current working directory of the file
        current_directory = os.path.dirname(os.path.abspath(__file__))

        # Define the path to save the image in the current directory
        file_path = os.path.join(
            current_directory,  # Use the current directory of the file
            f"{file_id}.png"  # You can modify this to use the actual filename with proper extension
        )

        # Save content to a file asynchronously
        with open(file_path, "wb") as file:
            file.write(response_content.content)

        print(f"File saved to: {file_path}")
    except Exception as e:
        print(f"An error occurred while downloading file {file_id}: {str(e)}")

async def download_response_image(agent, file_ids: list[str]):
    if file_ids:
        # Iterate over file_ids and download each one
        for file_id in file_ids:
            await download_file_content(agent, file_id)

機能は現在 Java では使用できません。

ユーザー入力に対する Agent 応答を生成するには、メッセージと AgentThreadを指定してエージェントを呼び出します。 この例では、ストリーム応答を選択し、生成された File References をキャプチャして、応答サイクルの最後にダウンロードして確認します。 生成されたコードは、応答メッセージに Metadata キーが存在することによって識別され、会話型の応答と区別されることに注意してください。

bool isCode = false;
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
{
    if (isCode != (response.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false))
    {
        Console.WriteLine();
        isCode = !isCode;
    }

    // Display response.
    Console.Write($"{response.Content}");

    // Capture file IDs for downloading.
    fileIds.AddRange(response.Items.OfType<StreamingFileReferenceContent>().Select(item => item.FileId));
}
Console.WriteLine();

// Download any files referenced in the response.
await DownloadResponseImageAsync(fileClient, fileIds);
fileIds.Clear();
is_code = False
last_role = None
async for response in agent.invoke_stream(messages=user_input, thread=thread):
    current_is_code = response.metadata.get("code", False)

    if current_is_code:
        if not is_code:
            print("\n\n```python")
            is_code = True
        print(response.content, end="", flush=True)
    else:
        if is_code:
            print("\n```")
            is_code = False
            last_role = None
        if hasattr(response, "role") and response.role is not None and last_role != response.role:
            print(f"\n# {response.role}: ", end="", flush=True)
            last_role = response.role
        print(response.content, end="", flush=True)
    file_ids.extend([
        item.file_id for item in response.items if isinstance(item, StreamingFileReferenceContent)
    ])
    thread = response.thread
if is_code:
    print("```\n")
print()

await download_response_image(agent, file_ids)
file_ids.clear()

機能は現在 Java では使用できません。

最終

すべての手順をまとめて、この例の最後のコードを作成します。 完全な実装を以下に示します。

次の推奨される入力を使用してみてください。

  1. ファイルを比較して、州または都道府県が定義されていない国の数を合計カウントと比較して判断します
  2. 都道府県が定義されている国のテーブルを作成します。 州または都道府県の数と総人口を含める
  3. 名前が同じ文字で始まり、x 軸を最も高い数から最も低い値に並べ替える国の横棒グラフを指定します (すべての国を含む)
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI.Assistants;
using OpenAI.Files;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace AgentsSample;

public static class Program
{
    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();

        // Upload files
        Console.WriteLine("Uploading files...");
        OpenAIFile fileDataCountryDetail = await fileClient.UploadFileAsync("PopulationByAdmin1.csv", FileUploadPurpose.Assistants);
        OpenAIFile fileDataCountryList = await fileClient.UploadFileAsync("PopulationByCountry.csv", FileUploadPurpose.Assistants);

        // Define assistant
        Console.WriteLine("Defining assistant...");
        Assistant assistant =
            await assistantClient.CreateAssistantAsync(
                settings.AzureOpenAI.ChatModelDeployment,
                name: "SampleAssistantAgent",
                instructions:
                        """
                        Analyze the available data to provide an answer to the user's question.
                        Always format response using markdown.
                        Always include a numerical index that starts at 1 for any lists or tables.
                        Always sort lists in ascending order.
                        """,
                enableCodeInterpreter: true,
                codeInterpreterFileIds: [fileDataCountryList.Id, fileDataCountryDetail.Id]);

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

        // Create the conversation thread
        Console.WriteLine("Creating thread...");
        AssistantAgentThread agentThread = new();

        Console.WriteLine("Ready!");

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

                var message = new ChatMessageContent(AuthorRole.User, input);

                Console.WriteLine();

                bool isCode = false;
                await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
                {
                    if (isCode != (response.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false))
                    {
                        Console.WriteLine();
                        isCode = !isCode;
                    }

                    // Display response.
                    Console.Write($"{response.Content}");

                    // Capture file IDs for downloading.
                    fileIds.AddRange(response.Items.OfType<StreamingFileReferenceContent>().Select(item => item.FileId));
                }
                Console.WriteLine();

                // Download any files referenced in the response.
                await DownloadResponseImageAsync(fileClient, fileIds);
                fileIds.Clear();

            } while (!isComplete);
        }
        finally
        {
            Console.WriteLine();
            Console.WriteLine("Cleaning-up...");
            await Task.WhenAll(
                [
                    agentThread.DeleteAsync(),
                    assistantClient.DeleteAssistantAsync(assistant.Id),
                    fileClient.DeleteFileAsync(fileDataCountryList.Id),
                    fileClient.DeleteFileAsync(fileDataCountryDetail.Id),
                ]);
        }
    }

    private static async Task DownloadResponseImageAsync(OpenAIFileClient client, ICollection<string> fileIds)
    {
        if (fileIds.Count > 0)
        {
            Console.WriteLine();
            foreach (string fileId in fileIds)
            {
                await DownloadFileContentAsync(client, fileId, launchViewer: true);
            }
        }
    }

    private static async Task DownloadFileContentAsync(OpenAIFileClient client, string fileId, bool launchViewer = false)
    {
        OpenAIFile fileInfo = client.GetFile(fileId);
        if (fileInfo.Purpose == FilePurpose.AssistantsOutput)
        {
            string filePath =
                Path.Combine(
                    Path.GetTempPath(),
                    Path.GetFileName(Path.ChangeExtension(fileInfo.Filename, ".png")));

            BinaryData content = await client.DownloadFileAsync(fileId);
            await using FileStream fileStream = new(filePath, FileMode.CreateNew);
            await content.ToStream().CopyToAsync(fileStream);
            Console.WriteLine($"File saved to: {filePath}.");

            if (launchViewer)
            {
                Process.Start(
                    new ProcessStartInfo
                    {
                        FileName = "cmd.exe",
                        Arguments = $"/C start {filePath}"
                    });
            }
        }
    }
}
import asyncio
import logging
import os

from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.contents import StreamingFileReferenceContent

logging.basicConfig(level=logging.ERROR)

"""
The following sample demonstrates how to create a simple,
OpenAI assistant agent that utilizes the code interpreter
to analyze uploaded files.
"""

# Let's form the file paths that we will later pass to the assistant
csv_file_path_1 = os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
    "resources",
    "PopulationByAdmin1.csv",
)

csv_file_path_2 = os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
    "resources",
    "PopulationByCountry.csv",
)


async def download_file_content(agent: AzureAssistantAgent, file_id: str):
    try:
        # Fetch the content of the file using the provided method
        response_content = await agent.client.files.content(file_id)

        # Get the current working directory of the file
        current_directory = os.path.dirname(os.path.abspath(__file__))

        # Define the path to save the image in the current directory
        file_path = os.path.join(
            current_directory,  # Use the current directory of the file
            f"{file_id}.png",  # You can modify this to use the actual filename with proper extension
        )

        # Save content to a file asynchronously
        with open(file_path, "wb") as file:
            file.write(response_content.content)

        print(f"File saved to: {file_path}")
    except Exception as e:
        print(f"An error occurred while downloading file {file_id}: {str(e)}")


async def download_response_image(agent: AzureAssistantAgent, file_ids: list[str]):
    if file_ids:
        # Iterate over file_ids and download each one
        for file_id in file_ids:
            await download_file_content(agent, file_id)


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 [csv_file_path_1, csv_file_path_2]:
        with open(path, "rb") as file:
            file = await client.files.create(file=file, purpose="assistants")
            file_ids.append(file.id)

    # Get the code interpreter tool and resources
    code_interpreter_tools, code_interpreter_tool_resources = AzureAssistantAgent.configure_code_interpreter_tool(
        file_ids=file_ids
    )

    # Create the assistant definition
    definition = await client.beta.assistants.create(
        model=model,
        instructions="""
            Analyze the available data to provide an answer to the user's question.
            Always format response using markdown.
            Always include a numerical index that starts at 1 for any lists or tables.
            Always sort lists in ascending order.
            """,
        name="SampleAssistantAgent",
        tools=code_interpreter_tools,
        tool_resources=code_interpreter_tool_resources,
    )

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

    thread: AssistantAgentThread = None

    try:
        is_complete: bool = False
        file_ids: list[str] = []
        while not is_complete:
            user_input = input("User:> ")
            if not user_input:
                continue

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

            is_code = False
            last_role = None
            async for response in agent.invoke_stream(messages=user_input, thread=thread):
                current_is_code = response.metadata.get("code", False)

                if current_is_code:
                    if not is_code:
                        print("\n\n```python")
                        is_code = True
                    print(response.content, end="", flush=True)
                else:
                    if is_code:
                        print("\n```")
                        is_code = False
                        last_role = None
                    if hasattr(response, "role") and response.role is not None and last_role != response.role:
                        print(f"\n# {response.role}: ", end="", flush=True)
                        last_role = response.role
                    print(response.content, end="", flush=True)
                file_ids.extend([
                    item.file_id for item in response.items if isinstance(item, StreamingFileReferenceContent)
                ])
                thread = response.thread
            if is_code:
                print("```\n")
            print()

            await download_response_image(agent, file_ids)
            file_ids.clear()

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


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

上記のように、完全な コードがリポジトリにあります。

機能は現在 Java では使用できません。

次のステップ