"Cook until fragrant": teaching an AI to understand vague recipe language
By Chris Artmann ·
Here's a line from a real recipe: "Add a thumb of ginger and the garlic, and cook until fragrant."
A person reads that and just does it. They grab a bit of ginger about the size of their thumb. They stir until the kitchen smells good. Then they move on.
Now try teaching that line to software. How many grams is a thumb? How long is "until fragrant"? Should your app start a timer? Should the shopping list say "ginger, 1 thumb"?
Recipes are full of words like this. They aren't measurements. They're shortcuts that work because the cook is standing at the stove with a nose and a pair of eyes. Your app has neither. And if you hand the problem to an LLM, it'll give you a confident number. Sometimes that number is right.
We see this every day. Our glossary pages that explain these phrases get more search traffic than almost anything else on the site. People search "what does cook until fragrant mean" and "how much is a heaping tablespoon" all the time. If humans have to look them up, your parser is going to struggle too.
Four kinds of vague
After going through a lot of recipe text, we think almost all of these phrases fall into four groups. Each group needs different handling, so it's worth telling them apart.
Amount words stand in for a quantity. A thumb of ginger. A knob of butter. A pinch of salt, a handful of spinach, a bunch of parsley, a heaping tablespoon. These have a rough, agreed size. A thumb of ginger is about 5 cm and weighs around 15 to 25 g. A knob of butter is about 15 to 25 g too. You can turn them into numbers, as long as you keep the range.
Doneness cues tell you when to stop by what the food looks or feels like. Golden brown. Until translucent. Coat the back of a spoon. These are the real instruction. Any time attached to them is a guess, and often a bad one. Recipes say onions go translucent in 3 to 5 minutes. Most take closer to 8 to 10.
Timing cues sound like doneness cues but really describe a short, fairly fixed amount of time. Until fragrant is the classic. For minced garlic or ginger in hot oil, that's about 30 to 60 seconds. For whole cumin seeds, 1 to 2 minutes. Go much longer and they turn bitter.
Judgement calls have no right number at all. To taste. Season generously. Adjust the seasoning. Those words are there to tell the cook to decide. Turning them into "1 tsp salt" changes what the recipe says.
The mistake we see most is treating all four the same way. A parser finds "a thumb of ginger" and either throws it away (no number, no quantity) or makes one up (1 unit of "thumb"). An LLM finds "until fragrant" and confidently says "2 minutes". Both are wrong, in different ways.
So we asked the models
We gave Claude Haiku 5.5, Sonnet 5.5 and Opus 5.5 the same prompt. We said we were building a cooking app and needed numbers. For each phrase, we asked for one best guess, a range, and a sentence of reasoning. Here's what came back, next to the figures from our glossary:
| Phrase | Haiku 5.5 | Sonnet 5.5 | Opus 5.5 | Our glossary |
|---|---|---|---|---|
| A thumb of ginger | 10 g (8–15) | 25 g (15–40) | 20 g (15–30) | 15–25 g |
| A knob of butter | 15 g (10–20) | 15 g (10–25) | 20 g (10–30) | 15–25 g |
| Garlic "until fragrant" | 30 s (20–60) | 30 s (15–60) | 30 s (15–60) | 30–60 s |
| Heaping tbsp of flour | 10 g (9–12) | 15 g (12–20) | 14 g (11–18) | 1½–2 level tbsp, about 12–16 g |
This was one run each, so treat it as a snapshot, not a benchmark. Still, a few things stand out.
The bigger models are pretty good. Opus lands inside our range on every line, and its reasoning is sound. "A level tablespoon weighs about 8 g, and a heaping one holds about 1.5 to 2 times that." That's exactly how you'd work it out by hand.
The small model is off in a consistent direction. Haiku's thumb of ginger is 10 g, about half of what most cooks mean. It even describes a thumb as "2 inches long and 1 inch wide" and then gives a weight that fits a 1 inch piece. Its heaping tablespoon is also on the low side. Each answer sounds sure of itself. Only the numbers are off.
Sonnet shows a different problem. It said a thumb of ginger "means roughly a 1-inch piece". That mixes up two phrases. In American recipes, a 1 inch piece is a common size, and it's about half a thumb. The final number (25 g) is fine, but the reasoning behind it would mislead you. If your app showed that explanation to a user, it would teach them something wrong.
And every model picked 30 seconds for "until fragrant", which is the short end. That's actually a sensible choice, because garlic burns fast. But it shows that the number depends on judgement, not a fact. Opus said so itself: "If your app shows a gram amount, also tell users the original phrase was approximate." Good advice.
The takeaway isn't "LLMs are bad at this". The best ones are surprisingly good. The real lesson is that a single number throws away the most useful thing you know: how sure you are. So don't store a single number.
Here's the approach we'd suggest, whether you use a model, a lookup table or both.
Keep the original text. Always. Whatever you parse, store the line the author wrote right next to it. That way you can always show the cook what the recipe really said, and you can parse it again later when your parser gets better. This is how the Tiny Plates API works. Every ingredient has an original field with the raw line, a display field with a cleaned-up version, and the structured quantity beside them. We wrote more about this in How to parse "2 cups flour, sifted" and Ingredient lines that read in the recipe's own language.
Store ranges, not points. When the source gives a range, keep it. Our API does this already. "5 to 6 drops green food coloring" comes back as:
{
"original": "5 to 6 drops green food coloring",
"display": "5-6 drops green food coloring",
"quantity": { "value": 5, "max": 6, "unit": "drop" }
}
Do the same for your estimates. "A thumb of ginger" should become something like { "value": 15, "max": 25, "unit": "g", "estimated": true }, not 20 g. The range lets you scale a recipe honestly. It also lets you round a shopping list sensibly and show "about 20 g" instead of a fake-precise "20 g".
Let "unknown" stay unknown. Some lines have no amount at all, like "colored sprinkles" or "salt, to taste". It's tempting to fill the gap. Don't. In our API, a missing quantity means "the recipe didn't say", and that's useful information. A made-up "1 tsp" looks exactly like a real one, and nobody downstream can tell the difference.
Mark sensory steps, so the UI shows a cue instead of a timer. This is the one that matters most for cooking apps. Look at this real step:
Bake for 30 to 35 minutes, or until the edges look dark and the middle feels firm to the touch.
The time is a guide. The cue is the real instruction. If your app shows a big countdown and a beep, people will trust the beep over their eyes. A better design shows the time as a check-in, with the cue as the main message:
type Step = {
text: string
duration?: { seconds: number; max?: number }
cue?: string // "edges look dark, middle firm to the touch"
cueKind?: 'doneness' | 'timing' | 'taste'
}
const format = (d?: Step['duration']) =>
d === undefined ? 'a moment' : `${Math.round(d.seconds / 60)} min`
function stepPrompt(step: Step) {
if (step.cueKind === 'doneness') {
return `Check at ${format(step.duration)}: ${step.cue}`
}
if (step.cueKind === 'timing') {
return `About ${format(step.duration)}, until ${step.cue}. Don't walk away.`
}
return step.text
}
"Cook until fragrant" gets a short timer and a nudge to stay at the stove. "Until translucent" gets a check-in, not an alarm. "Season to taste" gets no number at all, just a reminder to taste.
This is also where an LLM really earns its place. Sorting a step into "doneness", "timing" or "taste", and pulling out the cue, is a language job. Models are very good at that. Making up grams is the part they're less reliable at. So let the model label the text, and let a lookup table or a curated source supply the numbers. If you need a table to start from, our glossary pages each come with typical sizes and times. Volume to weight is its own rabbit hole, which we covered in Cups to grams needs a density table.
We tested that second part properly, too. In Can AI do cups to grams? We tested 5 models, we ran a whole set of conversions through several models and scored the answers against a density table.
Vague recipe language isn't a bug in recipes. It's how people cook. The job of your software isn't to remove the vagueness. It's to keep it, size it honestly, and show it at the right moment.