Spring AI 第二讲 之 Chat Model API 第三节Azure OpenAI Chat

由 ChatGPT 提供支持的 Azure OpenAI 产品超越了传统的 OpenAI 功能,提供具有增强功能的人工智能驱动的文本生成。Azure 还提供更多的人工智能安全和负责任的人工智能功能,最近的更新中重点介绍了这些功能。
Azure 为 Java 开发人员提供了充分发挥人工智能潜力的机会,将其与一系列 Azure 服务集成,其中包括与人工智能相关的资源,如 Azure 上的矢量存储。

先决条件

从 Azure 门户上的 Azure OpenAI 服务部分获取 Azure OpenAI 端点和 api-key。Spring AI 定义了一个名为 spring.ai.azure.openai.api-key 的配置属性,应将其设置为从 Azure 获取的 API 密钥的值。还有一个名为 spring.ai.azure.openai.endpoint 的配置属性,应将其设置为在 Azure 中配置模型时获得的端点 URL。导出环境变量是设置这些配置属性的一种方法:

export SPRING_AI_AZURE_OPENAI_API_KEY=<INSERT KEY HERE>
export SPRING_AI_AZURE_OPENAI_ENDPOINT=<INSERT ENDPOINT URL HERE>

部署名称

要使用运行 Azure AI 应用程序,请通过 [Azure AI 门户](oai.azure.com/portal) 创建 Azure AI 部署。

在 Azure 中,每个客户端必须指定一个部署名称才能连接到 Azure OpenAI 服务。

必须明白,部署名称与您选择部署的模型是不同的。

例如,名为 "MyAiDeployment "的部署可以配置为使用 GPT 3.5 Turbo 模型或 GPT 4.0 模型。

现在,为了保持简单,可以使用以下设置创建部署:

部署名称:gpt-35-turbo 型号名称:gpt-35-turbo

此 Azure 配置将与 Spring Boot Azure AI Starter 及其自动配置功能的默认配置保持一致。

如果使用不同的部署名称,请相应更新配置属性:

spring.ai.azure.openai.chat.options.deployment-name=<my deployment name>

Azure OpenAI 和 OpenAI 的部署结构不同,因此 Azure OpenAI 客户端库中有一个名为 deploymentOrModelName 的属性。这是因为在 OpenAI 中没有部署名称,只有模型名称。

注意:属性 spring.ai.azure.openai.chat.options.model 已更名为 spring.ai.azure.openai.chat.options.eployment-name。

添加资源库和 BOM

Spring AI 工件发布在 Spring Milestone 和 Snapshot 资源库中。请参阅 "资源库 "部分,将这些资源库添加到您的构建系统中。

为了帮助进行依赖性管理,Spring AI 提供了一个 BOM(物料清单),以确保在整个项目中使用一致的 Spring AI 版本。请参阅 "依赖关系管理 "部分,将 Spring AI BOM 添加到构建系统中。

自动配置

Spring AI 为 Azure OpenAI 聊天客户端提供 Spring Boot 自动配置功能。要启用它,请在项目的 Maven pom.xml 文件中添加以下依赖项:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
</dependency>

或 Gradle build.gradle 构建文件。

dependencies {
    implementation 'org.springframework.ai:spring-ai-azure-openai-spring-boot-starter'
}

请参阅 "依赖关系管理 "部分,将 Spring AI BOM 添加到构建文件中。

聊天属性

前缀 spring.ai.azure.openai 是配置与 Azure OpenAI 连接的属性前缀。

PropertyDescriptionDefault

spring.ai.azure.openai.api-key

资源管理 "下的 "Azure AI OpenAI 密钥和端点 "部分中的密钥

-

spring.ai.azure.openai.endpoint

端点来自资源管理下的 Azure AI OpenAI 密钥和端点部分

-

前缀 spring.ai.azure.openai.chat 是为 Azure OpenAI 配置 ChatModel 实现的属性前缀。

PropertyDescriptionDefault

spring.ai.azure.openai.chat.enabled

启用 Azure OpenAI 聊天模型。

true

spring.ai.azure.openai.chat.options.deployment-name

* 在与 Azure 一起使用时,这指的是模型的 "部署名称",您可以在 oai.azure.com/portal 中找到该名称。需要注意的是,在 Azure OpenAI 部署中,"部署名称 "不同于模型本身。造成这些术语混淆的原因是,Azure OpenAI 客户端库要与原始 OpenAI 端点兼容。Azure OpenAI 提供的部署结构与 Sam Altman 的 OpenAI 有很大不同。作为本完成请求的一部分提供的部署模型名称。

gpt-35-turbo

