Prompt Engineering: A Practical Guide for Developers
Prompt engineering is the practice of designing inputs to a language model so that it reliably produces the output you want. It's not a magic trick or a set of secret incantations — it's closer to writing a clear spec for a very literal, very fast collaborator who has no memory of your project and no context beyond what you give it in the request.
If you're here because your LLM outputs are inconsistent, too verbose, ignoring instructions, or hallucinating structure that isn't there, the fix is almost always in how the prompt is built, not in switching models. This guide covers the techniques that consistently move the needle, in the order you should try them.
Start With Structure, Not Cleverness
The biggest mistake in prompt engineering is treating it like persuasion — trying to "convince" the model with tone or urgency. What actually works is structure: clearly separating instructions, context, and the task.
A well-structured prompt typically has:
- Role/system context — who the model is acting as and what constraints apply
- Task description — the specific thing to do, stated as an instruction, not a question
- Input data — clearly delimited (use headers, XML-style tags, or triple backticks)
- Output format — exactly what shape the response should take
- Examples (optional but powerful) — 1-3 examples of input/output pairs
System: You are a support ticket classifier. Only respond with valid JSON.
Task: Classify the ticket below into one of: billing, bug, feature_request, other.
Ticket:
"""
My card was charged twice this month for the same plan.
"""
Output format:
{"category": "string", "confidence": 0.0-1.0}
This structure removes ambiguity. The model doesn't have to guess where the instructions end and the data begins.
Techniques That Reliably Improve Output
Be explicit about format. If you want JSON, say "respond only with valid JSON, no prose before or after." If you want a specific schema, show it. Models default to conversational filler unless told not to.
Use few-shot examples for tone and edge cases. Zero-shot prompts work fine for straightforward tasks. For anything with nuance — tone matching, edge-case handling, domain-specific classification — 2-3 examples outperform paragraphs of instructions.
Give the model room to reason before answering, when it matters. For tasks involving multi-step logic, asking the model to "think step by step" or reason first and give the final answer last improves accuracy. For simple extraction or classification tasks, this just adds latency and cost — skip it.
Constrain scope explicitly. "Summarize this in 3 bullet points, each under 15 words" produces far more consistent output than "summarize this briefly." Vague quantifiers get vague results.
Separate system-level rules from per-request instructions. Rules that should apply to every call (tone, safety constraints, output format) belong in the system prompt. Task-specific details belong in the user message. Mixing them makes prompts harder to maintain and easier to break when you update one part.
Test negative instructions carefully. "Don't include a preamble" works less reliably than "start your response directly with the JSON object." Positive instructions about what to do beat negative instructions about what to avoid.
Prompt Engineering for Tool Use and Agents
When a model has access to tools (function calling, retrieval, code execution), prompt engineering extends beyond the text prompt to how you describe the tools themselves. Tool names and descriptions are part of the prompt — a vaguely named function like process() gives the model far less to work with than create_calendar_event(title, start_time, end_time).
Key practices for tool-using prompts:
- Write tool descriptions as if explaining them to a new engineer, not a marketing summary
- Specify exactly when a tool should and shouldn't be called
- Handle the case where the model should ask for clarification instead of guessing parameters
If you're building on the Claude API and want a straightforward way to wire this up, /docs/tools covers the request/response shape for tool calls through SubToAPI's Claude-compatible API.
Iterating Like an Engineer, Not a Writer
Treat prompts as code: version them, test them against real inputs, and measure output quality objectively where possible (exact match, schema validation, or a scoring rubric) rather than eyeballing a handful of examples.
A practical loop:
- Write a baseline prompt and run it against 10-20 representative real inputs, not synthetic ones
- Log failures and categorize them (wrong format, wrong content, missing edge case)
- Fix the most common failure category first — usually format issues, which are the cheapest to fix
- Re-run the full set after each change to catch regressions
- Freeze the prompt version once failure rate is acceptable, and keep the old version around for comparison
This is where usage metadata matters. If you're iterating on prompts against the Claude API, being able to see token counts and response times per request helps you catch prompts that got more expensive or slower without a corresponding quality gain. SubToAPI's dashboard surfaces this per API key, which is useful when you have multiple prompt versions running in parallel during testing — see /docs/messages for the request format.
Common Failure Modes and Fixes
- Model ignores part of a long prompt → move critical instructions to the start or end; models weight the edges of context more heavily than the middle
- Inconsistent formatting across calls → add explicit output schema and consider requesting the model wrap output in fixed delimiters you can parse
- Model over-explains when you want just an answer → explicitly state "no explanation, only the answer"
- Model invents information not in the provided context → add "if the answer isn't in the provided text, say so" as an explicit instruction
None of these fixes require a different model — they require a more precise prompt. If you're testing prompts against Claude and want an API key to experiment with quickly, /signup gives you a free trial, and /docs/quickstart walks through the first request.
Wrapping Up
Prompt engineering is fundamentally about removing ambiguity: structuring instructions, data, and expected output so the model has as little to guess as possible. Start with structure, add examples where nuance matters, constrain output format explicitly, and treat your prompts like versioned code that you test against real inputs. The techniques here apply regardless of which model or API you're calling — good prompts are a durable skill, not something tied to one vendor.
Questions
Does prompt engineering matter less as models get better? No — better models reduce the need for workarounds around model limitations, but ambiguous instructions still produce inconsistent output on any model. Structure and clear output specs remain valuable.
Should I use one giant prompt or break tasks into smaller steps? Break complex tasks into smaller prompts chained together when each step has a clear, checkable output. This makes failures easier to isolate and fix than debugging one large prompt.
How many examples should I include in a few-shot prompt? Start with 2-3 well-chosen examples covering different cases. More examples increase token cost and rarely improve results beyond 4-5 unless the task has many distinct edge cases.