0Pricing
Spring Boot 4 Complete Guide · Pelajaran

ChatClient, Prompt, dan Output Terstruktur

Panggil model percakapan melalui ChatClient dengan templat prompt dan pemetaan output terstruktur bertipe.

ChatClient, Prompt, dan Output Terstruktur adalah pelajaran Spring Boot 4 Complete Guide gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Spring Boot 4 Complete Guide, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Spring Boot 4 Complete Guide mencakup 4 pelajaran total.

Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.

Why ChatClient?

Spring AI gives you a fluent, high-level API for talking to LLMs: the ChatClient. Instead of hand-building HTTP requests to OpenAI, Anthropic, or Ollama, you describe what you want and let the framework handle transport, retries, and message assembly.

  • ChatClient — fluent builder for one-shot or streaming calls.
  • Prompt — a list of messages (system, user, assistant) plus options.
  • Structured output — map the model's text reply directly into a typed Java object.

It is portable: swap the underlying ChatModel (OpenAI → Anthropic) and your ChatClient code stays the same.

Auto-configuration and dependencies

Add a Spring AI model starter and Spring Boot auto-configures a ChatModel bean plus a ChatClient.Builder you can inject.

  • The starter (e.g. spring-ai-starter-model-openai) reads your API key and model from properties.
  • You never construct ChatClient directly — you inject the builder and call .build().

Typical configuration in application.yml:

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o
          temperature: 0.2

Creating a ChatClient

Inject the auto-configured ChatClient.Builder and build a client once, usually in your service constructor. You can attach default system prompts or options here so every call inherits them.

Building per-service (not per-request) keeps configuration in one place and is cheap.

@Service
public class AssistantService {

    private final ChatClient chatClient;

    public AssistantService(ChatClient.Builder builder) {
        this.chatClient = builder
            .defaultSystem("You are a concise Spring expert. Answer in one sentence.")
            .build();
    }
}

A first call: prompt().user().content()

The fluent chain reads like a sentence. Start with prompt(), add a user(...) message, then terminate with call() for a blocking response and content() to get the plain text.

  • call() — synchronous request/response.
  • content() — extracts the assistant's text.
  • chatResponse() — returns metadata (token usage, finish reason) instead.
public String ask(String question) {
    return chatClient.prompt()
        .user(question)
        .call()
        .content();
}

System vs user messages

An LLM prompt is a sequence of messages with roles:

  • System — instructions and persona; sets behavior.
  • User — the actual request from the end user.
  • Assistant — prior model replies (for multi-turn context).

You can override the default system message per call. Keep untrusted user input in user(...), never inside the system instruction, to reduce prompt-injection risk.

String answer = chatClient.prompt()
    .system("You are a senior Java reviewer. Be blunt and specific.")
    .user("Review this code: " + snippet)
    .call()
    .content();

Prompt templates with variables

Hard-coding strings does not scale. Spring AI uses template placeholders (default {name} syntax via StringTemplate) that you fill with param(...). The framework substitutes values before the request is sent.

  • Define the template text once with {placeholders}.
  • Bind values with .user(u -> u.text(...).param(...)).

This separates wording from data and keeps user values clearly bound.

String reply = chatClient.prompt()
    .user(u -> u
        .text("Summarize the topic {topic} for a {level} audience.")
        .param("topic", "reactive streams")
        .param("level", "beginner"))
    .call()
    .content();

How template substitution works

Under the hood Spring AI builds a PromptTemplate and renders it. You can also use the template directly when you want to reuse it or load it from a resource file.

Here is the same idea as a plain Java program you can run to see substitution — no Spring needed, just string formatting that mirrors what the renderer does:

import java.util.Map;

public class TemplateDemo {
    static String render(String tmpl, Map<String, String> vars) {
        String out = tmpl;
        for (var e : vars.entrySet()) {
            out = out.replace("{" + e.getKey() + "}", e.getValue());
        }
        return out;
    }

    public static void main(String[] args) {
        String t = "Summarize {topic} for a {level} audience.";
        System.out.println(render(t, Map.of("topic", "reactive streams", "level", "beginner")));
    }
}

