RAG-antwoorden genereren en verwerken

Voltooid

Een klant wil weten welke pedalen passen op hun Mountain-500 fiets. U gebruikt vectorzoekopdrachten om de relevante producten te vinden, ze te formatteren als JSON en een prompt te maken met grondinformatie. De stappen voor ophalen en uitbreiden zijn afgerond. Nu komt de "G" in RAG: generatie. In deze stap verzendt u alles naar een taalmodel en krijgt u een antwoord.

Denk er als volgt aan: u hebt alle ingrediënten verzameld (opgehaalde gegevens), het recept voorbereid (augmented prompt) en nu plaatst u het in de oven (het model aanroepend) om het uiteindelijke gerecht (het antwoord) te bakken. Het model gebruikt de context die u hebt opgegeven om een geaard antwoord te genereren.

Het model aanroepen vanuit SQL

U denkt misschien dat deze stap T-SQL moet verlaten en toepassingscode moet schrijven. MAAR SQL Server en Azure SQL Database kunnen REST-eindpunten rechtstreeks aanroepen met behulp van sp_invoke_external_rest_endpoint. Deze opgeslagen procedure verzendt HTTPS-aanvragen naar externe services en retourneert het antwoord. De opgeslagen procedure is standaard ingeschakeld in Azure SQL Database en kan worden ingeschakeld in SQL Server 2025 met behulp van sp_configure.

Dit is het basispatroon:

DECLARE @response NVARCHAR(MAX);
DECLARE @returnValue INT;

