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

快速入门:使用自己的数据与 Azure OpenAI 模型聊天

参考 | 源代码 | 包 (pypi) | 示例

上述链接引用 OpenAI API for Python。 没有特定于 Azure 的 OpenAI Python SDK。 了解如何在 OpenAI 服务和 Azure OpenAI 服务之间切换

在本快速入门中,可以将自己的数据与 Azure OpenAI 模型配合使用。 对数据使用 Azure OpenAI 模型可以提供功能强大的对话 AI 平台,从而实现更快、更准确的通信。

先决条件

使用 Azure OpenAI Studio 添加数据

提示

可以使用 Azure Developer CLI 以编程方式创建 Azure OpenAI On Your Data 所需的资源

导航到 Azure OpenAI Studio,然后使用有权访问 Azure OpenAI 资源的凭据登录。 在登录过程中或登录之后,选择适当的目录、Azure 订阅和 Azure OpenAI 资源。

  1. 选择“自带数据”磁贴

    Azure OpenAI Studio 登陆页的屏幕截图。

  2. 在显示的窗格中,选择“选择数据源”下的“上传文件(预览版)”。 Azure OpenAI 需要存储资源和搜索资源来访问数据并编制数据索引。

    提示

    1. 要使 Azure OpenAI 访问存储帐户,需要启用跨原点资源共享 (CORS)。 如果尚未为 Azure Blob 存储资源启用 CORS,请选择“启用 CORS”。

    2. 选择 Azure AI 搜索资源,然后选择确认以表明知晓连接该资源将使用你的帐户。 然后,选择“下一步”。

    显示用于在 Azure OpenAI Studio 中选择数据源的选项的屏幕截图。

  3. 在“上传文件”窗格中,选择“浏览文件”,并选择从先决条件部分下载的文件或自己的数据。 然后选择“上传文件”。 然后,选择“下一步”。

  4. 在“数据管理”窗格中,可以选择为索引启用语义搜索还是向量搜索

    重要

    • 语义搜索矢量搜索需要额外定价。 需要选择“基本或更高 SKU”才能启用语义搜索或矢量搜索。 有关详细信息,请参阅定价层差异服务限制
    • 为了帮助提高信息检索和模型响应的质量,我们建议为以下数据源语言启用语义搜索:英语、法语、西班牙语、葡萄牙语、意大利语、德国、中文(Zh)、日语、韩语、俄语、阿拉伯语。
  5. 查看输入的详细信息,然后选择“保存并关闭”。 现在,你可以与模型聊天,模型将使用数据中的信息来构造响应。

聊天操场

通过聊天操场使用开始使用无代码方法浏览 Azure OpenAI 功能。 这是一个简单的文本框,可以在其中提交提示以生成补全内容。 在此页中,可以快速循环访问和试验这些功能。

Azure OpenAI Studio 操场页的屏幕截图,其中突出显示了各个部分。

操场为你提供定制聊天体验的选项。 在右侧,可以选择“部署”来确定哪个模型使用索引中的搜索结果生成响应。 可以选择要包含为对话历史记录的以往消息数,供将来生成的响应使用。 对话历史记录提供用于生成相关响应的上下文,但也会占用令牌使用量。 输入令牌进度指示器跟踪所提交问题的令牌计数。

左侧的“高级设置”是运行时参数,可让你控制从数据中检索和搜索相关信息的操作。 一个典型的用例是,当你想要确保仅根据数据生成响应,或者发现模型无法根据数据的现有信息生成响应时,便可以使用“高级设置”。

  • “严格性”确定系统基于相似性分数筛选搜索文档的激进性。 将严格性设置为 5 表示系统会激进地筛选出文档,并应用非常高的相似性阈值。 语义搜索在此场景中可能非常有用,因为排名模型可以更好地推断查询的意图。 严格性级别较低时会产生更详细的答案,但也可能包括索引中未包含的信息。 此项默认设置为 3。

  • “检索的文档数”是一个整数,可设置为 3、5、10 或 20,它控制提供给大型语言模型的文档区块数,以形成最终响应。 默认情况下,它设置为 5。

  • 当启用了“限制对数据的响应”时,模型会尝试仅依赖你的文档做出响应。 此项默认设置为 true。

“高级设置”的屏幕截图。

发送第一个查询。 聊天模型在问答练习中表现最佳。 例如“可用的健康计划有哪些?”或“健康升级选项是什么?”

需要数据分析的查询可能会失败,例如“哪种健康计划最受欢迎?”。 需要有关所有数据的信息的查询也可能会失败,例如“我上传了多少文档?”。 请记住,搜索引擎会查找具有确切或类似字词、短语或查询构造的区块。 虽然模型可能会理解该问题,但如果搜索结果是数据集中的区块,则它不是回答此类问题的正确信息。

聊天受限于响应中返回的文档(区块)数(在 Azure OpenAI Studio 操场中限制为 3-20)。 正如你想象的,提出有关“所有标题”的问题需要对整个矢量存储进行完全扫描。