Structured output: entity()

Often you do not want prose — you want a typed object. Spring AI's structured output converters do three things: inject a format instruction into the prompt, receive the model's text, and deserialize it into your type.

Define a plain Java record, then call .entity(MyType.class) instead of .content().

public record MovieReview(String title, int year, double rating, String verdict) {}

public MovieReview review(String movie) {
    return chatClient.prompt()
        .user("Give a short structured review of the movie: " + movie)
        .call()
        .entity(MovieReview.class);
}

Generic types with ParameterizedTypeReference

For collections or generic containers, Java erases the type parameter at runtime, so List.class is not enough. Pass a ParameterizedTypeReference so Spring AI knows the element type and generates the right JSON schema instruction.

import org.springframework.core.ParameterizedTypeReference;
import java.util.List;

public record Actor(String name, List<String> films) {}

public List<Actor> castOf(String movie) {
    return chatClient.prompt()
        .user("List the main cast of " + movie)
        .call()
        .entity(new ParameterizedTypeReference<List<Actor>>() {});
}

What entity() does to the prompt

It is worth understanding the mechanism: entity() uses a BeanOutputConverter that generates a JSON Schema from your record and appends a format instruction telling the model to reply with matching JSON only.

  • The model returns JSON text.
  • The converter parses it (via Jackson) into your record.
  • If the model adds stray prose, parsing can fail — lower temperature and keep records flat for reliability.

You can call the converter yourself to inspect the injected instruction:

import org.springframework.ai.converter.BeanOutputConverter;

record Weather(String city, double celsius) {}

var converter = new BeanOutputConverter<>(Weather.class);
String formatInstruction = converter.getFormat();
// This text is appended to your user prompt by entity()
System.out.println(formatInstruction);

Streaming and response metadata

For long answers, stream tokens as they arrive using stream() instead of call(), which returns a reactive Flux<String>. For observability, grab the full ChatResponse to read token usage and the finish reason.

  • .stream().content() — Flux<String> of incremental chunks.
  • .call().chatResponse().getMetadata().getUsage() — prompt/completion tokens.
import reactor.core.publisher.Flux;

public Flux<String> streamAnswer(String question) {
    return chatClient.prompt()
        .user(question)
        .stream()
        .content();
}

Quick Check

You need the model's reply mapped into a List<Actor>. Which terminal call is correct?

Recap

You learned to call LLMs the Spring way with ChatClient:

  • Inject ChatClient.Builder, set defaultSystem, and build() once per service.
  • Use the fluent chain: prompt().system(...).user(...).call().content().
  • Keep system instructions and untrusted user input in separate messages.
  • Use {placeholder} templates with .param(...) to separate wording from data.
  • Map replies to typed records with .entity(Type.class), and use ParameterizedTypeReference for generics like List<T>.
  • Stream with .stream().content() and inspect token usage via chatResponse().getMetadata().

For reliable structured output, keep records flat and lower the temperature.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “ChatClient, Prompt, dan Output Terstruktur” gratis?

Ya — teks lengkap “ChatClient, Prompt, dan Output Terstruktur” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Spring Boot 4 Complete Guide, upgrade ke CoddyKit PRO. Kursus Spring Boot 4 Complete Guide mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “ChatClient, Prompt, dan Output Terstruktur”?

Panggil model percakapan melalui ChatClient dengan templat prompt dan pemetaan output terstruktur bertipe. Kamu berlatih Spring Boot 4 Complete Guide dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Spring Boot 4 Complete Guide?

Tidak diperlukan pengalaman sebelumnya. Spring Boot 4 Complete Guide di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “ChatClient, Prompt, dan Output Terstruktur” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Spring Boot 4 Complete Guide ini?

Ya. Setiap pelajaran Spring Boot 4 Complete Guide menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. ChatClient, Prompt, dan Output Terstruktur
  2. Embedding dan Pengambilan dari Penyimpanan Vektor
  3. Pipeline Generasi Berbantuan Pengambilan
  4. Pemanggilan Alat dan Penasihat Agen
← Kembali ke Spring Boot 4 Complete Guide