Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Руководство: Поиск файла
Важно
Эта функция находится на этапе релиз-кандидата. Функции на этом этапе почти завершены и обычно стабильны, хотя они могут пройти незначительные уточнения или оптимизации, прежде чем достичь полной общедоступной доступности.
Обзор
В этом примере мы рассмотрим, как с помощью 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
Важно
При управлении пакетами NuGet в Visual Studio убедитесь, что 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>
Кроме того, скопируйте содержимое общественного домена Grimms-The-King-of-the-Golden-Mountain.txt, Grimms-The-Water-of-Life.txt и Grimms-The-White-Snake.txt из проекта Семантического Ядра LearnResources. Добавьте эти файлы в папку проекта и настройте их копирование в выходной каталог:
<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>
Начните с создания папки, в которую будут храниться скрипт (.py файл) и примеры ресурсов. Включите следующие импорты в верхней части .py файла:
import asyncio
import os
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.contents import StreamingAnnotationContent
Кроме того, скопируйте содержимое общественного домена Grimms-The-King-of-the-Golden-Mountain.txt, Grimms-The-Water-of-Life.txt и Grimms-The-White-Snake.txt из проекта Семантического Ядра LearnResources. Добавьте эти файлы в папку проекта.
Функция в настоящее время недоступна в 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" "https://lightspeed-team-shared-openai-eastus.openai.azure.com/"
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 файл в корне проекта (где выполняется скрипт).
Настройте следующие параметры в .env файле для Azure OpenAI или OpenAI:
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 требуется версия API по крайней мере 2024-05-01-preview. По мере создания новых функций версии API обновляются соответствующим образом. По состоянию на этот момент последняя версия — 2025-01-01-preview. Для получения информации о самой актуальной версии см. жизненный цикл предварительного просмотра API Azure OpenAI.
После настройки соответствующие классы служб ИИ будут собирать необходимые переменные и использовать их во время инициализации.
Функция в настоящее время недоступна в Java.
Написание кода
Процесс написания кода для этого примера включает в себя:
- Настройка — инициализация настроек и подключаемого модуля.
-
Определение агента — создайте _Chat_Completion
Agentс шаблонизированными инструкциями и плагином. Цикл чата — напишите цикл, который управляет взаимодействием пользователя и агента.
Полный пример кода представлен в заключительном разделе. См. этот раздел для полной реализации.
Настройка
Перед созданием OpenAIAssistantAgentубедитесь, что параметры конфигурации доступны и подготовьте ресурсы файлов.
Создайте экземпляр класса Settings, упоминаемого в предыдущем разделе Конфигурация. Используйте параметры, чтобы также создать AzureOpenAIClient, который будет использоваться для определения агента, а также для загрузки файлов и создания VectorStore.
Settings settings = new();
AzureOpenAIClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));
Статический метод create_client() агента помощника выполняет создание клиента и возвращает его на основе требуемой конфигурации. Параметры Pydantic используются для загрузки переменных среды, сначала из них самих, а затем из файла .env. Можно передать api_key, api_version, deployment_name или endpoint, которые будут иметь приоритет над любыми переменными среды, настроенными.
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client()
Функция в настоящее время недоступна в Java.
Теперь создайте пустую _Vector Store для использования с инструментом поиска файлов:
Используйте AzureOpenAIClient, чтобы получить доступ к VectorStoreClient и создать VectorStore.
Console.WriteLine("Creating store...");
VectorStoreClient storeClient = client.GetVectorStoreClient();
CreateVectorStoreOperation operation = await storeClient.CreateVectorStoreAsync(waitUntilCompleted: true);
string storeId = operation.VectorStoreId;
# Upload the files to the client
file_ids: list[str] = []
for path in [get_filepath_for_filename(filename) for filename in filenames]:
with open(path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
file_ids.append(file.id)
vector_store = await client.vector_stores.create(
name="assistant_search",
file_ids=file_ids,
)
# Get the file search tool and resources
file_search_tools, file_search_tool_resources = AzureAssistantAgent.configure_file_search_tool(
vector_store_ids=vector_store.id
)
Функция в настоящее время недоступна в Java.
Давайте объявим три файла содержимого, описанные в предыдущем разделе конфигурации :
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",
]
Функция в настоящее время недоступна в Java.
Теперь отправьте эти файлы и добавьте их в векторное хранилище, используя ранее созданных VectorStoreClient клиентов для загрузки каждого файла с OpenAIFileClient и добавления его в векторное хранилище, сохраняя полученные ссылки на файлы.
Dictionary<string, OpenAIFile> fileReferences = [];
Console.WriteLine("Uploading files...");
OpenAIFileClient fileClient = 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);
}
Функция в настоящее время недоступна в Java.
Определение агента
Теперь мы готовы создать экземпляр OpenAIAssistantAgent. Агент настроен с целевой моделью, инструкциями, а также с включенным инструментом поиска файлов. Кроме того, мы явно связываем векторное хранилище с средством поиска файлов.
Мы будем использовать AzureOpenAIClient еще раз в рамках создания OpenAIAssistantAgent:
Console.WriteLine("Defining assistant...");
Assistant assistant =
await assistantClient.CreateAssistantAsync(
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);
// Create agent
OpenAIAssistantAgent agent = new(assistant, assistantClient);
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
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.
""",
name="SampleAssistantAgent",
tools=file_search_tools,
tool_resources=file_search_tool_resources,
)
# Create the agent using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
Функция в настоящее время недоступна в Java.
Цикл чата
Наконец, мы можем координировать взаимодействие между пользователем и Agent. Сначала создайте AgentThread для поддержания состояния беседы, а также создайте пустой цикл.
Давайте также убедимся, что ресурсы удаляются в конце процесса, чтобы свести к минимуму ненужные затраты.
Console.WriteLine("Creating thread...");
OpenAIAssistantAgent agentThread = new();
Console.WriteLine("Ready!");
try
{
bool isComplete = false;
do
{
// Processing occurs here
} while (!isComplete);
}
finally
{
Console.WriteLine();
Console.WriteLine("Cleaning-up...");
await Task.WhenAll(
[
agentThread.DeleteAsync();
assistantClient.DeleteAssistantAsync(assistant.Id),
storeClient.DeleteVectorStoreAsync(storeId),
..fileReferences.Select(fileReference => fileClient.DeleteFileAsync(fileReference.Key))
]);
}
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
is_complete: bool = False
while not is_complete:
# Processing occurs here
finally:
print("\nCleaning up resources...")
[await client.files.delete(file_id) for file_id in file_ids]
await client.vector_stores.delete(vector_store.id)
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 добавим вспомогательный метод для переформатирования скобок аннотации Unicode в скобки ANSI.
private static string ReplaceUnicodeBrackets(this string content) =>
content?.Replace('【', '[').Replace('】', ']');
# No special handling required.
Функция в настоящее время недоступна в Java.
Чтобы создать Agent ответ на входные данные пользователя, вызовите агент, указав сообщение и поток агента. В этом примере мы выбираем потоковый ответ и фиксируем все связанные аннотации цитирований для отображения в конце цикла ответа. Обратите внимание, что каждый потоковый блок переформатируется, используя предыдущий вспомогательный метод.
List<StreamingAnnotationContent> footnotes = [];
await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(message, agentThread))
{
// 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(messages=user_input, thread=thread):
thread = response.thread
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})"
)
Функция в настоящее время недоступна в Java.
Финал
Объединив все шаги, мы получили окончательный код для этого примера. Полная реализация представлена ниже.
Попробуйте использовать эти предлагаемые входные данные:
- Что такое количество абзацей для каждой истории?
- Создайте таблицу, которая идентифицирует главного героя и антагониста для каждой истории.
- Что такое мораль в Белой змеи?
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.VectorStores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
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();
// 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();
VectorStoreClient storeClient = client.GetVectorStoreClient();
// Create the vector store
Console.WriteLine("Creating store...");
CreateVectorStoreOperation operation = await storeClient.CreateVectorStoreAsync(waitUntilCompleted: true);
string storeId = operation.VectorStoreId;
// Upload files and retain file references.
Console.WriteLine("Uploading files...");
Dictionary<string, OpenAIFile> fileReferences = [];
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);
}
// Define assistant
Console.WriteLine("Defining assistant...");
Assistant assistant =
await assistantClient.CreateAssistantAsync(
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);
// 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;
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();
List<StreamingAnnotationContent> footnotes = [];
await foreach (StreamingChatMessageContent chunk in agent.InvokeStreamingAsync(message, agentThread))
{
// 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(
[
agentThread.DeleteAsync(),
assistantClient.DeleteAssistantAsync(assistant.Id),
storeClient.DeleteVectorStoreAsync(storeId),
..fileReferences.Select(fileReference => fileClient.DeleteFileAsync(fileReference.Key))
]);
}
}
private static string ReplaceUnicodeBrackets(this string content) =>
content?.Replace('【', '[').Replace('】', ']');
}
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.contents import StreamingAnnotationContent
"""
The following sample demonstrates how to create a simple,
OpenAI assistant agent that utilizes the vector store
to answer questions based on the uploaded documents.
This is the full code sample for the Semantic Kernel Learn Site: How-To: Open AI Assistant Agent File Search
https://learn.microsoft.com/semantic-kernel/frameworks/agent/examples/example-assistant-search?pivots=programming-language-python
"""
def get_filepath_for_filename(filename: str) -> str:
base_directory = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
"resources",
)
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():
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client()
# Upload the files to the client
file_ids: list[str] = []
for path in [get_filepath_for_filename(filename) for filename in filenames]:
with open(path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
file_ids.append(file.id)
vector_store = await client.vector_stores.create(
name="assistant_search",
file_ids=file_ids,
)
# Get the file search tool and resources
file_search_tools, file_search_tool_resources = AzureAssistantAgent.configure_file_search_tool(
vector_store_ids=vector_store.id
)
# Create the assistant definition
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
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.
""",
name="SampleAssistantAgent",
tools=file_search_tools,
tool_resources=file_search_tool_resources,
)
# Create the agent using the client and the assistant definition
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
thread: AssistantAgentThread | None = None
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
footnotes: list[StreamingAnnotationContent] = []
async for response in agent.invoke_stream(messages=user_input, thread=thread):
footnotes.extend([item for item in response.items if isinstance(item, StreamingAnnotationContent)])
print(f"{response.content}", end="", flush=True)
thread = response.thread
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("\nCleaning up resources...")
[await client.files.delete(file_id) for file_id in file_ids]
await client.vector_stores.delete(vector_store.id)
await thread.delete() if thread else None
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
Вы можете найти полный код, как показано выше, в нашем репозитории.
Функция в настоящее время недоступна в Java.