共用方式為


對向量資料庫驗證和授權 App Service

本文示範如何管理 App Service .NET 應用程式與向量資料庫解決方案之間的連線。 其涵蓋了針對支援的服務使用 Microsoft Entra 受控識別,並安全地儲存其他服務的連接字串。

藉由將向量資料庫新增至您的應用程式,您可以為您的 AI 啟用語意記憶體。 適用於 .NET 的語意核心 SDK 可讓您使用慣用的向量資料庫解決方案輕鬆地實作記憶體儲存和叫回。

必要條件

使用 Microsoft Entra 受控識別進行驗證

如果向量資料庫服務支援 Microsoft Entra 驗證,您可以使用受控識別搭配 App Service 安全地存取向量資料庫,而不必手動佈建或輪替任何祕密。 如需支援 Microsoft Entra 驗證的 Azure 服務清單,請參閱支援 Microsoft Entra 驗證的 Azure 服務

將受控識別新增至 App Service

您的應用程式可以授與兩種類型的身分識別:

  • 系統指派的身分識別會繫結至您的應用程式,如果您的應用程式已刪除,則會被刪除。 一個應用程式只能有一個系統指派的身分識別。
  • 使用者指派的身分識別是一項獨立 Azure 資源,可指派給您的應用程式。 應用程式可以有多個使用者指派的身分識別。

新增系統指派的身分識別

  1. 瀏覽至 Azure 入口網站中的應用程式頁面,然後向下捲動至 [設定] 群組。
  2. 選取 [身分識別]。
  3. 在 [系統指派] 索引標籤上,將 [狀態] 切換為 [開啟],然後選取 [儲存]

執行 az webapp identity assign 命令以建立系統指派的身分識別:

az webapp identity assign --name <appName> --resource-group <groupName>

新增使用者指派的身分識別

若要將使用者指派的身分識別新增至您的應用程式,請建立身分識別,然後將其資源識別碼新增至您的應用程式設定。

  1. 遵循下列指示,建立使用者指派的受控識別資源。

  2. 在應用程式頁面的左側瀏覽窗格中,向下捲動至 [設定] 群組。

  3. 選取 [身分識別]。

  4. 選取 [使用者指派]>[新增]

  5. 找出您稍早建立的身分識別、將其選取,然後選取 [新增]

    重要

    在您選取 [新增] 之後,應用程式即會重新啟動。

  1. 建立使用者指派的受控識別:

    az identity create --resource-group <groupName> --name <identityName>
    
  2. 將身分識別指定給您的應用程式:

    az webapp identity assign --resource-group <groupName> --name <appName> --identities <identityId>
    

將 Azure 角色新增至受控識別

  1. Azure 入口網站中,瀏覽至您想要授與向量資料庫存取權的範圍。 範圍可以是 [管理群組]、[訂用帳戶]、[資源群組],或特定 Azure 資源。
  2. 在左側導覽中,選取 [存取控制 (IAM)]
  3. 選取 [新增],然後選取 [新增角色指派]
  4. 在 [角色] 索引標籤上,選取適當的角色,授與向量資料庫的讀取存取權。
  5. 在 [成員] 索引標籤上,選取受控識別。
  6. 在 [檢閱 + 指派] 索引標籤上,選取 [檢閱 + 指派] 以指派角色。

資源範圍

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/<providerName>/<resourceType>/<resourceSubType>/<resourceName>"

資源群組範圍

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>"

訂用帳戶範圍

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>"

管理群組範圍

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/providers/Microsoft.Management/managementGroups/<managementGroupName>"

使用向量資料庫實作權杖型驗證