spring.ai.azure.openai.chat.options.maxTokens

要生成的token的最大数量。

-

spring.ai.azure.openai.chat.options.temperature

采样温度,用于控制生成的补间明显的创造性。取值越高,输出结果越随机,取值越低,结果越集中和确定。不建议针对同一个补全请求修改温度和 top_p,因为这两个设置之间的相互作用很难预测。

0.7

spring.ai.azure.openai.chat.options.topP

温度采样的另一种方法称为核采样。该值会使模型考虑具有所提供概率质量的标记的结果。

-

spring.ai.azure.openai.chat.options.logitBias

GPT 标记 ID 和偏差分数之间的映射,可影响特定标记在完成响应中出现的概率。令牌 ID 是通过外部令牌生成器工具计算的,而偏差分数的范围是 -100 到 100,最小值和最大值分别对应于完全禁止或完全选择令牌。给定偏差分数的具体行为因模型而异。

-

spring.ai.azure.openai.chat.options.user

操作的呼叫方或最终用户的标识符。可用于跟踪或限制速率。

-

spring.ai.azure.openai.chat.options.n

聊天完成回复应生成的聊天完成选择数量。

-

spring.ai.azure.openai.chat.options.stop

文本序列集合,用于结束补全生成。

-

spring.ai.azure.openai.chat.options.presencePenalty

一个值,用于根据生成文本中已存在的标记影响生成标记出现的概率。正值会降低已经存在的标记出现的可能性,并增加模型输出新主题的可能性。

-

spring.ai.azure.openai.chat.options.responseFormat

指定模型必须输出的格式的对象。使用 AzureOpenAiResponseFormat.JSON 可启用 JSON 模式,保证模型生成的信息是有效的 JSON。使用 AzureOpenAiResponseFormat.TEXT 可启用 TEXT 模式。

-

spring.ai.azure.openai.chat.options.frequencyPenalty

根据生成文本中的累积频率影响生成标记出现概率的值。正值会随着词块出现频率的增加而降低其出现概率,并降低模型逐字重复相同语句的可能性。

-

所有以 spring.ai.azure.openai.chat.options 为前缀的属性都可以通过在提示调用中添加特定于请求的运行时选项在运行时重写。

运行时选项

AzureOpenAiChatOptions.java提供了模型配置,如要使用的模型、温度、频率惩罚等。
启动时,可使用 AzureOpenAiChatModel(api, options) 构造函数或 spring.ai.azure.openai.chat.options.* 属性配置默认选项。
在运行时,您可以通过向提示调用添加新的、特定于请求的选项来覆盖默认选项。例如,覆盖特定请求的默认模型和温度: 

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the names of 5 famous pirates.",
        AzureOpenAiChatOptions.builder()
            .withModel("gpt-4-32k")
            .withTemperature(0.4)
        .build()
    ));

提示:除了特定于模型的 AzureOpenAiChatOptions.java 之外,您还可以使用通过 ChatOptionsBuilder#builder() 创建的便携式 ChatOptions 实例。

功能调用

您可以向 AzureOpenAiChatModel 注册自定义 Java 函数,然后让模型智能地选择输出包含参数的 JSON 对象,以调用一个或多个已注册函数。这是一种将 LLM 功能与外部工具和 API 相连接的强大技术。了解有关 Azure OpenAI 函数调用的更多信息。

示例Controller

创建一个新的 Spring Boot 项目,并将 spring-ai-azure-openai-spring-boot-starter 添加到你的 pom(或 gradle)依赖项中。
在 src/main/resources 目录下添加 application.properties 文件,以启用和配置 OpenAi 聊天模型:

spring.ai.azure.openai.api-key=YOUR_API_KEY
spring.ai.azure.openai.endpoint=YOUR_ENDPOINT
spring.ai.azure.openai.chat.options.deployment-name=gpt-35-turbo
spring.ai.azure.openai.chat.options.temperature=0.7

将 api-key 和端点替换为您的 Azure OpenAI 凭据。

这将创建一个 AzureOpenAiChatModel 实现,您可以将其注入到您的类中。下面是一个使用聊天模型生成文本的简单 @Controller 类的示例。

@RestController
public class ChatController {

    private final AzureOpenAiChatModel chatModel;

    @Autowired
    public ChatController(AzureOpenAiChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/ai/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
	public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return chatModel.stream(prompt);
    }
}

手动配置

AzureOpenAiChatModel 实现了 ChatModel 和 StreamingChatModel,并使用了 Azure OpenAI Java 客户端。
要启用它,请在项目的 Maven pom.xml 文件中添加 spring-ai-azure-openai 依赖关系:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-azure-openai</artifactId>
</dependency>

