How to write good prompts
I’ve tried every trick in the book to get Large Language Models (LLMs) to follow my instructions. I’ve resorted to threats of physical violence, offered bribes, and even made a coding agent call me big daddy1.
After all that trial and error, I’ve learned a few things about writing prompts. This is a key part of using LLMs, but it’s also one of the most hyped and abused techniques. There are so many AI influencers selling and sharing their bulletproof prompting techniques that the whole thing feels closer to astrology than to engineering.
This article is a no-BS guide to help you get the basics right. It won’t solve all the problems in your agentic workflow or LLM-based apps, but it will help you avoid the most obvious mistakes.
Let’s get started!
What is a prompt?
A prompt is any text you send to an LLM to guide its behavior or generate a response. Chat-based models work with two types of instructions:
- System/developer prompt: Sets the “big picture” or high-level rules for the entire conversation. Examples: “You are a helpful assistant.”; “Always answer in haiku.”
- User prompt: The actual question the end-user types and any additional context. Examples: “What’s today’s weather in Dublin?”; “Summarize the following documents.”
The system prompt gives the assistant a “role,” while the user prompt requests specific content within that framework.
Prompts are provided as messages, which are a list of objects with a role and a content:
These messages are passed through a chat template and converted into a single string that is sent to the model to generate a response.
For example, this is the resulting message text used by Qwen3 after combining the system and user prompts:
After you make the request, the model will respond with an assistant message that contains the model’s reply2.
It looks like this:
You’ll generally only set the system and user prompts to instruct the model. But for some prompting techniques, such as few-shot prompting, you might include assistant messages to simulate model responses.
Components of a good prompt
There are many useful free resources online you can use to learn more about prompt engineering. I recommend this article by Anthropic or this one by OpenAI.
Most of the advice boils down to these six principles:
- Be clear and specific
- Provide examples
- Let models think
- Structure prompts into sections and use delimiters
- Split complex tasks into smaller steps
- Repeat instructions when the context is long
Let’s go through each of these in more detail.
Principle 1: Be clear and specific
This is the most important principle. If you cannot describe in detail the task you want to perform, the model will not be able to perform it. Whenever you write a prompt, ask yourself: “If I didn’t have any background knowledge in this domain, could I complete this task based on the text I just wrote in this prompt?”
In addition to describing the task, you should also provide a role for the model. For example, if you’re classifying documents, you can use a role like “You’re an expert in document classification.” Or if you’re dealing with financial data, you can use a role like “You’re an expert in financial analysis.”
Here’s an example of this principle in practice:
You're an expert in business writing. Please review and improve this email by addressing the following issues:
- Fix any grammatical errors and typos
- Improve clarity and conciseness
- Ensure a professional tone throughout
- Strengthen the subject line to be more specific
- Add a clear call-to-action if missing
- Format for better readability (bullets, paragraphs, etc.)
<EMAIL CONTENT>This information will tell the LLM its role and the specific task you want it to perform. This should go in the system prompt.
Principle 2: Provide examples
One of the lowest-hanging fruits in prompt engineering is to provide examples. It’s as simple as showing the model a couple of input and output pairs.
This technique is formally known as a “few-shot prompt.” It’s a simple but effective way to improve the quality of the output in many tasks.
Here’s an example of a few-shot prompt:
You are an expert in solving simple word puzzles using reasoning steps. Provided with a list of 4 names, you will concatenate the last letters into a word.
## Examples
**Example 1**:
Input: 'Ian Peter Bernard Stephen'
Output: 'NRDN'
**Example 2**:
Input: 'Javier Dylan Christopher Joseph'
Output: 'RNRH'
## Task
Input: 'Maria Julia Pedro Joe'In my experience, it’s better to provide these examples directly in the system prompt because it’s easier to read, keeps everything close together, and — if the prompt is long enough — you’ll often benefit from caching.
Some people prefer to use assistant messages to provide examples. In those cases, I’d recommend having the examples first and then the task.
Principle 3: Let models think
LLMs think in tokens. If you want them to achieve better results, you should let them use tokens to reason about the problem before generating the final answer.
This process is formally known as “Chain of Thought” (CoT) prompting. Similar to few-shot prompts, it’s a powerful way to improve the quality of results in many tasks.
A zero-shot CoT prompt means that you explicitly ask the model to think step by step to solve the problem but don’t provide any examples of how it should reason about it. A few-shot CoT prompt means that you provide examples of how the model should reason about the problem (e.g., 1-shot means you provide one example, 2-shot means two examples, etc.).
Although this approach has seemingly become less relevant with the release of reasoning models, I still see it often in practice because providers either do not provide the full reasoning process or limit how you can use/access it.
Here are two examples of CoT prompts:
0-Shot CoT Prompt
1-Shot CoT Prompt
<example>
**Question:** Emily buys 3 notebooks at $4 each and 2 pens at $1.50 each. What's her total cost?
**Reasoning:**
1. Cost of notebooks = 3 × $4 = $12
2. Cost of pens = 2 × $1.50 = $3
3. Total cost = $12 + $3 = $15
**Answer:** $15
</example>
**Question:** A cinema sold 120 tickets at $8 each. What was the total revenue?These days, most providers have options to let models think without explicitly asking them to do so in the prompt. With OpenAI models, you can use models from the o-family (e.g., o3, o3-mini, o4-mini) or GPT-5. For Anthropic and Gemini, you can configure Claude 3.7+ or Gemini 2.5 models to use thinking tokens by setting a specific parameter. However, as I’m writing this, only Gemini and Claude 3.7 gives you access to the full thinking tokens in the response. OpenAI and Anthropic latest models will give you a summarized version of the thinking process.
Principle 4: Structure prompts into sections and use delimiters
It’s a common practice to structure system and user prompts into sections. Some people like to use Markdown formatting to make the prompt more readable, while others use XML tags. You can also use triple backticks (```) to delimit code blocks or JSON objects. There’s no clear better way between delimiters. The only problem is not doing it consistently.
I really haven’t checked if there’s any hard evidence proving this improves performance. It just feels right and makes prompts easier to read. You’ll spend a lot of time iterating on prompts, so being able to read them quickly is already a good investment on its own.
System prompt
For system prompts, you can use the following structure:
**Role and objective**
You’re an expert document classifier. Your goal is to classify this document…
**Rules**
1. Documents that contain information about medical treatments should be classified as …
2. Do not classify documents into multiple categories
3. …
**Examples**
Input: [document text]
Classification: [document category]
…
**Output**
You should generate a JSON object with this structure: [JSON schema]
**(Optional) Reiterate objective and elicit thinking**
Your goal is to XYZ… Before writing your answers, write your reasoning step by step.The headers are for reference only, you you can modify them or even skip them. You also don’t need to include all of these sections in your prompt.
User prompt
I prefer to keep user prompts short:
In its simplest form, you just provide the context the LLM needs to work with and reiterate the objective.
Principle 5: Split complex tasks into smaller steps
LLMs often get confused when the context is too long and/or the instructions are complex.
For example, you might have a document classifier that precedes a conditional entity extraction. Instead of doing a single LLM call with a prompt that does both the document classification and the entity extraction, you can split the task into two steps:
- First, classify the document into a category.
- Then, extract the entities from the document based on the category.
Here’s an example of the same task split into two steps.
Big complex prompt
This prompt tries (and likely fails) to do two complex tasks at once.
You're an expert document classifier. First, classify the document into the following categories:
- Medical
- Financial
- Legal
Then, if the document is classified as "Medical", extract the following entities:
...
If the document is classified as "Financial", extract the following entities:
...
If the document is classified as "Legal", extract the following entities:
...Smaller, simpler prompts
This second approach splits the task into two smaller prompts that do each task separately.
Prompt 1: Document classification
Prompt N: Entity extraction (one for each category)
Principle 6: Repeat instructions when the context is long
LLMs often get confused when the context is too long and the instructions are complex. When the context exceeds a certain length, it’s better to repeat the instructions at the bottom of the prompt. Anthropic has reported up to a 30% performance improvement when using this technique.
You can use the following structure:
When dealing with long contexts, I generally reiterate the objective at the bottom of both the system and user prompts.
Other advanced prompting techniques
After you’ve mastered the basics, you’re 90% of the way there. There are other, more advanced techniques that might also be worth trying:
- Exemplar Selection KNN (ES-KNN): Instead of having a fixed selection of examples, you can embed the user query and the examples, and then use a KNN algorithm to select the most relevant examples. This has been shown to improve the quality of results in many tasks.
- Self-consistency (SC): You use the model to generate multiple responses and then select the most consistent one by marginalizing over the noise. This has been shown to boost performance in CoT prompting.
- Thread of Thought (ThoT): This is a two-tiered prompting system that first asks the LLM to do an analytical dissection of the context, step by step, and summarize intermediate results. Then, it uses another prompt to distill the analysis into a final answer.
There are more advanced techniques that I’m not going to cover here. This paper by E.G. Santana et al. is a good starting point.
Using LLMs to write prompts
This is something I don’t like highlighting too much because people tend to abuse it: you can use LLMs to help you write prompts faster.
But please, don’t just copy-paste what the model generates. You’ll often get generic prompts that sound impressive but don’t actually help. Always review and refine the output yourself, especially if performance matters for your task. I haven’t found cases where letting an LLM write my prompts without supervision gives me better results than doing it myself.
Conclusion
This article is a short guide to help you write better prompts. Good prompt engineering can be summarized in 6 key principles:
- Be clear and specific
- Provide examples
- Let models think
- Structure prompts into sections and use delimiters
- Split complex tasks into smaller steps
- Repeat instructions when the context is long
These principles will not make your crappy LLM pipeline go from barely usable to raising millions from VC firms. But they will definitely get you on the right path3.
I hope you found this article useful. If you have any questions or feedback, leave a comment below.
Footnotes
Citation
@online{castillo2025,
author = {Castillo, Dylan},
title = {How to Write Good Prompts},
date = {2025-06-26},
url = {https://dylancastillo.co/posts/prompt-engineering-101.html},
langid = {en}
}