EXECUTE @returnValue = sp_invoke_external_rest_endpoint
    @url = N'https://<endpoint>.openai.azure.com/openai/deployments/<model>/chat/completions?api-version=<api-version>',
    @method = 'POST',
    @payload = @payload,
    @credential = [https://<endpoint>.openai.azure.com],
    @response = @response OUTPUT;

De @url parameter verwijst naar uw Azure OpenAI-implementatie-eindpunt. Het @method is meestal 'POST' voor generatieaanvragen. De @payload bevat de JSON-prompt die u eerder hebt gemaakt. De @credential referentie verwijst naar een databasereferentie die uw verificatiegegevens bevat. De @response uitvoerparameter legt het antwoord van het model vast.

Wanneer u het implementatie-eindpunt van uw model aanroept met uw uitgebreide prompt, verwerkt het model het en retourneert het resultaat. De opgeslagen procedure retourneert 0 wanneer de HTTP-aanroep slaagt met een 2xx-statuscode of de werkelijke HTTP-statuscode wanneer deze mislukt.

Verifiëren met het eindpunt

De @credential parameter verwijst naar een databasereferentie die uw verificatiegegevens bevat. U stelt deze referenties in wanneer u een extern model maakt, met behulp van een beheerde identiteit of een API-sleutel. Dezelfde referentie werkt voor zowel externe modeloproepen als directe REST-eindpuntoproepen met sp_invoke_external_rest_endpoint.

Haal het antwoord uit de reactie

Wanneer het model klaar is met het verwerken van uw prompt, sp_invoke_external_rest_endpoint retourneert u het resultaat dat is verpakt in een standaard envelop. De opgeslagen procedure voegt metagegevens toe over de HTTP-transactie en plaatst vervolgens het werkelijke API-antwoord binnen een result-eigenschap.

{
  "response": {
    "status": {
      "http": {
        "code": 200,
        "description": "OK"
      }
    }
  },
  "result": {
    "choices": [
      {
        "message": {
          "role": "assistant",
          "content": "The Mountain-500 is compatible with several pedal options..."
        }
      }
    ]
  }
}

Het antwoord dat je zoekt is te vinden op $.result.choices[0].message.content. JSON_VALUEGebruik hiervoor , waarmee scalaire waarden uit JSON worden geëxtraheerd:

IF @returnValue = 0
BEGIN
    DECLARE @answer NVARCHAR(MAX);
    SET @answer = JSON_VALUE(@response, '$.result.choices[0].message.content');
    SELECT @answer AS AssistantResponse;
END
ELSE
BEGIN
    SELECT 
        @returnValue AS HttpStatus,
        JSON_VALUE(@response, '$.response.status.http.description') AS ErrorDescription;
END

Als u ooit een JSON-object of -array moet extraheren in plaats van één waarde, gebruik dan in plaats daarvan JSON_QUERY. Voor de meeste RAG-scenario's is de inhoud van het bericht met JSON_VALUE alles wat u nodig hebt.

Fouten en nieuwe pogingen beheren

Als u een externe service aanroept vanuit een database, kunnen foutmodi worden geïntroduceerd die u niet tegenkomt met lokale query's. Het eindpunt is mogelijk tijdelijk niet beschikbaar, uw aanvraag krijgt mogelijk een frequentielimiet of verificatie kan mislukken. Uw SQL-query's moeten deze voorwaarden probleemloos afhandelen.

De retourwaarde van sp_invoke_external_rest_endpoint vertelt je wat er is gebeurd. Een 0 betekent dat de HTTP-aanroep is geslaagd met de status 2xx. Voor fouten is de retourwaarde de HTTP-statuscode zelf. Een 429-status betekent bijvoorbeeld dat de service uw aanvragen beperkt. Een 401- of 403 verwijst naar referentieproblemen:

IF @returnValue = 0
    SET @answer = JSON_VALUE(@response, '$.result.choices[0].message.content');
ELSE IF @returnValue = 429
    RAISERROR('Service is busy. Try again later.', 16, 1);
ELSE IF @returnValue = 401 OR @returnValue = 403
    RAISERROR('Authentication failed. Check your credential configuration.', 16, 1);
ELSE
BEGIN
    DECLARE @errorMsg NVARCHAR(500) = 'API call failed with status ' + CAST(@returnValue AS NVARCHAR(10));
    RAISERROR(@errorMsg, 16, 1);
END

Voor tijdelijke fouten, zoals time-outs of tijdelijke onbeschikbaarheid van de service, kan de opgeslagen procedure het automatisch opnieuw proberen. Voeg de @retry_count parameter toe en in dit voorbeeld wordt de aanroep maximaal drie keer geprobeerd voordat u het opgeeft:

EXECUTE @returnValue = sp_invoke_external_rest_endpoint
    @url = @url,
    @payload = @payload,
    @credential = @credentialName,
    @retry_count = 3,
    @response = @response OUTPUT;

Deze parameter verwerkt het veelvoorkomende geval waarin een aanvraag eenmaal mislukt, maar slaagt bij de volgende poging.

Een volledige opgeslagen RAG-procedure bouwen

Je kent nu elk stuk van de RAG-puzzel. Laten we ze samenvoegen in één opgeslagen procedure die door een klantenserviceapplicatie kan worden aangeroepen. De procedure accepteert een vraag in natuurlijke taal en retourneert een antwoord dat is geaard in uw productgegevens.

Dit is wat de procedure doet:

  1. Converteert de vraag naar een insluiting, zodat u deze kunt vergelijken met uw productbeschrijvingen.
  2. Hiermee vindt u de meest relevante producten met behulp van vectorafstand om de insluiting van de vraag te vergelijken met de vooraf berekende beschrijving van elk product.
  3. Hiermee wordt de prompt samengesteld met een systeembericht dat aangeeft dat het model zich aan de opgegeven gegevens moet houden en een gebruikersbericht dat de opgehaalde producten combineert met de oorspronkelijke vraag.
  4. Verzendt alles naar Azure OpenAI.
  5. Extraheert het antwoord uit de reactie en stuurt het terug naar de beller.
CREATE PROCEDURE dbo.AskProductQuestion
    @Question NVARCHAR(1000),
    @Answer NVARCHAR(MAX) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @questionVector VECTOR(1536);
    DECLARE @context NVARCHAR(MAX);
    DECLARE @payload NVARCHAR(MAX);
    DECLARE @response NVARCHAR(MAX);
    DECLARE @returnValue INT;
    
    -- Step 1:Convert question to embedding
    SELECT @questionVector = AI_GENERATE_EMBEDDINGS(@Question USE MODEL my_embedding_model);
    
    -- Step 2: Retrieve relevant products using vector search
    SET @context = (
        SELECT TOP 3 
            p.Name AS ProductName, 
            p.Color, 
            p.Size, 
            pm.Name AS Model
        FROM Production.Product p
        INNER JOIN Production.ProductModel pm ON p.ProductModelID = pm.ProductModelID
        ORDER BY VECTOR_DISTANCE('cosine', p.DescriptionVector, @questionVector)
        FOR JSON PATH
    );
    
    -- Step 3: Build augmented prompt
    SET @payload = JSON_OBJECT(
        'messages': JSON_ARRAY(
            JSON_OBJECT('role': 'system', 'content': 'You are an Adventure Works product assistant. Answer questions using only the provided product data.'),
            JSON_OBJECT('role': 'user', 'content': 'Products: ' + @context + ' Question: ' + @Question)
        ),
        'max_tokens': 500,
        'temperature': 0.5
    );
    
    -- Step 4: Call the model
    EXECUTE @returnValue = sp_invoke_external_rest_endpoint
        @url = N'https://adventureworks-openai.openai.azure.com/openai/deployments/gpt-5.2/chat/completions?api-version=2024-10-21',
        @method = 'POST',
        @payload = @payload,
        @credential = [https://adventureworks-openai.openai.azure.com],
        @response = @response OUTPUT;
    
    -- Extract and return the answer
    IF @returnValue = 0
        SET @Answer = JSON_VALUE(@response, '$.result.choices[0].message.content');
    ELSE
        SET @Answer = 'Unable to process your question. Please try again.';
END;

U hebt de RAG-pijplijn in T-SQL voltooid. Een klant vraagt "Welke pedalen werken met de Mountain-500?" Uw procedure converteert die vraag naar een vector, zoekt de meest relevante producten, stuurt deze naar het model met grondinstructies en retourneert een antwoord op basis van uw werkelijke voorraad. Geen middleware, geen externe toepassingscode, alleen SQL die AI aanroept en resultaten retourneert.

Belangrijke punten

De generatiestap is waar uw RAG-pijplijn waarde levert. U verzendt de uitgebreide prompt naar Azure OpenAI met behulp van sp_invoke_external_rest_endpoint, waarmee de HTTP-communicatie wordt afgehandeld zonder T-SQL te verlaten. Verificatie maakt gebruik van dezelfde databasereferenties die u hebt ingesteld bij het maken van externe modellen. Wanneer het antwoord terugkomt, haalt JSON_VALUE het antwoord van de assistent eruit. Ingebouwde foutafhandeling omdat netwerkoproepen mislukken op manieren waarop lokale query's dat niet doen. Nu alle drie de RAG-stappen worden uitgevoerd in T-SQL, wordt uw database meer dan opslag. Het wordt een intelligente service die vragen beantwoordt met behulp van uw gegevens.