Instrukcje: otwieranie wyszukiwania plików agenta asystenta sztucznej inteligencji (eksperymentalne)
Ostrzeżenie
Struktura agenta jądra semantycznego jest eksperymentalna, nadal w programowania i może ulec zmianie.
Omówienie
W tym przykładzie dowiesz się, jak używać narzędzia wyszukiwania plików agenta Asystenta open AI do wykonywania zadań zrozumienia. Podejście będzie krok po kroku, zapewniając przejrzystość i precyzję w całym procesie. W ramach zadania agent udostępni cytaty dokumentów w odpowiedzi.
Przesyłanie strumieniowe będzie używane do dostarczania odpowiedzi agenta. Zapewni to aktualizacje w czasie rzeczywistym w miarę postępu zadania.
Wprowadzenie
Przed kontynuowaniem kodowania funkcji upewnij się, że środowisko deweloperskie jest w pełni skonfigurowane i skonfigurowane.
Aby dodać zależności pakietów z wiersza polecenia, użyj dotnet
polecenia :
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
Jeśli zarządzasz pakietami NuGet w programie Visual Studio, upewnij się, że
Include prerelease
jest zaznaczone.
Plik projektu (.csproj
) powinien zawierać następujące PackageReference
definicje:
<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>
Struktura agenta jest eksperymentalna i wymaga pomijania ostrzeżeń. Może to zostać rozwiązane jako właściwość w pliku projektu (.csproj
):
<PropertyGroup>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
</PropertyGroup>
Ponadto skopiuj zawartość domeny publicznej Grimms-The-King-of-the-Golden-Mountain.txt
i z Grimms-The-White-Snake.txt
Grimms-The-Water-of-Life.txt
semantycznego projektu jądra.LearnResources
Dodaj te pliki w folderze projektu i skonfiguruj ich skopiowanie do katalogu wyjściowego:
<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>
Zacznij od utworzenia folderu, który będzie przechowywać skrypt (.py
plik) i przykładowe zasoby. Uwzględnij następujące importy w górnej części .py
pliku:
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
Ponadto skopiuj zawartość domeny publicznej Grimms-The-King-of-the-Golden-Mountain.txt
i z Grimms-The-White-Snake.txt
Grimms-The-Water-of-Life.txt
semantycznego projektu jądra.LearnResources
Dodaj te pliki w folderze projektu.
Agenci są obecnie niedostępni w języku Java.
Konfigurowanie
Ten przykład wymaga ustawienia konfiguracji w celu nawiązania połączenia z usługami zdalnymi. Musisz zdefiniować ustawienia dla interfejsu Open AI lub 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"
Poniższa klasa jest używana we wszystkich przykładach agentów. Pamiętaj, aby uwzględnić go w projekcie, aby zapewnić odpowiednią funkcjonalność. Ta klasa służy jako podstawowy składnik dla poniższych przykładów.
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();
}
}
Najszybszym sposobem rozpoczęcia pracy z właściwą konfiguracją uruchamiania przykładowego kodu jest utworzenie .env
pliku w katalogu głównym projektu (w którym jest uruchamiany skrypt).
Skonfiguruj następujące ustawienia w .env
pliku dla usługi Azure OpenAI lub 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=""
Po skonfigurowaniu odpowiednie klasy usługi sztucznej inteligencji będą pobierać wymagane zmienne i używać ich podczas tworzenia wystąpienia.
Agenci są obecnie niedostępni w języku Java.
Kodowanie
Proces kodowania dla tego przykładu obejmuje:
- Konfiguracja — inicjowanie ustawień i wtyczki.
- Definicja agenta — utwórz Chat_Completion_Agent za pomocą instrukcji templatized i wtyczki.
- Pętla czatu — zapis pętli, która napędza interakcję użytkownika/agenta.
Pełny przykładowy kod znajduje się w sekcji Final (Final). Zapoznaj się z sekcją dotyczącą pełnej implementacji.
Ustawienia
Przed utworzeniem agenta Programu Open AI Assistant upewnij się, że ustawienia konfiguracji są dostępne i przygotuj zasoby plików.
Settings
Utwórz wystąpienie klasy, do których odwołuje się poprzednia sekcja Konfiguracja. Użyj ustawień, aby również utworzyć element OpenAIClientProvider
, który będzie używany dla definicji agenta, a także przekazywania plików i tworzenia elementu VectorStore
.
Settings settings = new();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(
new AzureCliCredential(),
new Uri(settings.AzureOpenAI.Endpoint));
Agenci są obecnie niedostępni w języku Java.
Teraz utwórz pusty magazyn _Vector do użycia z narzędziem wyszukiwania plików:
Użyj elementu , OpenAIClientProvider
aby uzyskać dostęp do elementu VectorStoreClient
i utworzyć element 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)
Agenci są obecnie niedostępni w języku Java.
Zadeklarujmy trzy pliki zawartości opisane w poprzedniej sekcji Konfiguracja :
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",
]
Agenci są obecnie niedostępni w języku Java.
Teraz przekaż te pliki i dodaj je do magazynu wektorów przy użyciu wcześniej utworzonych VectorStoreClient
klientów, aby przekazać każdy plik z elementem OpenAIFileClient
i dodać go do magazynu wektorów, zachowując wynikowe odwołania do plików.
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);
}
Agenci są obecnie niedostępni w języku Java.
Definicja agenta
Teraz możemy utworzyć wystąpienie agenta Asystenta OpenAI. Agent jest skonfigurowany z włączonym modelem docelowym, instrukcjami i narzędziem wyszukiwania plików. Ponadto jawnie skojarzymy magazyn wektorów z narzędziem wyszukiwania plików.
Użyjemy OpenAIClientProvider
ponownie w ramach tworzenia elementu OpenAIAssistantAgent
:
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],
)
Agenci są obecnie niedostępni w języku Java.
Pętla czatu
Na koniec możemy koordynować interakcję między użytkownikiem a agentem. Zacznij od utworzenia wątku asystenta, aby zachować stan konwersacji i utworzyć pustą pętlę.
Upewnijmy się również, że zasoby zostaną usunięte na końcu wykonywania, aby zminimalizować niepotrzebne opłaty.
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()
Agenci są obecnie niedostępni w języku Java.
Teraz przechwyć dane wejściowe użytkownika w ramach poprzedniej pętli. W takim przypadku puste dane wejściowe zostaną zignorowane, a termin EXIT
będzie sygnalizować, że konwersacja zostanie ukończona. Prawidłowy element nput zostanie dodany do wątku Asystenta jako komunikat użytkownika .
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)
)
Agenci są obecnie niedostępni w języku Java.
Przed wywołaniem odpowiedzi agenta dodajmy metodę pomocnika, aby ponownie sformatować nawiasy adnotacji Unicode do nawiasów ANSI.
private static string ReplaceUnicodeBrackets(this string content) =>
content?.Replace('【', '[').Replace('】', ']');
# No special handling required.
Agenci są obecnie niedostępni w języku Java.
Aby wygenerować odpowiedź agenta na dane wejściowe użytkownika, wywołaj agenta, określając wątek Asystenta. W tym przykładzie wybieramy strumieniową odpowiedź i przechwycimy wszystkie skojarzone adnotacje cytatów , które mają być wyświetlane na końcu cyklu odpowiedzi. Zwróć uwagę, że każdy strumień fragmentu jest ponownie sformatowany przy użyciu poprzedniej metody pomocniczej.
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})"
)
Agenci są obecnie niedostępni w języku Java.
Końcowa
Łącząc wszystkie kroki, mamy końcowy kod dla tego przykładu. Pełną implementację podano poniżej.
Spróbuj użyć tych sugerowanych danych wejściowych:
- Jaka jest liczba akapitów dla każdego scenariusza?
- Utwórz tabelę, która identyfikuje bohatera i antagonistę dla każdej historii.
- Co to jest moralna w Białym Wężu?
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())
Agenci są obecnie niedostępni w języku Java.