{"course":{"slug":"evaluating-ai","title":"Knowing If It Works","url":"https://addaly.com/learn/evaluating-ai","level":"intermediate","track":"build"},"lesson":{"slug":"error-analysis","title":"Reading fifty failures","url":"https://addaly.com/learn/evaluating-ai/error-analysis","position":54,"of":76,"minutes":9,"answer":"Read fifty failures, write the cause in your own words before categorising, and label each cause as data, retrieval, prompt, model, label or product: most of them will not be prompt problems.","keyIdea":"Read fifty failures, write the cause in your own words before categorising, and label each cause as data, retrieval, prompt, model, label or product: most of them will not be prompt problems."},"body":{"format":"markdown","text":"## The highest-value hour in applied AI\n\nSit down with fifty failures. Read each one. Write one line saying why it failed. Then group the lines.\n\nThat is the whole technique, it takes about ninety minutes, and it will change what you work on next more than any other activity in this course. Teams that do it routinely stop guessing; teams that do not spend months rewriting prompts against problems that were never prompt problems.\n\nThe reason it works is the distribution. Failures are never spread evenly across twenty causes. Three causes are usually 60 to 80 per cent of them, and you cannot see which three from a summary metric.\n\n## Do it in this order\n\n**1. Take failures, not a random sample.** You are diagnosing, not estimating a rate. Fifty is plenty; twenty is enough to see the big clusters.\n\n**2. Write the cause in your own words, before naming a category.** \"Only the first page of the receipt was in the input\", not \"extraction error\". Free text first. Categories imposed too early hide the thing you did not expect.\n\n**3. Cluster afterwards.** Sort the fifty lines, merge the ones that say the same thing, count.\n\n**4. Assign each cluster an owner and a *kind*.** This is the step that pays. Kinds:\n\n- **Data**: the input was wrong, missing, or not what the system was given.\n- **Retrieval**: the information was not supplied.\n- **Prompt**: the instruction was ambiguous or absent.\n- **Model**: the instruction was clear and it did not comply.\n- **Label**: the expected answer was wrong. It happens more than teams expect.\n- **Product**: the request was reasonable and the system is not designed to serve it.\n\n## What it looks like\n\nA receipt-extraction system, 50 failures:\n\n- **22: multi-page receipts, only page one uploaded.** *Data.* The mobile client sent one image. No prompt change would have helped.\n- **11: dates read as MM/DD when written DD/MM.** *Prompt.* One sentence naming the locale convention, plus a deterministic check that the parsed date is not in the future.\n- **8: illegible photographs.** *Product.* The answer is to detect blur and ask for a retake, not to extract harder.\n- **5: totals wrong because a discount line was subtracted twice.** *Model.* Real, and the smallest cluster.\n- **4: miscellaneous.**\n\nThe team had been comparing three prompt variants for a fortnight. Two of the three top causes were not in the prompt at all, and the biggest one was a client bug. That is the typical shape of this exercise, not a dramatic example chosen to make a point.\n\n> Figure: Fifty receipt-extraction failures, by cause. Bars (failures out of 50): Multi-page receipt, only page one uploaded (data) 22; Date read MM/DD when written DD/MM (prompt) 11; Genuinely illegible photograph (product) 8; Discount line subtracted twice (model) 5; Miscellaneous 4. The team had spent a fortnight comparing three prompt variants. The largest cause was a client bug, and only five of the fifty failures were the model's.\n\n## Turn the clusters into a taxonomy\n\nWrite the cause names down and reuse them. Tag every future failure with one. Within two months you have a chart of failure causes over time, and it answers the question no pass rate can: *what is going wrong now, and is it the same thing as last month?*\n\nA cluster that keeps reappearing after a fix was shipped means the fix did not work, which is exactly the fact that a stable overall score conceals.\n\n## Cheap tricks that speed it up\n\n- **Sort failures by input length, language, or slice tag** before reading. Clusters often fall out of the ordering for free.\n- **Cluster automatically for a first pass.** Embed the failure outputs with a free local model, run k-means with k around 8, read three items per cluster. This is a way to *find* candidate groups quickly, not a substitute for reading. The names you get from reading are better than the ones you get from a centroid.\n- **Diff against a run that passed.** For items that used to pass and now fail, put the two outputs side by side. The cause is usually visible in seconds.\n- **Keep the fifty.** They become eval items with an `origin` field, which is the subject of a later lesson.\n\n## The rule\n\nNo prompt change without error analysis first. It sounds bureaucratic and it is the opposite: it is what stops you spending a fortnight on the 10 per cent cause while the 44 per cent cause sits in a client bug nobody has looked at.\n\nAnd it is the part of this work that does not automate. A model can cluster your failures; it cannot notice that the receipts are all from one chain whose printer cuts off the total. That noticing is the job."},"check":{"question":"A team's error analysis of 50 failures finds 21 caused by truncated inputs, 12 by an ambiguous instruction, 9 by genuine model errors and 8 miscellaneous. They have one week. What should they do?","options":[{"text":"Work on the 9 model errors, since those are the only failures the model itself is responsible for.","correct":false,"tempting":"Restricts the team to the failures that feel like AI problems, leaving the largest cluster untouched because it lives in another part of the system."},{"text":"Fix the truncation in the input pipeline first, then the ambiguous instruction, and leave the model errors for later.","correct":true},{"text":"Rewrite the prompt to handle all four clusters at once, since a single prompt revision is cheaper than four separate fixes.","correct":false,"tempting":"Assumes a prompt can address causes that sit outside the prompt, and bundles four changes so that no single one can be measured."},{"text":"Collect another 200 failures first, since 50 is too small a sample to allocate a week of work against.","correct":false,"tempting":"Applies sampling caution to a diagnostic exercise where the clusters are already stark enough to act on."}]},"prev":{"slug":"regression-testing-a-prompt","title":"Regression testing a prompt","url":"https://addaly.com/learn/evaluating-ai/regression-testing-a-prompt"},"next":{"slug":"ab-testing-honestly","title":"A/B testing a feature honestly","url":"https://addaly.com/learn/evaluating-ai/ab-testing-honestly"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Reading fifty failures', in Knowing If It Works. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/evaluating-ai/error-analysis (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Reading fifty failures","courseTitle":"Knowing If It Works","module":{"index":6,"slug":"evaluation-in-the-loop","title":"Evaluation in the working loop"},"answer":null,"keyIdea":"Read fifty failures, write the cause in your own words before categorising, and label each cause as data, retrieval, prompt, model, label or product: most of them will not be prompt problems.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"type":"bars","unit":"failures out of 50","title":"Fifty receipt-extraction failures, by cause","series":[{"label":"Multi-page receipt, only page one uploaded (data)","value":22,"highlight":true},{"label":"Date read MM/DD when written DD/MM (prompt)","value":11},{"label":"Genuinely illegible photograph (product)","value":8},{"label":"Discount line subtracted twice (model)","value":5},{"label":"Miscellaneous","value":4}],"caption":"The team had spent a fortnight comparing three prompt variants. The largest cause was a client bug, and only five of the fifty failures were the model’s."},"alt":"Figure: Fifty receipt-extraction failures, by cause. Bars (failures out of 50): Multi-page receipt, only page one uploaded (data) 22; Date read MM/DD when written DD/MM (prompt) 11; Genuinely illegible photograph (product) 8; Discount line subtracted twice (model) 5; Miscellaneous 4. The team had spent a fortnight comparing three prompt variants. The largest cause was a client bug, and only five of the fifty failures were the model’s."}},"blocks":[{"t":"h2","id":"the-highest-value-hour-in-applied-ai","runs":[{"text":"The highest-value hour in applied AI"}]},{"t":"p","runs":[{"text":"Sit down with fifty failures. Read each one. Write one line saying why it failed. Then group the lines."}]},{"t":"p","runs":[{"text":"That is the whole technique, it takes about ninety minutes, and it will change what you work on next more than any other activity in this course. Teams that do it routinely stop guessing; teams that do not spend months rewriting prompts against problems that were never prompt problems."}]},{"t":"p","runs":[{"text":"The reason it works is the distribution. Failures are never spread evenly across twenty causes. Three causes are usually 60 to 80 per cent of them, and you cannot see which three from a summary metric."}]},{"t":"h2","id":"do-it-in-this-order","runs":[{"text":"Do it in this order"}]},{"t":"p","runs":[{"text":"1. Take failures, not a random sample.","b":true},{"text":" You are diagnosing, not estimating a rate. Fifty is plenty; twenty is enough to see the big clusters."}]},{"t":"p","runs":[{"text":"2. Write the cause in your own words, before naming a category.","b":true},{"text":" “Only the first page of the receipt was in the input”, not “extraction error”. Free text first. Categories imposed too early hide the thing you did not expect."}]},{"t":"p","runs":[{"text":"3. Cluster afterwards.","b":true},{"text":" Sort the fifty lines, merge the ones that say the same thing, count."}]},{"t":"p","runs":[{"text":"**4. Assign each cluster an owner and a "},{"text":"kind","i":true},{"text":".** This is the step that pays. Kinds:"}]},{"t":"ul","items":[[{"text":"Data","b":true},{"text":": the input was wrong, missing, or not what the system was given."}],[{"text":"Retrieval","b":true},{"text":": the information was not supplied."}],[{"text":"Prompt","b":true},{"text":": the instruction was ambiguous or absent."}],[{"text":"Model","b":true},{"text":": the instruction was clear and it did not comply."}],[{"text":"Label","b":true},{"text":": the expected answer was wrong. It happens more than teams expect."}],[{"text":"Product","b":true},{"text":": the request was reasonable and the system is not designed to serve it."}]]},{"t":"h2","id":"what-it-looks-like","runs":[{"text":"What it looks like"}]},{"t":"p","runs":[{"text":"A receipt-extraction system, 50 failures:"}]},{"t":"ul","items":[[{"text":"22: multi-page receipts, only page one uploaded.","b":true},{"text":" "},{"text":"Data.","i":true},{"text":" The mobile client sent one image. No prompt change would have helped."}],[{"text":"11: dates read as MM/DD when written DD/MM.","b":true},{"text":" "},{"text":"Prompt.","i":true},{"text":" One sentence naming the locale convention, plus a deterministic check that the parsed date is not in the future."}],[{"text":"8: illegible photographs.","b":true},{"text":" "},{"text":"Product.","i":true},{"text":" The answer is to detect blur and ask for a retake, not to extract harder."}],[{"text":"5: totals wrong because a discount line was subtracted twice.","b":true},{"text":" "},{"text":"Model.","i":true},{"text":" Real, and the smallest cluster."}],[{"text":"4: miscellaneous.","b":true}]]},{"t":"p","runs":[{"text":"The team had been comparing three prompt variants for a fortnight. Two of the three top causes were not in the prompt at all, and the biggest one was a client bug. That is the typical shape of this exercise, not a dramatic example chosen to make a point."}]},{"t":"h2","id":"turn-the-clusters-into-a-taxonomy","runs":[{"text":"Turn the clusters into a taxonomy"}]},{"t":"p","runs":[{"text":"Write the cause names down and reuse them. Tag every future failure with one. Within two months you have a chart of failure causes over time, and it answers the question no pass rate can: "},{"text":"what is going wrong now, and is it the same thing as last month?","i":true}]},{"t":"p","runs":[{"text":"A cluster that keeps reappearing after a fix was shipped means the fix did not work, which is exactly the fact that a stable overall score conceals."}]},{"t":"h2","id":"cheap-tricks-that-speed-it-up","runs":[{"text":"Cheap tricks that speed it up"}]},{"t":"ul","items":[[{"text":"Sort failures by input length, language, or slice tag","b":true},{"text":" before reading. Clusters often fall out of the ordering for free."}],[{"text":"Cluster automatically for a first pass.","b":true},{"text":" Embed the failure outputs with a free local model, run k-means with k around 8, read three items per cluster. This is a way to "},{"text":"find","i":true},{"text":" candidate groups quickly, not a substitute for reading. The names you get from reading are better than the ones you get from a centroid."}],[{"text":"Diff against a run that passed.","b":true},{"text":" For items that used to pass and now fail, put the two outputs side by side. The cause is usually visible in seconds."}],[{"text":"Keep the fifty.","b":true},{"text":" They become eval items with an "},{"text":"origin","code":true},{"text":" field, which is the subject of a later lesson."}]]},{"t":"h2","id":"the-rule","runs":[{"text":"The rule"}]},{"t":"p","runs":[{"text":"No prompt change without error analysis first. It sounds bureaucratic and it is the opposite: it is what stops you spending a fortnight on the 10 per cent cause while the 44 per cent cause sits in a client bug nobody has looked at."}]},{"t":"p","runs":[{"text":"And it is the part of this work that does not automate. A model can cluster your failures; it cannot notice that the receipts are all from one chain whose printer cuts off the total. That noticing is the job."}]}],"check":{"question":[{"text":"A team’s error analysis of 50 failures finds 21 caused by truncated inputs, 12 by an ambiguous instruction, 9 by genuine model errors and 8 miscellaneous. They have one week. What should they do?"}],"options":[{"text":[{"text":"Work on the 9 model errors, since those are the only failures the model itself is responsible for."}],"correct":false,"tempting":[{"text":"Restricts the team to the failures that feel like AI problems, leaving the largest cluster untouched because it lives in another part of the system."}]},{"text":[{"text":"Fix the truncation in the input pipeline first, then the ambiguous instruction, and leave the model errors for later."}],"correct":true,"tempting":null},{"text":[{"text":"Rewrite the prompt to handle all four clusters at once, since a single prompt revision is cheaper than four separate fixes."}],"correct":false,"tempting":[{"text":"Assumes a prompt can address causes that sit outside the prompt, and bundles four changes so that no single one can be measured."}]},{"text":[{"text":"Collect another 200 failures first, since 50 is too small a sample to allocate a week of work against."}],"correct":false,"tempting":[{"text":"Applies sampling caution to a diagnostic exercise where the clusters are already stark enough to act on."}]}],"order":[3,1,2,0],"why":null},"prev":{"slug":"regression-testing-a-prompt","title":"Regression testing a prompt","minutes":8},"next":{"slug":"ab-testing-honestly","title":"A/B testing a feature honestly","minutes":8}}}