SSkilvy

A prompt is code affecting behavior

The first principle: treat prompts as code. A prompt determines the behavior of part of an application no less than ordinary code, so it deserves the same discipline: versioning, structure, careful changes, testing. An "unnoticed" prompt edit can change behavior across thousands of requests — this is not a trifle. Let us cover how to organize prompts as code.

Prompt in codeVersioningManaged changes Prompt as code Development discipline
Treat prompts as code: version them, keep them separate from logic, change them disciplinedly.

"Prompt as code" practices

  • Versioning: keep versions of prompts (in version control, like code). To understand what changed and roll back.
  • Separation from logic: keep prompts as explicit, readable parts (not scattered strings in the code) — easier to find, change, test.
  • Templates with substitution: a prompt template + variable substitution (user data, context) — like parameterized code.
  • Change discipline: change one at a time, test before rollout, be able to roll back (from LLMOps).
How to organize prompts as code in practice?
"Prompt as code" is organizing prompts with the same discipline as ordinary code. Practice: 1) VERSIONING (key): — Keep prompts under version control (like code). Why: to see the change history, understand WHAT changed between "worked" and "broke", roll back to a working version, compare options. — A prompt affects the applications behavior like code, so its changes must be trackable and reversible, not "fixed in production and forgot". 2) SEPARATE prompts from logic: — Do not scatter prompts as raw strings across the code. Keep them explicit, organized (separate files/constants/templates) where they are easy to find, read, change, test. — Pros: readability, maintenance, the ability to change a prompt without editing the logic and vice versa, easier to test prompts separately. 3) TEMPLATES with substitution (parameterization): — A production prompt is usually = a TEMPLATE + substituted variables (user data, context from RAG, parameters). E.g.: "Classify the review: {review_text}. Categories: {categories}". — This is like a parameterized function: a fixed structure + changing inputs. — IMPORTANT (security): substituting user data into a prompt is a potential prompt-INJECTION point (from LLMOps): a user can insert text trying to override the instructions. Treat substituted user data as untrusted, separate instructions and data, do not let user input control the behavior. (More — in the security/reliability lesson.) 4) CHANGE DISCIPLINE (like code, from LLMOps): — Change the prompt ONE change at a time (or you will not understand what helped/broke). — Test BEFORE rollout (on a set of examples — the testing module topic). — Be able to roll back (versioning gives this). — Do not edit the prompt blindly right in production — the change affects all requests. 5) DOCUMENT the intent: — It is useful to record WHY the prompt is such (what behavior it should give, why certain instructions were added). Prompts can be non-obvious — a comment/description helps maintenance. 6) UNIFORMITY and reuse: — Common parts (output format, role, rules) can be extracted and reused (system prompts — the next module) so as not to duplicate and to change in one place. 7) The tie with evaluation (LLMOps): versioning + testing = the basis of managed prompt improvement. Changed to tested on a set to compared with the past version to rolled out if better to rolled back on problems. So prompts improve without unnoticed regressions. Practical rule: treat prompts as code — version them (history, rollback), keep them separate from the logic (readability, maintenance, testability), use templates with substitution (but carefully with injection of user data), change disciplinedly (one at a time, with a test before rollout, with the ability to roll back), document the intent. This turns prompts from chaotic strings into manageable, maintainable artifacts. A prompt determines behavior no less than code, so it deserves the same engineering discipline. Without it teams get stuck in "we fixed the prompt — something broke, unclear what"; with it — prompts are reliable, changes predictable and reversible.

Templates with substitution — and caution with injections

A production prompt is usually = a template + substituted variables (user data, context from RAG): "Classify the review: {text}. Categories: {categories}". This is like a parameterized function: a fixed structure + changing inputs. But an important security point: substituting user data is a potential prompt-injection point (from LLMOps). A user can insert text trying to override the instructions ("ignore the rules"). Treat substituted user data as untrusted, separate instructions and data, do not let user input control the behavior (more in the reliable-output module).

Versioning + tests = managed improvement

A key tie with LLMOps: versioning + testing give managed prompt improvement. Changed to tested on a set of examples to compared with the past version to rolled out if better to rolled back on problems. So prompts improve without unnoticed regressions. Change one change at a time (or you will not understand what helped or broke), do not edit the prompt blindly right in production (the change affects all requests), document the intent (why the prompt is such — prompts can be non-obvious). Without this discipline teams get stuck in "we fixed the prompt — something broke, unclear what".

Rule: treat prompts as code — version them (history, rollback), keep them separate from the logic, use templates with substitution (carefully with injection of user data), change disciplinedly (one at a time, a test before rollout). Versions + tests = improvement without regressions.

🧠 What is important to account for when substituting user data into a prompt template?