Prompt engineering for LLMs: the basics that work with any model
A good prompt is not a spell but six concrete parts. We show them on one example where both the answer and the request price change.
5 min · · development · экономия
Prompt engineering for LLMs sounds grand, but at heart it is the skill of phrasing a task so the model does not have to guess. A bad answer is often explained not by a weak model but by an understated request: no format given, no context, no boundaries. Below are six parts of a good prompt, a before-and-after example and a calculation of how structure affects price. Prices are as of October 18, 2026.
What prompt engineering is and what it does not do
Prompt engineering is the design of a model's input text: instructions, data and examples. It needs no secret phrases. Spells like "you are the best expert in the world" without specifics add little, which is easy to check on your own tasks. What works is concrete: a clear goal, the necessary data, an understandable answer format.
It also does not replace verification. Even a perfect prompt does not guarantee correct facts, so answers must be checked. For more on the system part of a request, see the article How to write system prompts. The basics can be learned in an evening, but tuning a prompt to a specific model and task takes iteration.
Six parts of the structure
Not every part is needed in every prompt, but the checklist is handy to keep in view.
- Role. One line: who answers and for whom. "You are a support operator at an online store writing to customers." The role sets vocabulary and level of detail.
- Task. What exactly to do, with one verb. "Prepare a reply to the letter." One task per request; split a complex one into steps.
- Context. Facts the model does not have: company policy, order details, terminology. Everything needed for the answer must be in the request: the model does not know your internal rules.
- Format. Length, structure, language, form of address, JSON fields. "A letter up to 80 words, formal address, with the next step and deadline at the end."
- Examples. One to three samples of the desired result work better than long descriptions. More in the article on few-shot prompting.
- Constraints. What not to do: "do not promise what is not in the policy", "do not invent numbers and dates", "if data is missing, say exactly what".
A separate note on markup. Separate user data (a letter, a document, code) from instructions with delimiters, for example the tags <letter>...</letter>. That way the model does not take the letter text for instructions, and it is easier for you to insert data programmatically.
Example: a prompt before and after
A hypothetical store. A customer writes: "Order 4521 did not arrive, refund my money."
Version 1: a short request.
Reply to the customer's letter: Order 4521 did not arrive, refund my moneyThe model has to guess. Most likely you will get a long letter with generic apologies, a promise to refund in an unknown time frame, a request to "clarify details", and possibly invented refund conditions.
Version 2: a structured request.
Role: you are a support operator at an online store.
Task: prepare a reply to the customer's letter.
Context: we refund within 5 business days after non-delivery is confirmed.
Order 4521 was shipped on October 3, the tracking has not updated for 10 days.
Format: a letter up to 80 words, formal address, one apology, the next step
and a deadline at the end.
Constraints: do not promise anything that is not in the policy. Do not invent
numbers or dates. If data is missing, say exactly what.
<letter>
Order 4521 did not arrive, refund my money
</letter>Now the model has facts, boundaries and a format. The answer becomes shorter, more predictable and ready to send after a quick check. Version 2 is convenient to keep as a template and fill in with the letter and facts in code.
What it looks like in code
Through the OpenAI format (pip install openai):
from openai import OpenAI
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_your_key")
SYSTEM = """Role: you are a support operator at an online store.
Format: a letter up to 80 words, formal address, one apology, the next step and a deadline at the end.
Constraints: do not promise anything that is not in the policy. Do not invent numbers or dates.
If data is missing, say exactly what."""
def reply(letter, facts):
user = f"Prepare a reply to the letter.\nContext: {facts}\n\n<letter>\n{letter}\n</letter>"
r = client.chat.completions.create(
model="gpt-6.1-sol",
messages=[In the Anthropic format the system instruction is passed as a separate system parameter (the address has no /v1):
import anthropic
a = anthropic.Anthropic(base_url="https://api.zukko.pro", api_key="fetch_your_key")
m = a.messages.create(
model="claude-sonnet-5-5",
max_tokens=300,
system=SYSTEM,
messages=[{"role": "user", "content": "Prepare a reply to the letter.\n\n<letter>\nOrder 4521 did not arrive, refund my money\n</letter>"}],
)
print(m.content[0].text)Note max_tokens=300: in the Anthropic format the parameter is required, and it also limits the answer length.
How structure affects price
Output tokens cost more than input tokens: for claude-sonnet-5-5 input is 0.4 and output is 2 dollars per 1M tokens, so output is five times more expensive. So extra words in the answer cost more than extra words in the request.
Assumptions for the calculation (not measurements, a rough guide): version 1 has 30 request tokens and 600 answer tokens; version 2 has 300 request tokens and 150 answer tokens.
- Version 1: 30 × 0.4 / 1M + 600 × 2 / 1M = 0.000012 + 0.0012 = $0.001212.
- Version 2: 300 × 0.4 / 1M + 150 × 2 / 1M = 0.00012 + 0.0003 = $0.00042.
For 10,000 letters: version 1 gives 10,000 × 0.001212 = $12.12, version 2 gives 10,000 × 0.00042 = $4.20. The request became ten times longer, yet the cost is lower, because the answer got shorter. Your real numbers will differ, so measure the usage field on your own data. If the system part is long and does not change, put it at the start of the request so the cache can work (see how cache reads and writes are billed). Check current prices in GET https://api.zukko.pro/v1/models.
Iterating and verifying
A prompt rarely works on the first try. A working cycle:
- Collect 10–20 real example inputs, including awkward ones.
- Run the prompt on all of them at once and read the answers in full.
- Change one thing at a time and compare. If you change three parameters at once, you will not know what helped.
- Lock in checks in code: length, required words, valid JSON.
- After switching models, rerun the set: the same prompt may behave differently.
How to automate such a run is shown in the article How to test prompts. You can start by creating a key in the dashboard; payment from Russia is by SBP (the payment page adds an 8.5% fee on top), a MasterCard or cryptocurrency.
FAQ
What is prompt engineering in simple terms?
It is the skill of composing a request so that the model gets the goal, the necessary data and the requirements for the answer, and does not have to guess. The basis is structure: role, task, context, format, examples and constraints.
Do prompts have to be long?
Not necessarily long, but specific enough. Extra words hurt as much as missing facts. A guide: the request contains everything needed for the answer and nothing that does not affect the result.
Will one prompt fit all models?
The basic principles are shared, but models behave differently, and exact wording is best tested on the chosen model. After switching models, rerun your examples.
How do I cut token spending on prompts?
Ask for a specific format and answer length, limit max_tokens, do not repeat long context needlessly, and put the unchanging part at the start of the request so the cache works.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- Chatbot memory: how to store conversation history without paying twiceThe model does not remember earlier messages: you send the history with every request. We look at how dialogue cost grows and what keeps it in check.
- LangChain text splitters: how to cut text into chunks correctlyHow to choose chunk size and overlap in RecursiveCharacterTextSplitter, why you should count in tokens and how to check the count against an exact token number.
- LangChain RAG: a working example with a model via a gatewayWe build a simple RAG with LangChain: documents, chunks, vector search and a model answer via a gateway. We count what a question costs and trim wasted tokens.
- opencode agents: setting up roles, models and toolsA custom agent in opencode is a role, a model and a set of permissions. A working config where a cheap model handles routine work and a stronger one edits code.