Session 10· 02· 14 min

Specify & Constrain

What you'll learn
  • Define success before writing any prompt by listing inputs, outputs, format, and forbidden content
  • Apply four constraint techniques: delimiters, respond-with-only, stop sequences, and prefill
  • Rewrite a weak prompt into an engineered prompt using the specify-and-constrain pattern

Specify: define success first

A prompt cannot be well-engineered until you know what "correct" looks like. Before writing a single word of prompt copy, answer four questions.

  • Inputs — what does the model receive? (free text, structured JSON, code snippet, ...)
  • Outputs — what should the model produce? (one JSON object, a regex string, a Python function, ...)
  • Format — exactly what format must the output obey? (UTF-8, double-quoted keys, no markdown fences, ...)
  • Forbidden content — what must never appear? (preamble, apologies, backticks, extra keys, ...)

Constrain: four techniques

1. Delimiters

Wrap variable content in XML tags, triple-hashes, or markdown headings to separate instructions from data. The model is less likely to confuse injected content with your instructions when they are visually distinct.

2. "Respond with only..."

Explicit exclusion beats implicit expectation. "Emit only raw JSON content — no markdown code fences, no backticks, no preamble" leaves no room for ambiguity.

3. Stop sequences

Pass stop=["\n\n"] or another sentinel to the API to cut off generation as soon as the model would add unwanted trailing text. Useful for single-line outputs such as regex patterns.

4. Prefill

Some APIs allow you to inject the first token(s) of the assistant turn. Starting with { for JSON or def for Python steers the model immediately into the correct format and makes it structurally hard to emit a preamble.

Weak prompt vs engineered prompt

Here is the same AWS-task wrapper written two ways. The weak version relies on the model's good nature. The engineered version makes success structurally inevitable.

wrap_user_weak.py
def wrap_user_weak(test_case):
    return f"""Please help with this AWS-related request. Think briefly if helpful, then answer clearly.

{test_case["task"]}

You may explain your reasoning before giving the final answer."""
wrap_user_engineered.py
def wrap_user_engineered(test_case):
    fmt = test_case["format"]
    crit = test_case.get("solution_criteria", "")
    return f"""## Task
{test_case["task"]}

## Deliverable
Type: **{fmt}** (this case expects exactly one {fmt} artifact).

## Output rules
1. Emit **only** raw {fmt} content — no markdown code fences, no backticks, no preamble.
2. JSON: UTF-8, double-quoted keys/strings, no comments or trailing commas.
3. Python: minimal valid code that satisfies the task; no prints unless required.
4. Regex: one pattern string only.

## Rubric alignment
{crit}
"""
fmt and crit are extracted from the test case so every rule is format-specific.
Markdown headings (##) act as delimiters separating task, deliverable spec, and output rules.
"Emit only raw ... content" is the respond-with-only constraint.
Per-format rules (JSON/Python/Regex) cover the three artifact types in the dataset.
Rubric alignment repeats the judge criteria verbatim so the generator knows exactly what will be graded.
Align generator output rules with judge criteria
Copying the solution_criteria into the prompt tells the model what the judge will look for. This is not cheating — the task definition IS the spec. The model should know the spec.
Knowledge Check
Which constraint technique physically prevents the model from emitting a preamble before a JSON object?
Recap — what you just learned
  • Define inputs, outputs, format, and forbidden content before writing prompt copy
  • Delimiters separate instructions from variable data
  • "Respond with only" constraints beat implicit expectations
  • Stop sequences and prefill enforce format at the API level, not just the instruction level
  • The engineered wrapper exposes the rubric to the generator so both sides share the same success definition
Next up: Structure & Demonstrate