部署模型

对 Azure OpenAI 工作室中的体验感到满意后,可以通过选择“部署到”按钮直接从工作室部署 Web 应用。

屏幕截图显示 Azure OpenAI Studio 中的模型部署按钮。

如果你在模型上使用自己的数据,这样就可以选择部署到独立的 Web 应用程序或 Copilot Studio(预览版)中的 Copilot。

例如,如果选择部署 Web 应用:

首次部署 Web 应用时,应选择“创建新的 Web 应用”。 为应用选择一个名称,该名称将成为应用 URL 的一部分。 例如,https://<appname>.azurewebsites.net

为已发布的应用选择订阅、资源组、位置和定价计划。 要更新现有应用,请选择“发布到现有 Web 应用”,然后从下拉菜单中选择上一个应用的名称。

如果选择部署 Web 应用,请参阅使用它的重要注意事项

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

创建新的 .NET Core 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,使用 dotnet new 命令创建名为 azure-openai-quickstart 的新控制台应用。 此命令将创建包含单个 C# 源文件的简单“Hello World”项目:Program.cs

dotnet new console -n azure-openai-quickstart

将目录更改为新创建的应用文件夹。 可使用以下代码生成应用程序:

dotnet build

生成输出不应包含警告或错误。

...
Build succeeded.
 0 Warning(s)
 0 Error(s)
...

使用以下项安装 OpenAI .NET 客户端库:

dotnet add package Azure.AI.OpenAI --prerelease

从项目目录中,打开 Program.cs 文件并将其内容替换为以下代码:

没有响应流式处理

using Azure;
using Azure.AI.OpenAI;
using System.Text.Json;
using static System.Environment;

string azureOpenAIEndpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
string azureOpenAIKey = GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
string deploymentName = GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_ID");
string searchEndpoint = GetEnvironmentVariable("AZURE_AI_SEARCH_ENDPOINT");
string searchKey = GetEnvironmentVariable("AZURE_AI_SEARCH_API_KEY");
string searchIndex = GetEnvironmentVariable("AZURE_AI_SEARCH_INDEX");


var client = new OpenAIClient(new Uri(azureOpenAIEndpoint), new AzureKeyCredential(azureOpenAIKey));

var chatCompletionsOptions = new ChatCompletionsOptions()
{
    Messages =
    {
        new ChatRequestUserMessage("What are my available health plans?"),
    },
    AzureExtensionsOptions = new AzureChatExtensionsOptions()
    {
        Extensions =
        {
            new AzureCognitiveSearchChatExtensionConfiguration()
            {
                SearchEndpoint = new Uri(searchEndpoint),
                Key = searchKey,
                IndexName = searchIndex,
            },
        }
    },
    DeploymentName = deploymentName
};

Response<ChatCompletions> response = client.GetChatCompletions(chatCompletionsOptions);

ChatResponseMessage responseMessage = response.Value.Choices[0].Message;

Console.WriteLine($"Message from {responseMessage.Role}:");
Console.WriteLine("===");
Console.WriteLine(responseMessage.Content);
Console.WriteLine("===");

Console.WriteLine($"Context information (e.g. citations) from chat extensions:");
Console.WriteLine("===");
foreach (ChatResponseMessage contextMessage in responseMessage.AzureExtensionsContext.Messages)
{
    string contextContent = contextMessage.Content;
    try
    {
        var contextMessageJson = JsonDocument.Parse(contextMessage.Content);
        contextContent = JsonSerializer.Serialize(contextMessageJson, new JsonSerializerOptions()
        {
            WriteIndented = true,
        });
    }
    catch (JsonException)
    {}
    Console.WriteLine($"{contextMessage.Role}: {contextContent}");
}
Console.WriteLine("===");

重要

对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

dotnet run program.cs

输出

Answer from assistant:
===
The available health plans in the Contoso Electronics plan and benefit packages are the Northwind Health Plus and Northwind Standard plans [^1^].
===
Context information (e.g. citations) from chat extensions:
===
tool: {
  "citations": [
    {
      "content": "...",
      "id": null,
      "title": "...",
      "filepath": "...",
      "url": "...",
      "metadata": {
        "chunking": "orignal document size=1011. Scores=3.6390076 and None.Org Highlight count=38."
      },
      "chunk_id": "2"
    },
    ...
  ],
  "intent": "[\u0022What are my available health plans?\u0022]"
}
===

这将等到模型生成其整个响应后再打印结果。 或者,如果要异步流式处理响应并输出结果,可以将 Program.cs 的内容替换为以下示例中的代码。

使用流式处理进行异步

using Azure;
using Azure.AI.OpenAI;
using System.Text.Json;
using static System.Environment;