或 Gradle build.gradle 构建文件。

dependencies {
    implementation 'org.springframework.ai:spring-ai-azure-openai'
}

请参阅 "依赖关系管理 "部分,将 Spring AI BOM 添加到构建文件中。

spring-ai-azure-openai 依赖关系还提供对 AzureOpenAiChatModel 的访问。有关AzureOpenAiChatModel 的更多信息,请参阅 Azure OpenAI Chat 部分。

接下来,创建 AzureOpenAiChatModel 实例并使用它生成文本回复:

var openAIClient = new OpenAIClientBuilder()
  .credential(new AzureKeyCredential(System.getenv("AZURE_OPENAI_API_KEY")))
  .endpoint(System.getenv("AZURE_OPENAI_ENDPOINT"))
  .buildClient();

var openAIChatOptions = AzureOpenAiChatOptions.builder()
  .withDeploymentName("gpt-35-turbo")
  .withTemperature(0.4f)
  .withMaxTokens(200)
  .build();

var chatModel = new AzureOpenAiChatModel(openAIClient, openAIChatOptions);

ChatResponse response = chatModel.call(
  new Prompt("生成 5 个著名海盗的名字。"));

// Or with streaming responses
Flux<ChatResponse> response = chatModel.stream(
  new Prompt("生成 5 个著名海盗的名字。"));

gpt-35-turbo 实际上是 Azure AI 门户中显示的部署名称。


Azure OpenAI 函数调用

通过函数调用,开发人员可以在代码中创建函数描述,然后在请求中将该描述传递给语言模型。模型的响应包括符合描述的函数名称以及调用该函数的参数。

您可以向 AzureOpenAiChatModel 注册自定义 Java 函数,然后让模型智能地选择输出一个包含参数的 JSON 对象,以调用一个或多个已注册函数。这样就可以将 LLM 功能与外部工具和 API 相连接。Azure 模型经过训练,可以检测函数何时应被调用,并使用符合函数签名的 JSON 作出响应。

并行函数调用仅支持 gpt-35-turbo (1106) 和 gpt-4 (1106-preview) (也称为 GPT-4 Turbo Preview)。

Azure OpenAI API 不会直接调用函数;相反,模型会生成 JSON,您可以用它在代码中调用函数,并将结果返回给模型以完成对话。

Spring AI 提供了灵活、用户友好的注册和调用自定义函数的方法。一般来说,自定义函数需要提供函数名称、描述和函数调用签名(作为 JSON 模式),以便让模型知道函数期望使用哪些参数。描述有助于模型了解何时调用函数。

作为开发人员,您需要实现一个函数,接收人工智能模型发送的函数调用参数,并将结果反馈给模型。您的函数可以反过来调用其他第三方服务来提供结果。

Spring AI 将此变得非常简单,只需定义一个 @Bean 定义,返回一个 java.util.Function 并在调用 ChatModel 时提供 bean 名称作为选项即可。

在引擎盖下,Spring 会用适当的适配器代码封装您的 POJO(函数),从而实现与 AI 模型的交互,使您无需编写繁琐的模板代码。底层基础架构的基础是 FunctionCallback.java 接口和配套的 FunctionCallbackWrapper.java 实用程序类,用于简化 Java 回调函数的实现和注册。

工作原理

假设我们想让人工智能模型回应它所不具备的信息,例如某个地点的当前温度。
我们可以向人工智能模型提供有关我们自身功能的元数据,让它在处理您的提示时可以用来检索这些信息。

例如,如果在处理提示时,人工智能模型确定它需要有关给定地点温度的额外信息,它就会启动服务器端生成的请求/响应交互。人工智能模型会调用客户端函数。AI 模型以 JSON 格式提供方法调用细节,客户端负责执行该函数并返回响应。

Spring AI 大大简化了为支持函数调用而编写的代码。它为您提供函数调用对话的中介。您只需以 @Bean 的形式提供函数定义,然后在提示选项中提供函数的 Bean 名称即可。您还可以在提示中引用多个函数 Bean 名称。

快速入门

让我们创建一个聊天机器人,通过调用我们自己的函数来回答问题。为了支持聊天机器人的回复,我们将注册我们自己的函数,该函数接收一个地点并返回该地点的当前天气。
当需要回答诸如 "波士顿的天气如何?"这样的问题时,人工智能模型将调用客户端,提供位置值作为参数传递给函数。这种类似 RPC 的数据以 JSON 格式传递。
我们的函数可以使用基于 SaaS 的天气服务 API,并将天气响应返回给模型,以完成对话。在本示例中,我们将使用一个名为 MockWeatherService 的简单实现,对不同地点的温度进行硬编码。
下面的 MockWeatherService.java 表示天气服务 API:

