Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

How to ask a model for JSON

After this lesson: I can ask for an answer in a shape my program can read.

60 min lesson4 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

The reply that broke the app

Asking a language model for JSON means telling it, in the prompt, the exact shape of the answer you want. It matters because a program can only use a reply it can read.

A school shop app asks a model to invent a snack and a price. One day the reply starts with "Sure, here you go" and the program stops. The model did what you asked, but not in a shape the program could read.

By the end of this lesson

Note

I can ask for an answer in a shape my program can read.

Key words

WordWhat it meansExample
Promptthe text you send to a model
JSONa text format for data, made of keys and values
Keythe name of one field in a JSON objectprice
Code fencethree backticks that wrap code in a reply
Parseto read text into data a program can use
Token limitthe most pieces of text a reply may have

The cells students fill in are left blank in this preview.

Say the shape in the prompt

A model guesses what you want from your words. So say the shape. Name the keys, say the type of each value and say what to leave out.

End with one plain rule: reply with only the JSON. The more you leave to chance, the more different replies you will get.

Worked example: three prompts for one snack

The prompt saysWhat may come back
Give me a snack and a pricePlain words, maybe a list, no fixed keys
Give me a snack as JSONProbably JSON, with keys you did not choose
Reply with a JSON object with the keys name (text) and price (a number). Reply with only the JSON.More likely to be the shape you asked for

The cells students fill in are left blank in this preview.

Show one example answer

An example is worth a paragraph of rules. Put one complete example answer in the prompt, with made-up values, and say the real answer must have the same keys.

Models tend to copy the layout of an example. Use values that cannot be mistaken for real ones, or a copied example looks like a real answer.

Write the model helper

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    return (await res.json()).choices[0].message.content;' '  } catch (error) {' '    console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' > model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the first script, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '' 'const messages = [' '  { role: \"system\", content: \"You answer with JSON only.\" },' '  { role: \"user\", content: \"Invent one snack for a school shop. Reply with a JSON object with the keys name (text) and price (a number in pounds). Reply with only the JSON.\" },' '];' '// Recorded sample, used only when no model answers. It is messy on purpose.' 'const fence = \"\x60\x60\x60\";' 'const sample = \"Sure, here is your snack:\n\" + fence + \"json\n\" + JSON.stringify({ name: \"Oat flapjack\", price: 1.2 }) + \"\n\" + fence + \"\nHope that helps.\";' > ask1.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the first script, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function pullJson(text) {' '  try { return JSON.parse(text); } catch (error) { }' '  const start = text.indexOf(\"{\");' '  const end = text.lastIndexOf(\"}\");' '  if (start === -1 || end < start) return null;' '  try { return JSON.parse(text.slice(start, end + 1)); } catch (error) { return null; }' '}' '' 'async function main() {' '  const reply = await ask(messages, sample, 100);' '  console.log(\"Raw reply:\");' '  console.log(reply);' '  let whole = true;' '  try { JSON.parse(reply); } catch (error) { whole = false; }' '  console.log(\"The whole reply is JSON:\", whole ? \"yes\" : \"no\");' '  console.log(\"Pulled out:\", JSON.stringify(pullJson(reply)));' '}' 'main();' >> ask1.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run it and read the reply

Command
docker exec -w /home/node/project agent node ask1.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

One possible output

LineWhat it may show
Raw replyA sentence, then the JSON in a fence, then another sentence
The whole reply is JSONno
Pulled out{"name":"Oat flapjack","price":1.2}

The cells students fill in are left blank in this preview.

Why a good prompt can still fail

Even a clear prompt can fail. The model may add a greeting, wrap the JSON in a fence, or change a key name. It may also stop early if the token limit is too small, which leaves JSON cut off half way.

So you always parse and check. Asking well makes a bad reply rarer. It never makes one impossible.

A common mistake

Warning

Many people think a clear enough prompt means they can skip the check. A prompt only lowers the chance of a bad reply. Keep the check even when the last hundred replies were fine.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.