string azureOpenAIEndpoint = GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
string azureOpenAIKey = GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
string deploymentName = GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_ID");
string searchEndpoint = GetEnvironmentVariable("AZURE_AI_SEARCH_ENDPOINT");
string searchKey = GetEnvironmentVariable("AZURE_AI_SEARCH_API_KEY");
string searchIndex = GetEnvironmentVariable("AZURE_AI_SEARCH_INDEX");


var client = new OpenAIClient(new Uri(azureOpenAIEndpoint), new AzureKeyCredential(azureOpenAIKey));

var chatCompletionsOptions = new ChatCompletionsOptions()
{
    DeploymentName = deploymentName,
    Messages =
    {
        new ChatRequestUserMessage("What are my available health plans?"),
    },
    AzureExtensionsOptions = new AzureChatExtensionsOptions()
    {
        Extensions =
        {
            new AzureCognitiveSearchChatExtensionConfiguration()
            {
                SearchEndpoint = new Uri(searchEndpoint),
                Key = searchKey,
                IndexName = searchIndex,
            },
        }
    }
};
await foreach (StreamingChatCompletionsUpdate chatUpdate in client.GetChatCompletionsStreaming(chatCompletionsOptions))
{
    if (chatUpdate.Role.HasValue)
    {
        Console.Write($"{chatUpdate.Role.Value.ToString().ToUpperInvariant()}: ");
    }
    if (!string.IsNullOrEmpty(chatUpdate.ContentUpdate))
    {
        Console.Write(chatUpdate.ContentUpdate);
    }
}

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 有关详细信息,请参阅使用 Azure AI 工作室添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resource.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPEN_AI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户的“资源管理”>“部署”下,或者在 Azure AI 工作室的“管理”>“部署”下找到此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置”>“密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

注意

Spring AI 将该模型名称默认为 gpt-35-turbo。 仅当你部署了具有不同名称的模型时,才需要提供 SPRING_AI_AZURE_OPENAI_MODEL 值。

export SPRING_AI_AZURE_OPENAI_ENDPOINT=REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
export SPRING_AI_AZURE_OPENAI_API_KEY=REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
export SPRING_AI_AZURE_COGNITIVE_SEARCH_ENDPOINT=REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
export SPRING_AI_AZURE_COGNITIVE_SEARCH_API_KEY=REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
export SPRING_AI_AZURE_COGNITIVE_SEARCH_INDEX=REPLACE_WITH_YOUR_INDEX_NAME_HERE
export SPRING_AI_AZURE_OPENAI_MODEL=REPLACE_WITH_YOUR_MODEL_NAME_HERE

创建新的 Spring 应用程序

Spring AI 目前不支持 AzureCognitiveSearchChatExtensionConfiguration 选项,该选项允许 Azure AI 查询封装检索增强生成 (RAG) 方法,并向用户隐藏详细信息。 作为替代方法,你仍然可以直接在应用程序中调用 RAG 方法以查询 Azure AI 搜索索引中的数据,并使用检索到的文档来增强你的查询。

Spring AI 支持 VectorStore 抽象,可以将 Azure AI 搜索包装在 Spring AI VectorStore 实现中,以便查询自定义数据。 以下项目实现了由 Azure AI 搜索支持的自定义 VectorStore,并直接执行 RAG 操作。

在 Bash 窗口中,为应用创建一个新目录,然后导航到它。

mkdir ai-custom-data-demo && cd ai-custom-data-demo

从工作目录运行 spring init 命令。 此命令会为 Spring 项目创建一个标准目录结构,包括主 Java 类源文件和用于管理基于 Maven 的项目的 pom.xml 文件。

spring init -a ai-custom-data-demo -n AICustomData --force --build maven -x

生成的文件和文件夹类似于以下结构:

ai-custom-data-demo/
|-- pom.xml
|-- mvn
|-- mvn.cmd
|-- HELP.md
|-- src/
    |-- main/
    |   |-- resources/
    |   |   |-- application.properties
    |   |-- java/
    |       |-- com/
    |           |-- example/
    |               |-- aicustomdatademo/
    |                   |-- AiCustomDataApplication.java
    |-- test/
        |-- java/
            |-- com/
                |-- example/
                    |-- aicustomdatademo/
                        |-- AiCustomDataApplicationTests.java

