Structured data
You ask Claude to return a JSON object describing an AWS EventBridge rule. It gives you exactly what you asked for — wrapped in a friendly "Here's the JSON you requested:" preamble, surrounded by markdown code fences, followed by a two-sentence explanation of what the rule does. All of it perfectly helpful for a human reader, and completely unusable for json.loads(). This is the structured output problem, and there's a clean fix.
The problem
Claude's default mode is conversational. If you ask for JSON, it will often:
- Lead with explanatory text ("Here's a short example:")
- Wrap the output in markdown fences (
```json ... ```) - Follow with commentary ("This rule triggers when...")
All of that is fine in a chat window and disastrous in a pipeline. You don't want to write regex to strip the markdown every time — and regex fails in creative ways as soon as the model decides to put the fence on a different line.
The fix: prefill the assistant message, stop at the closing fence
You can put words in Claude's mouth by adding an assistant message to the conversation before calling the API. When Claude sees a partial assistant turn ending with the opening of a code fence, it continues from that point — meaning the first token it generates is the first character of real JSON, not "Here's the".
Combine that with a stop sequence — a string that tells the model "if you generate this, stop immediately" — and you can also cut the response off at the closing fence before any trailing explanation creeps in.
messages = []
add_user_message(messages, "Generate a very short EventBridge rule as JSON")
add_assistant_message(messages, "```json")
text = chat(messages, stop_sequences=["```"])
What happens on the wire:
- The conversation now ends with
assistant: "```json". - Claude continues the assistant turn, starting right after the opening fence — so the next token is the opening
{of the object. - When Claude would naturally emit the closing
```, the stop sequence fires and generation halts. - You receive back only the content that was between the fences.
No preamble. No explanation. No regex. Just the JSON.
Validating the output
The very next step, every time, is to parse it — both because that's what you're going to do with the output anyway, and because json.loads() gives you a clean, early failure if Claude's output isn't valid:
import json
clean_json = json.loads(text.strip())
The .strip() is there because the first character after the newline following the opening fence is sometimes whitespace. json.loads() is forgiving about surrounding whitespace, but .strip() is cheap insurance.
When to catch failures: wrap the parse in a try/except in production. If Claude ever emits malformed JSON, you want a clean error path — log the raw text, fall back to a retry or a default, but don't let a JSONDecodeError bubble up as an uncaught exception.
Why this pattern matters
This isn't just a trick for JSON. The same prefill-and-stop pattern works for any structured format:
- Python — prefill with
```pythonand stop at```. - CSV — prefill with a header row and stop at a sentinel.
- XML — prefill with the opening tag and stop at the closing tag.
Anywhere you need Claude to produce machine-readable output that gets parsed downstream, this is how you do it reliably. You'll see this exact pattern again in Module 4 when we build eval datasets, and again in Module 6 when we talk about tool schemas. Learn it once here, use it everywhere.
Key Takeaways
- 1By default, Claude wraps structured outputs in explanatory prose and markdown fences — fine for humans, unusable for parsers.
- 2Prefilling the assistant turn with an opening code fence makes Claude continue from that point, so the first generated token is real content rather than a preamble.
- 3Combining assistant prefill with a stop_sequence for the closing fence produces a clean, fence-free response ready to pass straight into json.loads().
- 4Always validate the parsed output and wrap json.loads() in a try/except in production so malformed responses fail cleanly.
- 5The prefill + stop sequence pattern works for any structured format — JSON, Python, CSV, XML — and is reused throughout the rest of the course.