Spring AI – [ Prompt Templates and Structured Outputs ]

One of the biggest challenges in working with large language models (LLMs) is ensuring that the model responds in the way your application needs.

Free-form text answers are fun to experiment with – but in real-world systems, you often need more structure and reusability.

That’s where two powerful Spring AI features come in:

  • Prompt Templates – Reusable prompts with dynamic placeholders;
  • Structured Outputs – Machine-readable JSON responses, directly mapped to Java objects.

1.Prompt Templates

A PromptTemplate is like a format string for prompts. Instead of hardcoding text, you define placeholders that get filled in at runtime.

This makes your prompts:

  • Reusable across multiple use cases
  • Maintainable if wording changes
  • Safer since you avoid string concatenation

Example:

import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.openai.OpenAiChatClient;
import java.util.Map;

public class PromptTemplateExample {

    private final OpenAiChatClient chatClient;

    public PromptTemplateExample(OpenAiChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public String translate(String text, String language) {
        PromptTemplate template = new PromptTemplate("Translate the following sentence into {language}: {text}");

        UserMessage message = template.createMessage(Map.of(
                "language", language,
                "text", text));

        return chatClient.call(message);
    }

    public static void main(String[] args) {
        OpenAiChatClient chatClient = OpenAiChatClient.builder().build();
        PromptTemplateExample example = new PromptTemplateExample(chatClient);

        String result = example.translate("Hello, how are you?", "French");
        System.out.println(result);
    }
}
/*
 * Output:
 * Bonjour, comment ça va?
 */

2.Structured Outputs

By default, LLMs return plain text.

But what if your app needs structured data – like a JSON object that maps directly to a DTO?

Spring AI’s BeanOutputParser helps you guide the model to respond in valid JSON, and then parse it straight into Java objects.

Example:

import java.util.Map;

import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.parser.BeanOutputParser;

public class StructuredOutputExample {
    private static class Person {
        private String name;
        private int age;
        private String city;

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }

        public String getCity() {
            return city;
        }
    }

    public static void main(String[] args) {
        BeanOutputParser<Person> parser = new BeanOutputParser<>(Person.class);

        String formattedPrompt = parser.getFormat(); // ensures model outputs correct JSON format

        PromptTemplate template = new PromptTemplate("Extract person info from the text: {input}");

        Map<String, Object> params = Map.of(
                "input", "My name is Alice, I am 30 years old, and I live in Paris.");

        OpenAiChatClient chatClient = OpenAiChatClient.builder().build();

        ChatResponse response = chatClient.call(template.createMessage(params, formattedPrompt));

        Person person = parser.parse(response.getResult().getOutput().getContent());

        System.out.println(person.getName());
        System.out.println(person.getAge());
        System.out.println(person.getCity());
    }
}
/*
 * Output:
 *      Alice
 *      30
 *      Paris
 */

3.Real World Example – Customer Support Ticket Extraction

Imagine a support system where users submit free-form text describing their issue.

You want to automatically extract structured fields like category, priority, and summary.

import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.parser.BeanOutputParser;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping("/ticket")
public class TicketController {

    private final OpenAiChatClient chatClient;

    public TicketController(OpenAiChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @PostMapping
    public SupportTicket extractTicket(@RequestBody String issueDescription) {
        PromptTemplate template = new PromptTemplate(
                "Analyze the support request: {text}. " +
                        "Extract fields: category, priority (low, medium, high), summary.");

        BeanOutputParser<SupportTicket> parser = new BeanOutputParser<>(SupportTicket.class);

        String format = parser.getFormat();

        ChatResponse response = chatClient.call(
                template.createMessage(Map.of("text", issueDescription), format));

        return parser.parse(response.getResult().getOutput().getContent());
    }

    private static class SupportTicket {
        private String category;
        private String priority;
        private String summary;
        public String getCategory() {
            return category;
        }
        public void setCategory(String category) {
            this.category = category;
        }
        public String getPriority() {
            return priority;
        }
        public void setPriority(String priority) {
            this.priority = priority;
        }
        public String getSummary() {
            return summary;
        }
        public void setSummary(String summary) {
            this.summary = summary;
        }
    }
}

Example Request:

curl -X POST http://localhost:8080/ticket \
     -H "Content-Type: text/plain" \
     -d "My internet is down since yesterday and I cannot work. Please fix this urgently."

Possible AI Response – Parsed into SupportTicket:

{
  "category": "Internet",
  "priority": "high",
  "summary": "Internet outage preventing user from working"
}

Conclusion

  • Prompt Templates keep prompts flexible and maintainable.
  • Structured Outputs ensure AI responses can directly feed into your applications.

Together, they transform AI from a “chat toy” into a robust backend tool that integrates seamlessly with enterprise Java systems.