编辑 Spring 应用程序

  1. 编辑 pom.xml 文件。

    在项目目录的根中,在你偏好的编辑器或 IDE 中打开 pom.xml 文件,并使用以下内容覆盖该文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.2.0</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>ai-custom-data-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>AICustomData</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>17</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.experimental.ai</groupId>
                <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
                <version>0.7.0-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-search-documents</artifactId>
                <version>11.6.0-beta.10</version>
                <exclusions>
                    <!-- exclude this to avoid changing the default serializer and the null-value behavior -->
                    <exclusion>
                        <groupId>com.azure</groupId>
                        <artifactId>azure-core-serializer-json-jackson</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
        <repositories>
            <repository>
                <id>spring-snapshots</id>
                <name>Spring Snapshots</name>
                <url>https://repo.spring.io/snapshot</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
            </repository>
        </repositories>
    </project>
    
  2. src/main/java/com/example/aicustomdatademo 文件夹中,在你偏好的编辑器或 IDE 中打开 AiCustomDataApplication.java,然后粘贴以下代码:

    package com.example.aicustomdatademo;
    
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Optional;
    import java.util.stream.Collectors;
    
    import org.springframework.ai.client.AiClient;
    import org.springframework.ai.document.Document;
    import org.springframework.ai.embedding.EmbeddingClient;
    import org.springframework.ai.prompt.Prompt;
    import org.springframework.ai.prompt.SystemPromptTemplate;
    import org.springframework.ai.prompt.messages.MessageType;
    import org.springframework.ai.prompt.messages.UserMessage;
    import org.springframework.ai.vectorstore.VectorStore;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    
    import com.azure.core.credential.AzureKeyCredential;
    import com.azure.core.util.Context;
    import com.azure.search.documents.SearchClient;
    import com.azure.search.documents.SearchClientBuilder;
    import com.azure.search.documents.models.IndexingResult;
    import com.azure.search.documents.models.SearchOptions;
    import com.azure.search.documents.models.RawVectorQuery;
    
    import lombok.AllArgsConstructor;
    import lombok.NoArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.extern.jackson.Jacksonized;
    
    @SpringBootApplication
    public class AiCustomDataApplication implements CommandLineRunner
    {
        private static final String ROLE_INFO_KEY = "role";
    
        private static final String template = """
                You are a helpful assistant. Use the information from the DOCUMENTS section to augment answers.
    
                DOCUMENTS:
                {documents}
                """;
    
        @Value("${spring.ai.azure.cognitive-search.endpoint}")
        private String acsEndpoint;
    
        @Value("${spring.ai.azure.cognitive-search.api-key}")
        private String acsApiKey;
    
        @Value("${spring.ai.azure.cognitive-search.index}")
        private String acsIndexName;
    
        @Autowired
        private AiClient aiClient;
    
        @Autowired
        private EmbeddingClient embeddingClient;
    
        public static void main(String[] args) {
            SpringApplication.run(AiCustomDataApplication.class, args);
        }
    
        @Override
        public void run(String... args) throws Exception
        {
            System.out.println(String.format("Sending custom data prompt to AI service. One moment please...\r\n"));
    
            final var store = vectorStore(embeddingClient);
    
            final String question = "What are my available health plans?";
    
            final var candidateDocs = store.similaritySearch(question);
    
            final var userMessage = new UserMessage(question);
    
            final String docPrompts =
                    candidateDocs.stream().map(entry -> entry.getContent()).collect(Collectors.joining("\n"));
    
            final SystemPromptTemplate promptTemplate = new SystemPromptTemplate(template);
            final var systemMessage = promptTemplate.createMessage(Map.of("documents", docPrompts));
    
            final var prompt = new Prompt(List.of(systemMessage, userMessage));
    
            final var resps = aiClient.generate(prompt);
    
            System.out.println(String.format("Prompt created %d generated response(s).", resps.getGenerations().size()));
    
            resps.getGenerations().stream()
              .forEach(gen -> {
                  final var role = gen.getInfo().getOrDefault(ROLE_INFO_KEY, MessageType.ASSISTANT.getValue());
    
                  System.out.println(String.format("Generated respose from \"%s\": %s", role, gen.getText()));
              });
    
        }
    
        @Bean
        public VectorStore vectorStore(EmbeddingClient embeddingClient)
        {
            final SearchClient searchClient = new SearchClientBuilder()
                    .endpoint(acsEndpoint)
                    .credential(new AzureKeyCredential(acsApiKey))
                    .indexName(acsIndexName)
                    .buildClient();
            return new AzureCognitiveSearchVectorStore(searchClient, embeddingClient);
        }
    
        public static class AzureCognitiveSearchVectorStore implements VectorStore
        {
            private static final int DEFAULT_TOP_K = 4;
    
            private static final Double DEFAULT_SIMILARITY_THRESHOLD = 0.0;
    
            private SearchClient searchClient;
    
            private final EmbeddingClient embeddingClient;
    
            public AzureCognitiveSearchVectorStore(SearchClient searchClient, EmbeddingClient embeddingClient)
            {
                this.searchClient = searchClient;
                this.embeddingClient = embeddingClient;
            }
    
            @Override
            public void add(List<Document> documents)
            {
                final var docs = documents.stream().map(document -> {
    
                    final var embeddings = embeddingClient.embed(document);
    
                    return new DocEntry(document.getId(), "", document.getContent(), embeddings);
    
                }).toList();
    
                searchClient.uploadDocuments(docs);
            }
    
            @Override
            public Optional<Boolean> delete(List<String> idList)
            {
                final List<DocEntry> docIds = idList.stream().map(id -> DocEntry.builder().id(id).build())
                    .toList();
    
                var results = searchClient.deleteDocuments(docIds);
    
                boolean resSuccess = true;
    
                for (IndexingResult result : results.getResults())
                    if (!result.isSucceeded()) {
                        resSuccess = false;
                        break;
                    }
    
                return Optional.of(resSuccess);
            }
    
            @Override
            public List<Document> similaritySearch(String query)
            {
                return similaritySearch(query, DEFAULT_TOP_K);
            }
    
            @Override
            public List<Document> similaritySearch(String query, int k)
            {
                return similaritySearch(query, k, DEFAULT_SIMILARITY_THRESHOLD);
            }
    
            @Override
            public List<Document> similaritySearch(String query, int k, double threshold)
            {
                final var searchQueryVector = new RawVectorQuery()
                        .setVector(toFloatList(embeddingClient.embed(query)))
                        .setKNearestNeighborsCount(k)
                        .setFields("contentVector");
    
                final var searchResults = searchClient.search(null,
                        new SearchOptions().setVectorQueries(searchQueryVector), Context.NONE);
    
                return searchResults.stream()
                        .filter(r -> r.getScore() >= threshold)
                        .map(r -> {
    
                            final DocEntry entry = r.getDocument(DocEntry.class);
    
                            final Document doc = new Document(entry.getId(), entry.getContent(), Collections.emptyMap());
                            doc.setEmbedding(entry.getContentVector());
    
                            return doc;
                        })
                        .collect(Collectors.toList());
            }
    
            private List<Float> toFloatList(List<Double> doubleList)
            {
                return doubleList.stream().map(Double::floatValue).toList();
            }
    
        }
    
        @Data
        @Builder
        @Jacksonized
        @AllArgsConstructor
        @NoArgsConstructor
        static class DocEntry
        {
            private String id;
    
            private String hash;
    
            private String content;
    
            private List<Double> contentVector;
        }
    
    }
    

    重要

    对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

  3. 导航回项目根文件夹,然后使用以下命令运行应用:

    ./mvnw spring-boot:run
    

