你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:使用 Azure OpenAI 和 Azure AI 搜索在 Azure 应用服务中生成检索扩充生成应用(.NET)

在本教程中,你将使用 .NET Blazor、Azure OpenAI 和 Azure AI 搜索创建 .NET 检索扩充生成(RAG)应用程序,并将其部署到 Azure 应用服务。 此应用程序演示如何实现聊天界面,该界面从自己的文档检索信息,并利用 Azure AI 服务提供准确的上下文感知答案,并提供适当的引文。 解决方案使用托管标识在服务之间进行无密码身份验证。

屏幕截图显示了简介中的 Blazor 聊天界面。

本教程中,您将学习如何:

  • 部署将 RAG 模式与 Azure AI 服务配合使用的 Blazor 应用程序。
  • 为混合搜索配置 Azure OpenAI 和 Azure AI 搜索。
  • 上传文档并编制索引,以便在 AI 驱动的应用程序中使用。
  • 使用托管标识进行安全的服务到服务通信。
  • 使用生产服务在本地测试 RAG 实现。

体系结构概述

在开始部署之前,了解要生成的应用程序的体系结构会很有帮助。 下图来自 Azure AI 搜索的自定义 RAG 模式

显示连接到 Azure OpenAI 和 Azure AI 搜索的 Web 应用的体系结构图,其中存储作为数据源

在本教程中,应用服务中的 Blazer 应用程序负责应用 UX 和应用服务器。 但是,它不会对 Azure AI 搜索进行单独的知识查询。 相反,它指示 Azure OpenAI 使用 Azure AI 搜索作为数据源来进行知识查询。 此体系结构提供几个关键优势:

  • 集成矢量化:Azure AI 搜索的集成向量化功能可让你轻松快速地引入所有文档进行搜索,而无需更多代码来生成嵌入内容。
  • 简化的 API 访问:通过将 Azure OpenAI On Your Data 模式与 Azure AI 搜索结合使用作为 Azure OpenAI 完成的数据源,无需实现复杂的矢量搜索或嵌入生成。 这只是一个 API 调用,Azure OpenAI 处理所有内容,包括提示工程和查询优化。
  • 高级搜索功能:集成矢量化提供高级混合搜索所需的一切,并结合关键字匹配、矢量相似性和 AI 支持的排名的优势。
  • 完整的引文支持:响应自动包括对源文档的引文,使信息可验证和可跟踪。

先决条件

1.使用 Codespaces 打开示例

最简单的入门方法是使用 GitHub Codespaces,它提供一个完整的开发环境,并预装了所有必需的工具。

  1. 请导航至位于https://github.com/Azure-Samples/app-service-rag-openai-ai-search-dotnet的 GitHub 存储库。

  2. 选择 “代码 ”按钮,选择 “Codespaces ”选项卡,然后单击 main 上的“创建代码空间”。

  3. 请稍等片刻,让 Codespace 初始化。 准备就绪后,浏览器中会显示完全配置的 VS Code 环境。

2.部署示例体系结构

  1. 在终端中,使用 Azure 开发人员 CLI 登录到 Azure:

    azd auth login
    

    按照说明完成身份验证过程。

  2. 使用 AZD 模板预配 Azure 资源:

    azd provision
    
  3. 出现提示时,请提供以下答案:

    问题 答案
    输入新的环境名称: 键入唯一名称。
    选择要使用的 Azure 订阅: 选择订阅。
    选择要使用的资源组: 选择“新建资源组”
    选择要在其中创建资源组的位置: 选择任何区域。 实际上,资源将在 美国东部 2 中生成。
    输入新资源组的名称: 键入 Enter
  4. 等待部署完成。 此过程将:

    • 创建所有必需的 Azure 资源。
    • 将 Blazor 应用程序部署到 Azure 应用服务。
    • 使用托管标识配置安全的服务到服务身份验证。
    • 设置必要的角色分配,以确保服务之间的安全访问。

    注释

    若要详细了解托管标识的工作原理,请参阅什么是 Azure 资源的托管标识?以及如何对应用服务使用托管标识

  5. 成功部署后,会看到已部署应用程序的 URL。 记下此 URL,但尚未访问它,因为仍需要设置搜索索引。

3.上传文档并创建搜索索引

