A practice prompt we wrote. No company or candidate report names it, so it carries no company tag.

How to answer

Open with why loud matters: a model given “Summarize the ticket for {{customer_name}}” answers plausibly anyway. Your renderer is the last cheap check.

  1. Pin the contract. “render(template, variables) -> str. Missing variables raise one error naming all of them and the template. Unused ones raise too, since they usually mean a renamed placeholder, unless callers share one context across templates; then I warn.” Ask whether an empty string counts and how braces are escaped. Refuse None and non-strings: str(None) writes the word None into the prompt.
  2. Say why the standard tools fall short. str.format stops at the first missing name and follows attribute and index lookups, so an outside template can reach into your objects. Its single braces also collide with every JSON example, hence {{name}}. string.Template.safe_substitute leaves missing placeholders in place, the silent failure itself. Jinja renders an undefined name as empty text unless you configure StrictUndefined, which stops at the first one. Your own parser is fine, or strict Jinja after collecting every name with find_undeclared_variables. Say which.
  3. Parse once, at load time. Extract placeholders with one regex; reject bad names and unclosed braces before any request. In CI, a test renders every template file against a fixture of its declared variables.
  4. Substitute in one pass. Use re.sub with a function, so each value is inserted once, never rescanned.
  5. Return what helps debugging. The rendered text plus a template hash, so each call logs its prompt version.
  6. Test the failures first. All missing names in one error, a value full of braces left untouched, an escape, an unused variable, whitespace inside a placeholder.

The trap is for k, v in variables.items(): text = text.replace(...). It passes happy-path tests, then expands a customer name containing {{ticket_body}} into the whole ticket. Practice it in the strict prompt renderer drill.

Follow-ups

What the interviewer may ask next, once your first answer is on the table.

  • A customer’s name contains a placeholder, such as “{{ticket_body}}”. What does your renderer produce?
  • The caller passes a variable the template never uses. Error, warning or nothing?
  • An empty string arrives for a required variable. Is that missing?
  • How would you catch a broken template before it reaches production traffic?

Where answers go wrong

  • Using a lenient default, such as string.Template.safe_substitute or a defaultdict, so a missing value renders as a literal placeholder or as empty text and the model answers anyway.
  • Replacing placeholders one at a time, so a value that contains another placeholder gets expanded too.
  • Raising on the first missing name only, so the caller fixes one variable per failed deploy.
  • Calling str() on every value, so a None puts the word None in the prompt and a dict arrives as a Python repr.

Answer this in two minutes

Write the answer you would say out loud. The clock starts with your first word.

Two minutes

Model answer

“Here’s the contract I’ll build to. Placeholders are {{name}}, with whitespace allowed inside, so JSON examples with single braces pass through untouched.