ChatClient提供了fluent API用于与AI模型进行通信,支持同步和流式编程模型。
- 创建ChatClient的两种方式:
- builder:ChatClient.Builder builder = ChatClient.builder(myChatModel).build();允许对ChatClient进行详细地定制,包括可以设置系统prompt和用户prompt以及一些其他的选项等等。
- create:ChatClient chatClient = ChatClient.create(myChatModel); 简化版的快捷创建方法,适合不需要太多自定义的情况。
注:Fluent API 是一种面向对象的 API 设计风格,它通过方法链(method chaining)的方式让代码更易读、更流畅地表达逻辑。
- ChatClient fluent API 允许使用三种不同的方法创建prompt:
- Prompt():没有参数,使用fluent API构建完整的提示。 例如:
String response = chatClient.prompt() .system("You are a helpful assistant.") .user("Explain quantum computing in simple terms.") .call() .content();
- prompt(Prompt prompt):接收一个完整的prompt,用于已经有一个构造好的prompt对象的场景。
- prompt(String content):只传入用户输入,不需要其他高级功能,用于快速构建简单的prompt
- ChatClient API提供了多种使用流畅 API 格式化 AI 模型响应的方法。
- ChatResponse:包含响应生成相关的元数据,包括token数量,结束的原因,返回来的实际数据等等。
- Entity:将AI模型的返回数据封装成想要的实体,需要传入实体的类。 例如:
ActorFilms actorFilms = chatClient.prompt() .user("Generate the filmography for a random actor.") .call() .entity(EntityClass.class);
- Stream:使用stream()方法可以获得异步响应,这里我觉得并非是一种实际的格式,只是一种数据返回的形式。
- Prompt Templates:ChatClient fluent API允许提供用户和系统文本作为模板,并在运行时替换变量。 例如:
String answer = ChatClient.create(chatModel).prompt()
.user(u -> u
.text("Tell me the names of 5 movies whose soundtrack was composed by {composer}")
.param("composer", "John Williams"))
.call()
.content();
- 返回值:
- String content:返回的是AI模型实际响应的字符串 例如:
String result = chatClient.prompt() .user("What is the capital of France?") .call() .content(); System.out.println(result); // 输出类似:"The capital of France is Paris."
- Entity:返回的是你给出的实体类的一个实体对象
- ChatResponse:ChatResponse对象,包含更多的元信息
ChatResponse response = chatClient.prompt() .user("Explain quantum computing in simple terms.") .call() .chatResponse();
- ChatClientResponse:这是最全面的响应对象,不仅包含 ChatResponse,还包含整个请求执行过程中的一些附加信息(如 RAG 中检索到的文档) 注:这种返回类型虽然SpringAI框架文档中提到了,但是在我用1.0.0-M6中没有这个返回方法。
- 上述所说的返回值是call()方法的返回值,stream流式请求同理,但是stream没有提到Entity返回方法。
- ChatClient中的一些默认值设置
- 默认的system text:在构建chatClient的时候设置默认system text(像一个“角色设定”或“人格模板”,在每次对话中都会被 AI 使用,决定它的语气、风格和行为方式。) 例如:
@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(); } }
- defaultFunction(String name, String description, java.util.function.Function<I, O> function):这个方法允许在 Java 应用中定义一个“外部函数”,然后把这个函数的能力告诉 AI 模型。这样,当用户输入需要调用这个函数时,AI 模型会自动识别并调用它。
- defaultOptions(ChatOptions chatOptions):传入ChatOptions类中定义的可移植选项或模型特定的选项例如 OpenAiChatOptions。
- defaultFunctions(String… functionNames):应用程序上下文中定义的
java.util.Function
的 bean 名称。
- Advisors:Advisor是SpringAI提供的一种拦截机制,可以在请求前对请求进行处理,或者请求后对结果进行处理。
- 常用场景包括:
- 添加对话历史(让模型记住上下文)
- 插入外部数据(如文档、数据库内容)——这是 RAG 的核心
- 修改系统提示词
- 记录日志、统计 token 使用等
Advisor配置接口AdvisorSpec:
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 实现类
- MessageChatMemoryAdvisor
- 将记忆作为一组 Message(角色+内容)插入到 prompt 中。
- 适合保留完整的对话结构(用户说的、AI 回答的)。
- PromptChatMemoryAdvisor
- 把记忆内容插入到系统提示词(system message)中。
- 适用于只需要简单摘要式历史的情况。
- QuestionAnswerAdvisor
- 结合 VectorStore 使用,实现 RAG(Retrieval-Augmented Generation)。
- 根据用户问题检索相关文档并插入 prompt。
Advisor示例:
@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), // RAG
new SimpleLoggerAdvisor() // LOGGING
)
.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();
}
}