此版本仍在开发中,尚未被视为稳定版本。最新的快照版本请使用 Spring AI 1.0.0-SNAPSHOT!spring-doc.cn

聊天客户端 API

它提供了一个 Fluent API,用于与 AI 模型通信。 它支持同步和流式编程模型。ChatClientspring-doc.cn

Fluent API 具有构建 Prompt 的组成部分的方法,这些部分作为输入传递给 AI 模型。 该 包含指导 AI 模型的输出和行为的说明文本。从 API 的角度来看,提示由一组消息组成。Promptspring-doc.cn

AI 模型处理两种主要类型的消息:用户消息(来自用户的直接输入)和系统消息(由系统生成以指导对话)。spring-doc.cn

这些消息通常包含占位符,这些占位符在运行时根据用户输入进行替换,以自定义 AI 模型对用户输入的响应。spring-doc.cn

还有一些可以指定的 Prompt 选项,例如要使用的 AI 模型的名称以及控制生成输出的随机性或创造性的温度设置。spring-doc.cn

创建 ChatClient

这是使用对象创建的。 您可以为任何 ChatModel Spring Boot 自动配置获取自动配置的实例,也可以以编程方式创建一个。ChatClientChatClient.BuilderChatClient.Builderspring-doc.cn

使用自动配置的 ChatClient.Builder

在最简单的用例中, Spring AI 提供 Spring Boot 自动配置,创建一个原型 bean 供你注入到你的类中。 下面是检索对简单用户请求的响应的简单示例。ChatClient.BuilderStringspring-doc.cn

@RestController
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();
    }
}

在这个简单的示例中,用户输入设置用户消息的内容。 该方法向 AI 模型发送请求,该方法将 AI 模型的响应作为 .call()content()Stringspring-doc.cn

以编程方式创建 ChatClient

您可以通过设置属性 来禁用自动配置 。 如果同时使用多个聊天模型,这非常有用。 然后,以编程方式为每个需要创建一个实例:ChatClient.Builderspring.ai.chat.client.enabled=falseChatClient.BuilderChatModelspring-doc.cn

ChatModel myChatModel = ... // usually autowired

ChatClient.Builder builder = ChatClient.builder(this.myChatModel);

// or create a ChatClient with the default builder settings:

ChatClient chatClient = ChatClient.create(this.myChatModel);

ChatClient Fluent API

Fluent API 允许您使用重载方法以三种不同的方式创建提示,以启动 Fluent API:ChatClientpromptspring-doc.cn

  • prompt():这种不带参数的方法允许您开始使用 Fluent API,从而允许您构建 user、system 和 prompt的其他部分。spring-doc.cn

  • prompt(Prompt prompt):此方法接受一个参数,允许您传入使用 Prompt 的非 Fluent API 创建的实例。PromptPromptspring-doc.cn

  • prompt(String content):这是一种类似于前面的重载的便捷方法。它获取用户的文本内容。spring-doc.cn

ChatClient 响应

API 提供了多种使用 Fluent API 格式化 AI 模型的响应的方法。ChatClientspring-doc.cn

返回 ChatResponse

来自 AI 模型的响应是由类型定义的丰富结构。 它包括有关响应生成方式的元数据,还可以包含多个响应,称为 Generations,每个响应都有自己的元数据。 元数据包括用于创建响应的标记数(每个标记大约是一个单词的 3/4)。 此信息非常重要,因为托管 AI 模型根据每个请求使用的令牌数量收费。ChatResponsespring-doc.cn

通过在方法后调用,如下所示返回包含元数据的对象的示例。ChatResponsechatResponse()call()spring-doc.cn

ChatResponse chatResponse = chatClient.prompt()
    .user("Tell me a joke")
    .call()
    .chatResponse();

返回实体

您通常需要返回从返回的 . 该方法提供此功能。Stringentity()spring-doc.cn

例如,给定 Java 记录:spring-doc.cn

record ActorFilms(String actor, List<String> movies) {}

您可以使用该方法轻松地将 AI 模型的输出映射到此记录,如下所示:entity()spring-doc.cn

ActorFilms actorFilms = chatClient.prompt()
    .user("Generate the filmography for a random actor.")
    .call()
    .entity(ActorFilms.class);

还有一个带有签名的重载方法,允许您指定类型,例如泛型 List:entityentity(ParameterizedTypeReference<T> type)spring-doc.cn

List<ActorFilms> actorFilms = chatClient.prompt()
    .user("Generate the filmography of 5 movies for Tom Hanks and Bill Murray.")
    .call()
    .entity(new ParameterizedTypeReference<List<ActorFilms>>() {});

