Prompt Engineering: PromptTemplate and Dynamic Prompts


The Problem We Are Solving

Raj, a new hire in the engineering team, uses the SmartHR bot for the first time. He gets a generic answer that starts with "At a typical company...". He messages Sarah:

"The bot doesn't even know I work here. Can it give answers that actually apply to TechCorp and mention my name?"

Sarah passes it to Dev. The fix: PromptTemplate.


What You Will Learn


What Is a PromptTemplate?

A PromptTemplate is a reusable prompt with named placeholders, just like a mail-merge template:

PromptTemplate template = new PromptTemplate("""
        You are an HR assistant for TechCorp.
        The employee asking is {name} from the {department} department.
        Their role is {role}.

        Answer their question professionally and mention TechCorp by name where relevant:
        {question}
        """);

Map<String, Object> variables = Map.of(
        "name", "Raj",
        "department", "Engineering",
        "role", "Software Engineer",
        "question", "How do I request my laptop setup?"
);

Prompt prompt = template.create(variables);

Loading Templates from Files

Instead of hardcoding templates in Java, store them in resources/prompts/:

src/main/resources/prompts/
├── hr-assistant.st          ← main HR prompt template
└── onboarding.st            ← onboarding-specific template
// Load from classpath
@Value("classpath:prompts/hr-assistant.st")
private Resource hrPromptTemplate;

PromptTemplate template = new PromptTemplate(hrPromptTemplate);

hr-assistant.st:

You are a professional HR assistant for TechCorp, a technology company.
You are speaking with {name}, a {role} in the {department} department.

Guidelines:
- Address {name} by name in your response
- Reference TechCorp policies specifically
- Be concise and professional
- If you don't know TechCorp's specific policy, say so clearly

Employee question: {question}

What You Will Build — Personalised HR Endpoint

// POST /hr/ask/personalised
public record PersonalisedRequest(String name, String department,
                                   String role, String question) {}

@PostMapping("/ask/personalised")
public HrResponse askPersonalised(@RequestBody PersonalisedRequest request) {
    Prompt prompt = template.create(Map.of(
            "name",       request.name(),
            "department", request.department(),
            "role",       request.role(),
            "question",   request.question()
    ));

    String answer = chatClient.prompt(prompt).call().content();
    return new HrResponse(request.question(), answer, "personalised");
}

Test it:

curl -s -X POST http://localhost:8080/hr/ask/personalised \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Raj",
    "department": "Engineering",
    "role": "Software Engineer",
    "question": "How do I get my development tools set up on my first day?"
  }'

Prompt Engineering Best Practices

Practice Example
Be specific about the role "You are an HR assistant" not "You are an assistant"
Define output format "Answer in 3 bullet points"
Set boundaries "Only answer HR-related questions"
Give examples "For example: ..."
Control tone "Be professional but friendly"

Summary

In this chapter you will:


What's Next

In Chapter 5, we make the AI return structured Java objects instead of raw text — using BeanOutputConverter to parse a resume into a Resume record with fields like name, skills, experience, and education.

Code for this chapter: code/chapter-04-prompt-engineering/