
Prompt Engineering for Developers
A practical guide to prompt engineering, focused on techniques that developers can use to get better results from language models like GPT and Claude.
✨TL;DR / Executive Summary
A practical guide to prompt engineering, focused on techniques that developers can use to get better results from language models like GPT and Claude.
💡 TL;DR (Too Long; Didn't Read)
Prompt engineering is the art of creating effective inputs for language models (LLMs). For developers, the most important techniques are: providing rich context (code, error logs), using delimiters (like
```or<xml>), defining a clear role for the AI (e.g., "act as a senior Python expert developer"), and using the Chain-of-Thought (CoT) technique, asking the AI to "think step by step" before giving the final answer.
What is Prompt Engineering (and why should devs care)?
Prompt Engineering is the process of structuring the text you provide to a language model (LLM) to get the most accurate, relevant, and useful response possible. For a developer, this isn't just "chatting with a chatbot"; it's a new way to interact with a powerful productivity tool.
Mastering this skill means:
- More accurate code responses: Generate code that works the first time.
- Faster debugging: Get root cause analyses instead of generic suggestions.
- Task automation: Create scripts, documentation, and tests more efficiently.
Essential Techniques for Developers
1. Provide Rich and Specific Context
LLMs don't have access to your local environment. You need to provide all necessary context.
- Bad: "My code doesn't work, help me."
- Good: "I'm getting a
TypeError: cannot read property 'map' of undefinederror in a React component. Here's the component code, the complete console error, and an example of thepropsobject it receives."
Practical Example:
typescript
// MyComponent.tsx component
function MyComponent({ items }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}
```
**Console Error:**
`TypeError: cannot read property 'map' of undefined`
**Received `props` object:**
`{}` (empty)
**Question:**
"Act as a senior React developer. Analyze the error, the component, and the props object, and tell me the root cause and how I can fix the component to be more robust against this error."2. Use Clear Delimiters
Delimiters tell the AI exactly where a text section begins and ends (like a code snippet, error log, or example). This prevents the model from confusing instructions with data.
Common delimiters:
- Triple quotes:
""" - Triple backticks for code blocks:
``` - XML tags:
<code>...</code>,<error>...</error>
Example:
Analyze the following Go code delimited by ```go and suggest performance improvements.
```go
func Sum(nums []int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
### 3. Assign a Role (Persona)
Instructing the AI to "act as" a specific persona activates the model's knowledge related to that domain, resulting in more specialized responses.
- **For code:** "Act as a Principal Software Engineer with 20 years of experience in C++ and low-latency systems."
- **For security:** "Act as an Application Security (AppSec) specialist."
- **For architecture:** "Act as an AWS Solutions Architect."
### 4. Chain-of-Thought (CoT) - The "Golden Technique"
This is perhaps the most powerful technique. Instead of asking for the final answer directly, ask the AI to "think step by step." This forces the model to externalize its reasoning process, which generally leads to more logical and correct conclusions.
**Debugging example:**
**Simple Prompt (bad):**
> "Fix this Python code:"
> ```python
> def get_user(id):
> return users[id]
> ```
**CoT Prompt (excellent):**
> "Analyze the following Python code. Think step by step about potential problems, especially regarding edge cases and runtime errors. After listing your reasoning, suggest a more robust version of the code."
> ```python
> def get_user(id):
> return users[id]
> ```
**Expected AI Response:**
> **Step-by-Step Reasoning:**
> 1. The function assumes the `users` variable exists in scope, but it's not defined.
> 2. The function assumes `users` is a dictionary or similar object.
> 3. The main problem is there's no handling for when the `id` doesn't exist in `users`. This would cause a `KeyError`.
> 4. The `id` type is not checked. If it's an invalid type, it could cause an error.
>
> **Suggested Robust Code:**
> ```python
> def get_user(users_dict: dict, user_id: int) -> dict | None:
> """Safely retrieves a user from a dictionary."""
> return users_dict.get(user_id)
> ```
### 5. "Few-Shot" Prompting (Learning by Example)
If you want the AI to generate something in a specific format, give it some examples.
**Example for generating tests:**
Generate a unit test for the following JavaScript function using the pattern I provide.
Function to test:
function sum(a, b) {
return a + b;
}Example test in desired format:
test('should sum 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});Your turn: Generate a test for the case where the function sums negative numbers.
## Anti-Patterns to Avoid
- **Ambiguity:** "Make this code better." (Better in what? Performance? Readability? Security?)
- **Lack of Context:** "Why am I getting an error?" (What error? What code?)
- **Long Continuous Conversations:** LLMs have a limited "context window." In very long conversations, they start to "forget" the beginning. It's better to start a new conversation with a complete prompt for a new task.
## Final Prompt: A Template for Developers
Use this template as a starting point for your own development tasks:
```markdown
**# CONTEXT**
I'm working on a [language/framework] application and need to [objective].
**# PERSONA**
Act as a [specialist role, e.g., REST API security expert].
**# TASK**
[Describe the task clearly and specifically, e.g., "Review the following controller function in Node.js and identify potential security vulnerabilities."]
**# CODE / DATA**
` ``[language]
// Paste your code, error log, or data here
` ``
**# OUTPUT RULES**
1. Provide your response in list format (Markdown).
2. For each vulnerability, explain the risk and provide a corrected code example.
3. Use the Chain-of-Thought technique: first explain your reasoning, then present the solution.
## Where the "{X}" and "{Y}" Placeholders Were
The error was caused by placeholders like `{'{X}'}` and `{'{Y}'}` that were in the document. The correct syntax to display literal braces inside an `.mdx` file is to use a string expression, like `{'{}'}`. The fix was applied.
`next-mdx-remote`, when encountering `{X}` or `{Y}`, tried to interpret them as JavaScript variables, which failed because `X` and `Y` were not defined. This triggered the `acorn` parser error. By changing to `{'{}'}`, we instructed MDX to simply render the literal string "{}" (or, in this case, "{X}" and "{Y}"), resolving the compilation error.