赞
踩
ChatClient 提供了与人工智能模型通信的流畅 API。它同时支持同步和反应编程模型。
流畅的应用程序接口(API)提供了一些方法,用于构建作为输入传递给人工智能模型的 "提示"(Prompt)的各个组成部分。提示包含指导人工智能模型输出和行为的指示文本。从应用程序接口的角度来看,提示由一系列信息组成。
人工智能模型主要处理两类信息:用户信息和系统信息,前者是用户的直接输入,后者则由系统生成,用于引导对话。
这些信息通常包含占位符,在运行时根据用户输入进行替换,以定制人工智能模型对用户输入的响应。
此外,还可以指定提示选项,如要使用的人工智能模型名称和控制生成输出的随机性或创造性的温度设置。
ChatClient 是使用 ChatClient.Builder 对象创建的。您可以为任何 ChatModel Spring Boot 自动配置获取一个自动配置的 ChatClient.Builder 实例,也可以通过编程创建一个。
在最简单的使用案例中,Spring AI 提供了 Spring Boot 自动配置功能,创建了一个 ChatClient.Builder Bean 原型,供您注入到您的类中。下面是一个对简单用户请求检索字符串响应的简单示例。
- @RestController
- public class MyController {
-
- private final ChatClient chatClient;
-
- public MyController(ChatClient.Builder chatClientBuilder) {
- this.chatClient = chatClientBuilder.build();
- }
-
- @GetMapping("/ai")
- String generation(String userInput) {
- return this.chatClient.prompt()
- .user(userInput)
- .call()
- .content();
- }
- }

在这个简单的例子中,用户输入设置了用户信息的内容。调用方法向人工智能模型发送请求,而上下文方法则以字符串形式返回人工智能模型的响应。
通过设置属性 spring.ai.chat.client.enabled=false,可以禁用 ChatClient.Builder 自动配置。如果同时使用多个聊天模型,这将非常有用。然后以编程方式为每个 ChatModel 创建一个 ChatClient.Builder 实例:
- ChatModel myChatModel = ... // usually autowired
-
- ChatClient.Builder builder = ChatClient.builder(myChatModel);
-
- // or create a ChatClient with the default builder settings:
-
- ChatClient chatClient = ChatClient.create(myChatModel);
ChatClient API 提供了几种格式化 AI 模型响应的方法。
人工智能模型的响应是一种丰富的结构,由 ChatResponse 类型定义。它包括关于如何生成回复的元数据,也可以包含多个回复,即所谓的 "代",每个 "代 "都有自己的元数据。元数据包括用于创建回复的标记数(每个标记约为一个单词的 3/4)。这一信息非常重要,因为托管人工智能模型是根据每个请求所使用的标记数来收费的。
下面是在 call() 方法后调用 chatResponse() 返回包含元数据的 ChatResponse 对象的示例。
- ChatResponse chatResponse = chatClient.prompt()
- .user("Tell me a joke")
- .call()
- .chatResponse();
您经常希望返回一个实体类,该实体类由返回的字符串映射而成。实体方法提供了这种功能。
例如,给定 Java record:
- record ActorFilms(String actor, List<String> movies) {
- }
您可以使用实体方法轻松地将人工智能模型的输出映射到该记录,如下所示:
- ActorFilms actorFilms = chatClient.prompt()
- .user("Generate the filmography for a random actor.")
- .call()
- .entity(ActorFilms.class);
还有一个重载的实体方法,其签名为 entity(ParameterizedTypeReference<T> type),可让您指定通用列表等类型:
- List<ActorFilms> actorFilms = chatClient.prompt()
- .user("Generate the filmography of 5 movies for Tom Hanks and Bill Murray.")
- .call()
- .entity(new ParameterizedTypeReference<List<ActorsFilms>>() {
- });
流可让您获得异步响应,如下所示(目前市面上都采用此方法:前后端交互【见下期案例】)
- Flux<String> output = chatClient.prompt()
- .user("Tell me a joke")
- .stream()
- .content();
您还可以使用 Flux<ChatResponse> chatResponse() 方法流式传输 ChatResponse。
在 1.0.0 M2 版本中,我们将提供一种方便的方法,让您使用反应式 stream() 方法返回 Java 实体。与此同时,您应该使用结构化输出转换器来转换聚合响应,如下图所示。这也演示了流畅 API 中参数的使用,我们将在后面的文档中详细讨论。
- var converter = new BeanOutputConverter<>(new ParameterizedTypeReference<List<ActorsFilms>>() {
- });
-
- Flux<String> flux = this.chatClient.prompt()
- .user(u -> u.text("""
- Generate the filmography for a random actor.
- {format}
- """)
- .param("format", converter.getFormat()))
- .stream()
- .content();
-
- String content = flux.collectList().block().stream().collect(Collectors.joining());
-
- List<ActorFilms> actorFilms = converter.convert(content);
在指定 ChatClient 的调用方法后,有几种不同的响应类型可供选择。
您还可以调用流方法,而不是调用和
在 ChatClient 上指定流方法后,有几个响应类型选项:
在 @Configuration 类中创建带有默认系统文本的 ChatClient 可简化运行时代码。通过设置默认值,您只需在调用 ChatClient 时指定用户文本,而无需在运行时代码路径中为每个请求设置系统文本。
在下面的示例中,我们将配置系统文本始终以海盗的声音回复。为了避免在运行时代码中重复系统文本,我们将在 @Configuration 类中创建一个 ChatClient 实例。
- @Configuration
- class Config {
-
- @Bean
- ChatClient chatClient(ChatClient.Builder builder) {
- return builder.defaultSystem("You are a friendly chat bot that answers question in the voice of a Pirate")
- .build();
- }
-
- }
和调用它的 @RestController
- @RestController
- class AIController {
-
- private final ChatClient chatClient;
-
- AIController(ChatClient chatClient) {
- this.chatClient = chatClient;
- }
-
- @GetMapping("/ai/simple")
- public Map<String, String> completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
- return Map.of("completion", chatClient.prompt().user(message).call().content());
- }
- }
通过 curl 调用它,可以得到
- ❯ curl localhost:8080/ai/simple
- {"generation":"Why did the pirate go to the comedy club? To hear some arrr-rated jokes! Arrr, matey!"}
在下面的示例中,我们将在系统文本中使用占位符,在运行时而不是设计时指定完成的语音。
- @Configuration
- class Config {
-
- @Bean
- ChatClient chatClient(ChatClient.Builder builder) {
- return builder.defaultSystem("You are a friendly chat bot that answers question in the voice of a {voice}")
- .build();
- }
-
- }
- @RestController
- class AIController {
- private final ChatClient chatClient
- AIController(ChatClient chatClient) {
- this.chatClient = chatClient;
- }
- @GetMapping("/ai")
- Map<String, String> completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message, String voice) {
- return Map.of(
- "completion",
- chatClient.prompt()
- .system(sp -> sp.param("voice", voice))
- .user(message)
- .call()
- .content());
- }
- }

