{"course":{"slug":"building-with-ai","title":"Building with AI","url":"https://addaly.com/learn/building-with-ai","level":"intermediate","track":"build"},"lesson":{"slug":"the-prompt-is-an-interface","title":"A prompt is an interface, not a paragraph","url":"https://addaly.com/learn/building-with-ai/the-prompt-is-an-interface","position":11,"of":80,"minutes":9,"answer":"Write rules you could assert on, always define an explicit sentinel for I-do-not-know, and prune the prompt by deleting lines and re-running your cases.","keyIdea":"Write rules you could assert on, always define an explicit sentinel for I-do-not-know, and prune the prompt by deleting lines and re-running your cases, because unread instructions still bill on every call and compete with the ones that matter."},"body":{"format":"markdown","text":"## The shape that survives\n\nAlmost every prompt that lasts in production has the same five parts, in roughly this order. The order is not aesthetic; each part is placed where it is for a mechanical reason.\n\n1. **Role and scope.** Two sentences. Who this assistant is and, more importantly, what it does not do.\n2. **The task**, stated as a procedure rather than a wish.\n3. **The material**: the retrieved documents, the ticket, the code. Long, variable, and the reason for the call.\n4. **Rules and format**, including what to do when the material does not contain the answer.\n5. **The user's actual question**, last.\n\nParts 1, 2 and 4 are stable across calls. Parts 3 and 5 change. That split is not incidental: it is exactly the boundary that prompt caching bills at, and getting the order wrong can cost you a 90 per cent discount you did not know you were entitled to.\n\nPutting the question last also matters for a second reason. Recall is measurably strongest at the beginning and the end of a long context. The instruction that governs the answer should not be buried at position 4,000 of 12,000.\n\n## Behaviour, not adjectives\n\nThe most common wasted line in a prompt is an adjective. *Be helpful, accurate and concise* changes nothing you can measure, because it does not describe an action.\n\n> Figure: The five parts, and where the cache boundary falls. Layers, top to bottom: 1. Role and scope: stable (Two sentences: who this assistant is and, more importantly, what it does not do); 2. The task, as a procedure: stable (Steps you could hand to a new colleague, not a wish); 3. The material: variable (The retrieved passages, the ticket, the code: long, and the reason for the call); 4. Rules, format and the sentinel: stable (Including what to output when the material does not contain the answer); 5. The user's question: variable, last (Recall is strongest at the beginning and the end of a long context). Parts one, two and four are byte-identical on every call; parts three and five change. Keeping the stable block above the variable one is what a provider's prefix cache bills at, and putting the question last is what stops it being buried at position 4,000 of 12,000.\n\nCompare:\n\n> Be concise and professional. Do not make things up.\n\nagainst:\n\n> Answer in at most four sentences. If the documents do not contain the answer, reply exactly: `NOT_IN_DOCS`, and nothing else. Never name a price that does not appear verbatim in the documents.\n\nThe second version can be tested. You can count sentences, you can grep for the sentinel, you can check every price in the output against the source. The first version can only be argued about. **A rule you cannot write an assertion for is a rule the model will follow inconsistently and you will never notice.**\n\n## Say what to do when it does not know\n\nThis is the single highest-value line in most prompts and the one most often missing. A model with no path to \"I cannot answer this\" will produce something, because producing text is what it does. The path has to be explicit, and it has to be cheap for the model to take.\n\nGive it a token:\n\n> If the retrieved passages do not answer the question, output exactly `INSUFFICIENT_CONTEXT`. Do not apologise, do not speculate, do not offer a general answer.\n\nA sentinel beats a sentence, because your code can branch on it. `INSUFFICIENT_CONTEXT` is a control-flow signal; \"I'm sorry, I don't have enough information to answer that\" is prose you would have to pattern-match, and the pattern changes every time the model version does.\n\nThen make the fallback good. When your code sees the sentinel it should show the user something useful: the closest documents, a search box, a route to a human. Handled well, an honest refusal raises trust more than a confident guess ever does.\n\n## Delimiters, and why they are not decoration\n\nWhen your prompt contains user-supplied text, mark the boundary explicitly:\n\n```text\n<document>\n{{ document_text }}\n</document>\n\n<question>\n{{ user_question }}\n</question>\n```\n\nXML-style tags work well because models have seen enormous quantities of tagged text and because they are visually unambiguous. Markdown headings are weaker: a document containing its own `## Instructions` heading blends straight into your prompt.\n\nThis is partly a correctness measure and partly a security one. Text you did not write is data. Delimiters are the first, weakest layer of keeping it that way: necessary, and nowhere near sufficient, which is the subject of a later module.\n\n## Prefill the answer\n\nA technique that is underused and costs nothing. Most APIs let you begin the assistant's turn yourself, and the model continues from where you stopped.\n\n```python\nmessages = [\n  {\"role\": \"user\", \"content\": prompt},\n  {\"role\": \"assistant\", \"content\": \"{\"},      # it must now continue JSON\n]\n```\n\nThat one character removes preambles, removes code fences, and forces the shape you want. Prefill with `-` for a list, with `{` for an object, with `Analysis:` to skip the pleasantries. It is more reliable than asking for the same thing in words, because you have removed the option rather than requested it.\n\n## Length is not quality\n\nPrompts grow by accretion. Every bug gets a new line, nothing is ever deleted, and after four months the system prompt is 2,000 tokens of contradictory instructions written by six people. Two failures follow.\n\nInstructions **conflict** (an early line says be thorough, a later one says be brief) and which wins is unpredictable per call. And the whole thing is **paid for on every request**: 2,000 tokens at $3 per million, a million calls a month, is $6,000 a year for a prompt nobody has read end to end.\n\nSo prune deliberately. Delete a rule, run your test cases, see whether anything broke. Most teams discover that a third of their prompt is doing nothing, and that removing it improves compliance with the rules that remain: the model has fewer instructions competing for attention. The best prompt is not the longest one. It is the shortest one that passes."},"check":{"question":"A retrieval assistant sometimes answers questions its documents do not cover, using general knowledge. The prompt already says \"only use the provided documents\". What is the most effective addition?","options":[{"text":"Repeat the instruction at both the start and the end of the prompt so it cannot be missed.","correct":false,"tempting":"Improves salience slightly but still leaves the model with no defined action other than producing an answer of some kind."},{"text":"Lower the temperature to zero so it stops improvising.","correct":false,"tempting":"Reduces variation between runs without giving the model any alternative behaviour; the most likely token sequence can still be an unsupported answer."},{"text":"Define an exact sentinel to emit when the documents do not answer the question, and branch on it in code.","correct":true},{"text":"Add examples of good answers so it learns the expected standard.","correct":false,"tempting":"Teaches the shape of answers that exist, which does not help in the case where the correct behaviour is to produce no answer at all."}]},"prev":{"slug":"images-files-and-audio-in","title":"Sending images, PDFs and audio, and what they cost","url":"https://addaly.com/learn/building-with-ai/images-files-and-audio-in"},"next":{"slug":"examples-that-teach","title":"Examples that teach, and examples that mislead","url":"https://addaly.com/learn/building-with-ai/examples-that-teach"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'A prompt is an interface, not a paragraph', in Building with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-with-ai/the-prompt-is-an-interface (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"A prompt is an interface, not a paragraph","courseTitle":"Building with AI","module":{"index":2,"slug":"prompting-as-engineering","title":"Prompting as engineering"},"answer":null,"keyIdea":"Write rules you could assert on, always define an explicit sentinel for I-do-not-know, and prune the prompt by deleting lines and re-running your cases, because unread instructions still bill on every call and compete with the ones that matter.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure 2.1","figure":{"type":"stack","title":"The five parts, and where the cache boundary falls","layers":[{"label":"1. Role and scope: stable","detail":"Two sentences: who this assistant is and, more importantly, what it does not do"},{"label":"2. The task, as a procedure: stable","detail":"Steps you could hand to a new colleague, not a wish"},{"label":"3. The material: variable","detail":"The retrieved passages, the ticket, the code: long, and the reason for the call"},{"label":"4. Rules, format and the sentinel: stable","detail":"Including what to output when the material does not contain the answer"},{"label":"5. The user’s question: variable, last","detail":"Recall is strongest at the beginning and the end of a long context"}],"caption":"Parts one, two and four are byte-identical on every call; parts three and five change. Keeping the stable block above the variable one is what a provider’s prefix cache bills at, and putting the question last is what stops it being buried at position 4,000 of 12,000."},"alt":"Figure: The five parts, and where the cache boundary falls. Layers, top to bottom: 1. Role and scope: stable (Two sentences: who this assistant is and, more importantly, what it does not do); 2. The task, as a procedure: stable (Steps you could hand to a new colleague, not a wish); 3. The material: variable (The retrieved passages, the ticket, the code: long, and the reason for the call); 4. Rules, format and the sentinel: stable (Including what to output when the material does not contain the answer); 5. The user’s question: variable, last (Recall is strongest at the beginning and the end of a long context). Parts one, two and four are byte-identical on every call; parts three and five change. Keeping the stable block above the variable one is what a provider’s prefix cache bills at, and putting the question last is what stops it being buried at position 4,000 of 12,000."}},"blocks":[{"t":"h2","id":"the-shape-that-survives","runs":[{"text":"The shape that survives"}]},{"t":"p","runs":[{"text":"Almost every prompt that lasts in production has the same five parts, in roughly this order. The order is not aesthetic; each part is placed where it is for a mechanical reason."}]},{"t":"ol","start":1,"items":[[{"text":"Role and scope.","b":true},{"text":" Two sentences. Who this assistant is and, more importantly, what it does not do."}],[{"text":"The task","b":true},{"text":", stated as a procedure rather than a wish."}],[{"text":"The material","b":true},{"text":": the retrieved documents, the ticket, the code. Long, variable, and the reason for the call."}],[{"text":"Rules and format","b":true},{"text":", including what to do when the material does not contain the answer."}],[{"text":"The user’s actual question","b":true},{"text":", last."}]]},{"t":"p","runs":[{"text":"Parts 1, 2 and 4 are stable across calls. Parts 3 and 5 change. That split is not incidental: it is exactly the boundary that prompt caching bills at, and getting the order wrong can cost you a 90 per cent discount you did not know you were entitled to."}]},{"t":"p","runs":[{"text":"Putting the question last also matters for a second reason. Recall is measurably strongest at the beginning and the end of a long context. The instruction that governs the answer should not be buried at position 4,000 of 12,000."}]},{"t":"h2","id":"behaviour-not-adjectives","runs":[{"text":"Behaviour, not adjectives"}]},{"t":"p","runs":[{"text":"The most common wasted line in a prompt is an adjective. "},{"text":"Be helpful, accurate and concise","i":true},{"text":" changes nothing you can measure, because it does not describe an action."}]},{"t":"p","runs":[{"text":"Compare:"}]},{"t":"quote","runs":[{"text":"Be concise and professional. Do not make things up."}]},{"t":"p","runs":[{"text":"against:"}]},{"t":"quote","runs":[{"text":"Answer in at most four sentences. If the documents do not contain the answer, reply exactly: "},{"text":"NOT_IN_DOCS","code":true},{"text":", and nothing else. Never name a price that does not appear verbatim in the documents."}]},{"t":"p","runs":[{"text":"The second version can be tested. You can count sentences, you can grep for the sentinel, you can check every price in the output against the source. The first version can only be argued about. "},{"text":"A rule you cannot write an assertion for is a rule the model will follow inconsistently and you will never notice.","b":true}]},{"t":"h2","id":"say-what-to-do-when-it-does-not-know","runs":[{"text":"Say what to do when it does not know"}]},{"t":"p","runs":[{"text":"This is the single highest-value line in most prompts and the one most often missing. A model with no path to “I cannot answer this” will produce something, because producing text is what it does. The path has to be explicit, and it has to be cheap for the model to take."}]},{"t":"p","runs":[{"text":"Give it a token:"}]},{"t":"quote","runs":[{"text":"If the retrieved passages do not answer the question, output exactly "},{"text":"INSUFFICIENT_CONTEXT","code":true},{"text":". Do not apologise, do not speculate, do not offer a general answer."}]},{"t":"p","runs":[{"text":"A sentinel beats a sentence, because your code can branch on it. "},{"text":"INSUFFICIENT_CONTEXT","code":true},{"text":" is a control-flow signal; “I’m sorry, I don’t have enough information to answer that” is prose you would have to pattern-match, and the pattern changes every time the model version does."}]},{"t":"p","runs":[{"text":"Then make the fallback good. When your code sees the sentinel it should show the user something useful: the closest documents, a search box, a route to a human. Handled well, an honest refusal raises trust more than a confident guess ever does."}]},{"t":"h2","id":"delimiters-and-why-they-are-not-decoration","runs":[{"text":"Delimiters, and why they are not decoration"}]},{"t":"p","runs":[{"text":"When your prompt contains user-supplied text, mark the boundary explicitly:"}]},{"t":"code","lang":"text","label":"Text","text":"<document>\n{{ document_text }}\n</document>\n\n<question>\n{{ user_question }}\n</question>"},{"t":"p","runs":[{"text":"XML-style tags work well because models have seen enormous quantities of tagged text and because they are visually unambiguous. Markdown headings are weaker: a document containing its own "},{"text":"## Instructions","code":true},{"text":" heading blends straight into your prompt."}]},{"t":"p","runs":[{"text":"This is partly a correctness measure and partly a security one. Text you did not write is data. Delimiters are the first, weakest layer of keeping it that way: necessary, and nowhere near sufficient, which is the subject of a later module."}]},{"t":"h2","id":"prefill-the-answer","runs":[{"text":"Prefill the answer"}]},{"t":"p","runs":[{"text":"A technique that is underused and costs nothing. Most APIs let you begin the assistant’s turn yourself, and the model continues from where you stopped."}]},{"t":"code","lang":"python","label":"Python","text":"messages = [\n  {\"role\": \"user\", \"content\": prompt},\n  {\"role\": \"assistant\", \"content\": \"{\"},      # it must now continue JSON\n]"},{"t":"p","runs":[{"text":"That one character removes preambles, removes code fences, and forces the shape you want. Prefill with "},{"text":"-","code":true},{"text":" for a list, with "},{"text":"{","code":true},{"text":" for an object, with "},{"text":"Analysis:","code":true},{"text":" to skip the pleasantries. It is more reliable than asking for the same thing in words, because you have removed the option rather than requested it."}]},{"t":"h2","id":"length-is-not-quality","runs":[{"text":"Length is not quality"}]},{"t":"p","runs":[{"text":"Prompts grow by accretion. Every bug gets a new line, nothing is ever deleted, and after four months the system prompt is 2,000 tokens of contradictory instructions written by six people. Two failures follow."}]},{"t":"p","runs":[{"text":"Instructions "},{"text":"conflict","b":true},{"text":" (an early line says be thorough, a later one says be brief) and which wins is unpredictable per call. And the whole thing is "},{"text":"paid for on every request","b":true},{"text":": 2,000 tokens at $3 per million, a million calls a month, is $6,000 a year for a prompt nobody has read end to end."}]},{"t":"p","runs":[{"text":"So prune deliberately. Delete a rule, run your test cases, see whether anything broke. Most teams discover that a third of their prompt is doing nothing, and that removing it improves compliance with the rules that remain: the model has fewer instructions competing for attention. The best prompt is not the longest one. It is the shortest one that passes."}]}],"check":{"question":[{"text":"A retrieval assistant sometimes answers questions its documents do not cover, using general knowledge. The prompt already says “only use the provided documents”. What is the most effective addition?"}],"options":[{"text":[{"text":"Repeat the instruction at both the start and the end of the prompt so it cannot be missed."}],"correct":false,"tempting":[{"text":"Improves salience slightly but still leaves the model with no defined action other than producing an answer of some kind."}]},{"text":[{"text":"Lower the temperature to zero so it stops improvising."}],"correct":false,"tempting":[{"text":"Reduces variation between runs without giving the model any alternative behaviour; the most likely token sequence can still be an unsupported answer."}]},{"text":[{"text":"Define an exact sentinel to emit when the documents do not answer the question, and branch on it in code."}],"correct":true,"tempting":null},{"text":[{"text":"Add examples of good answers so it learns the expected standard."}],"correct":false,"tempting":[{"text":"Teaches the shape of answers that exist, which does not help in the case where the correct behaviour is to produce no answer at all."}]}],"order":[3,0,2,1],"why":null},"prev":{"slug":"images-files-and-audio-in","title":"Sending images, PDFs and audio, and what they cost","minutes":9},"next":{"slug":"examples-that-teach","title":"Examples that teach, and examples that mislead","minutes":9}}}