public class MockWeatherService implements Function<Request, Response> {

	public enum Unit { C, F }
	public record Request(String location, Unit unit) {}
	public record Response(double temp, Unit unit) {}

	public Response apply(Request request) {
		return new Response(30.0, Unit.C);
	}
}

将函数注册为 Bean

通过 AzureOpenAiChatModelAuto-Configuration,您可以使用多种方法在 Spring 上下文中将自定义函数注册为 Bean。
我们首先介绍对 POJO 最友好的选项。

普通 Java 函数

在这种方法中,您可以在应用程序上下文中定义 @Beans,就像定义其他 Spring 托管对象一样。
在内部,Spring AI ChatModel 会创建一个 FunctionCallbackWrapper 封装器实例,该封装器会添加通过 AI 模型调用的逻辑。@Bean 的名称将作为 ChatOption 传递。

@Configuration
static class Config {

	@Bean
	@Description("Get the weather in location") // function description
	public Function<MockWeatherService.Request, MockWeatherService.Response> weatherFunction1() {
		return new MockWeatherService();
	}
	...
}

@Description 注解是可选的,它提供了一个函数描述 (2),帮助模型理解何时调用函数。这是一个需要设置的重要属性,可帮助人工智能模型确定要调用的客户端函数。
另一种提供函数说明的方法是在 MockWeatherService.Request 上使用 @JsonClassDescription 注解来提供函数说明:

@Configuration
static class Config {
@Bean
public Function<Request, Response> currentWeather3() { // (1) Bean 名称作为函数名称。
return new MockWeatherService();
}
...
}
@JsonClassDescription("Get the weather in location") // (2) 函数描述
public record Request(String location, Unit unit) {}

最佳做法是为请求对象注释信息,使生成的函数 JSON 模式尽可能具有描述性,以帮助人工智能模型选择要调用的正确函数。
FunctionCallWithFunctionBeanIT.java 演示了这种方法。

函数回调包装器

注册函数的另一种方法是创建一个 FunctionCallbackWrapper 封装器,如下所示:

@Configuration
static class Config {

	@Bean
	public FunctionCallback weatherFunctionInfo() {

		return FunctionCallbackWrapper.builder(new MockWeatherService())
			.withName("CurrentWeather") // (1) function name
			.withDescription("Get the current weather in a given location") // (2) function description
			.build();
	}
	...
}

它封装了第三方 MockWeatherService 函数,将其注册为 AzureAiChatModel 的 CurrentWeather 函数,并提供了说明 (2)。

默认响应转换器会对响应对象进行 JSON 序列化。

FunctionCallbackWrapper 会根据 MockWeatherService.Request 类在内部解析函数调用签名,并在内部生成函数调用的 JSON 模式。

在聊天选项中指定函数

要让模型知道并调用您的 CurrentWeather 功能,您需要在提示请求中启用该功能:

AzureOpenAiChatModel chatModel = ...

UserMessage userMessage = new UserMessage("What's the weather like in San Francisco, Tokyo, and Paris?");

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
		AzureOpenAiChatOptions.builder().withFunction("CurrentWeather").build())); // (1) Enable the function

logger.info("Response: {}", response);

上述用户问题将触发对 CurrentWeather 函数的 3 次调用(每个城市一次),最终响应将类似于下面这样:

Here is the current weather for the requested cities:
- San Francisco, CA: 30.0°C
- Tokyo, Japan: 10.0°C
- Paris, France: 15.0°C

FunctionCallWithFunctionWrapperIT.java 测试演示了这种方法。

使用提示选项注册/调用函数
除了自动配置外,您还可以通过 Prompt 请求动态注册回调函数:

AzureOpenAiChatModel chatModel = ...

UserMessage userMessage = new UserMessage("What's the weather like in San Francisco, Tokyo, and Paris?  Use Multi-turn function calling.");

var promptOptions = AzureOpenAiChatOptions.builder()
	.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
		.withName("CurrentWeather")
		.withDescription("Get the weather in location")
		.build()))
	.build();

ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), promptOptions));

在该请求的持续时间内,提示中注册的功能默认为启用。

这种方法允许根据用户输入动态选择要调用的不同函数。

FunctionCallWithPromptFunctionIT.java 集成测试提供了一个完整示例,说明如何使用 AzureOpenAiChatModel 注册函数并在提示请求中使用该函数。

下节:Spring AI 第二讲 之 Chat Model API 第四节Amazon Bedrock

代码演示后期补充

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值