输出

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.5)

2023-11-07T14:40:45.250-06:00  INFO 18557 --- [           main] c.e.a.AiCustomDataApplication            : No active profile set, falling back to 1 default profile: "default"
2023-11-07T14:40:46.035-06:00  INFO 18557 --- [           main] c.e.a.AiCustomDataApplication            : Started AiCustomDataApplication in 1.095 seconds (process running for 1.397)
Sending custom data prompt to AI service. One moment please...

Prompt created 1 generated response(s).
Generated response from "assistant": The available health plans in the Contoso Electronics plan and benefit packages are the Northwind Health Plus and Northwind Standard plans.

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

创建 Node 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,为应用创建一个新目录并导航到该目录。 然后运行 npm init 命令以使用 package.json 文件创建一个 node 应用程序。

npm init

安装客户端库

使用 npm 安装适用于 JavaScript 的 Azure OpenAI 客户端和 Azure 标识库:

npm install @azure/openai @azure/identity

你的应用的 package.json 文件将随依赖项进行更新。

创建一个简单的应用程序

在需要新项目的位置打开命令提示符,并创建名为 ChatWithOwnData.js 的新文件。 将以下代码复制到 ChatWithOwnData.js 文件中。

const { OpenAIClient, AzureKeyCredential } = require("@azure/openai");

// Set the Azure and AI Search values from environment variables
const endpoint = process.env["AZURE_OPENAI_ENDPOINT"];
const azureApiKey = process.env["AZURE_OPENAI_API_KEY"];
const deploymentId = process.env["AZURE_OPENAI_DEPLOYMENT_ID"];
const searchEndpoint = process.env["AZURE_AI_SEARCH_ENDPOINT"];
const searchKey = process.env["AZURE_AI_SEARCH_API_KEY"];
const searchIndex = process.env["AZURE_AI_SEARCH_INDEX"];


async function main(){
  const client = new OpenAIClient(endpoint, new AzureKeyCredential(azureApiKey));

  const messages = [
    { role: "user", content: "What are my available health plans?" },
  ];

  console.log(`Message: ${messages.map((m) => m.content).join("\n")}`);

  const events = await client.streamChatCompletions(deploymentId, messages, { 
    maxTokens: 128,
    azureExtensionOptions: {
      extensions: [
        {
          type: "AzureCognitiveSearch",
          endpoint: searchEndpoint,
          key: searchKey,
          indexName: searchIndex,
        },
      ],
    },
  });
  let response = "";
  for await (const event of events) {
    for (const choice of event.choices) {
      const newText = choice.delta?.content;
      if (!!newText) {
        response += newText;
        // To see streaming results as they arrive, uncomment line below
        // console.log(newText);
      }
    }
  }
  console.log(response);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});



module.exports = { main };

重要

对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

node.exe ChatWithOwnData.js

输出

