Prompt engineering is the work of expressing the goal, relevant background, constraints, expected process, completion criteria, and output form so that a model is more likely to behave as intended across similar tasks. It is not a collection of magic phrases, and it does not require JSON. Good prose is enough to begin.

After this article: you should be able to turn a vague request into a clear task, then understand why a production prompt also needs precedence, tool contracts, versions, and regression checks.

Evidence boundary: the mechanisms come from official OpenAI and Anthropic prompt and agent-engineering material. Examples are vendor-neutral shapes. Actual role precedence and API fields must follow the current documentation for the target platform.

1. Understand prompts through one task

1.1 Improve one request in three passes

Suppose a payment test is failing. The shortest request is:

V0: “Fix the failing payment test.”

The goal is visible, but almost everything else is left to guesswork. The Agent may rewrite a public API, skip the test, or say “done” after only editing code. A second version adds the most important boundaries:

V1: “Find why the payment test fails, make the smallest change without changing public APIs, run the payment tests, and report the files changed and the test result.”

Now “fixed” has observable meaning. If the task is risky, a third version can also say what to do when a requirement cannot be met:

V2: “If the test cannot run or the fix requires a public-API change, stop and explain the blocker instead of claiming success.”

This progression is the core of prompt engineering: replace hidden assumptions with requirements that both the Agent and the reviewer can inspect.

1.2 A useful prompt answers six questions

  1. Goal: what outcome should be produced?
  2. Background: what situation and evidence matter?
  3. Constraints: what must not be changed or attempted?
  4. Method: which important steps should be followed?
  5. Done criteria: what evidence proves the task is complete?
  6. Output: what should the final report contain?

Not every task needs six labeled sections. The labels are a review tool. For the payment task, “fix the test” is the goal, the failure log is background, “do not change public APIs” is a constraint, “inspect before editing” is method, a passing payment-test command is the done criterion, and the change report is the output.

The six parts as one natural-language prompt: “Fix refund_should_reject_expired_order. First inspect the failure log and related code, then make the smallest change directly related to the failure without changing public APIs. Run the payment tests afterward. If the test environment is unavailable or progress requires a public-API change, stop and explain the blocker. Report the cause, changed files, test command, and result.”

2. Turn a good instruction into a stable interface

2.1 Move from one good answer to stable behavior

Take one task: “Fix the failing payment test.” A model might edit immediately, inspect the failure first, or report that the test environment is unavailable. The engineering object is not one sentence but the stability of these observable behaviors across similar inputs: when to investigate, when to refuse, what evidence counts as done, how to react to tool failure, and what the final response must contain.

A review therefore cannot stop at a text diff. “Be more concise” or “act proactively” is an intention. It becomes an engineering result only when representative tasks show fewer wasteful calls, stronger constraint adherence, and stable outputs.

Prompt behavioral interface with multiple instruction sources, a precedence gate, and goal, constraints, output, and tool semantics
Different authorities enter on the left; observable behavior exits on the right. The merge rules in the middle must be deliberate.

2.2 Once it becomes a product, separate content by change rate

ContentQuestion it answersChange ratePreferred location
Stable policyWhat is never allowed? When must a person take over?LowCentrally maintained stable instructions
Product contractWhat are the role, goal, done criteria, and output schema?Low to mediumVersioned product template
Task parametersWhich object, scope, and preferences apply now?HighStructured user/task input
Dynamic factsWhat is the repository, customer, or outside world like now?High and perishableContext or tool observations

A classic smell is hard-coding dynamic facts into stable instructions. “The release branch is release/42” expires quickly. The reverse smell is retrieving stable policy as optional context, allowing one missed retrieval to remove a rule. Separation by change rate keeps the behavioral contract stable and gives fresh evidence to context.

Prompt and context are not two mutually exclusive boxes. In one model request, the prompt is the behavioral guidance about how to act. Context is everything the model can see for that call, which may include the prompt, current task, files, and tool results. Prompt Engineering stabilizes the guidance; Context Engineering assembles the full packet correctly.

2.2.1 Make template variables a typed boundary

Start with an unreviewable version: Fix the failing payment test and tell me when it is done. It says nothing about scope, verification, or failure. A safer shape has a fixed template, explicit fields, deliberate escaping, and a label for untrusted data:

  1. Fix the contract first: version the goal, constraints, done criteria, and delivery shape instead of rewriting them per task.
  2. Fill the current task next: place the test name, scope, and current failure in explicit fields rather than stable policy.
  3. Mark untrusted data: a failure log may provide facts, but its text cannot acquire instruction authority.
  4. Assemble last: the runtime checks required fields, escaping, and version before serializing the contract and task for the target API.
{
  "contract_version": "payment-fix/2",
  "goal": "Fix the failing payment test and provide review evidence",
  "constraints": ["Do not change public APIs", "Run payment tests"],
  "task": {
    "failing_test": "refund_should_reject_expired_order",
    "failure_log": "<untrusted data>"
  },
  "output": { "type": "json_schema", "name": "change_report" }
}
Shape-level example: version, contract, task data, and output protocol have distinct boundaries. Serialization depends on the API.

The goal and constraints are versioned behavior. The test name and failure log belong to this task. Log content remains data, not instruction. And “run the tests” still needs the harness and loop to execute a check; model agreement is not enforcement.