部署基础结构后,需要上传文档并创建应用程序将使用的搜索索引:

  1. 在 Azure 门户中,导航到部署创建的存储帐户。 该名称以前面提供的环境名称开头。

  2. 从左侧导航菜单中选择 “容器 ”,然后打开 文档 容器。

  3. 单击“ 上传”上传示例文档。 可以使用存储库中文件夹中的示例文档 sample-docs ,或者你自己的 PDF、Word 或文本文件。

    显示如何将文档上传到存储容器的屏幕截图。

  4. 在 Azure 门户中导航到 Azure AI 搜索服务。

  5. 选择 “导入”并向量化数据 以开始创建搜索索引的过程。

    显示 Azure AI 搜索中的“导入和矢量化数据”按钮的屏幕截图。

  6. 在“连接到数据”步骤中

    • 选择 Azure Blob 存储 作为数据源。
    • 选择 RAG
    • 选择存储帐户和 文档 容器。
    • 确保已选择 使用托管标识进行身份验证
    • 选择“下一步”。
  7. 向量化文本 步骤中:

    • 选择 Azure OpenAI 服务。
    • 选择 文本嵌入-ada-002 作为嵌入模型。 AZD 模板已为你部署了此模型。
    • 选择 系统分配的标识 进行身份验证。
    • 请勾选用于确认额外费用的复选框。
    • 选择“下一步”。
  8. 矢量化和扩充图像 步骤中:

    • 保留默认设置。
    • 选择“下一步”。
  9. “高级设置” 步骤中:

    • 确保已选择 “启用语义排名器 ”。
    • (可选)选择索引计划。 如果要使用最新文件更改定期刷新索引,这非常有用。
    • 选择“下一步”。
  10. “审阅”和“创建 ”步骤中:

    • 复制 对象名称前缀 值。 这是您的搜索索引名称。
    • 选择 “创建 ”以启动索引过程。
  11. 等待索引进程完成。 这可能需要几分钟时间,具体取决于文档的大小和数量。

  12. 若要测试数据导入,请选择 “开始搜索 ”并尝试搜索查询,例如 “告诉我你的公司”。

  13. 返回 Codespace 终端,将搜索索引名称设置为 AZD 环境变量:

    azd env set SEARCH_INDEX_NAME <your-search-index-name>
    

    <your-search-index-name> 替换为之前复制的索引名称。 AZD 在后续部署中使用此变量来设置应用服务应用设置。

4.测试应用程序并部署

如果想要在部署前后在本地测试应用程序,可以直接从 Codespace 运行它:

  1. 在 Codespace 终端中,获取 AZD 环境值:

    azd env get-values
    
  2. 打开 appsettings.Development.json。 使用终端输出,更新值 OpenAIEndpointSearchServiceUrl以及 SearchIndexName

  3. 使用 Azure CLI 登录到 Azure:

    az login
    

    这允许示例代码中的 Azure 标识客户端库接收已登录用户的身份验证令牌。

  4. 在本地运行应用程序:

    dotnet run
    
  5. 当看到 端口 5017 上运行的应用程序可用时,请选择 “在浏览器中打开”。

  6. 请尝试在聊天界面中提出几个问题。 如果收到响应,应用程序将成功连接到 Azure OpenAI 资源。

  7. 在 Azure 中应用新 SEARCH_INDEX_NAME 配置并部署示例应用程序代码:

    azd up
    

5.测试已部署的 RAG 应用程序

在完全部署和配置应用程序后,现在可以测试 RAG 功能:

  1. 打开部署结束时提供的应用程序 URL。

  2. 你会看到一个聊天界面,你可以在其中输入有关已上传文档内容的问题。

    显示 Blazor 聊天界面的屏幕截图。

  3. 请尝试询问特定于文档内容的问题。 例如,如果在 sample-docs 文件夹中上传了文档,可以尝试这些问题:

    • Contoso 如何使用我的个人数据?
    • 如何提出保修索赔?
  4. 请注意响应如何包含引用源文档的引文。 这些引文可帮助用户验证信息的准确性,并在源材料中查找更多详细信息。

    显示包含源文档引文的响应的屏幕截图。

  5. 通过提出可能受益于不同搜索方法的问题来测试混合搜索功能:

    • 具有特定术语的问题(适用于关键字搜索)。
    • 有关使用不同术语(适合矢量搜索)描述的概念的问题。
    • 需要理解上下文的复杂问题(适用于语义排名)。

清理资源

完成应用程序后,可以删除所有资源,以避免产生进一步的成本:

azd down --purge

此命令将删除与应用程序关联的所有资源。

常见问题


示例代码如何从 Azure OpenAI 聊天生成的完成结果中检索引文?

该示例使用 AzureSearchChatDataSource() 作为聊天客户端的数据源,从中检索引文。 请求聊天完成时,响应将包含 Citations 消息上下文中的对象。 代码提取这些引文,如下所示:

var result = await _chatClient.CompleteChatAsync(messages, options);

