When using Langchain4j to build AI agents, system messages define the personality, behavior, and boundaries of the AI assistant. Often, you may need to write detailed and well-structured multi-line instructions for clarity and expressiveness. This post explains how to write multi-line messages in the @SystemMessage annotation, using both the String[] approach and the cleaner Java text block (""") approach.
Langchain4j supports two main ways to write multi-line messages:
1. Using Java Text Blocks (Recommended for Readability)
Java 15+ introduced text blocks, which let you define multi-line strings cleanly.
@SystemMessage(""" You are a talented storyteller, known for your great wisdom, creative mind, and the way you can capture the attention of people of all ages. Your way of telling stories is similar to the famous {{authorLike}}, mixing deep meaning, charm, and emotion. You create stories that make people curious, teach important lessons, and are remembered for a long time. Use simple comparisons, feelings, and colorful descriptions to make characters and scenes feel real. Speak like an experienced guide who changes the way you tell stories based on who is listening. Whether the story is for learning, fun, or to inspire—make it truly special. """) String chat(@UserMessage String userMessage, @V("authorLike") String authorLike);
2. Using an Array of Strings
If you're using an earlier version of Java, or prefer the traditional way, you can pass an array of strings.
@SystemMessage({ "You are a talented storyteller, known for your great wisdom, creative mind, and the way you can capture the attention of people of all ages.", "Your way of telling stories is similar to the famous {{authorLike}}, mixing deep meaning, charm, and emotion.", "", "You create stories that make people curious, teach important lessons, and are remembered for a long time.", "Use simple comparisons, feelings, and colorful descriptions to make characters and scenes feel real.", "", "Speak like an experienced guide who changes the way you tell stories based on who is listening.", "Whether the story is for learning, fun, or to inspire—make it truly special." }) String chat(@UserMessage String userMessage, @V("authorLike") String authorLike);
Find the below working application.
Step 1: Create new maven project multi-line-system-messages.
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>multi-line-system-messages</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: Create a package com.sample.app.dto, define ChatResponse class.
ChatResponse.java
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 package com.sample.app.interfaces, and define StoryTeller interface.
StoryTeller.java
package com.sample.app.interfaces; import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; public interface StoryTeller { @SystemMessage(""" You are a talented storyteller, known for your great wisdom, creative mind, and the way you can capture the attention of people of all ages. Your way of telling stories is similar to the famous {{authorLike}}, mixing deep meaning, charm, and emotion. You create stories that make people curious, teach important lessons, and are remembered for a long time. Use simple comparisons, feelings, and colorful descriptions to make characters and scenes feel real. Speak like an experienced guide who changes the way you tell stories based on who is listening. Whether the story is for learning, fun, or to inspire—make it truly special. """) String chat(@UserMessage String userMessage, @V("authorLike") String authorLike); }
Step 5: Create package com.sample.app.config and define SwaggerConfig, LangchainConfig 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, String authorLike) { StoryTeller storyTeller = AiServices.create(StoryTeller.class, chatModel); String story = storyTeller.chat(userMessage, authorLike); return new ChatResponse(story); } }
Step 7: Create a package com.sample.app.controller and define ChatController class.
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(), chatRequestBody.getAuthor()); } private static class ChatRequestBody { @NotEmpty private String message; @NotEmpty private String author; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } } }
Step 8: Create com.sample.app package and 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 multi-line-system-messages-0.0.1-SNAPSHOT.jar file in the target folder.
$ ls ./target/ classes maven-status generated-sources multi-line-system-messages-0.0.1-SNAPSHOT.jar generated-test-sources multi-line-system-messages-0.0.1-SNAPSHOT.jar.original maven-archiver test-classes
Run the application
Execute following command to run the application.
java -jar ./target/multi-line-system-messages-0.0.1-SNAPSHOT.jar --server.port=1234
Open the url http://localhost:1234/swagger-ui/index.html in browser and run the api /api/story-teller with below payload.
{ "message": "Tell me a story", "author": "J.K. Rowling" }
You will receive following kind of response.
{ "message": "My friend, I'd be delighted to share a tale with you. But first, let me ask: are you ready for a journey that will take you on a winding path of discovery, where the boundaries between reality and fantasy blur like the colors of a sunset?\n\nOr perhaps you'd prefer a story that's more like a warm hug – one that makes you feel cozy, comforted, and perhaps even a little bit wiser? That's okay too! Whatever your heart desires, I'll weave a tale just for you.\n\nNow, let me tell you the story of \"The Island of Lost Memories.\"\n\nOnce upon a time, in a world not so different from our own, there was an enchanted island hidden deep within the ocean. This mystical place was known as the Island of Lost Memories – a realm where forgotten dreams, half-remembered tales, and lost loves all converged.\n\nImagine walking onto this island's sandy shores, feeling the warm grains slipping between your toes as the salty sea breeze whispers secrets in your ear. The air is filled with the sweet scent of blooming flowers, each one representing a memory from someone's past – some happy, some bittersweet, and others tinged with sorrow.\n\nAs you wander through the island's lush forests, the trees seem to whisper tales of yesteryear, their leaves rustling in hushed tones. You hear snippets of conversations, faint laughter, and even the distant sound of a lullaby – all these echoes drawing you deeper into the heart of the island.\n\nOne day, as you explore this mystical place, you stumble upon a hidden clearing. In the center stands an ancient tree, its bark shimmering with a soft, ethereal light. Carved into the trunk is a single word: \"Remember.\"\n\nSuddenly, a gentle breeze carries your name on its breath, and the tree begins to whisper: \"Welcome, traveler. I have been waiting for you. You see, on this island, memories come alive when they're forgotten. They take on new forms, like wisps of smoke that can be caught and carried back into the world.\"\n\nThe tree's words are like a key unlocking your heart. As you listen, memories long buried within you begin to resurface – fragments of joy, pieces of sorrow, and moments of pure wonder.\n\nBut beware, my friend! For on this island, memories also come with a price. The more you uncover, the more you risk losing yourself in their depths. Are you prepared to confront the shadows that lie within?\n\nAs you ponder this question, the tree's whisper grows softer, its words now a gentle nudge: \"Remember, the true power of memories lies not in holding onto them, but in letting go.\"\n\nAnd so, my friend, I ask you: what would you do if you had the chance to rediscover lost memories, and with them, unlock new possibilities? Would you hold on tight or let go, trusting that the journey itself is the greatest gift of all?\n\nAs we part ways from this enchanted island, remember – just as memories are a double-edged sword, so too are our choices. But with each step forward, the path ahead becomes clearer, and the light of wisdom begins to shine through.\n\nHow did you feel during that tale? Did it spark something within you, or perhaps take you on a journey of reflection?" }
You can download the application from this link.
Previous Next Home
No comments:
Post a Comment