Add getting-started module: ChatClient fluent API, system/user prompts, streaming, and provider switching via spring.ai.model.chat
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# GET /api/chat -- ChatClient.prompt().user(...).call().content()
|
||||
|
||||
$ curl 'http://localhost:34201/api/chat?message=What+package+is+ChatClient+in?'
|
||||
|
||||
You said: "What package is ChatClient in?". That is 30 characters.
|
||||
@@ -0,0 +1,9 @@
|
||||
# GET /api/chat/as -- a templated system prompt, filled via .param("voice", ...)
|
||||
|
||||
$ curl 'http://localhost:34201/api/chat/as?voice=pirate&message=Where+is+my+jar+cached'
|
||||
|
||||
Response body:
|
||||
As a pirate: Where is my jar cached -- yes, and it is exactly 22 characters long.
|
||||
|
||||
Exact text FakeChatModel received (proves the {voice} placeholder was substituted by ChatClient before the ChatModel ever saw the prompt):
|
||||
Answer in the voice of a pirate, still in two sentences.Where is my jar cached
|
||||
@@ -0,0 +1,6 @@
|
||||
# GET /api/chat/stream -- ChatClient.prompt().user(...).stream().content()
|
||||
|
||||
$ curl -N 'http://localhost:34201/api/chat/stream?message=Stream+this'
|
||||
|
||||
Chunks received: 1
|
||||
Joined: You said: "Stream this". That is 11 characters.
|
||||
@@ -0,0 +1,4 @@
|
||||
# Which ChatModel class spring.ai.model.chat selects
|
||||
|
||||
spring.ai.model.chat=openai -> org.springframework.ai.openai.OpenAiChatModel
|
||||
spring.ai.model.chat=ollama -> org.springframework.ai.ollama.OllamaChatModel
|
||||
@@ -0,0 +1,26 @@
|
||||
# A real HTTP round trip to OpenAI (not scripted) -- captured manually, not by run-all.sh
|
||||
|
||||
This one is not reproducible by scripts/run-all.sh: it needs a live network path to
|
||||
api.openai.com, which the automated test suite deliberately does not depend on (see
|
||||
ChatClientEndpointsTest, which uses FakeChatModel instead). It is included because it is the
|
||||
one exhibit in this module that touches a real provider, and it proves the request pipeline
|
||||
-- ChatClient, the OpenAiChatModel bean spring.ai.model.chat=openai selected, and the OpenAI
|
||||
Java SDK underneath it -- is wired correctly all the way to OpenAI's own server, not just to
|
||||
a stub.
|
||||
|
||||
Command (full application, spring-boot:run, a syntactically valid but fake key):
|
||||
|
||||
$ export OPENAI_API_KEY=sk-test-placeholder-not-a-real-key
|
||||
$ curl 'http://localhost:8080/api/chat?message=hi'
|
||||
|
||||
Response: HTTP 500, body in 05-real-openai-401-response-body.txt
|
||||
|
||||
Application log root cause (grepped from the running process's stdout):
|
||||
|
||||
com.openai.errors.UnauthorizedException: 401: Incorrect API key provided: sk-test-**********************-key. You can find your API key at https://platform.openai.com/account/api-keys.
|
||||
|
||||
That 401 comes from OpenAI's own server, not from Spring AI or from this sandbox -- OpenAI
|
||||
validated the key format, rejected it, and said so in its own error class
|
||||
(com.openai.errors.UnauthorizedException). A malformed request, a wrong base URL, or a client
|
||||
that never left the JVM would not look like this. Swap in a real key and this becomes a real
|
||||
reply.
|
||||
@@ -0,0 +1 @@
|
||||
{"timestamp":"2026-09-23T03:53:37.888Z","status":500,"error":"Internal Server Error","path":"/api/chat"}
|
||||
@@ -0,0 +1,12 @@
|
||||
# The original surefire failure that led to overriding FakeChatModel.stream()
|
||||
|
||||
Captured from `mvn -B -o test` before FakeChatModel had a stream() override -- ChatModel's own
|
||||
default implementation was assumed (wrongly) to wrap call() in a single-element Flux. Trimmed to
|
||||
the relevant frames; jar version suffixes kept exactly as printed.
|
||||
|
||||
2026-09-23T03:50:42.884Z ERROR 1145 --- [getting-started] [o-auto-1-exec-3] o.s.ai.chat.model.MessageAggregator : Aggregation Error
|
||||
|
||||
java.lang.UnsupportedOperationException: streaming is not supported
|
||||
at org.springframework.ai.chat.model.ChatModel.stream(ChatModel.java:65) ~[spring-ai-model-2.0.1.jar:2.0.1]
|
||||
at org.springframework.ai.chat.client.advisor.ChatModelStreamAdvisor.adviseStream(ChatModelStreamAdvisor.java:53) ~[spring-ai-client-chat-2.0.1.jar:2.0.1]
|
||||
at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.lambda$nextStream$5(DefaultAroundAdvisorChain.java:158) ~[spring-ai-client-chat-2.0.1.jar:2.0.1]
|
||||
Reference in New Issue
Block a user