Prompt Engineering Tutorial: Learn Advanced LLM Prompting (2026)
Prompt engineering has evolved from a curiosity to a core skill for anyone working with LLMs. After building production prompt systems for customer support automation, code generation, and data extraction, I have learned that effective prompting is not about 'magic phrases' — it is about structured communication, constraint design, and systematic evaluation.
This advanced tutorial moves beyond 'write a clear prompt.' You will learn chain-of-thought, structured output extraction, multi-turn agent design, prompt compression, evaluation frameworks, and the anti-patterns that separate expert prompt engineers from beginners.
Chain-of-Thought Reasoning
Chain-of-thought (CoT) prompting asks the model to reason step by step before giving a final answer. This dramatically improves performance on math, logic, and multi-step problems. The simplest form is appending 'Let's think step by step.' More structured variants include few-shot CoT and self-consistency (generating multiple reasoning paths and picking the majority answer).
For code generation, CoT means asking the model to outline the algorithm in pseudocode first. For data extraction, ask it to list relevant entities before formatting the output. Reasoning tokens improve final accuracy by 15-30% on hard problems.
prompt = """Question: A store has 120 apples. It sells 2/3 in the morning
and 3/4 of the remaining in the afternoon. How many apples are left?
Let's think step by step."""
code_prompt = """Write a Python function that finds the longest palindromic substring.
First, explain the approach you'll use.
Then write the code.
Finally, trace through an example."""
Structured Output with JSON Mode
Raw text responses are hard to parse reliably. Modern LLMs support constrained output formats: JSON mode, function calling, and grammar-constrained generation. JSON mode forces the model to output valid JSON that matches a schema you provide.
For production extraction pipelines, define the schema upfront with type constraints. Use the model's function-calling API rather than instructing it in text. This gives guaranteed parseable output and focuses the model's attention on generating values within the schema.
prompt = """Extract information from this invoice and return JSON.
Schema:
{
"invoice_number": string,
"date": string (ISO format),
"total": number,
"line_items": [{"description": string, "amount": number}]
}
Invoice: ACME Corp - INV-2026-0892, dated 2026-07-01,
Widget A x2 @ $45.00, Widget B x1 @ $120.00, Total: $210.00
Return only the JSON."""
Multi-Turn Agent Design
Advanced agents chain multiple LLM calls, each with a specific tool or sub-task. A typical agent loop: (1) receive user request, (2) call classifier to determine intent, (3) call extraction to get parameters, (4) execute tool, (5) format response. Each step uses a distinct prompt optimized for its specific task.
The key insight: a single mega-prompt with all instructions performs worse than a pipeline of focused prompts. Each prompt has a system instruction, a specific schema, and few-shot examples. Measure each step's accuracy independently.
class Agent:
def __init__(self):
self.classifier = Prompt('Classify intent: schedule, query, action')
self.extractor = Prompt('Extract params as JSON: ...')
self.responder = Prompt('Format response: ...')
def handle(self, user_input):
intent = self.classifier.run(user_input)
params = self.extractor.run(user_input)
result = self.execute_tool(intent, params)
return self.responder.run(result)
Prompt Compression and Cost Optimization
Long prompts cost more and may exceed context windows. Prompt compression techniques include: removing redundant instructions, using concise terminology, consolidating few-shot examples, and leveraging the model's pre-existing knowledge rather than spelling everything out. A 50% reduction in prompt tokens is often achievable without quality loss.
For production, implement a prompt versioning system. Track prompt length, cost, and accuracy per version. Use LLM-as-judge evaluation to compare version performance before rolling out changes.
# Before (verbose): 450 tokens
prompt = "You are a helpful assistant that translates English to French. "
prompt += "Please translate the following English text to French. "
prompt += "Only respond with the translation, nothing else."
# After (concise): 180 tokens
prompt = "Translate to French. Respond only with translation.\n\nText: {input}"
Evaluation Frameworks
You cannot improve what you do not measure. Build an evaluation dataset of 100+ examples with expected outputs. Run each prompt version against this dataset and compute accuracy. For subjective quality, use LLM-as-judge: ask a strong model (GPT-4, Gemini Pro) to rate response quality on a 1-5 scale.
Key metrics: exact match (for structured output), BLEU/ROUGE (for text), F1 (for extraction), and pass@k (for code). Track these metrics over time in a dashboard.
eval_dataset = [
{'input': 'What is 2+2?', 'expected': '4'},
{'input': 'Capital of France?', 'expected': 'Paris'},
]
def evaluate(prompt_template):
correct = 0
for example in eval_dataset:
response = llm.call(prompt_template.format(input=example['input']))
if response.strip() == example['expected']:
correct += 1
return correct / len(eval_dataset)
Common Anti-Patterns
After reviewing thousands of production prompts, these anti-patterns are the most common: (1) Putting all instructions in the user message instead of system prompt. (2) Over-specifying format. (3) Assuming the model saw your training data — always include relevant context. (4) Not handling refusal — models may refuse valid requests; implement retry with rephrasing.
Best practices: test with temperature=0.3 (not 0 — some randomness helps avoid repetitive loops), include an example of the desired output format, and always validate output before presenting it to users.
# Anti-pattern: over-specification
bad = "You MUST answer in JSON. No other text. Only JSON. I repeat: JSON ONLY."
# Better: concise instruction with example
good = """Answer in JSON format.
{"answer": ""}
Question: {input}"""
Frequently Asked Questions
What is the most important skill for prompt engineering?
Iterative testing. The first prompt is never the best. Build an evaluation set, measure changes, and treat prompt engineering as an empirical science rather than guessing. Track version history and revert quickly when accuracy drops.
Should I use system prompt or user message for instructions?
System prompt carries more authority and is less likely to be ignored. Put core instructions, persona, and constraints in the system prompt. Use the user message for the specific task input. This separation improves reliability.
How do I handle prompt injection attacks?
Use input validation (strip special tokens), separate instructions from data, use output filtering, and never expose the full system prompt to end users. Consider using a separate classification model to detect injection attempts.
What is the best way to manage prompts in production?
Version control your prompts, store them as templates separate from code, implement A/B testing, log all prompt-response pairs for debugging, and set up monitoring for cost, latency, and refusal rate. Never hardcode prompts in application code.
Originally published on Ayodhyyya. Last updated June 1, 2026.