操作指南:
重要
這項功能位於候選版階段。 此階段的功能幾乎完整且一般穩定,不過在達到完整正式運作之前,它們可能會經歷輕微的精簡或優化。
概觀
在此範例中,我們將探索如何使用 的 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
重要
如果在 Visual Studio 中管理 NuGet 套件,請確定 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"
下列類別用於所有 Agent 範例中。 請務必將它包含在專案中,以確保適當的功能。 這個類別可作為後續範例的基礎元件。
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 小幫手至少需要 2024-05-01-preview 的 API 版本。 隨著新功能的推出,API 版本會據以更新。 截至本文所述,最新版本為 2025-01-01-preview。 如需最新版本資訊,請參閱 Azure OpenAI API 預覽生命週期 。
設定之後,個別的 AI 服務類別會挑選必要的變數,並在具現化期間使用這些變數。
Java 中目前無法使用的功能。
撰寫程式碼
這個範例的編碼程式牽涉到:
完整範例程式代碼會在 Final 區段中提供。 如需完整的實作,請參閱該區段。
設定
建立 OpenAIAssistantAgent之前,請確定組態設定可供使用,並準備文件資源。
請實例化Settings類別,該類別已在上一節的設定中參考過。 使用設定來創建一個 AzureOpenAIClient,這將用於 代理定義,以及檔案上傳和創建一個 VectorStore。
Settings settings = new();
AzureOpenAIClient client = OpenAIAssistantAgent.CreateAzureOpenAIClient(new AzureCliCredential(), new Uri(settings.AzureOpenAI.Endpoint));
Assistant Agent 上的靜態方法 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 中目前無法使用的功能。