答复是
- http localhost:8080/ai voice=='Robert DeNiro'
- {
- "completion": "You talkin' to me? Okay, here's a joke for ya: Why couldn't the bicycle stand up by itself? Because it was two tired! Classic, right?"
- }
其他默认设置
在 ChatClient.Builder 层级,您可以指定默认提示。
您可以在运行时使用不带默认前缀的相应方法覆盖这些默认值。
在使用用户文本调用人工智能模型时,一种常见的模式是使用上下文数据附加或增强提示。
这种上下文数据可以是不同类型的。常见类型包括
向量数据库存储了人工智能模型不知道的数据。当用户向人工智能模型发送问题时,QuestionAnswerAdvisor 会查询向量数据库中与用户问题相关的文档。
向量数据库中的回复会附加到用户文本中,为人工智能模型生成回复提供上下文。
假设您已经将数据加载到向量存储中,您可以通过向聊天客户端提供一个 QuestionAnswerAdvisor 实例来执行检索增强生成(RAG)。
- ChatResponse response = ChatClient.builder(chatModel)
- .build().prompt()
- .advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()))
- .user(userText)
- .call()
- .chatResponse();
在本例中,SearchRequest.defaults() 将对矢量数据库中的所有文档执行相似性搜索。为了限制搜索的文档类型,SearchRequest 使用了类似 SQL 的过滤表达式,这种表达式可以在所有 VectorStores 中使用。
接口 ChatMemory 表示聊天对话历史记录的存储空间。它提供了向*对话添加信息、从对话中检索信息和清除对话历史记录的方法。
有一个 InMemoryChatMemory 实现可为聊天对话历史记录提供内存存储。
有两个顾问实现使用 ChatMemory 接口为提示对话历史提供建议,它们在如何将内存添加到提示对话历史的细节上有所不同
使用多个顾问的 @Service 实现示例如下所示
- @Service
- public class CustomerSupportAssistant {
-
- private final ChatClient chatClient;
-
- public CustomerSupportAssistant(ChatClient.Builder builder, VectorStore vectorStore, ChatMemory chatMemory) {
-
- this.chatClient = builderh
- .defaultSystem("""
- 您是一家名为 "Funnair "的航空公司的客户聊天支持人员、
- 乐于助人。
- 在提供预订信息或取消预订之前,您必须始终
- 从用户处获取以下信息:预订号、客户名和姓。
- 在更改预订之前,必须确保条款允许更改预订。
- 如果更改需要收费,则必须在征得用户同意后方可进行。
- """)
- .defaultAdvisors(
- new PromptChatMemoryAdvisor(chatMemory),
- // new MessageChatMemoryAdvisor(chatMemory), // CHAT MEMORY
- new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()),
- new LoggingAdvisor()) // RAG
- .defaultFunctions("getBookingDetails", "changeBooking", "cancelBooking") // FUNCTION CALLING
- .build();
- }
-
- public Flux<String> chat(String chatId, String userMessageContent) {
-
- return this.chatClient.prompt()
- .user(userMessageContent)
- .advisors(a -> a
- .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
- .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
- .stream().content();
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。