Message: What are my available health plans?
The available health plans in the Contoso Electronics plan and benefit packages are the Northwind Health Plus and Northwind Standard plans.

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

创建 Python 环境

  1. 为项目新建一个名为 openai-pytho 的文件夹,并且新建一个名为 main.py 的 Python 代码文件。 更改到该目录:
mkdir openai-python
cd openai-python
  1. 安装以下 Python 库:
pip install openai
pip install python-dotenv

创建 Python 应用

  1. 从项目目录中,打开 main.py 文件并添加以下代码:
import os
import openai
import dotenv

dotenv.load_dotenv()

endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
api_key = os.environ.get("AZURE_OPENAI_API_KEY")
deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_ID")

client = openai.AzureOpenAI(
    azure_endpoint=endpoint,
    api_key=api_key,
    api_version="2024-02-01",
)

completion = client.chat.completions.create(
    model=deployment,
    messages=[
        {
            "role": "user",
            "content": "What are my available health plans?",
        },
    ],
    extra_body={
        "data_sources":[
            {
                "type": "azure_search",
                "parameters": {
                    "endpoint": os.environ["AZURE_AI_SEARCH_ENDPOINT"],
                    "index_name": os.environ["AZURE_AI_SEARCH_INDEX"],
                    "authentication": {
                        "type": "api_key",
                        "key": os.environ["AZURE_AI_SEARCH_API_KEY"],
                    }
                }
            }
        ],
    }
)

print(completion.model_dump_json(indent=2))

重要

对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

  1. 运行以下命令:
python main.py

应用程序以适合在许多场景下使用的 JSON 格式打印响应。 它包含对来自已上传文件的查询和引文的答案。

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

示例 PowerShell 命令

Azure OpenAI 聊天模型已经过优化,可以处理设置为对话格式的输入。 变量 messages 会传递一组字典,这些字典在按系统、用户、工具和助手划定的对话中具有不同角色。 变量 dataSources 会连接到 Azure 认知搜索索引,并支持 Azure OpenAI 模型使用数据做出响应。

若要触发模型回复,在用户消息的末尾应提示该轮到助手回复了。

提示

可以使用多个参数来更改模型的响应,例如 temperaturetop_p。 有关详细信息,请查看参考文档

# Azure OpenAI metadata variables
   $openai = @{
       api_key     = $Env:AZURE_OPENAI_API_KEY
       api_base    = $Env:AZURE_OPENAI_ENDPOINT # your endpoint should look like the following https://YOUR_RESOURCE_NAME.openai.azure.com/
       api_version = '2023-07-01-preview' # this may change in the future
       name        = 'YOUR-DEPLOYMENT-NAME-HERE' #This will correspond to the custom name you chose for your deployment when you deployed a model.
   }

   $acs = @{
       search_endpoint     = 'YOUR ACS ENDPOINT' # your endpoint should look like the following https://YOUR_RESOURCE_NAME.search.windows.net/
       search_key    = 'YOUR-ACS-KEY-HERE' # or use the Get-Secret cmdlet to retrieve the value
       search_index = 'YOUR-INDEX-NAME-HERE' # the name of your ACS index
   }

   # Completion text
   $body = @{
    dataSources = @(
        @{
            type = 'AzureCognitiveSearch'
            parameters = @{
                    endpoint = $acs.search_endpoint
                    key = $acs.search_key
                    indexName = $acs.search_index
                }
        }
    )
    messages = @(
            @{
                role = 'user'
                content = 'What are my available health plans?'
            }
    )
   } | convertto-json -depth 5

   # Header for authentication
   $headers = [ordered]@{
       'api-key' = $openai.api_key
   }

   # Send a completion call to generate an answer
   $url = "$($openai.api_base)/openai/deployments/$($openai.name)/extensions/chat/completions?api-version=$($openai.api_version)"

   $response = Invoke-RestMethod -Uri $url -Headers $headers -Body $body -Method Post -ContentType 'application/json'
   return $response.choices.messages[1].content

示例输出

The available health plans in the Contoso Electronics plan and benefit packages are the Northwind Health Plus and Northwind Standard plans.

重要

对于生产,请使用安全的方式存储和访问凭据,例如使用 Azure Key Vault 的 PowerShell Secret Management。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

使用 Web 应用与模型聊天

要开始与使用你的数据的 Azure OpenAI 模型聊天,可以使用 Azure OpenA 工作室或我们在 GitHub 上提供的示例代码来部署 Web 应用。 此应用使用 Azure 应用服务进行部署,并提供用于发送查询的用户界面。 此应用可由使用数据的 Azure OpenAI 模型使用,也可以由不使用数据的模型使用。 有关要求、设置和部署的说明,请参阅存储库中的自述文件。 可以选择性地通过更改源代码来自定义 Web 应用的前端和后端逻辑

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

