A Practical Guide to Prompt Engineering

What Is Prompt Engineering?

Prompt engineering is the art of giving precise instructions to an LLM to get the desired output. Even with the same model, the quality of responses varies dramatically depending on how the prompt is written. It’s like cooking — the same ingredients produce different dishes depending on the recipe.

In this post, we’ll cover six key techniques from Zero-shot to Chain of Thought, with code examples.

Key Techniques Overview

TechniqueDescriptionBest For
Zero-shotDirect instruction without examplesSimple tasks, classification, summarization
Few-shotProvide input-output examplesGuiding specific formats/styles
Chain of Thought (CoT)Guide step-by-step reasoningMath, logic problems
System PromptPre-define roles and rulesMaintaining consistent tone/format
Structured OutputSpecify format like JSONAPI responses, data extraction
Self-ConsistencyMultiple reasoning passes with majority voteTasks where accuracy is critical

Zero-shot Prompting

The most basic approach — direct instruction without examples. For GPT-4 class models, this is sufficiently effective for simple tasks.

from openai import OpenAI

client = OpenAI()

# Zero-shot: direct instruction without examples
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "user", "content": "Classify the sentiment of the following sentence as positive/negative/neutral: 'I absolutely love this product!'"}
    ]
)
print(response.choices[0].message.content)
# Positive

Clear instruction is the key to Zero-shot. Instead of “analyze this,” explicitly specify the output format like “classify as positive/negative/neutral” for higher accuracy.

Few-shot Prompting

Provide 2—5 input-output examples so the model can learn the pattern. This is effective when you need the output to follow a specific format or style.

# Few-shot: provide examples to guide format
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "user", "content": "Summarize product reviews in one line."},
        # Example 1
        {"role": "user", "content": "Review: Shipping was fast but the packaging was terrible. The product itself is fine."},
        {"role": "assistant", "content": "Fast shipping but poor packaging; product quality is acceptable"},
        # Example 2
        {"role": "user", "content": "Review: Great performance for the price. Just a bit noisy though."},
        {"role": "assistant", "content": "Excellent value but has noise issues"},
        # Actual request
        {"role": "user", "content": "Review: The design is beautiful but the battery doesn't last a full day. Charging is slow too."},
    ]
)
print(response.choices[0].message.content)
# Beautiful design but poor battery life and slow charging

The quality of your examples directly determines the quality of the response. Examples must maintain consistent format and length for the model to accurately identify the pattern.

Chain of Thought (CoT)

Adding the instruction “think step by step” causes the model to go through intermediate reasoning steps, producing more accurate answers. This is highly effective for math problems, logical reasoning, and complex analysis.

# Chain of Thought: guide step-by-step reasoning
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "Solve the problem step by step. Show each step clearly."},
        {"role": "user", "content": """
At a cafe, you ordered 3 americanos ($4.50 each) and 2 slices of cake ($6.00 each).
If you apply a 10% discount coupon, what is the final amount?
"""}
    ]
)
print(response.choices[0].message.content)
# Step 1: 3 americanos = $4.50 x 3 = $13.50
# Step 2: 2 slices of cake = $6.00 x 2 = $12.00
# Step 3: Total = $13.50 + $12.00 = $25.50
# Step 4: 10% discount = $25.50 x 0.9 = $22.95
# Final amount: $22.95

According to Wei et al. (2022), CoT prompting improved accuracy on the math reasoning benchmark (GSM8K) by approximately 3x (18% to 57%) on PaLM 540B compared to standard prompting. The effect is particularly pronounced on large models with 100B+ parameters.

System Prompt Design

The System Prompt defines the model’s role, tone, and constraints. It is set before the conversation begins and maintains consistent behavior throughout the entire conversation.

# Define role and rules with System Prompt
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": """
You are a senior Python developer.
Rules:
1. Include comments in your code
2. Use type hints
3. Warn about security vulnerabilities in code
4. Keep responses concise, under 200 characters
"""},
        {"role": "user", "content": "Create a function that takes user input and executes a SQL query"}
    ]
)
print(response.choices[0].message.content)

Here’s a summary of the elements that make an effective System Prompt.

ElementExampleEffect
Role definition”Senior Python developer”Sets expertise level
Output format”Respond in JSON”Parseable output
Constraints”Under 200 characters”Controls response length
Restrictions”Don’t speculate”Prevents hallucination
Tone setting”Friendly but professional”Consistent style

Structured Output Requests

When LLM responses need to be processed by a program, specifying a structured format like JSON makes parsing easy.

# Request structured JSON output
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "Output your response strictly in JSON format only. Do not include any other text."},
        {"role": "user", "content": """
Extract the person's information from the following text:
"John Smith is a 35-year-old software engineer living in Seoul who primarily uses Python and Go."

JSON schema:
{"name": string, "age": number, "job": string, "city": string, "skills": string[]}
"""}
    ],
    response_format={"type": "json_object"}  # Force JSON mode
)
print(response.choices[0].message.content)
# {"name": "John Smith", "age": 35, "job": "Software Engineer", "city": "Seoul", "skills": ["Python", "Go"]}

Using OpenAI API’s response_format={"type": "json_object"} forces the model to always return valid JSON. Similarly, with the Claude API, you can specify a json_schema type in output_config to enforce structured output.

Practical Tips: Bad Prompts vs Good Prompts

Bad PromptGood PromptImprovement
”Write some code""Write a JWT authentication middleware in Python using FastAPI.”Specifies language, framework, purpose
”Summarize this""Summarize this article in 3 key points. Each point should be one sentence.”Specifies output format and length
”What’s wrong?""Find the bug in this Python code and explain the cause and fix.”Specific action instruction
”Make it good""Refactor this function for performance and readability. Explain changes in comments.”Specifies criteria and supplementary tasks

Summary

The core of prompt engineering is specific and clear instructions. Here are the key principles:

  • Assign a role to get expert-level responses (System Prompt)
  • Provide examples to guide the desired format (Few-shot)
  • Request step-by-step thinking to improve accuracy on complex reasoning (CoT)
  • Specify the output format to make programmatic integration easier (JSON, etc.)
  • Instead of “do it well,” specify “what, in what format, by what criteria”

Was this article helpful?