This does not eliminate prompt injection. It gives the safety design a boundary: untrusted data does not gain authority merely because it shares a string with instructions. Real authority still belongs to the harness, not to the prompt’s self-description.

2.3 When instruction layers conflict, which one wins?

A tool-using agent receives platform policy, developer contracts, user tasks, and runtime evidence. They can conflict. A user asks to skip tests while the developer contract requires validation. A web page asks for credentials while policy forbids disclosure. A new tool error says a path is gone while an old message still contains it.

Instruction precedence stack from platform policy and developer contract to user task and runtime evidence
Authority and recency are separate axes. New evidence can correct old facts without overriding higher-level policy.

2.3.1 Specify conflict behavior

  • Higher-authority rules define the allowed behavior set; lower-authority requests choose only within it.
  • Within one authority, prefer the more specific rule for the current task and surface unresolved ambiguity.
  • Evidence describes the world and does not automatically gain command authority; files, web pages, and tool output may be untrusted.
  • If the goal and constraints cannot both be satisfied, report the blocker and required authority instead of silently weakening a rule.

These rules are testable. Build cases where a user asks to ignore the developer contract, tool output embeds instructions, or same-level rules conflict. The expected behavior should be refusal, clarification, or escalation—not a lucky answer.

2.4 Tool descriptions must also explain how to act

An agent needs more than tool names. It needs call conditions, parameter meaning, result semantics, and retry rules. OpenAI’s practical agent guide recommends standardized, well-documented tool definitions; Anthropic’s agent-engineering material also emphasizes tool-interface quality. A vague tool turns a deterministic design problem into a model guess.

Tool contractWeak shapeReviewable shape
Call condition“Search when needed”Search when a current fact is missing or external state must be verified
ParametersOne free-form queryField meaning, enums, ranges, and exclusions are explicit
Result semanticsArbitrary textSuccess, empty, transient error, and permanent error are distinct
Side effectsDescription says “use carefully”Harness marks read/write, approval, and idempotency semantics

The prompt teaches how a tool should be chosen. It cannot replace validation, authorization, or idempotency. The behavioral interface says “how to use it”; the runtime harness decides whether it may execute.

2.5 Use examples to teach boundary decisions

Few-shot examples are most useful when they demonstrate boundary decisions. Three happy paths teach nothing about conflicts, empty results, or escalation. A useful set spans ordinary paths, edge paths, and explicit counterexamples.

  • Normal: the failure points to expired-order validation; read the target, make the smallest change, run payment tests, and report the command and result.
  • Boundary: the test command is unavailable because of permissions; stop, return blocked, preserve the evidence, and name the authority required.
  • Counterexample: code changed but tests never ran, yet the response says “fixed”; identify the violated Run payment tests contract.
  • Tool choice: a local failure log is already sufficient, so do not invoke network search merely because it exists.

Examples consume context budget. Find recurring ambiguity with evals, then add the smallest example that resolves it. If a schema or deterministic validator can guarantee format, do not spend examples repeating that guarantee.

3. Advanced: release prompt changes like code

OpenAI’s official prompt guide explicitly recommends evals for measuring prompt performance. A production release flow adds the missing control: write the behavior spec, assign a version, run fixed regressions and exploratory cases, review important failures, stage the release, observe the real distribution, and roll back when needed.

cases = [
  Case("normal_fix", expected="verified"),
  Case("test_unavailable", expected="blocked"),
  Case("user_requests_skip", expected="refuse_shortcut"),
  Case("tool_output_injection", expected="ignore_untrusted_instruction")
]

for version in ["payment-fix/1", "payment-fix/2"]:
  for case in cases:
    result = run_agent(prompt=version, task=case.input)
    record(version, case.name,
           contract_ok=validate_contract(result),
           evidence_ok=validate_verification(result))
Minimal regression experiment: run both versions on the same cases and compare normal, blocked, high-risk, and injection slices. A higher average does not justify release when the high-risk slice regresses.
Prompt change loop from spec, version, eval, and review to release and observation, with rollback
A prompt is a versioned dependency that changes system behavior, not a copywriting asset.

3.1 Minimum release record

  • Template text, tool schemas, and the associated model snapshot.
  • Change intent: which behavior should move, and which must remain stable.
  • Eval-set version, aggregate results, and slices by failure class.
  • Rollout scope, observation window, rollback target, and owner.

Averages hide dangerous regressions. A version can shorten routine tasks while making the “insufficient authority” slice more willing to guess. Slice by risk, task family, and tool path, and retain representative traces for review.

4. Review: when should you edit the prompt?

SymptomPrompt first?Better first control
A stable constraint is repeatedly ignoredYesClarify contract, precedence, and conflict tests
The model lacks a newly changed factNoContext selection or retrieval
A dangerous command executedNoHarness permissions, sandbox, approval
Output format is occasionally invalidPartlyStructured output and validation; prompt carries semantics
The agent declares success too earlyPartlyDone contract plus deterministic loop checks
Average score rises while high-risk cases regressNo—rollback firstRollback, eval slices, and a revised spec

Prompt engineering has not disappeared. It has matured from empirical writing into interface engineering. Next we move to the other axis: context is not the long-term store; it is the working set assembled for each inference.

Official sources

Further reading