Dela via


Använda plugin-program för hämtning av utökad generation (RAG)

Dina AI-agenter måste ofta hämta data från externa källor för att generera jordade svar. Utan den här ytterligare kontexten kan dina AI-agenter hallucinera eller ge felaktig information. För att åtgärda detta kan du använda plugin-program för att hämta data från externa källor.

När du överväger plugin-program för hämtning av utökad generation (RAG) bör du ställa dig två frågor:

  1. Hur kommer du (eller DIN AI-agent) att "söka" efter nödvändiga data? Behöver du semantisk sökning eller klassisk sökning?
  2. Känner du redan till de data som AI-agenten behöver i förväg (förinstallerade data) eller behöver AI-agenten hämta data dynamiskt?
  3. Hur ska du skydda dina data och förhindra överdelning av känslig information?

När du utvecklar plugin-program för RAG (Retrieval Augmented Generation) kan du använda två typer av sökning: semantisk sökning och klassisk sökning.

Semantisk sökning använder vektordatabaser för att förstå och hämta information baserat på frågans innebörd och kontext i stället för att bara matcha nyckelord. Med den här metoden kan sökmotorn förstå språkets nyanser, till exempel synonymer, relaterade begrepp och den övergripande avsikten bakom en fråga.

Semantisk sökning utmärker sig i miljöer där användarfrågor är komplexa, öppna eller kräver en djupare förståelse av innehållet. Till exempel skulle sökning efter "bästa smartphones för fotografering" ge resultat som överväger kontexten för fotograferingsfunktioner i smartphones, snarare än att bara matcha orden "bäst", "smartphones" och "fotografering".

När du tillhandahåller en LLM med en semantisk sökfunktion behöver du vanligtvis bara definiera en funktion med en enda sökfråga. LLM använder sedan den här funktionen för att hämta nödvändig information. Nedan visas ett exempel på en semantisk sökfunktion som använder Azure AI Search för att hitta dokument som liknar en viss fråga.

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; }
    }
}

Klassisk sökning, även kallat attributbaserad eller villkorsbaserad sökning, förlitar sig på filtrering och matchning av exakta termer eller värden i en datamängd. Det är särskilt effektivt för databasfrågor, inventeringssökningar och alla situationer där filtrering efter specifika attribut är nödvändig.

Om en användare till exempel vill hitta alla beställningar som görs av ett visst kund-ID eller hämta produkter inom ett specifikt prisintervall och en viss kategori, ger klassisk sökning exakta och tillförlitliga resultat. Klassisk sökning begränsas dock av dess oförmåga att förstå kontext eller variationer i språket.

Dricks

I de flesta fall stöder dina befintliga tjänster redan klassisk sökning. Innan du implementerar en semantisk sökning bör du överväga om dina befintliga tjänster kan tillhandahålla den kontext som krävs för dina AI-agenter.

Ta till exempel ett plugin-program som hämtar kundinformation från ett CRM-system med klassisk sökning. Här behöver AI:n helt enkelt anropa GetCustomerInfoAsync funktionen med ett kund-ID för att hämta nödvändig information.

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);
    }
}

Att uppnå samma sökfunktion med semantisk sökning skulle sannolikt vara omöjligt eller opraktiskt på grund av den icke-deterministiska karaktären hos semantiska frågor.

När du ska använda varje

Valet mellan semantisk och klassisk sökning beror på frågans natur. Det är idealiskt för innehållsintensiva miljöer som kunskapsbas och kundsupport där användarna kan ställa frågor eller söka efter produkter som använder naturligt språk. Klassisk sökning bör däremot användas när precision och exakta matchningar är viktiga.

I vissa scenarier kan du behöva kombinera båda metoderna för att tillhandahålla omfattande sökfunktioner. En chattrobot som hjälper kunder i en e-handelsbutik kan till exempel använda semantisk sökning för att förstå användarfrågor och klassisk sökning för att filtrera produkter baserat på specifika attribut som pris, varumärke eller tillgänglighet.

