Procedura: Aprire la ricerca file 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 di ricerca file di un agente Open AI Assistant per completare le attività di comprensione. L'approccio sarà dettagliato, garantendo chiarezza e precisione in tutto il processo. Nell'ambito dell'attività, l'agente fornirà citazioni di documenti all'interno della risposta.
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 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 il Grimms-The-King-of-the-Golden-Mountain.txt
Grimms-The-Water-of-Life.txt
contenuto del dominio pubblico e Grimms-The-White-Snake.txt
dal progetto kernelLearnResources
semantico. Aggiungere questi file nella cartella del progetto e configurarli per copiarli nella directory di output:
<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>
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_annotation_content import StreamingAnnotationContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
Copiare anche il Grimms-The-King-of-the-Golden-Mountain.txt
Grimms-The-Water-of-Life.txt
contenuto del dominio pubblico e Grimms-The-White-Snake.txt
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" "https://lightspeed-team-shared-openai-eastus.openai.azure.com/"
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 Chat_Completion_Agent con istruzioni templatizzate e plug-in.
- 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, nonché per il caricamento di file e la creazione di un oggetto VectorStore
.
Settings settings = new();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(
new AzureCliCredential(),
new Uri(settings.AzureOpenAI.Endpoint));
Gli agenti non sono attualmente disponibili in Java.
Creare ora un archivio _Vector vuoto da usare con lo strumento Ricerca file:
OpenAIClientProvider
Usare per accedere VectorStoreClient
a e creare un oggetto VectorStore
.
Console.WriteLine("Creating store...");
VectorStoreClient storeClient = clientProvider.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.dirname(os.path.realpath(__file__))
return os.path.join(base_directory, filename)
Gli agenti non sono attualmente disponibili in Java.
Dichiariamo i tre file di contenuto descritti nella sezione Configurazione precedente:
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",
]
Gli agenti non sono attualmente disponibili in Java.
Caricare ora questi file e aggiungerli all'archivio vettoriale usando i client creati VectorStoreClient
in precedenza per caricare ogni file con un OpenAIFileClient
e aggiungerlo all'archivio vettoriale, mantenendo i riferimenti ai file risultanti.
Dictionary<string, OpenAIFile> fileReferences = [];
Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = clientProvider.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);
}
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 Ricerca file abilitato. Inoltre, associamo in modo esplicito l'archivio vettoriale allo strumento Ricerca file.
Verrà utilizzato OpenAIClientProvider
di nuovo come parte della creazione OpenAIAssistantAgent
di :
Console.WriteLine("Defining agent...");
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
clientProvider,
new OpenAIAssistantDefinition(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,
},
new Kernel());
agent = await AzureAssistantAgent.create(
kernel=Kernel(),
service_id="agent",
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.
""",
enable_file_search=True,
vector_store_filenames=[get_filepath_for_filename(filename) for filename in filenames],
)
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;
do
{
// Processing occurrs here
} while (!isComplete);
}
finally
{
Console.WriteLine();
Console.WriteLine("Cleaning-up...");
await Task.WhenAll(
[
agent.DeleteThreadAsync(threadId),
agent.DeleteAsync(),
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()
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. Il valore nput 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
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 un metodo helper per riformattare le parentesi di annotazione Unicode tra parentesi quadre ANSI.
private static string ReplaceUnicodeBrackets(this string content) =>
content?.Replace('【', '[').Replace('】', ']');
# No special handling required.
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 viene scelta una risposta trasmessa e vengono acquisite le annotazioni di citazione associate per la visualizzazione alla fine del ciclo di risposta. Si noti che ogni blocco trasmesso viene riformattato usando il metodo helper precedente.
List<StreamingAnnotationContent> footnotes = [];
await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(threadId))
{
// 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})"
)
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:
- Qual è il conteggio dei paragrafi per ognuna delle storie?
- Creare una tabella che identifichi il protagonista e l'antagonista per ogni storia.
- Qual è la morale di The White Snake?
using System;
using System.Collections.Generic;
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;
using OpenAI.VectorStores;
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();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(
new AzureCliCredential(),
new Uri(settings.AzureOpenAI.Endpoint));
Console.WriteLine("Creating store...");
VectorStoreClient storeClient = clientProvider.Client.GetVectorStoreClient();
CreateVectorStoreOperation operation = await storeClient.CreateVectorStoreAsync(waitUntilCompleted: true);
string storeId = operation.VectorStoreId;
// Retain file references.
Dictionary<string, OpenAIFile> fileReferences = [];
Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = clientProvider.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);
}
Console.WriteLine("Defining agent...");
OpenAIAssistantAgent agent =
await OpenAIAssistantAgent.CreateAsync(
clientProvider,
new OpenAIAssistantDefinition(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,
},
new Kernel());
Console.WriteLine("Creating thread...");
string threadId = await agent.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(threadId, new ChatMessageContent(AuthorRole.User, input));
Console.WriteLine();
List<StreamingAnnotationContent> footnotes = [];
await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(threadId))
{
// 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(
[
agent.DeleteThreadAsync(threadId),
agent.DeleteAsync(),
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.azure_assistant_agent import AzureAssistantAgent
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.streaming_annotation_content import StreamingAnnotationContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.kernel import Kernel
def get_filepath_for_filename(filename: str) -> str:
base_directory = os.path.dirname(os.path.realpath(__file__))
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():
agent = await AzureAssistantAgent.create(
kernel=Kernel(),
service_id="agent",
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.
""",
enable_file_search=True,
vector_store_filenames=[get_filepath_for_filename(filename) for filename in filenames],
)
print("Creating thread...")
thread_id = await agent.create_thread()
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=ChatMessageContent(role=AuthorRole.USER, content=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("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()
if __name__ == "__main__":
asyncio.run(main())
Gli agenti non sono attualmente disponibili in Java.