Guardrails AIguardrails-ai 0.11.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson

What Guardrails puts in the prompt

Lessons 17 and 18 handed parse text that was already JSON. A model has to be told to produce JSON, and the documentation makes it sound as if Guardrails does that for you.

The quickstart lists two ways structured output happens: function calling for models that support it, and prompt optimisation for the rest, where, in its words, the schema of the expected output is added to the prompt. Print what the model actually receives.

Example
from pretend_guardrails import PretendModel

model = PretendModel(replies=['{"order_id": "8821", "issue": "late", "priority": 2}'])
tickets = Guard.for_pydantic(Ticket)

tickets(model, messages=[{"role": "user", "content": "File a ticket for order 8821."}])

print(model.prompts[0][-1]["content"])

Byte for byte what you wrote. No schema, no instruction to return JSON, nothing. The stand-in returned valid JSON only because it was told to; a real model handed that prompt would have written a sentence.

Asking for it

Example
prompt = "File a ticket for order 8821.\n${gr.complete_json_suffix_v2}"

model = PretendModel(replies=['{"order_id": "8821", "issue": "late", "priority": 2}'])
tickets(model, messages=[{"role": "user", "content": prompt}])

print(model.prompts[0][-1]["content"])

${gr.complete_json_suffix_v2} is a placeholder Guardrails replaces with the schema, the instruction and four worked examples. It lives in guardrails/constants.xml alongside complete_json_suffix and complete_json_suffix_v3, which are shorter variants.

So the schema does reach the prompt, and only because you asked. Leave the placeholder out and Guardrails validates whatever arrives without ever having asked for the right shape. That is the difference between a course that runs and a course that works.

Filling in the question

The same substitution machinery takes values of your own through prompt_params.

Example
model = PretendModel(replies=['{"order_id": "8821", "issue": "late", "priority": 2}'])
messages = [{"role": "user", "content": "File a ticket for order ${order}."}]

tickets(model, messages=messages, prompt_params={"order": "8821"})

print(model.prompts[0][-1]["content"])

Worth using rather than an f-string, because the substitution happens inside Guardrails and the original template is what goes into the history. When you are looking at a week of calls, the template is the thing you want to group by.

Try it yourself
  • Swap complete_json_suffix_v2 for complete_json_suffix_v3 and compare the two prompts.
  • Add a description to each field of Ticket and print the prompt again. Descriptions travel to the model.
  • Leave a ${order} in the prompt and pass no prompt_params. Decide whether the result is what you want a customer to see.

This is what real progress feels like.