Write Prompts that Work - the Art of the Prompt
Think of prompt engineering as having a conversation with an AI - your words shape its response. It’s about writing your messages (prompts) to get the most helpful and accurate responses while being efficient with the AI’s processing power.
You’ve probably seen countless “ultimate prompt guides” and “secret prompt techniques” online. Here’s the truth: there’s no single “perfect prompt” that works for everything. Instead of looking for magic formulas, focus on understanding the core principles that make prompts effective.
Great prompting is iterative - you start with a basic prompt, see how it performs, and refine it based on the results. Think of it like tuning an instrument until you get the right note.
The Recipe
In this tutorial, we’ll focus on crafting single prompt that get you complete responses in one go. While you can always have back-and-forth conversations with AI models, in practice you’ll want to save on API/token costs.
Here’s my battle-tested template for writing effective prompts, this one is used by me and my colleagues on a daily basis. Think of it as a recipe - you don’t always need every ingredient, but each one serves a purpose:
- Task definition - clearly state what you want the model to do
- Role assignment - give the AI a specific perspective to work from
- Rules and constraints - set boundaries and requirements
- Output format - specify how you want the response structured
- Examples - show what good outputs look like
- Context - provide relevant background information
Remember: You don’t need to use every part of this template every time. Choose the elements that make sense for your specific needs.
Setup
Before we dive into prompt engineering, let’s set up our environment. We’ll use a popular open-source model that can run on your local computer.
We’ll use Llama 3.21, which is:
- Free and open source
- Small enough to run on your laptop
- Powerful enough for learning prompt engineering
To interact with the model, we’ll use Ollama2 - a tool that makes running AI models locally very easy.
Here’s a simple Python function we’ll use throughout this tutorial:
import ollama
MODEL = "llama3.2"
TEMPERATURE = 0
def call_model(prompt: str) -> str:
response = ollama.chat(
model=MODEL,
messages=[{"role": "user", "content": prompt}],
keep_alive="1h",
options={"temperature": TEMPERATURE},
)
return response.message.content
Try it out:
response = call_model("What is machine learning?")
print(response)
Note: While we’re using Llama 3.2, these prompting techniques work with most AI models (like GPT-4, Claude, etc.). The principles stay the same, even if the model changes.
Task definition
This part is required. You need to clearly specify what you want the model to do. Here’s an example:
prompt = "Write an error message for when a user's payment fails."
print(call_model(prompt))
Here is an example of an error message that can be displayed to the user when
their payment fails:
"Payment Failed
Unfortunately, your payment has been declined due to [insert reason for
failure, e.g. insufficient funds, expired card, etc.].
Please try again with a different payment method or contact our customer
support team at [insert contact information] for assistance.
Refund: [insert refund amount or percentage]
Transaction ID: [insert transaction ID]
If you have any questions or concerns about your payment, please don't hesitate
to reach out. We apologize for the inconvenience and appreciate your patience."
This error message provides the user with:
- A clear explanation of what went wrong
- An option to try again with a different payment method
- Contact information for customer support
- Information about any refund that may be due
- A unique transaction ID for reference
Feel free to customize this message to fit your specific use case and branding.
This is clearly too verbose (very common with some of the LLMs). We’ll work on refining this in the next sections.
Role assignment
Here we’ll focus on improving the clarity and actionability of the error message. We’ll do that by defining a role for the model to assume:
prompt = """
You are a UX writer specializing in clear, actionable error messages.
Write an error message for when a user's payment fails.
"""
Here is an example of a clear and actionable error message for when a payment fails:
**Error Message**
"Payment Failed
We were unable to process your payment at this time. Please try again or
contact our customer support team if you have any questions.
**What to do next:**
1. **Retry Payment**: Click the "Try Again" button to attempt another payment.
2. **Contact Support**: Send us a message and we'll be happy to assist you with
your order.
3. **Cancel Order**: If you'd like to cancel your order, click the "Cancel
Order" link.
**Additional Help**
If you're experiencing issues with recurring payments or have questions about
our payment terms, please visit our [Payment Terms](link) page for more
information."
This error message aims to:
1. Clearly state that the payment failed
2. Provide a clear call-to-action (CTA) for the user to try again
3. Offer alternative options for the user to resolve the issue
4. Provide additional resources or support for users who need help
By following these best practices, this error message aims to minimize
frustration and provide a positive experience for the user despite the payment
failure.
The main part of the output is the error message, which is clear and actionable. Good improvement, but still verbose. Let’s refine it further.
Rules and constraints
Here we’ll set some boundaries and requirements for the error message. This will help us keep it concise and focused:
prompt = """
You are a UX writer specializing in clear, actionable error messages.
Write a payment failure error message in 2 parts:
- What happened (max 10 words)
- What to do (max 15 words)
Tone: Helpful, not technical
Length: Maximum 25 words total
Audience: Regular online shoppers
"""
Here is a payment failure error message in 2 parts:
**What happened:** "We're having trouble processing your payment right now."
**What to do:** "Try again or contact our customer support team for assistance."
We have drastically reduced the overall length of the output. This is a good example of how constraints can help focus the response. Let’s push for a JSON format.
Output format
We’ll request the response to be in a JSON format:
prompt = """
You are a UX writer specializing in clear, actionable error messages.
Write a payment failure error message in 2 parts:
- What happened (max 10 words)
- What to do (max 15 words)
Tone: Helpful, not technical
Length: Maximum 25 words total
Audience: Regular online shoppers
The result should be a single error message that is 25 words or less.
Format it as a JSON object.
"""
Here's the payment failure error message in JSON format:
```
{
"error": {
"whatHappened": "Payment processing failed due to an issue with your card.",
"whatToDo": "Please try again with a different payment method or contact our support team for assistance."
}
}
```
We got what we wanted, but still the message is split into two parts. Let’s combine them into a single message.
Examples
We’ll show some examples of good error messages to guide the model:
prompt = """
You are a UX writer specializing in clear, actionable error messages.
Write a payment failure error message in 2 parts:
- What happened (max 10 words)
- What to do (max 15 words)
Tone: Helpful, not technical
Length: Maximum 25 words total
Audience: Regular online shoppers
The result should be a single error message that is 25 words or less.
Format it as a JSON object.
Examples:
<examples>
<example>
{
"type": "account_lockout",
"message": "Too many login attempts. Account temporarily locked. Please wait 15 minutes or reset your password via email."
}
</example>
<example>
{
"type": "upload_size_exceeded",
"message": "File is too large to upload (max 10MB). Please compress the file or split it into smaller parts."
}
</example>
<example>
{
"type": "network_connection",
"message": "Lost connection to our servers. Check your internet connection and refresh the page."
}
</example>
</examples>
"""
Here is a payment failure error message in 2 parts:
{
"type": "payment_failure",
"message": "Payment failed due to insufficient funds or expired card. Please try again with a different payment method or contact our support team for assistance."
}
Arguably, picking some good (and bad) examples can help the model understand what you’re looking for. In this case, the response is exactly what we wanted.
Context
The final tweak is to provide some specific information (context) to the model. This can help it generate a more relevant response:
prompt = """
You are a UX writer specializing in clear, actionable error messages.
Write a payment failure error message in 2 parts:
- What happened (max 10 words)
- What to do (max 15 words)
Tone: Helpful, not technical
Length: Maximum 25 words total
Audience: Regular online shoppers
The result should be a single error message that is 25 words or less. Format it as a JSON object.
Examples:
<examples>
<example>
{
"type": "account_lockout",
"message": "Too many login attempts. Account temporarily locked. Please wait 15 minutes or reset your password via email."
}
</example>
<example>
{
"type": "upload_size_exceeded",
"message": "File is too large to upload (max 10MB). Please compress the file or split it into smaller parts."
}
</example>
<example>
{
"type": "network_connection",
"message": "Lost connection to our servers. Check your internet connection and refresh the page."
}
</example>
</examples>
<context>
The user used a credit card that has expired.
</context>
"""
{
"type": "payment_failure",
"message": "Your payment method has expired. Please update your card details or use a different payment method to complete the transaction."
}
Note that this didn’t change the overall format of the response (something we want), but it did help the model generate a more relevant message.