流式响应

该方法允许您获得异步响应,如下所示:stream()spring-doc.cn

Flux<String> output = chatClient.prompt()
    .user("Tell me a joke")
    .stream()
    .content();

您还可以使用方法 .ChatResponseFlux<ChatResponse> chatResponse()spring-doc.cn

将来,我们将提供一种便捷的方法,让您使用 reactive 方法返回 Java 实体。 同时,您应该使用 Structured Output Converter 转换聚合响应显式,如下所示。 这也演示了 Fluent API 中参数的使用,这将在文档的后面部分更详细地讨论。stream()spring-doc.cn

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", this.converter.getFormat()))
    .stream()
    .content();

String content = this.flux.collectList().block().stream().collect(Collectors.joining());

List<ActorFilms> actorFilms = this.converter.convert(this.content);

call() 返回值

指定方法 on 后,响应类型有几种不同的选项。call()ChatClientspring-doc.cn

  • String content():返回响应的 String 内容spring-doc.cn

  • ChatResponse chatResponse():返回包含多个代的对象以及有关响应的元数据,例如用于创建响应的令牌数。ChatResponsespring-doc.cn

  • entity()返回 Java 类型spring-doc.cn

    • entity(ParameterizedTypeReference<T> type):用于返回 OF 实体类型。Collectionspring-doc.cn

    • entity(Class<T> type):用于返回特定实体类型。spring-doc.cn

    • entity(StructuredOutputConverter<T> structuredOutputConverter):用于指定 a 的实例以将 a 转换为实体类型。StructuredOutputConverterStringspring-doc.cn

您还可以调用 method 而不是 .stream()call()spring-doc.cn

stream() 返回值

指定方法 on 后,响应类型有几个选项:stream()ChatClientspring-doc.cn

  • Flux<String> content():返回 AI 模型生成的字符串的 a。Fluxspring-doc.cn

  • Flux<ChatResponse> chatResponse():返回对象的 a,其中包含有关响应的其他元数据。FluxChatResponsespring-doc.cn

使用默认值

在类中创建具有默认系统文本的 a 可简化运行时代码。 通过设置默认值,您只需在调用 时指定用户文本,无需为运行时代码路径中的每个请求设置系统文本。ChatClient@ConfigurationChatClientspring-doc.cn

默认系统文本

在以下示例中,我们将系统文本配置为始终以海盗的声音回复。 为了避免在运行时代码中重复系统文本,我们将在类中创建一个实例。ChatClient@Configurationspring-doc.cn

@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();
    }

}

和 a 来调用它:@RestControllerspring-doc.cn

@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", this.chatClient.prompt().user(message).call().content());
	}
}

通过 curl 调用应用程序端点时,结果为:spring-doc.cn

❯ curl localhost:8080/ai/simple
{"completion":"Why did the pirate go to the comedy club? To hear some arrr-rated jokes! Arrr, matey!"}

带参数的默认系统文本

在以下示例中,我们将在系统文本中使用占位符来指定在运行时(而不是设计时)完成的声音。spring-doc.cn

@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",
				this.chatClient.prompt()
						.system(sp -> sp.param("voice", voice))
						.user(message)
						.call()
						.content());
	}

}

通过 httpie 调用应用程序终端节点时,结果为:spring-doc.cn

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.Builderspring-doc.cn

  • defaultOptions(ChatOptions chatOptions):传入类中定义的可移植选项或特定于模型的选项,例如 .有关特定于模型的实现的更多信息,请参阅 JavaDocs。ChatOptionsOpenAiChatOptionsChatOptionsspring-doc.cn

  • defaultFunction(String name, String description, java.util.function.Function<I, O> function):用于在用户文本中引用函数。该函数解释了函数的用途,并帮助 AI 模型选择正确的函数以实现准确响应。参数是模型将在必要时执行的 Java 函数实例。namedescriptionfunctionspring-doc.cn

  • defaultFunctions(String…​ functionNames):在应用程序上下文中定义的 'java.util.Function' 的 bean 名称。spring-doc.cn

  • defaultUser(String text)、 、 :这些方法允许您定义用户文本。允许您使用 lambda 指定用户文本和任何默认参数。defaultUser(Resource text)defaultUser(Consumer<UserSpec> userSpecConsumer)Consumer<UserSpec>spring-doc.cn

  • defaultAdvisors(Advisor…​ advisor):顾问程序允许修改用于创建 .该实现通过在 prompt 后附加与用户文本相关的上下文信息来启用模式。PromptQuestionAnswerAdvisorRetrieval Augmented Generationspring-doc.cn

  • defaultAdvisors(Consumer<AdvisorSpec> advisorSpecConsumer):此方法允许您定义 a 以使用 配置多个 advisor。顾问可以修改用于创建最终 .允许您指定一个 lambda 来添加顾问,例如 ,它支持根据用户文本在提示后附加相关上下文信息。ConsumerAdvisorSpecPromptConsumer<AdvisorSpec>QuestionAnswerAdvisorRetrieval Augmented Generationspring-doc.cn