创建 Go 环境

  1. 为项目新建一个名为 openai-go 的文件夹,并且新建一个名为 sample.go 的 Go 代码文件。 更改到该目录:

    mkdir openai-go
    cd openai-go
    
  2. 安装以下 Go 包:

    go get github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai
    
  3. 为代码启用依赖项跟踪。

    go mod init example/azure-openai
    

创建 Go 应用

  1. 从项目目录中,打开 sample.go 文件并添加以下代码:

    package main
    
    import (
     "context"
     "fmt"
     "log"
     "os"
    
     "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai"
     "github.com/Azure/azure-sdk-for-go/sdk/azcore"
     "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
    )
    
    func main() {
     azureOpenAIKey := os.Getenv("AZURE_OPENAI_API_KEY")
     modelDeploymentID := os.Getenv("AZURE_OPENAI_DEPLOYMENT_ID")
    
     // Ex: "https://<your-azure-openai-host>.openai.azure.com"
     azureOpenAIEndpoint := os.Getenv("AZURE_OPENAI_ENDPOINT")
    
     // Azure AI Search configuration
     searchIndex := os.Getenv("AZURE_AI_SEARCH_INDEX")
     searchEndpoint := os.Getenv("AZURE_AI_SEARCH_ENDPOINT")
     searchAPIKey := os.Getenv("AZURE_AI_SEARCH_API_KEY")
    
     if azureOpenAIKey == "" || modelDeploymentID == "" || azureOpenAIEndpoint == "" || searchIndex == "" || searchEndpoint == "" || searchAPIKey == "" {
     	fmt.Fprintf(os.Stderr, "Skipping example, environment variables missing\n")
     	return
     }
    
     keyCredential := azcore.NewKeyCredential(azureOpenAIKey)
    
     // In Azure OpenAI you must deploy a model before you can use it in your client. For more information
     // see here: https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource
     client, err := azopenai.NewClientWithKeyCredential(azureOpenAIEndpoint, keyCredential, nil)
    
     if err != nil {
     	//  TODO: Update the following line with your application specific error handling logic
     	log.Fatalf("ERROR: %s", err)
     }
    
     resp, err := client.GetChatCompletions(context.TODO(), azopenai.ChatCompletionsOptions{
     	Messages: []azopenai.ChatRequestMessageClassification{
     		&azopenai.ChatRequestUserMessage{Content: azopenai.NewChatRequestUserMessageContent("What are my available health plans?")},
     	},
     	MaxTokens: to.Ptr[int32](512),
     	AzureExtensionsOptions: []azopenai.AzureChatExtensionConfigurationClassification{
     		&azopenai.AzureCognitiveSearchChatExtensionConfiguration{
     			// This allows Azure OpenAI to use an Azure AI Search index.
     			//
     			// > Because the model has access to, and can reference specific sources to support its responses, answers are not only based on its pretrained knowledge
     			// > but also on the latest information available in the designated data source. This grounding data also helps the model avoid generating responses
     			// > based on outdated or incorrect information.
     			//
     			// Quote from here: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data
     			Parameters: &azopenai.AzureCognitiveSearchChatExtensionParameters{
     				Endpoint:  &searchEndpoint,
     				IndexName: &searchIndex,
     				Authentication: &azopenai.OnYourDataAPIKeyAuthenticationOptions{
     					Key: &searchAPIKey,
     				},
     			},
     		},
     	},
     	DeploymentName: &modelDeploymentID,
     }, nil)
    
     if err != nil {
     	//  TODO: Update the following line with your application specific error handling logic
     	log.Fatalf("ERROR: %s", err)
     }
    
     // Contains contextual information from your Azure chat completion extensions, configured above in `AzureExtensionsOptions`
     msgContext := resp.Choices[0].Message.Context
    
     fmt.Fprintf(os.Stderr, "Extensions Context Role: %s\nExtensions Context (length): %d\n",
     	*msgContext.Messages[0].Role,
     	len(*msgContext.Messages[0].Content))
    
     fmt.Fprintf(os.Stderr, "ChatRole: %s\nChat content: %s\n",
     	*resp.Choices[0].Message.Role,
     	*resp.Choices[0].Message.Content,
     )
    }
    

    重要

    对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关凭据安全性的详细信息,请参阅 Azure AI 服务安全性一文。

  2. 运行以下命令:

    go run sample.go
    

    应用程序会打印响应,其中包括对来自已上传文件的查询和引文的答案。

检索所需的变量

要成功地对 Azure OpenAI 进行调用,需要使用以下变量。 本快速入门假定已将数据上传到 Azure Blob 存储帐户,并且已创建 Azure AI 搜索索引。 请参阅使用 Azure OpenAI Studio 添加数据

