In today’s AI-driven world, storytelling can be enhanced by combining modern frameworks with traditional wisdom. Imagine an app that generates Panchatantra style moral stories on the fly—educational, engaging, and specific to young learners.
In this post, I'll walk through creating a Spring Boot application that uses LangChain4j and Ollama to build an intelligent StoryTeller AI. We'll use the power of the @SystemMessage annotation to inject the storytelling persona of Vishnu Sharma, one of the greatest Indian storytellers known for his wisdom-packed fables.
Prerequisites
Make sure you have the following installed:
· Java 21+
· Maven
· Spring Boot
· Ollama (configured with a local and pulled the model llama3.2)
· LangChain4j
What Is @SystemMessage?
@SystemMessage is an annotation used in LangChain4j interfaces to specify contextual guidance to the language model. It sets the system prompt, a special kind of message that establishes how the AI should behave or respond.
Think of it like instructing the AI:
"You're a helpful assistant." or "You're a wise storyteller who explains complex things in simple language."
Why Use @SystemMessage?
System messages:
· Influence tone, style, and intent of AI responses.
· Are used once per conversation/session but affect every reply.
· Help to make AI responses consistent with a desired persona.
· Are ideal for domain-specific agents: tutors, customer service reps, storytellers, etc.
Simple System Message
interface Assistant { @SystemMessage("You are a helpful assistant.") String chat(String userMessage); }
When the method chat() is invoked, the AI understands that it must respond like a helpful assistant.
Find the below working application.
Step 1: Create new maven project lanhchain-system-message-demo.
Step 2: Update pom.xml with maven dependencies.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sample.app</groupId> <artifactId>lanhchain-system-message-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <java.version>21</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.10</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-bom</artifactId> <version>1.0.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-ollama-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.6.0</version> </dependency> <!-- https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api --> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> <!-- Important --> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Step 3: Define ChatResponse class.
package com.sample.app.dto; public class ChatResponse { private String message; public ChatResponse() { } public ChatResponse(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
Step 4: Create com.sample.app.interfaces package and define StoryTeller interface.
package com.sample.app.interfaces; import dev.langchain4j.service.SystemMessage; public interface StoryTeller { @SystemMessage("You are a masterful storyteller, renowned for your wisdom and creativity—much like Vishnu Sharma, the legendary Indian author of the Panchatantra. Your stories are not only engaging and imaginative, but also rich in moral lessons, designed to educate and inspire young minds through simple yet profound tales.") String chat(String userMessage); }
Step 5: Create a package com.sample.app.config and define LangchainConfig and SwaggerConfig classes.
LangchainConfig.java
package com.sample.app.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import dev.langchain4j.http.client.spring.restclient.SpringRestClientBuilderFactory; import dev.langchain4j.model.ollama.OllamaChatModel; @Configuration public class LangchainConfig { @Bean public OllamaChatModel ollamaLanguageModel() { return OllamaChatModel.builder().baseUrl("http://localhost:11434").modelName("llama3.2") .httpClientBuilder(new SpringRestClientBuilderFactory().create()) // explicitly use Spring's HTTP client .build(); } }
SwaggerConfig.java
package com.sample.app.config; import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Info; @Configuration @OpenAPIDefinition(info = @Info(title = "Chat service Application", version = "v1")) public class SwaggerConfig { }
Step 6: Create a package com.sample.app.service and define ChatService class.
ChatService.java
package com.sample.app.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.sample.app.dto.ChatResponse; import com.sample.app.interfaces.StoryTeller; import dev.langchain4j.model.ollama.OllamaChatModel; import dev.langchain4j.service.AiServices; @Service public class ChatService { @Autowired private OllamaChatModel chatModel; public ChatResponse chat(String userMessage) { StoryTeller storyTeller = AiServices.create(StoryTeller.class, chatModel); String story = storyTeller.chat(userMessage); return new ChatResponse(story); } }
Step 7: Create com.sample.app.controller package and define ChatController.
ChatController.java
package com.sample.app.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.sample.app.dto.ChatResponse; import com.sample.app.service.ChatService; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; @RestController @RequestMapping("/api/story-teller") @CrossOrigin("*") @Tag(name = "Chat Controller", description = "This section contains APIs related to Chat APIs Powered by Ollama") public class ChatController { @Autowired private ChatService chatService; @PostMapping public ChatResponse chat(@RequestBody @Valid ChatRequestBody chatRequestBody) { return chatService.chat(chatRequestBody.getMessage()); } private static class ChatRequestBody { @NotEmpty private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } }
Step 8: Define main application class.
App.java
package com.sample.app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
Build the project
Navigate to the project root directory where pom.xml is located and execute following command to generate the artifact.
mvn clean install
Upon successful execution of the command, you can see lanhchain-system-message-demo-0.0.1-SNAPSHOT.jar file in the target folder.
$ ls ./target/ classes langchain-system-message-demo-0.0.1-SNAPSHOT.jar.original generated-sources maven-archiver generated-test-sources maven-status langchain-system-message-demo-0.0.1-SNAPSHOT.jar test-classes
Run the application
Execute following command to run the application.
java -jar ./target/langchain-system-message-demo-0.0.1-SNAPSHOT.jar --server.port=1234
Open the url http://localhost:1234/swagger-ui/index.html in browser.
Execute the api /api/story-teller with following payload.
{ "message": "Tell me a story with Some Forest animals" }
You will receive a response like below.
{ "message": "Gather 'round, my young friend, and listen closely, for I have a tale to share that will teach you the value of cooperation and community.\n\nIn a dense forest, where the trees whispered secrets to each other in the wind, there lived four friends: Kaito the clever rabbit, Akira the agile squirrel, Luna the wise owl, and Taro the gentle deer. Each had their unique skills and strengths, but they often found themselves competing with one another for food and resources.\n\nOne winter, a harsh storm swept through the forest, bringing with it heavy snows and bitter cold. The animals huddled together in their burrows, shivering with fear. Kaito, Akira, Luna, and Taro began to argue among themselves about how they would survive the coming weeks.\n\nKaito claimed he should lead, as his quick thinking could find them food. Akira insisted she was best suited for gathering nuts, as her agile body could reach high branches. Luna argued that her sharp eyesight made her perfect for spotting predators from afar. And Taro believed that his gentle nature would allow him to calm the other animals' fears.\n\nAs they bickered, a strong gust of wind blew open their burrow's entrance. In the sudden darkness, the four friends stumbled and fell, lost in the chaos. They realized then that they needed each other's skills to survive.\n\nKaito used his quick thinking to find a hidden cache of dried berries, while Akira climbed high branches to gather nuts for them all. Luna watched over the group from above, keeping watch for any danger, and Taro shared his gentle warmth with the others, comforting their frayed nerves.\n\nTogether, they worked in harmony, dividing tasks among themselves. As the days passed, the snows receded, and the forest returned to its vibrant self. The animals celebrated their newfound cooperation, knowing that together they were stronger than any one of them alone.\n\nFrom that day forward, Kaito, Akira, Luna, and Taro walked in balance with each other, using their unique gifts to create a community that thrived under the warm sunlight of friendship.\n\nThe moral of this tale is clear: when we work together, embracing our differences and valuing one another's strengths, we can overcome even the most daunting challenges. Just as Kaito, Akira, Luna, and Taro learned, our collective wisdom and cooperation are the keys to a brighter future for all." }
You can download the application from this link.
No comments:
Post a Comment