您可以在运行时使用不带前缀的相应方法覆盖这些默认值。defaultspring-doc.cn

  • options(ChatOptions chatOptions)spring-doc.cn

  • function(String name, String description, java.util.function.Function<I, O> function)spring-doc.cn

  • functions(String…​ functionNames)spring-doc.cn

  • user(String text), ,user(Resource text)user(Consumer<UserSpec> userSpecConsumer)spring-doc.cn

  • advisors(Advisor…​ advisor)spring-doc.cn

  • advisors(Consumer<AdvisorSpec> advisorSpecConsumer)spring-doc.cn

顾问

Advisors API 提供了一种灵活而强大的方法来拦截、修改和增强 Spring 应用程序中的 AI 驱动的交互。spring-doc.cn

使用用户文本调用 AI 模型时,一种常见模式是使用上下文数据附加或增强提示。spring-doc.cn

此上下文数据可以是不同的类型。常见类型包括:spring-doc.cn

  • 您自己的数据:这是 AI 模型尚未训练的数据。即使模型看到了类似的数据,附加的上下文数据在生成响应时也优先。spring-doc.cn

  • 对话历史记录:聊天模型的 API 是无状态的。如果您告诉 AI 模型您的名字,它将在后续交互中不会记住它。必须随每个请求发送对话历史记录,以确保在生成响应时考虑以前的交互。spring-doc.cn

ChatClient 中的 Advisor 配置

ChatClient Fluent API 提供了用于配置 advisor 的接口。此接口提供了添加参数、一次设置多个参数以及将一个或多个 advisor 添加到链的方法。AdvisorSpecspring-doc.cn

interface AdvisorSpec {
    AdvisorSpec param(String k, Object v);
    AdvisorSpec params(Map<String, Object> p);
    AdvisorSpec advisors(Advisor... advisors);
    AdvisorSpec advisors(List<Advisor> advisors);
}
将 advisor 添加到链中的顺序至关重要,因为它决定了它们的执行顺序。每个 advisor 都以某种方式修改 prompt 或 context,并且一个 advisor 所做的更改将传递给链中的下一个 advisor。
ChatClient.builder(chatModel)
    .build()
    .prompt()
    .advisors(
        new MessageChatMemoryAdvisor(chatMemory),
        new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults())
    )
    .user(userText)
    .call()
    .content();

在此配置中,将首先执行 ,并将对话历史记录添加到提示符中。然后,将根据用户的问题和添加的对话历史记录执行搜索,从而可能提供更相关的结果。MessageChatMemoryAdvisorQuestionAnswerAdvisorspring-doc.cn

检索增强一代

矢量数据库存储 AI 模型不知道的数据。 将用户问题发送到 AI 模型时,a 会在向量数据库中查询与用户问题相关的文档。QuestionAnswerAdvisorspring-doc.cn

来自向量数据库的响应将附加到用户文本中,以便为 AI 模型生成响应提供上下文。spring-doc.cn

假设您已将数据加载到 中,则可以通过向 提供 来执行检索增强生成 (RAG)。VectorStoreQuestionAnswerAdvisorChatClientspring-doc.cn

ChatResponse response = ChatClient.builder(chatModel)
        .build().prompt()
        .advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()))
        .user(userText)
        .call()
        .chatResponse();

在此示例中,将对 Vector Database 中的所有文档执行相似性搜索。 为了限制搜索的文档类型,它采用一个类似 SQL 的过滤器表达式,该表达式可在所有 .SearchRequest.defaults()SearchRequestVectorStoresspring-doc.cn

动态筛选表达式

在运行时使用 advisor context 参数更新筛选条件表达式:SearchRequestFILTER_EXPRESSIONspring-doc.cn

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()))
    .build();

// Update filter expression at runtime
String content = this.chatClient.prompt()
    .user("Please answer my question XYZ")
    .advisors(a -> a.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "type == 'Spring'"))
    .call()
    .content();