下列程式碼範例需要這些額外的程式庫:

  1. 初始化 DefaultAzureCredential 物件,以挑選應用程式的受控識別:

    // Initialize a DefaultAzureCredential.
    // This credential type will try several authentication flows in order until one is available.
    // Will pickup Visual Studio or Azure CLI credentials in local environments.
    // Will pickup managed identity credentials in production deployments.
    TokenCredential credentials = new DefaultAzureCredential(
        new DefaultAzureCredentialOptions
        {
            // If using a user-assigned identity specify either:
            // ManagedIdentityClientId or ManagedIdentityResourceId.
            // e.g.: ManagedIdentityClientId = "myIdentityClientId".
        }
    );
    
  2. 為您的向量資料庫初始化 IMemoryStore 物件,然後使用其來建置 ISemanticTextMemory

    // Retrieve the endpoint obtained from the Azure AI Search deployment.
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
    string searchEndpoint = config["AZURE_AISEARCH_ENDPOINT"]!;
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // The Semantic Kernel SDK provides a connector extension for Azure AI Search.
    // Initialize an AzureAISearchMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new AzureAISearchMemoryStore(searchEndpoint, credentials);
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. 建置 Kernel 物件,然後使用 TextMemoryPlugin 匯入 ISemanticTextMemory 物件:

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  4. 使用 Kernel 物件來叫用包含記憶體收回的提示:

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");
    

使用 Key Vault 來儲存連線祕密

如果向量資料庫不支援 Microsoft Entra 驗證,您可以使用 Key Vault 來儲存連線祕密,並使用 App Service 應用程式擷取這些連線祕密。 藉由使用 Key Vault 來儲存連線祕密,您可以與多個應用程式共用這些連線祕密,並控制每個應用程式對個別祕密的存取。

在遵循這些步驟之前,請擷取向量資料庫的連接字串。 例如,請參閱搭配 ASP.NET Core Web 應用程式使用 Azure Cache for Redis

將連接字串新增至 Key Vault

重要

在遵循這些步驟之前,請確定您已使用 Azure 入口網站建立 Key Vault

  1. 瀏覽至 Azure 入口網站中的金鑰保存庫。
  2. 在 Key Vault 左側導覽中,選取 [物件] 然後選取 [祕密]
  3. 選取 [+ 產生/匯入]
  4. 在 [建立祕密] 畫面上選擇下列值:
    • 上傳選項Manual
    • 名稱:鍵入祕密的名稱。 祕密名稱在金鑰保存庫內必須是唯一的。
    • :向量資料庫的連接字串。
    • 將其他值保留為其預設值。 選取 建立
  5. 當您收到已成功建立祕密的訊息時,就可以在應用程式中使用該祕密。

重要

在遵循這些步驟之前,請確定您已使用 Azure CLI 建立 Key Vault

  1. 透過角色型存取控制 (RBAC) 將使用者帳戶權限授與金鑰保存庫,並使用 Azure CLI 命令 az role assignment create 指派角色:

    az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "<yourEmailAddress>" \
    --scope "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
    
  2. 使用 Azure CLI 命令 az keyvault secret set 將連接字串新增至 Key Vault:

    az keyvault secret set \
    --vault-name "<keyVaultName>" \
    --name "<secretName>" \
    --value "<connectionString>"
    

將 Key Vault 的存取權授與 App Service

  1. 將受控識別指派給 App Service
  2. Key Vault Secrets UserKey Vault Reader 角色新增至受控識別

從 Key Vault 實作連接字串擷取

若要使用下列程式庫範例,您需要這些額外的程式庫:

