使用外掛程式進行擷取增強產生 (RAG)
您的 AI 代理程式通常必須從外部來源擷取數據,以產生地面回應。 如果沒有這個額外的內容,您的 AI 代理程式可能會幻覺或提供不正確的資訊。 若要解決此問題,您可以使用外掛程式從外部來源擷取數據。
考慮擷取擴增世代的外掛程式時,您應該自行詢問兩個問題:
- 您(或 AI 代理程式)將如何「搜尋」所需的數據? 您需要語意搜尋或傳統搜尋嗎?
- 您已經知道 AI 代理程式事先需要的數據(預先擷取的數據),還是 AI 代理程式需要動態擷取數據?
- 如何保護您的數據安全,並 防止過度共用敏感性資訊?
語意與傳統搜尋
開發擷取擴增世代的外掛程式時,您可以使用兩種類型的搜尋:語意搜尋和傳統搜尋。
語意搜尋
語意搜尋會利用向量資料庫,根據查詢的意義和內容來瞭解和擷取資訊,而不只是比對關鍵詞。 此方法可讓搜尋引擎掌握語言的細微差別,例如同義字、相關概念,以及查詢背後的整體意圖。
語意搜尋在用戶查詢複雜、開放式或需要更深入地瞭解內容的環境中表現。 例如,搜尋“最佳攝影智能手機”會產生結果,考慮智慧手機中攝影功能的內容,而不只是比對“最佳”、“智能手機”和“攝影”字樣。
使用語意搜尋函式提供 LLM 時,您通常只需要使用單一搜尋查詢來定義函式。 LLM 接著會使用此函式來擷取必要的資訊。 以下是使用 Azure AI 搜尋來尋找類似指定查詢之文件的語意搜尋函式範例。
using System.ComponentModel;
using System.Text.Json.Serialization;
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Models;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Embeddings;
public class InternalDocumentsPlugin
{
private readonly ITextEmbeddingGenerationService _textEmbeddingGenerationService;
private readonly SearchIndexClient _indexClient;
public AzureAISearchPlugin(ITextEmbeddingGenerationService textEmbeddingGenerationService, SearchIndexClient indexClient)
{
_textEmbeddingGenerationService = textEmbeddingGenerationService;
_indexClient = indexClient;
}
[KernelFunction("Search")]
[Description("Search for a document similar to the given query.")]
public async Task<string> SearchAsync(string query)
{
// Convert string query to vector
ReadOnlyMemory<float> embedding = await _textEmbeddingGenerationService.GenerateEmbeddingAsync(query);
// Get client for search operations
SearchClient searchClient = _indexClient.GetSearchClient("default-collection");
// Configure request parameters
VectorizedQuery vectorQuery = new(embedding);
vectorQuery.Fields.Add("vector");
SearchOptions searchOptions = new() { VectorSearch = new() { Queries = { vectorQuery } } };
// Perform search request
Response<SearchResults<IndexSchema>> response = await searchClient.SearchAsync<IndexSchema>(searchOptions);
// Collect search results
await foreach (SearchResult<IndexSchema> result in response.Value.GetResultsAsync())
{
return result.Document.Chunk; // Return text from first result
}
return string.Empty;
}
private sealed class IndexSchema
{
[JsonPropertyName("chunk")]
public string Chunk { get; set; }
[JsonPropertyName("vector")]
public ReadOnlyMemory<float> Vector { get; set; }
}
}
傳統搜尋
傳統搜尋也稱為屬性型或準則型搜尋,依賴篩選和比對數據集內的確切字詞或值。 它特別適用於資料庫查詢、清查搜尋,以及需要依特定屬性進行篩選的任何情況。
例如,如果使用者想要尋找特定客戶標識符下的所有訂單,或擷取特定價格範圍和類別內的產品,傳統搜尋會提供精確且可靠的結果。 不過,傳統搜尋受限於無法瞭解語言內容或變化。
提示
在大部分情況下,您現有的服務已經支援傳統搜尋。 實作語意搜尋之前,請考慮現有的服務是否可為 AI 代理程式提供必要的內容。
例如,使用傳統搜尋從CRM系統擷取客戶資訊的外掛程式。 在這裡,AI 只需要使用客戶標識符呼叫 GetCustomerInfoAsync
函式,以擷取必要的資訊。
using System.ComponentModel;
using Microsoft.SemanticKernel;
public class CRMPlugin
{
private readonly CRMService _crmService;
public CRMPlugin(CRMService crmService)
{
_crmService = crmService;
}
[KernelFunction("GetCustomerInfo")]
[Description("Retrieve customer information based on the given customer ID.")]
public async Task<Customer> GetCustomerInfoAsync(string customerId)
{
return await _crmService.GetCustomerInfoAsync(customerId);
}
}
使用語意搜尋達到相同的搜尋功能,可能會因為語意查詢的不具決定性本質而不可能或不切實際。
使用每一個的時機
在語意和傳統搜尋之間選擇取決於查詢的性質。 它適用於內容繁重的環境,例如 知識庫和客戶支援,使用者可能會使用自然語言詢問問題或尋找產品。 另一方面,當精確度和完全相符專案很重要時,應該採用傳統搜尋。
在某些情況下,您可能需要結合這兩種方法來提供完整的搜尋功能。 例如,協助電子商務市集中客戶的聊天機器人可能會使用語意搜尋來瞭解使用者查詢和傳統搜尋,根據價格、品牌或可用性等特定屬性來篩選產品。
以下是結合語意和傳統搜尋的外掛程式範例,可從電子商務資料庫擷取產品資訊。
using System.ComponentModel;
using Microsoft.SemanticKernel;
public class ECommercePlugin
{
[KernelFunction("search_products")]
[Description("Search for products based on the given query.")]
public async Task<IEnumerable<Product>> SearchProductsAsync(string query, ProductCategories category = null, decimal? minPrice = null, decimal? maxPrice = null)
{
// Perform semantic and classic search with the given parameters
}
}
動態與預先擷取的數據
開發擷取擴增產生 (RAG) 的外掛程式時,您也必須考慮數據擷取程式是靜態還是動態的。 這可讓您只在必要時擷取數據,以優化 AI 代理程式的效能。
動態數據擷取
在大部分情況下,使用者查詢會決定 AI 代理程式需要擷取的數據。 例如,使用者可能會要求兩個不同的產品之間的差異。 然後,AI 代理程式必須從資料庫或 API 動態擷取產品資訊,以使用 函數呼叫來產生回應。 預先擷取所有可能產品資訊並提供給 AI 代理程式是不切實際的。
以下是使用者與需要動態數據擷取的 AI 代理程式之間來回聊天的範例。
角色 | 訊息 |
---|---|
🔵使用者 | 你能告訴我最好的床墊嗎? |
🔴小幫手(函數調用) | Products.Search("mattresses") |
🟢工具 | [{"id": 25323, "name": "Cloud Nine"},{"id": 63633, "name": "Best Sleep"}] |
🔴小幫手 | 當然! 我們有雲端九和最佳睡眠 |
🔵使用者 | 兩者之間有何差異? |
🔴小幫手(函數調用) | Products.GetDetails(25323) Products.GetDetails(63633) |
🟢工具 | { "id": 25323, "name": "Cloud Nine", "price": 1000, "material": "Memory foam" } |
🟢工具 | { "id": 63633, "name": "Best Sleep", "price": 1200, "material": "Latex" } |
🔴小幫手 | 雲九由記憶泡沫製成,成本為1000美元。 最佳睡眠是由乳膠製成,費用為1200美元。 |
預先擷取的數據擷取
靜態數據擷取牽涉到從外部來源擷取數據,並 一律 提供給 AI 代理程式。 當每個要求需要數據,或數據相對穩定且不會經常變更時,這非常有用。
例如,一律會回答當地天氣相關問題的代理程式。 假設您有 WeatherPlugin
,您可以從天氣 API 預先擷取天氣數據,並在聊天記錄中提供。 這可讓代理程式產生有關天氣的回應,而不會浪費時間向API要求數據。
using System.Text.Json;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey);
builder.Plugins.AddFromType<WeatherPlugin>();
Kernel kernel = builder.Build();
// Get the weather
var weather = await kernel.Plugins.GetFunction("WeatherPlugin", "get_weather").InvokeAsync(kernel);
// Initialize the chat history with the weather
ChatHistory chatHistory = new ChatHistory("The weather is:\n" + JsonSerializer.Serialize(weather));
// Simulate a user message
chatHistory.AddUserMessage("What is the weather like today?");
// Get the answer from the AI agent
IChatCompletionService chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var result = await chatCompletionService.GetChatMessageContentAsync(chatHistory);
保護數據安全
從外部來源擷取數據時,請務必確保數據安全且不會公開敏感性資訊。 若要防止過度共用敏感性資訊,您可以使用下列策略:
策略 | 描述 |
---|---|
使用使用者的驗證令牌 | 避免建立 AI 代理程式用來擷取使用者資訊的服務主體。 如此一來,就很難確認用戶能夠存取擷取的資訊。 |
避免重新建立搜尋服務 | 使用向量 DB 建立新的搜尋服務之前,請先檢查是否有具有必要數據的服務已經存在。 藉由重複使用現有的服務,您可以避免複製敏感性內容、利用現有的訪問控制,以及使用只傳回使用者可存取之數據的現有篩選機制。 |
將參考儲存在向量 DB 中,而不是內容 | 您可以儲存實際數據的參考,而不是將敏感性內容複製至向量 DB。 若要讓使用者存取這項資訊,其驗證令牌必須先用來擷取實際數據。 |
下一步
現在,您已瞭解如何使用來自外部來源的數據來將 AI 代理程式與數據接在一起,您現在可以瞭解如何使用 AI 代理程式將商務程式自動化。 若要深入瞭解,請參閱 使用工作自動化函式。