Spring AI Chat Client provides a fluent API for building AI-powered applications with LLMs, supporting advisors, streaming, structured outputs, and conversation memory
Advisors are interceptors that modify requests and responses in a chain-of-responsibility pattern.
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(SimpleLoggerAdvisor.builder().build())
.build();import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
SafeGuardAdvisor safeguard = SafeGuardAdvisor.builder()
.sensitiveWords(List.of("password", "secret"))
.failureResponse("Request blocked for security.")
.build();
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(safeguard)
.build();import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
ChatMemory chatMemory = new InMemoryChatMemory();
MessageChatMemoryAdvisor memoryAdvisor =
MessageChatMemoryAdvisor.builder(chatMemory)
.conversationId("user-123")
.build();
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(memoryAdvisor)
.build();import org.springframework.ai.chat.client.advisor.StructuredOutputValidationAdvisor;
StructuredOutputValidationAdvisor validator =
StructuredOutputValidationAdvisor.builder()
.outputType(Person.class)
.maxRepeatAttempts(3)
.build();
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(validator)
.build();Advisors execute in order (lower values first):
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(
SafeGuardAdvisor.builder().order(100).build(), // First
MessageChatMemoryAdvisor.builder(chatMemory)
.order(1001).build(), // Second
SimpleLoggerAdvisor.builder()
.order(Ordered.LOWEST_PRECEDENCE).build() // Last
)
.build();Standard Order Values:
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
class TimingAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(
ChatClientRequest request,
CallAdvisorChain chain
) {
long start = System.currentTimeMillis();
ChatClientResponse response = chain.nextCall(request);
long duration = System.currentTimeMillis() - start;
System.out.println("Request took: " + duration + "ms");
return response;
}
@Override
public String getName() {
return "TimingAdvisor";
}
@Override
public int getOrder() {
return 0;
}
}import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
class MetadataAdvisor implements BaseAdvisor {
@Override
public ChatClientRequest before(
ChatClientRequest request,
AdvisorChain chain
) {
request.context().put("requestId", UUID.randomUUID().toString());
request.context().put("timestamp", System.currentTimeMillis());
return request;
}
@Override
public ChatClientResponse after(
ChatClientResponse response,
AdvisorChain chain
) {
long duration = System.currentTimeMillis() -
(long) response.context().get("timestamp");
response.context().put("duration", duration);
return response;
}
@Override
public String getName() {
return "MetadataAdvisor";
}
@Override
public int getOrder() {
return 100;
}
}Override default advisors for specific requests:
// Default advisors
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(advisor1, advisor2)
.build();
// Override for this request
String response = client
.prompt("Query")
.advisors(advisor3, advisor4) // Replaces defaults
.call()
.content();Pass parameters to advisors at request time:
chatClient
.prompt("Continue conversation")
.advisors(spec -> spec
.advisors(memoryAdvisor)
.param("conversationId", "user-123")
.param("maxHistory", 10)
)
.call()
.content();Advisors share data through context maps:
class FirstAdvisor implements BaseAdvisor {
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
request.context().put("myData", "value");
return request;
}
// ...
}
class SecondAdvisor implements BaseAdvisor {
@Override
public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
String data = (String) request.context().get("myData");
// Use data
return request;
}
// ...
}