這些程式碼範例會使用 Redis 資料庫,但您可以將其套用至任何支援連接字串的向量資料庫。

  1. 初始化 DefaultAzureCredential 物件,以挑選應用程式的受控識別:

    // Initialize a DefaultAzureCredential.
    // This credential type will try several authentication flows in order until one is available.
    // Will pickup Visual Studio or Azure CLI credentials in local environments.
    // Will pickup managed identity credentials in production deployments.
    TokenCredential credentials = new DefaultAzureCredential(
        new DefaultAzureCredentialOptions
        {
            // If using a user-assigned identity specify either:
            // ManagedIdentityClientId or ManagedIdentityResourceId.
            // e.g.: ManagedIdentityClientId = "myIdentityClientId".
        }
    );
    
  2. 在建置您的設定時新增 Key Vault,這會將您的 Key Vault 祕密對應至 IConfigurationRoot 物件:

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets
    IConfigurationRoot config = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .AddAzureKeyVault(new Uri("{vaultURI}"), credentials)
        .Build();
    
    // Retrieve the Redis connection string obtained from the Key Vault.
    string redisConnectionString = config["AZURE_REDIS_CONNECT_STRING"]!;
    
  3. 使用 Key Vault 中的向量資料庫連接字串來初始化 IMemoryStore 物件,然後使用其來建置 ISemanticTextMemory

    // Use the connection string to connect to the database
    IDatabase database = (
        await ConnectionMultiplexer.ConnectAsync(redisConnectionString)
    ).GetDatabase();
    
    // The Semantic Kernel SDK provides a connector extension for Redis.
    // Initialize an RedisMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new RedisMemoryStore(database);
    
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  4. 建置 Kernel 物件,然後使用 TextMemoryPlugin 匯入 ISemanticTextMemory 物件:

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  5. 使用 Kernel 物件來叫用包含記憶體收回的提示:

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");
    

使用應用程式設定來儲存連線祕密

如果向量資料庫不支援 Microsoft Entra 驗證,您可以使用 App Service 應用程式設定來儲存連線祕密。 藉由使用應用程式設定,您可以儲存連線祕密,而不需佈建任何其他 Azure 資源。

在遵循這些步驟之前,請擷取向量資料庫的連接字串。 例如,請參閱在 .NET Framework 中使用 Azure Cache for Redis

將連接字串新增至應用程式設定

  1. 瀏覽至 Azure 入口網站上的應用程式頁面。
  2. 在應用程式的左側功能表中,選取 [設定]>[應用程式設定]
    • 根據預設,應用程式設定的值會基於安全性隱藏在入口網站中。
    • 若要查看應用程式設定的隱藏值,請選取其 [值] 欄位。
  3. 選取 [新連線設定]
  4. 在 [新增/編輯連接字串] 畫面上,選擇下列值:
    • 名稱:輸入設定的名稱。 設定名稱必須是唯一的。
    • :向量資料庫的連接字串。
    • 類型:連線的類型,如果沒有其他類型適用,則為 Custom
    • 將其他值保留為其預設值。 選取 [確定]。
  5. 在 [設定] 頁面中選取 [儲存]

使用 Azure CLI 命令 az webapp config connection-string set 新增或編輯應用程式設定:

az webapp config connection-string set \
--name "<appName>" \
--resource-group "<groupName>" \
--connection-string-type "<connectionType>" \
--settings <connectionName>='<connectionString>'

從應用程式設定實作連接字串擷取

若要使用下列程式庫範例,您需要這些額外的程式庫:

這些程式碼範例會使用 Redis 資料庫,但您可以將其套用至任何支援連接字串的向量資料庫。

  1. 在建置您的設定時新增環境變數,這會將您的連接字串對應至 IConfigurationRoot 物件:

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets
    IConfigurationRoot config = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .AddEnvironmentVariables()
        .Build();
    
    // Retrieve the Redis connection string obtained from the app settings.
    // The connection string name should match the entry in application settings
    string redisConnectionString = config.GetConnectionString("AZURE_REDIS")!;
    
  2. 使用應用程式設定中的向量資料庫連接字串來初始化 IMemoryStore 物件,然後使用其來建置 ISemanticTextMemory

    // Use the connection string to connect to the database
    IDatabase database = (
        await ConnectionMultiplexer.ConnectAsync(redisConnectionString)
    ).GetDatabase();
    
    // The Semantic Kernel SDK provides a connector extension for Redis.
    // Initialize an RedisMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new RedisMemoryStore(database);
    
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. 建置 Kernel 物件,然後使用 TextMemoryPlugin 匯入 ISemanticTextMemory 物件:

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  4. 使用 Kernel 物件來叫用包含記憶體收回的提示:

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");