Procedura: Aprire l'interprete del codice dell'agente assistente intelligenza artificiale (sperimentale)
Avviso
Il framework dell'agente del kernel semantico è sperimentale, ancora in fase di sviluppo ed è soggetto a modifiche.
Panoramica
In questo esempio verrà illustrato come usare lo strumento dell'interprete del codice di un agente Open AI Assistant per completare le attività di analisi dei dati. L'approccio verrà suddiviso passo dopo passo fino alla luce elevata delle parti chiave del processo di codifica. Come parte dell'attività, l'agente genererà sia risposte di immagine che di testo. Ciò dimostrerà la versatilità di questo strumento nell'esecuzione di analisi quantitative.
Lo streaming verrà usato per recapitare le risposte dell'agente. In questo modo verranno forniti aggiornamenti in tempo reale man mano che l'attività procede.
Introduzione
Prima di procedere con la codifica delle funzionalità, assicurarsi che l'ambiente di sviluppo sia completamente configurato e configurato.
Per iniziare, creare un progetto console . Includere quindi i riferimenti al pacchetto seguenti per assicurarsi che tutte le dipendenze necessarie siano disponibili.
Per aggiungere le dipendenze dei pacchetti dalla riga di comando, usare il 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 si gestiscono pacchetti NuGet in Visual Studio, verificare che
Include prerelease
sia selezionata.
Il file di progetto (.csproj
) deve contenere le definizioni seguenti 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 è sperimentale e richiede l'eliminazione degli avvisi. Ciò può essere risolto come proprietà nel file di progetto (.csproj
):
<PropertyGroup>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
</PropertyGroup>
Copiare anche i PopulationByAdmin1.csv
file di dati e PopulationByCountry.csv
dal progetto kernelLearnResources
semantico. Aggiungere questi file nella cartella del progetto e configurarli per copiarli nella directory di output:
<ItemGroup>
<None Include="PopulationByAdmin1.csv">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="PopulationByCountry.csv">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
Per iniziare, creare una cartella che conterrà lo script (.py
file) e le risorse di esempio. Includere le importazioni seguenti all'inizio del .py
file:
import asyncio
import os
from semantic_kernel.agents.open_ai.azure_assistant_agent import AzureAssistantAgent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.streaming_file_reference_content import StreamingFileReferenceContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
Copiare anche i PopulationByAdmin1.csv
file di dati e PopulationByCountry.csv
dal progetto kernelLearnResources
semantico. Aggiungere questi file nella cartella del progetto.
Gli agenti non sono attualmente disponibili in Java.
Impostazione
Questo esempio richiede l'impostazione di configurazione per connettersi ai servizi remoti. Sarà necessario definire le impostazioni per Open AI o Azure Open AI.
# Open AI
dotnet user-secrets set "OpenAISettings:ApiKey" "<api-key>"
dotnet user-secrets set "OpenAISettings:ChatModel" "gpt-4o"
# Azure Open AI
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"
La classe seguente viene usata in tutti gli esempi di Agent. Assicurarsi di includerlo nel progetto per garantire una funzionalità appropriata. Questa classe funge da componente di base per gli esempi seguenti.
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();
}
}
Il modo più rapido per iniziare a usare la configurazione corretta per eseguire il codice di esempio consiste nel creare un .env
file nella radice del progetto (dove viene eseguito lo script).
Configurare le impostazioni seguenti nel .env
file per Azure OpenAI o OpenAI:
AZURE_OPENAI_API_KEY="..."
AZURE_OPENAI_ENDPOINT="https://..."
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME="..."
AZURE_OPENAI_API_VERSION="..."
OPENAI_API_KEY="sk-..."
OPENAI_ORG_ID=""
OPENAI_CHAT_MODEL_ID=""
Dopo la configurazione, le rispettive classi di servizi di intelligenza artificiale rileveranno le variabili necessarie e le useranno durante la creazione di istanze.
Gli agenti non sono attualmente disponibili in Java.
Scrittura del codice
Il processo di codifica per questo esempio prevede:
- Installazione : inizializzazione delle impostazioni e del plug-in.
- Definizione agente: creare il OpenAI_Assistant_Agent con istruzioni e plug-in templatizzati.
- Ciclo chat - Scrivere il ciclo che determina l'interazione utente/agente.
Il codice di esempio completo viene fornito nella sezione Finale . Fare riferimento a questa sezione per l'implementazione completa.
Attrezzaggio
Prima di creare un agente Open AI Assistant, assicurarsi che le impostazioni di configurazione siano disponibili e preparare le risorse del file.
Creare un'istanza della Settings
classe a cui si fa riferimento nella sezione Configurazione precedente. Usare le impostazioni per creare anche un OpenAIClientProvider
oggetto che verrà usato per la definizione dell'agente e per il caricamento di file.
Settings settings = new();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));
Gli agenti non sono attualmente disponibili in Java.
OpenAIClientProvider
Usare per accedere a e OpenAIFileClient
caricare i due file di dati descritti nella sezione Configurazione precedente, mantenendo il riferimento file per la pulizia finale.
Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = clientProvider.Client.GetOpenAIFileClient();
OpenAIFile fileDataCountryDetail = await fileClient.UploadFileAsync("PopulationByAdmin1.csv", FileUploadPurpose.Assistants);
OpenAIFile fileDataCountryList = await fileClient.UploadFileAsync("PopulationByCountry.csv", FileUploadPurpose.Assistants);
# 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__))),
"PopulationByAdmin1.csv",
)
csv_file_path_2 = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
"PopulationByCountry.csv",
)
Gli agenti non sono attualmente disponibili in Java.
Definizione agente
È ora possibile creare un'istanza di un agente Assistente OpenAI. L'agente viene configurato con il modello di destinazione, istruzioni e lo strumento interprete del codice abilitato. Inoltre, i due file di dati vengono associati in modo esplicito allo strumento Interprete codice.
Console.WriteLine("Defining agent...");
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
clientProvider,
new OpenAIAssistantDefinition(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],
},
new Kernel());
agent = await AzureAssistantAgent.create(
kernel=Kernel(),
service_id="agent",
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.
""",
enable_code_interpreter=True,
code_interpreter_filenames=[csv_file_path_1, csv_file_path_2],
)
Gli agenti non sono attualmente disponibili in Java.
Ciclo chat
Infine, è possibile coordinare l'interazione tra l'utente e l'agente. Per iniziare, creare un thread assistente per mantenere lo stato della conversazione e creare un ciclo vuoto.
Assicurarsi anche che le risorse vengano rimosse alla fine dell'esecuzione per ridurre al minimo gli addebiti non necessari.
Console.WriteLine("Creating thread...");
string threadId = await agent.CreateThreadAsync();
Console.WriteLine("Ready!");
try
{
bool isComplete = false;
List<string> fileIds = [];
do
{
} while (!isComplete);
}
finally
{
Console.WriteLine();
Console.WriteLine("Cleaning-up...");
await Task.WhenAll(
[
agent.DeleteThreadAsync(threadId),
agent.DeleteAsync(),
fileClient.DeleteFileAsync(fileDataCountryList.Id),
fileClient.DeleteFileAsync(fileDataCountryDetail.Id),
]);
}
print("Creating thread...")
thread_id = await agent.create_thread()
try:
is_complete: bool = False
file_ids: list[str] = []
while not is_complete:
# agent interaction logic here
finally:
print("Cleaning up resources...")
if agent is not None:
[await agent.delete_file(file_id) for file_id in agent.code_interpreter_file_ids]
await agent.delete_thread(thread_id)
await agent.delete()
Gli agenti non sono attualmente disponibili in Java.
Ora si acquisisce l'input dell'utente all'interno del ciclo precedente. In questo caso, l'input vuoto verrà ignorato e il termine EXIT
segnalerà che la conversazione è stata completata. L'input valido verrà aggiunto al thread assistente come messaggio utente .
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(threadId, 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))
Gli agenti non sono attualmente disponibili in Java.
Prima di richiamare la risposta di Agent, aggiungere alcuni metodi helper per scaricare tutti i file che possono essere prodotti dall'agente.
Qui si inserisce il contenuto dei file nella directory temporanea definita dal sistema e quindi si avvia l'applicazione visualizzatore definita dal sistema.
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)
Gli agenti non sono attualmente disponibili in Java.
Per generare una risposta dell'agente all'input dell'utente, richiamare l'agente specificando il thread assistente. In questo esempio si sceglie una risposta trasmessa e si acquisisce qualsiasi riferimento al file generato per il download e la revisione alla fine del ciclo di risposta. È importante notare che il codice generato è identificato dalla presenza di una chiave di metadati nel messaggio di risposta, distinguendolo dalla risposta conversazionale.
bool isCode = false;
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(threadId))
{
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: bool = False
async for response in agent.invoke(stream(thread_id=thread_id):
if is_code != metadata.get("code"):
print()
is_code = not is_code
print(f"{response.content})
file_ids.extend(
[item.file_id for item in response.items if isinstance(item, StreamingFileReferenceContent)]
)
print()
await download_response_image(agent, file_ids)
file_ids.clear()
Gli agenti non sono attualmente disponibili in Java.
Finale
Riunire tutti i passaggi, è disponibile il codice finale per questo esempio. Di seguito è riportata l'implementazione completa.
Provare a usare questi input suggeriti:
- Confrontare i file per determinare il numero di paesi in cui non è definito uno stato o una provincia rispetto al conteggio totale
- Creare una tabella per i paesi con stato o provincia definiti. Includere il numero di stati o province e la popolazione totale
- Fornire un grafico a barre per i paesi i cui nomi iniziano con la stessa lettera e ordinare l'asse x in base al conteggio più alto al più basso (includere tutti i paesi)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI.Files;
namespace AgentsSample;
public static class Program
{
public static async Task Main()
{
// Load configuration from environment variables or user secrets.
Settings settings = new();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));
Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = clientProvider.Client.GetOpenAIFileClient();
OpenAIFile fileDataCountryDetail = await fileClient.UploadFileAsync("PopulationByAdmin1.csv", FileUploadPurpose.Assistants);
OpenAIFile fileDataCountryList = await fileClient.UploadFileAsync("PopulationByCountry.csv", FileUploadPurpose.Assistants);
Console.WriteLine("Defining agent...");
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
clientProvider,
new OpenAIAssistantDefinition(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],
},
new Kernel());
Console.WriteLine("Creating thread...");
string threadId = await agent.CreateThreadAsync();
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;
}
await agent.AddChatMessageAsync(threadId, new ChatMessageContent(AuthorRole.User, input));
Console.WriteLine();
bool isCode = false;
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(threadId))
{
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(
[
agent.DeleteThreadAsync(threadId),
agent.DeleteAsync(),
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 os
from semantic_kernel.agents.open_ai.azure_assistant_agent import AzureAssistantAgent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.streaming_file_reference_content import StreamingFileReferenceContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
# 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__))),
"PopulationByAdmin1.csv",
)
csv_file_path_2 = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
"PopulationByCountry.csv",
)
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)
async def main():
agent = await AzureAssistantAgent.create(
kernel=Kernel(),
service_id="agent",
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.
""",
enable_code_interpreter=True,
code_interpreter_filenames=[csv_file_path_1, csv_file_path_2],
)
print("Creating thread...")
thread_id = await agent.create_thread()
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
await agent.add_chat_message(
thread_id=thread_id, message=ChatMessageContent(role=AuthorRole.USER, content=user_input)
)
is_code: bool = False
async for response in agent.invoke_stream(thread_id=thread_id):
if is_code != response.metadata.get("code"):
print()
is_code = not is_code
print(f"{response.content}", end="", flush=True)
file_ids.extend([
item.file_id for item in response.items if isinstance(item, StreamingFileReferenceContent)
])
print()
await download_response_image(agent, file_ids)
file_ids.clear()
finally:
print("Cleaning up resources...")
if agent is not None:
[await agent.delete_file(file_id) for file_id in agent.code_interpreter_file_ids]
await agent.delete_thread(thread_id)
await agent.delete()
if __name__ == "__main__":
asyncio.run(main())
Gli agenti non sono attualmente disponibili in Java.