var ctx = result.Value.GetMessageContext();

var response = new ChatResponse
{
    Content = result.Value.Content,
    Citations = ctx?.Citations
};

return response;

在聊天响应中,内容使用 [doc#] 表示法引用列表中的相应引文,允许用户跟踪信息回原始源文档。 有关详细信息,请参见:


在此解决方案中使用托管标识有什么优势?

托管标识无需在代码或配置中存储凭据。 通过使用托管标识,应用程序可以在不管理机密的情况下安全地访问 Azure 服务,例如 Azure OpenAI 和 Azure AI 搜索。 此方法遵循零信任安全原则,并降低凭据泄露的风险。


此体系结构和示例应用程序中如何使用系统分配的托管标识?

AZD 部署为 Azure 应用服务、Azure OpenAI 和 Azure AI 搜索创建系统分配的托管标识。 它还为他们中的每一个进行角色分配(请参阅 main.bicep 文件)。 有关所需角色分配的信息,请参阅 Azure OpenAI On Your Data 的网络和访问配置

在示例应用程序中,Azure SDK 使用此托管标识安全地对请求进行身份验证,而无需在任何地方存储凭据或机密。 例如,AzureOpenAIClient 使用 DefaultAzureCredential 初始化,它在 Azure 中运行时使用托管标识:

_openAIClient = new AzureOpenAIClient(
    new Uri(_settings.OpenAIEndpoint),
    new DefaultAzureCredential()
);

同样,在为 Azure AI 搜索配置数据源时,为身份验证指定托管标识:

options.AddDataSource(new AzureSearchChatDataSource()
{
    Endpoint = new Uri(_settings.SearchServiceUrl ?? throw new ArgumentNullException(nameof(_settings.SearchServiceUrl))),
    IndexName = _settings.SearchIndexName,
    Authentication = DataSourceAuthentication.FromSystemManagedIdentity(), // Use system-assigned managed identity
    // ...
});

这可实现 Blazor 应用与 Azure 服务之间的安全无密码通信,遵循零信任安全性的最佳做法。 详细了解 DefaultAzureCredential 和适用于 .NET 的 Azure Identity 客户端库


如何在示例应用程序中实现语义排名器混合搜索?

示例应用程序使用 Azure.AI.Search.Documents SDK 配置具有语义排名的混合搜索。 在后端中,数据源按如下所示进行设置:

options.AddDataSource(new AzureSearchChatDataSource()
{
    // ...
    QueryType = DataSourceQueryType.VectorSemanticHybrid, // Combines vector search with keyword matching and semantic ranking
    VectorizationSource = DataSourceVectorizer.FromDeploymentName(_settings.OpenAIEmbeddingDeployment),
    SemanticConfiguration = _settings.SearchIndexName + "-semantic-configuration", // Build semantic configuration name from index name
});

此配置使应用程序能够在单个查询中合并矢量搜索(语义相似性)、关键字匹配和语义排名。 语义排名器对结果进行重新排序,以返回最相关的上下文适当的答案,然后由 Azure OpenAI 用于生成响应。 语义配置名称由集成向量化过程自动定义。 它使用搜索索引名称作为前缀,并追加 -semantic-configuration 为后缀。 这可确保语义配置与相应的索引唯一关联,并遵循一致的命名约定。


为什么在美国东部 2 中创建所有资源?

此示例使用 gpt-4o-minitext-embedding-ada-002 模型,这两种模型都可用于美国东部 2 的标准部署类型。 此外,还会选择这些模型,因为它们不会很快停用,从而为示例部署提供稳定性。 模型可用性和部署类型可能因区域而异,因此选择美国东部 2 以确保示例开箱即用。 如果要使用不同的区域或模型,请确保选择可用于同一区域中相同部署类型的模型。 选择自己的模型时,请检查其可用性和停用日期以避免中断。


是否可以使用自己的 OpenAI 模型而不是 Azure 提供的模型?

此解决方案旨在与 Azure OpenAI 服务配合使用。 虽然可以修改代码以使用其他 OpenAI 模型,但会丢失集成安全功能、托管标识支持以及此解决方案提供的与 Azure AI 搜索的无缝集成。


如何提高响应质量?

可以通过以下方法提高响应质量:

  • 上传质量更高、更相关的文档。
  • 在 Azure AI 搜索索引管道中调整分块策略。 但是,不能使用本教程中显示的集成矢量化自定义分块。
  • 在应用程序代码中试验不同的提示模板。
  • 使用 AzureSearchChatDataSource 类中的其他属性微调搜索。
  • 为特定域使用更专用的 Azure OpenAI 模型。

更多资源