Nedan visas ett exempel på ett plugin-program som kombinerar semantisk och klassisk sökning för att hämta produktinformation från en e-handelsdatabas.

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
    }
}

Dynamisk kontra förhämtning av data

När du utvecklar plugin-program för RAG (Retrieval Augmented Generation) måste du också överväga om datahämtningsprocessen är statisk eller dynamisk. På så sätt kan du optimera dina AI-agenters prestanda genom att endast hämta data när det behövs.

Dynamisk datahämtning

I de flesta fall avgör användarfrågan de data som AI-agenten behöver hämta. En användare kan till exempel be om skillnaden mellan två olika produkter. AI-agenten skulle sedan behöva hämta produktinformationen dynamiskt från en databas eller ett API för att generera ett svar med hjälp av funktionsanrop. Det skulle vara opraktiskt att i förväg hämta all möjlig produktinformation i förväg och ge den till AI-agenten.

Nedan visas ett exempel på en fram och tillbaka-chatt mellan en användare och en AI-agent där dynamisk datahämtning krävs.

Roll Meddelande
🔵Användare Kan du berätta om de bästa madrasserna?
🔴Assistent (funktionsanrop) Products.Search("mattresses")
🟢Verktyg [{"id": 25323, "name": "Cloud Nine"},{"id": 63633, "name": "Best Sleep"}]
🔴Assistent Javisst! Vi har både Cloud Nine och Best Sleep
🔵Användare Vad är skillnaden mellan dem?
🔴Assistent (funktionsanrop) Products.GetDetails(25323) Products.GetDetails(63633)
🟢Verktyg { "id": 25323, "name": "Cloud Nine", "price": 1000, "material": "Memory foam" }
🟢Verktyg { "id": 63633, "name": "Best Sleep", "price": 1200, "material": "Latex" }
🔴Assistent Cloud Nine är tillverkat av minnesskum och kostar $1000. Bästa sömn är gjord av latex och kostar $ 1200.

Hämtning av förinstallerade data

Hämtning av statiska data innebär att hämta data från externa källor och alltid tillhandahålla dem till AI-agenten. Detta är användbart när data krävs för varje begäran eller när data är relativt stabila och inte ändras ofta.

Ta till exempel en agent som alltid svarar på frågor om det lokala vädret. Förutsatt att du har en WeatherPluginkan du hämta väderdata i förväg från ett väder-API och ange dem i chatthistoriken. Detta gör att agenten kan generera svar om vädret utan att slösa tid på att begära data från API:et.

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);

Skydda data

När du hämtar data från externa källor är det viktigt att se till att data är säkra och att känslig information inte exponeras. För att förhindra överdelning av känslig information kan du använda följande strategier:

Strategi beskrivning
Använda användarens autentiseringstoken Undvik att skapa tjänstens huvudnamn som används av AI-agenten för att hämta information för användare. Det gör det svårt att verifiera att en användare har åtkomst till den hämtade informationen.
Undvik att återskapa söktjänster Innan du skapar en ny söktjänst med en vektordatabas kontrollerar du om det redan finns en för den tjänst som har nödvändiga data. Genom att återanvända befintliga tjänster kan du undvika att duplicera känsligt innehåll, använda befintliga åtkomstkontroller och använda befintliga filtreringsmekanismer som endast returnerar data som användaren har åtkomst till.
Lagra referens i vektor-DB:er i stället för innehåll I stället för att duplicera känsligt innehåll till vektor-DB:er kan du lagra referenser till faktiska data. För att en användare ska få åtkomst till den här informationen måste deras autentiseringstoken först användas för att hämta verkliga data.

Nästa steg

Nu när du nu kan grunda dina AI-agenter med data från externa källor kan du nu lära dig hur du använder AI-agenter för att automatisera affärsprocesser. Mer information finns i använda funktioner för uppgiftsautomatisering.