变量名称
AZURE_OPENAI_ENDPOINT 在从 Azure 门户检查 Azure OpenAI 资源时,可在“密钥和终结点”部分中找到此值。 也可在“Azure AI 工作室”>“聊天操场”>“代码视图”中查找该值。 示例终结点为:https://my-resoruce.openai.azure.com
AZURE_OPENAI_API_KEY 在 Azure 门户检查 Azure OpenAI 资源时,可在“资源管理”>“密钥和终结点”部分中找到此值。 可以使用 KEY1KEY2。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_OPENAI_DEPLOYMENT_ID 此值将对应于在部署模型时为部署选择的自定义名称。 可在 Azure 门户中的“资源管理”>“部署”下,或者在 Azure AI 工作室中的“管理”>“部署”下查找此值。
AZURE_AI_SEARCH_ENDPOINT 在 Azure 门户检查 Azure AI 搜索资源时,可在“概览”部分中找到此值。
AZURE_AI_SEARCH_API_KEY 在 Azure 门户检查 Azure AI 搜索资源时,可在“设置>密钥”部分中找到此值。 你可以使用主要管理密钥或辅助管理密钥。 始终准备好两个密钥可以安全地轮换和重新生成密钥,而不会导致服务中断。
AZURE_AI_SEARCH_INDEX 此值对应于为存储数据而创建的索引的名称。 在从 Azure 门户检查 Azure AI 搜索资源时,可以在“概述”部分找到它。

环境变量

setx AZURE_OPENAI_ENDPOINT REPLACE_WITH_YOUR_AOAI_ENDPOINT_VALUE_HERE
setx AZURE_OPENAI_API_KEY REPLACE_WITH_YOUR_AOAI_KEY_VALUE_HERE
setx AZURE_OPENAI_DEPLOYMENT_ID REPLACE_WITH_YOUR_AOAI_DEPLOYMENT_VALUE_HERE
setx AZURE_AI_SEARCH_ENDPOINT REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_VALUE_HERE
setx AZURE_AI_SEARCH_API_KEY REPLACE_WITH_YOUR_AZURE_SEARCH_RESOURCE_KEY_VALUE_HERE
setx AZURE_AI_SEARCH_INDEX REPLACE_WITH_YOUR_INDEX_NAME_HERE

示例 cURL 命令

Azure OpenAI 聊天模型已经过优化,可以处理设置为对话格式的输入。 变量 messages 会传递一组字典,这些字典在按系统、用户、工具和助手划定的对话中具有不同角色。 变量 dataSources 会连接到 Azure AI 搜索索引,并支持 Azure OpenAI 模型使用数据做出响应。

若要触发模型回复,在用户消息的末尾应提示该轮到助手回复了。

提示

可以使用多个参数来更改模型的响应,例如 temperaturetop_p。 有关详细信息,请查看参考文档

curl -i -X POST $AZURE_OPENAI_ENDPOINT/openai/deployments/$AZURE_OPENAI_DEPLOYMENT_ID/chat/completions?api-version=2024-02-15-preview \
-H "Content-Type: application/json" \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-d \
'
{
    "data_sources": [
        {
            "type": "AzureCognitiveSearch",
            "parameters": {
                "endpoint": "'$AZURE_AI_SEARCH_ENDPOINT'",
                "key": "'$AZURE_AI_SEARCH_API_KEY'",
                "index_name": "'$AZURE_AI_SEARCH_INDEX'"
            }
        }
    ],
    "messages": [
        {
            "role": "user",
            "content": "What are my available health plans?"
        }
    ]
}
'

示例输出

{
    "id": "12345678-1a2b-3c4e5f-a123-12345678abcd",
    "model": "gpt-4",
    "created": 1709835345,
    "object": "extensions.chat.completion",
    "choices": [
        {
            "index": 0,
            "finish_reason": "stop",
            "message": {
                "role": "assistant",
                "content": "The available health plans in the Contoso Electronics plan and benefit packages are the Northwind Health Plus and Northwind Standard plans. [doc1].",
                "end_turn": true,
                "context": {
                    "citations": [
                        {
                            "content": "...",
                            "title": "...",
                            "url": "https://mysearch.blob.core.windows.net/xyz/001.txt",
                            "filepath": "001.txt",
                            "chunk_id": "0"
                        }
                    ],
                    "intent": "[\"Available health plans\"]"
                }
            }
        }
    ],
    "usage": {
        "prompt_tokens": 3779,
        "completion_tokens": 105,
        "total_tokens": 3884
    }
}

使用 Web 应用与模型聊天

要开始与使用你的数据的 Azure OpenAI 模型聊天,可以使用 Azure OpenA 工作室或我们在 GitHub 上提供的示例代码来部署 Web 应用。 此应用使用 Azure 应用服务进行部署,并提供用于发送查询的用户界面。 此应用可由使用数据的 Azure OpenAI 模型使用,也可以由不使用数据的模型使用。 有关要求、设置和部署的说明,请参阅存储库中的自述文件。 可以选择性地通过更改源代码来自定义 Web 应用的前端和后端逻辑

清理资源

如果想要清理和移除 Azure OpenAI 资源或 Azure AI 搜索资源,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

后续步骤