该参数允许您根据提供的表达式动态筛选搜索结果。FILTER_EXPRESSIONspring-doc.cn

聊天记忆

该接口表示聊天对话历史记录的存储。它提供了向对话添加消息、从对话中检索消息以及清除对话历史记录的方法。ChatMemoryspring-doc.cn

当前有两个实现 和 ,它们分别为聊天对话历史记录提供内存中的存储,并相应地使用 持久化。InMemoryChatMemoryCassandraChatMemorytime-to-livespring-doc.cn

要创建 with :CassandraChatMemorytime-to-livespring-doc.cn

CassandraChatMemory.create(CassandraChatMemoryConfig.builder().withTimeToLive(Duration.ofDays(1)).build());

以下 advisor 实现使用接口向 Prompt 提供 conversation history 的通知,这些 conversation history 在如何将内存添加到提示的细节上有所不同ChatMemoryspring-doc.cn

  • MessageChatMemoryAdvisor:检索内存并将其作为消息集合添加到提示符中spring-doc.cn

  • PromptChatMemoryAdvisor:检索内存并将其添加到提示的系统文本中。spring-doc.cn

  • VectorStoreChatMemoryAdvisor:构造函数此构造函数允许您:VectorStoreChatMemoryAdvisor(VectorStore vectorStore, String defaultConversationId, int chatHistoryWindowSize, int order)spring-doc.cn

    1. 指定用于管理和查询文档的 VectorStore 实例。spring-doc.cn

    2. 设置在上下文中未提供任何内容时使用的默认对话 ID。spring-doc.cn

    3. 根据令牌大小定义聊天历史记录检索的窗口大小。spring-doc.cn

    4. 提供用于 Chat Advisor 系统的系统文本建议。spring-doc.cn

    5. 设置此 advisor 在链中的优先顺序。spring-doc.cn

该方法允许您指定默认对话 ID、聊天历史记录窗口大小以及要检索的聊天历史记录的顺序。VectorStoreChatMemoryAdvisor.builder()spring-doc.cn

使用多个 advisor 的示例实现如下所示。@Servicespring-doc.cn

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Service
public class CustomerSupportAssistant {

    private final ChatClient chatClient;

    public CustomerSupportAssistant(ChatClient.Builder builder, VectorStore vectorStore, ChatMemory chatMemory) {

        this.chatClient = builder
            .defaultSystem("""
                    You are a customer chat support agent of an airline named "Funnair". Respond in a friendly,
                    helpful, and joyful manner.

                    Before providing information about a booking or cancelling a booking, you MUST always
                    get the following information from the user: booking number, customer first name and last name.

                    Before changing a booking you MUST ensure it is permitted by the terms.

                    If there is a charge for the change, you MUST ask the user to consent before proceeding.
                    """)
            .defaultAdvisors(
                    new MessageChatMemoryAdvisor(chatMemory), // CHAT MEMORY
                    new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()), // RAG
                    new SimpleLoggerAdvisor())
            .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();
    }

}

Logging

它是一个 advisor,用于记录 和 的数据。 这对于调试和监控 AI 交互非常有用。SimpleLoggerAdvisorrequestresponseChatClientspring-doc.cn

Spring AI 支持 LLM 和向量存储交互的可观察性。有关更多信息,请参阅 可观测性指南 。

要启用日志记录,请在创建 ChatClient 时将 添加到 advisor 链中。 建议将其添加到链的末尾:SimpleLoggerAdvisorspring-doc.cn

ChatResponse response = ChatClient.create(chatModel).prompt()
        .advisors(new SimpleLoggerAdvisor())
        .user("Tell me a joke?")
        .call()
        .chatResponse();

要查看日志,请将 advisor 包的日志记录级别设置为:DEBUGspring-doc.cn

logging.level.org.springframework.ai.chat.client.advisor=DEBUG

将此文件添加到您的 or 文件中。application.propertiesapplication.yamlspring-doc.cn

您可以使用以下构造函数自定义 from 和 what data is logged (来自和记录的数据):AdvisedRequestChatResponsespring-doc.cn

SimpleLoggerAdvisor(
    Function<AdvisedRequest, String> requestToString,
    Function<ChatResponse, String> responseToString
)

用法示例:spring-doc.cn

SimpleLoggerAdvisor customLogger = new SimpleLoggerAdvisor(
    request -> "Custom request: " + request.userText,
    response -> "Custom response: " + response.getResult()
);

这允许您根据自己的特定需求定制记录的信息。spring-doc.cn

在生产环境中记录敏感信息时要小心。