How-To: Open AI Assistant Agent File Search (Experimental)
Warnung
Das semantische Kernel-Agent-Framework ist experimentell, befindet sich noch in der Entwicklung und unterliegt Änderungen.
Übersicht
In diesem Beispiel erfahren Sie, wie Sie das Dateisuchetool eines Open AI-Assistenten zum Ausführen von Verständnisaufgaben verwenden. Der Ansatz wird schrittweise erfolgen und sorgt für Klarheit und Präzision während des gesamten Prozesses. Als Teil der Aufgabe stellt der Agent Dokumentzitate innerhalb der Antwort bereit.
Streaming wird verwendet, um die Antworten des Agents zu übermitteln. Dadurch werden Echtzeitaktualisierungen bereitgestellt, während der Vorgang fortschreitet.
Erste Schritte
Bevor Sie mit der Featurecodierung fortfahren, stellen Sie sicher, dass Ihre Entwicklungsumgebung vollständig eingerichtet und konfiguriert ist.
Verwenden Sie den dotnet
Befehl, um Paketabhängigkeiten aus der Befehlszeile hinzuzufügen:
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
Wenn Sie NuGet-Pakete in Visual Studio verwalten, stellen Sie sicher, dass
Include prerelease
sie aktiviert ist.
Die Projektdatei (.csproj
) sollte die folgenden PackageReference
Definitionen enthalten:
<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>
Das Agent Framework ist experimentell und erfordert eine Warnunterdrückung. Dies kann als Eigenschaft in der Projektdatei adressiert werden (.csproj
):
<PropertyGroup>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;OPENAI001</NoWarn>
</PropertyGroup>
Kopieren Sie außerdem den Inhalt und den Grimms-The-King-of-the-Golden-Mountain.txt
Inhalt öffentlicher Domänen aus dem semantischen KernelprojektLearnResources
. Grimms-The-Water-of-Life.txt
Grimms-The-White-Snake.txt
Fügen Sie diese Dateien in Ihrem Projektordner hinzu, und konfigurieren Sie sie so, dass sie in das Ausgabeverzeichnis kopiert werden:
<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>
Erstellen Sie zunächst einen Ordner, der Ihr Skript (.py
Datei) und die Beispielressourcen enthält. Fügen Sie die folgenden Importe am Anfang der .py
Datei ein:
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
Kopieren Sie außerdem den Inhalt und den Grimms-The-King-of-the-Golden-Mountain.txt
Inhalt öffentlicher Domänen aus dem semantischen KernelprojektLearnResources
. Grimms-The-Water-of-Life.txt
Grimms-The-White-Snake.txt
Fügen Sie diese Dateien in Ihrem Projektordner hinzu.
Agents sind derzeit in Java nicht verfügbar.
Konfiguration
In diesem Beispiel ist konfigurationseinstellung erforderlich, um eine Verbindung mit Remotediensten herzustellen. Sie müssen Einstellungen für Open AI oder Azure Open AI definieren.
# 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"
Die folgende Klasse wird in allen Agent-Beispielen verwendet. Achten Sie darauf, sie in Ihr Projekt einzuschließen, um die ordnungsgemäße Funktionalität sicherzustellen. Diese Klasse dient als grundlegende Komponente für die folgenden Beispiele.
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();
}
}
Die schnellste Möglichkeit, mit der richtigen Konfiguration zu beginnen, um den Beispielcode auszuführen, besteht darin, eine .env
Datei im Stammverzeichnis Ihres Projekts zu erstellen (wo Ihr Skript ausgeführt wird).
Konfigurieren Sie die folgenden Einstellungen in Ihrer .env
Datei für Azure OpenAI oder 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=""
Nach der Konfiguration werden die entsprechenden KI-Dienstklassen die erforderlichen Variablen abholen und während der Instanziierung verwenden.
Agents sind derzeit in Java nicht verfügbar.
Codieren
Der Codierungsprozess für dieses Beispiel umfasst:
- Setup – Initialisieren von Einstellungen und dem Plug-In.
- Agentdefinition – Erstellen Sie die Chat_Completion_Agent mit templatisierten Anweisungen und Plug-Ins.
- Die Chatschleife – Schreiben Sie die Schleife , die die Benutzer-/Agent-Interaktion steuert.
Der vollständige Beispielcode wird im Abschnitt "Final " bereitgestellt. Weitere Informationen finden Sie in diesem Abschnitt für die vollständige Implementierung.
Setup
Stellen Sie vor dem Erstellen eines Open AI Assistant Agent sicher, dass die Konfigurationseinstellungen verfügbar sind, und bereiten Sie die Dateiressourcen vor.
Instanziieren Sie die Klasse, auf die Settings
im vorherigen Konfigurationsabschnitt verwiesen wird. Verwenden Sie die Einstellungen, um auch ein OpenAIClientProvider
Element zu erstellen, das für die Agentdefinition sowie für den Dateiupload und die Erstellung einer VectorStore
.
Settings settings = new();
OpenAIClientProvider clientProvider =
OpenAIClientProvider.ForAzureOpenAI(
new AzureCliCredential(),
new Uri(settings.AzureOpenAI.Endpoint));
Agents sind derzeit in Java nicht verfügbar.
Erstellen Sie nun einen leeren _Vector Store für die Verwendung mit dem Tool "Dateisuche ":
Verwenden Sie den OpenAIClientProvider
Zugriff auf ein VectorStoreClient
und erstellen Sie eine 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)
Agents sind derzeit in Java nicht verfügbar.
Deklarieren wir die drei im vorherigen Konfigurationsabschnitt beschriebenen Inhaltsdateien:
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",
]
Agents sind derzeit in Java nicht verfügbar.
Laden Sie diese Dateien jetzt hoch, und fügen Sie sie zum Vector Store hinzu, indem Sie die zuvor erstellten VectorStoreClient
Clients verwenden, um jede Datei mit einer OpenAIFileClient
hochzuladen und sie dem Vector Store hinzuzufügen, wobei die resultierenden Dateiverweise erhalten bleiben.
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);
}
Agents sind derzeit in Java nicht verfügbar.
Agentdefinition
Wir sind jetzt bereit, einen OpenAI Assistant Agent zu instanziieren. Der Agent ist mit dem Zielmodell, den Anweisungen und dem aktivierten Tool für die Dateisuche konfiguriert. Darüber hinaus ordnen wir den Vektorspeicher explizit dem Tool " Dateisuche " zu.
Wir werden das OpenAIClientProvider
wieder als Teil der Erstellung OpenAIAssistantAgent
der :
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],
)
Agents sind derzeit in Java nicht verfügbar.
Die Chatschleife
Schließlich können wir die Interaktion zwischen dem Benutzer und dem Agent koordinieren. Erstellen Sie zunächst einen Assistententhread , um den Unterhaltungszustand beizubehalten und eine leere Schleife zu erstellen.
Stellen wir außerdem sicher, dass die Ressourcen am Ende der Ausführung entfernt werden, um unnötige Gebühren zu minimieren.
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()
Agents sind derzeit in Java nicht verfügbar.
Lassen Sie uns nun Benutzereingaben innerhalb der vorherigen Schleife erfassen. In diesem Fall wird leere Eingabe ignoriert, und der Ausdruck EXIT
signalisiert, dass die Unterhaltung abgeschlossen ist. Gültige nput wird dem Assistententhread als Benutzernachricht hinzugefügt.
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)
)
Agents sind derzeit in Java nicht verfügbar.
Bevor wir die Agent-Antwort aufrufen, fügen wir eine Hilfsmethode hinzu, um die Unicode-Anmerkungsklammern in ANSI-Klammern neu zu formatieren.
private static string ReplaceUnicodeBrackets(this string content) =>
content?.Replace('【', '[').Replace('】', ']');
# No special handling required.
Agents sind derzeit in Java nicht verfügbar.
Um eine Agent-Antwort auf Benutzereingaben zu generieren, rufen Sie den Agent auf, indem Sie den Assistententhread angeben. In diesem Beispiel wählen wir eine gestreamte Antwort aus und erfassen alle zugehörigen Zitatanmerkungen für die Anzeige am Ende des Antwortzyklus. Beachten Sie, dass jeder gestreamte Block mit der vorherigen Hilfsmethode neu formatiert wird.
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})"
)
Agents sind derzeit in Java nicht verfügbar.
Endphase
Alle Schritte zusammenzuführen, haben wir den endgültigen Code für dieses Beispiel. Die vollständige Implementierung wird unten bereitgestellt.
Versuchen Sie, diese vorgeschlagenen Eingaben zu verwenden:
- Was ist die Absatzanzahl für die einzelnen Textabschnitte?
- Erstellen Sie eine Tabelle, die den Protagonisten und Protagonisten für jede Geschichte identifiziert.
- Was ist die Moral in der weißen Schlange?
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())
Agents sind derzeit in Java nicht verfügbar.