Spring AI Structured Output Converters
π Fun with Spring AI Structured Output Convertersβ
So, youβve got an LLM (Large Language Model) churning out text, but you need it structured neatlyβno wild, unstructured responses allowed! Enter Spring AI Structured Output Convertersβyour best buddies for transforming AI-generated chaos into well-organized Lists, Maps, or Java Beans. π©β¨
These converters ensure that the AI plays nice by:
- Giving clear instructions about the required format (JSON, XML, etc.).
- Parsing the response into neat Java objectsβno messy surprises! π―
π 1. Setupβ
Before we unleash the AI magic, make sure your system is ready to roll:
π Set up OpenAI API Keyβ
export OPENAI_API_KEY=[your_openai_api_key]
And letβs make sure your Spring Boot app knows where to find it:
spring.ai.openai.api-key=${OPENAI_API_KEY}
π¦ Add Dependenciesβ
Add the magic potion (Spring AI OpenAI dependency) to your pom.xml
:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
Now, weβre ready to explore the converters! π
π 2. MapOutputConverter: The "Everything-in-a-Map" Trickβ
This converter ensures LLM responds in a Map format (RFC8259-compliant JSON). Think of it like stuffing AIβs response neatly into a HashMap. πΊοΈ
public class MapOutputConverter extends AbstractMessageOutputConverter<Map<String, Object>> {
@Override
public String getFormat() {
return """
Your response should be in JSON format.
The data structure for the JSON should match this Java class: java.util.HashMap
Do not include any explanations, only provide an RFC8259-compliant JSON response.
""";
}
}
π― Example: Country-Capital Lookupβ
@GetMapping("/country-capital-service/map")
public Map<String, Object> getCapitalNamesInMap(@RequestParam String countryNamesCsv) {
if (countryNamesCsv == null || countryNamesCsv.isEmpty()) {
throw new IllegalArgumentException("Country names CSV cannot be null or empty");
}
MapOutputConverter converter = new MapOutputConverter();
PromptTemplate pt = new PromptTemplate("For these countries {countryNamesCsv}, return their capitals. {format}");
Prompt renderedPrompt = pt.create(Map.of("countryNamesCsv", countryNamesCsv, "format", converter.getFormat()));
ChatResponse response = chatClient.call(renderedPrompt);
return converter.parse(response.getResult().getOutput().getContent());
}
β Output? A sweet, structured JSON response, neatly packed in a Map! πΊοΈ
π 3. ListOutputConverter: "Gimme a List!"β
This one is all about lists! It forces the AI to return comma-separated values (CSV) and then parses them into a Java List. π
public class ListOutputConverter extends AbstractConversionServiceOutputConverter<List<String>> {
@Override
public String getFormat() {
return """
Your response should be a list of comma-separated values.
eg: `foo, bar, baz`
""";
}
}
π― Example: Capital Cities as a Listβ
@GetMapping("/country-capital-service/list")
public List<String> getCapitalNamesInList(@RequestParam String countryNamesCsv) {
if (countryNamesCsv == null || countryNamesCsv.isEmpty()) {
throw new IllegalArgumentException("Country names CSV cannot be null or empty");
}
ListOutputConverter converter = new ListOutputConverter(new DefaultConversionService());
PromptTemplate pt = new PromptTemplate("For these countries {countryNamesCsv}, return their capitals. {format}");
Prompt renderedPrompt = pt.create(Map.of("countryNamesCsv", countryNamesCsv, "format", converter.getFormat()));
ChatResponse response = chatClient.call(renderedPrompt);
return converter.parse(response.getResult().getOutput().getContent());
}
β
Expected Output: "New Delhi, Washington D.C., Ottawa, Jerusalem"
neatly parsed into a List<String>
. β
π 4. BeanOutputConverter: The "Shape It Like a POJO" Trickβ
This converter tells AI to shape the response according to a Java POJOβno extra fluff! π
public class BeanOutputConverter<T> implements StructuredOutputConverter<T> {
@Override
public String getFormat() {
return """
Your response should be in JSON format.
Do not include explanations or markdown. Just an RFC8259-compliant JSON response.
JSON Schema to follow:
```%s```
""";
}
}
π― Example: Top 10 Cities of a Countryβ
public record Pair(String countryName, List<String> cities) {}
@GetMapping("/country-capital-service/bean")
public Pair getCapitalNamesInPojo(@RequestParam String countryName) {
BeanOutputConverter<Pair> converter = new BeanOutputConverter<>(Pair.class);
PromptTemplate pt = new PromptTemplate("For {countryName}, return the 10 most popular cities. {format}");
Prompt renderedPrompt = pt.create(Map.of("countryName", countryName, "format", converter.getFormat()));
ChatResponse response = chatClient.call(renderedPrompt);
return converter.parse(response.getResult().getOutput().getContent());
}
β
AI now returns a Pair object with countryName
and List<String> cities
. π
π¬ 5. Conclusionβ
Spring AI Structured Output Converters are the boss level cheats for making LLMs respond in a structured and predictable format. Whether you need Maps, Lists, or Java Beans, these converters keep everything in order. π§Ήπ‘
So go aheadβexperiment, tweak, and see what kind of structured magic you can pull off! π₯
Happy Coding! π§βπ»π