Professional Prompt Engineering

The bar: you can turn a vague ask into a prompt that produces the same correct, structured output every time — and prove it with a repeatable test instead of a lucky screenshot.

Prompt engineering is not incantation. It is the same discipline you already know from writing code: state the contract, control the inputs, constrain the outputs, and verify the result. The difference between a demo that works once and a feature that ships is whether you can rely on the model to behave the same way on the hundredth call as it did on the first.

Every technique below exists to remove ambiguity. When a model gives you garbage, the usual cause is not the model — it is a prompt that left too much open to interpretation. Treat these patterns the way you treat function signatures: deliberate choices you can defend in review.

18.1 Prompting Fundamentals

Objective: apply the basic prompting techniques and know when each one earns its place.

The simplest tool is zero-shot — direct instructions with no examples. It works when the task is common and the format is obvious. Reach for it first; do not add machinery you do not need. When the model keeps guessing wrong about the shape you want, move up.

One-shot gives a single worked example, and few-shot gives several. Examples teach format and edge cases far more reliably than adjectives do. If you want output in a particular style, showing two or three clean input-output pairs beats a paragraph describing them. The common mistake is stacking on more prose instructions when one concrete example would have settled it.

A system prompt sets the standing behavior — the role, tone, and rules that hold across every message in a session. Put durable policy there (who the model is, what it must never do) and keep the per-request user prompt focused on the specific task. Mixing the two is how people end up repeating the same instructions in every call.

  • Drill: write a zero-shot prompt, then convert it to one-shot and few-shot and compare outputs on the same input.
  • Drill: author a system prompt that fixes tone and constraints, then verify it holds across several user turns.
  • Drill: identify one task where few-shot examples fix a formatting problem that instructions alone could not.

18.2 Advanced Reasoning

Objective: guide a model through multi-step problems instead of hoping it lands the answer in one leap.

Chain of Thought asks the model to reason step by step before answering. For anything involving math, logic, or multi-part decisions, this alone can turn wrong answers right — the model commits to intermediate steps rather than jumping to a conclusion. Self-Consistency runs the same reasoning prompt several times and takes the majority answer, trading a few extra calls for stability on problems where a single pass is noisy.

Tree of Thoughts goes further: the model explores multiple branches of reasoning, evaluates them, and prunes the weak ones — useful for planning or search-like problems where the first path is often not the best. It costs more, so save it for problems that genuinely fork.

ReAct interleaves reasoning with acting — the model thinks, calls a tool or looks something up, reads the result, then reasons again. This is the backbone of agents that touch real systems. The gotcha across all four: more elaborate reasoning burns more tokens and latency, so match the technique to the problem's actual difficulty rather than defaulting to the fanciest one.

  • Drill: add "think step by step" to a failing logic prompt and confirm chain-of-thought fixes it.
  • Drill: run a prompt five times and implement a majority vote for self-consistency.
  • Drill: sketch a tree-of-thoughts prompt that generates and scores multiple candidate plans.
  • Drill: build a minimal ReAct loop: reason, call one tool, feed the result back, reason again.

18.3 Structural Optimization

Objective: structure prompts so the output is reliable enough to parse in code.

Wrap distinct parts of your prompt in XML tags or clear delimiters<context>, <question>, <examples>. This tells the model exactly where the instructions end and the data begins, which matters most when you are pasting in user content that might itself look like an instruction. Delimiters are cheap insurance against prompt confusion.

Output format constraints and schema-guided generation are what make model output safe to consume downstream. If a function is going to JSON.parse the response, say so explicitly and give the exact schema — field names, types, required keys. Better yet, provide the schema and one conforming example. The classic self-taught mistake is eyeballing output in a chat window and then being shocked when the same prompt returns prose with a friendly preamble in production.

Prompt templates turn a good one-off into a reusable asset: fixed scaffolding with slots for the variable parts. Once a prompt is a template, you can version it, review it, and swap inputs without rewriting the structure each time.

  • Drill: rewrite a messy prompt using <xml> tags to separate instructions, context, and data.
  • Drill: demand strict JSON output against a named schema and parse it in code without cleanup.
  • Drill: build a parameterized template with named slots for the parts that change per call.

18.4 Meta-Prompting

Objective: use the model itself to sharpen your prompts.

Role assignment and expert personas frame the model's perspective — "you are a senior Python reviewer" pulls answers toward the depth and vocabulary of that role. This is not theater; it measurably shifts which knowledge the model foregrounds. Keep the persona specific and relevant to the task, not a costume.

Prompt optimization means handing a weak prompt to the model and asking it to rewrite it for clarity and reliability. It is fast, and it often surfaces ambiguity you were blind to. Pair it with A/B testing: run two prompt variants against the same set of inputs and compare results on a metric you defined up front. That is the difference between "this feels better" and "this is better." Do not skip the metric — a preference you cannot measure is a preference you cannot defend.

  • Drill: assign an expert persona and measure how the answer's depth changes on a hard question.
  • Drill: ask the model to rewrite one of your prompts, then test whether the rewrite actually wins.
  • Drill: run an A/B test of two prompt variants over the same inputs against a defined metric.

18.5 Hands-On Lab: Prompt Library

Objective: build a versioned prompt system you can evaluate and improve over time.

What you ship

A working prompt library that treats prompts as engineered assets, not scratch text:

  • A Jinja2 template system where each prompt is a versioned template with named variables, rendered at call time.
  • Evaluation metrics that score model output against expected results, so quality is a number you can track — not a vibe.
  • An A/B testing framework that runs two template versions over a shared input set and reports which one wins on your metrics.

Deliverable: a repo where a teammate can add a prompt, render it, score it, and compare it against the current version without touching the surrounding plumbing.

On the VWC codebase

If you wire a prompt-backed feature into the Vets Who Code app, remember it currently runs the Next.js Pages Router: the model call lives behind an API handler in src/pages/api/, not an App Router route handler. Any server-side data the prompt needs is fetched in getServerSideProps or getStaticProps, not a Server Component. Keep the model client and prompt templates in src/lib/ as domain logic, and never construct provider clients per file — share one instance the way the app shares its Prisma singleton.