<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aditya Verma</title>
    <description>The latest articles on DEV Community by Aditya Verma (@adityaverma).</description>
    <link>https://dev.to/adityaverma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F587005%2F2d813241-0b58-48a6-9642-cf870b5ebac7.png</url>
      <title>DEV Community: Aditya Verma</title>
      <link>https://dev.to/adityaverma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adityaverma"/>
    <language>en</language>
    <item>
      <title>AI Evals 101: How to Actually Know If Your AI Is Any Good</title>
      <dc:creator>Aditya Verma</dc:creator>
      <pubDate>Wed, 05 Aug 2026 17:57:59 +0000</pubDate>
      <link>https://dev.to/adityaverma/ai-evals-101-how-to-actually-know-if-your-ai-is-any-good-k6i</link>
      <guid>https://dev.to/adityaverma/ai-evals-101-how-to-actually-know-if-your-ai-is-any-good-k6i</guid>
      <description>&lt;p&gt;If you have ever shipped an AI feature and then crossed your fingers hoping it works, this post is for you. An eval is a structured test that measures how well your AI system performs: its quality, reliability, and correctness across a range of scenarios. Think of it as the unit test of the LLM world, except the thing you are testing is probabilistic, moody, and changes every time a new model drops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bother with Evals?
&lt;/h2&gt;

&lt;p&gt;Teams that invest in evals see four big payoffs. First, they cut development time because you get rapid iteration cycles and can test locally across multiple LLMs instead of eyeballing outputs one at a time. Second, they reduce costs because automated evals replace slow manual review and let you release faster. Third, they enhance quality because real-time monitoring and compliance checks reduce risk and improve the customer experience. Finally, they scale teams because a good eval setup lets non-technical collaborators contribute to building the best possible product experience.&lt;/p&gt;

&lt;p&gt;Greg Brockman captured the idea in a memorable line:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1733553161884127435-223" src="https://platform.twitter.com/embed/Tweet.html?id=1733553161884127435"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1733553161884127435-223');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1733553161884127435&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The point is not that prompts, observability, or human judgment stop mattering. It is that once an AI system can produce plausible outputs, the hard part is often knowing whether your next change made it better.&lt;/p&gt;

&lt;p&gt;The mental model has three pillars. Prompt and context engineering give you a place to prototype behavior. Evals answer the single most important question in AI development: did I just improve things, or did I regress? Depending on what you measure, a result might be a number, a pass or fail, a category, or written feedback. AI observability tells you what is actually happening in production, so when something breaks you can turn the failure into a reproducible test instead of relying on a guess.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2q9p9ayxmn3ymmk3xs8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2q9p9ayxmn3ymmk3xs8e.png" alt="AI Development Loop" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Useful Model for Most Evals
&lt;/h2&gt;

&lt;p&gt;Most offline evals can be understood through the same three parts, even though frameworks give them different names.&lt;/p&gt;

&lt;p&gt;The target is the code, prompt, model, or workflow you want to evaluate. Some tools call this a task, application, predict function, or system under test. It can be as small as one model call or as large as an entire agent workflow. The important part is that the same input can be run through different versions so you can compare their behavior.&lt;/p&gt;

&lt;p&gt;The dataset is your collection of test cases. A case usually includes an input and may also include a reference answer, expected properties, a rubric, metadata, tags, or other context. The exact schema depends on the framework and the behavior you are testing. A reference is not always necessary: safety, style, latency, and many other criteria can be evaluated without one exact ideal output.&lt;/p&gt;

&lt;p&gt;The evaluator is the logic that measures the target's behavior. Some frameworks call it a scorer, grader, metric, or judge. It can be deterministic code, a model-based judge, a human review, or a combination of them, and it can return a number, boolean, label, ranking, or structured feedback.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmgwofa3nz8gt19ml43s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmgwofa3nz8gt19ml43s.png" alt="Anatomy of AI Evals" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline vs. Online: Two Eval Mental Models
&lt;/h2&gt;

&lt;p&gt;Two common modes are offline and online evaluation, and mature teams often use both.&lt;/p&gt;

&lt;p&gt;Offline evals run on curated or historical test cases, usually during development, in CI, or before a release. The point is to catch regressions, compare versions, and understand tradeoffs under controlled conditions. You can run them with a local script, a test framework, a notebook, or an evaluation platform; the workflow is the same even when the interface changes.&lt;/p&gt;

&lt;p&gt;Online evals measure selected production interactions as the system runs. They often operate on traces, logs, user feedback, or sampled traffic and focus on signals that do not require a known reference answer, such as safety, policy compliance, relevance, latency, or user satisfaction. Tracing and evaluation are related but different: tracing records what happened, while an evaluator judges some aspect of it. Interesting production cases should be reviewed and curated before they become offline test cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffx6q0nb7slgso4syh7wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffx6q0nb7slgso4syh7wd.png" alt="Offline and online evals" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Eval Framework: A Simple 2x2
&lt;/h2&gt;

&lt;p&gt;Here is a mental framework worth memorizing. When you compare an output with an evaluator's result, there are four possibilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output quality&lt;/th&gt;
&lt;th&gt;Evaluation result&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Good output&lt;/td&gt;
&lt;td&gt;Positive&lt;/td&gt;
&lt;td&gt;Everything is working&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad output&lt;/td&gt;
&lt;td&gt;Negative&lt;/td&gt;
&lt;td&gt;The eval caught a real problem, so improve the AI app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good output&lt;/td&gt;
&lt;td&gt;Negative&lt;/td&gt;
&lt;td&gt;The eval is too strict or measures the wrong behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad output&lt;/td&gt;
&lt;td&gt;Positive&lt;/td&gt;
&lt;td&gt;The eval rewards a failure and needs improvement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The interesting quadrants are the mismatches. A good output with a negative result, or a bad output with a positive result, means your evaluation criteria need improvement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4pxekqpqdzx4bzi7731.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4pxekqpqdzx4bzi7731.png" alt="The Eval 2x2" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The practical takeaway is to create a baseline and start iterating immediately. Do not wait around for a perfect golden dataset that never arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Target Patterns: From Model Calls to Agents
&lt;/h2&gt;

&lt;p&gt;The simplest target is a single model call. Its prompt may combine instructions with variables such as the user's question, retrieved context, or conversation state. Template syntax varies across libraries, so the important contract is the data you pass in, not the braces used to represent it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System: Answer using the supplied context.
User question: {question}
Context: {context}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Single-call targets are useful for testing instructions, examples, output formats, retrieval context, and model choices in isolation.&lt;/p&gt;

&lt;p&gt;For multi-turn scenarios, evaluate a sequence of messages or an entire conversation. This is a good fit for measuring whether a chat experience remembers context, follows changing instructions, and stays coherent across turns.&lt;/p&gt;

&lt;p&gt;Tool-using systems add another layer. The evaluator may need to inspect not only the final answer but also tool selection, arguments, permissions, intermediate results, cost, and latency. The tool can be implemented in any language or service; what matters is the observable contract between the model and the tool.&lt;/p&gt;

&lt;p&gt;Agents and multi-step workflows combine model calls, tools, state, routing, and control logic. Evaluating them usually means scoring both the outcome and the trajectory: whether the system reached the right result in a safe, efficient, and reproducible way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aw1bav41sz0m75twzwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aw1bav41sz0m75twzwv.png" alt="Target patterns" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Datasets: Start Small, Never Stop
&lt;/h2&gt;

&lt;p&gt;Datasets collect your test cases so you can run repeatable evaluations and track improvements over time. Three tips make the difference between a dataset that helps and one that rots:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start small and iterate. Focus on building a feedback loop rather than a perfect dataset.&lt;/li&gt;
&lt;li&gt;Never stop iterating. Use production logs to capture new edge cases and make your evals more holistic over time.&lt;/li&gt;
&lt;li&gt;Implement human review to establish ground truth, especially when you rely on an expected-output field.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Evaluators: The Spec for Your Project
&lt;/h2&gt;

&lt;p&gt;There are two common families of automated evaluators.&lt;/p&gt;

&lt;p&gt;Code-based evaluators handle anything deterministic: exact matches, numeric comparisons, structured checks, or factual checks. Something as simple as the following counts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They can also run in your CI pipeline. Techniques like schema validation, exact match, string-similarity measures such as Levenshtein distance, numeric tolerances, and binary checks fit here too.&lt;/p&gt;

&lt;p&gt;Model-based judges handle work that needs semantic or subjective interpretation, such as relevance, tone, completeness, or improvement across drafts. A judge prompt can be as simple as: "Does this response contain an apology? Return PASS or FAIL and briefly explain why."&lt;/p&gt;

&lt;p&gt;Two common judge patterns are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct assessment, where you design a rubric.&lt;/li&gt;
&lt;li&gt;Pairwise comparison, where the judge picks the better of two outputs and a ranking algorithm sorts overall quality. This is particularly useful for subjective tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few hard-won tips for evaluators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a judge capable enough for the criterion, and keep its configuration separate from the system being evaluated.&lt;/li&gt;
&lt;li&gt;Treat evaluators like real judges evaluating intent, style, and overall quality, not just correctness.&lt;/li&gt;
&lt;li&gt;Break evaluation into focused criteria such as accuracy, creativity, safety, and formatting so you can pinpoint exactly what broke.&lt;/li&gt;
&lt;li&gt;Calibrate judge prompts against representative examples with human labels before trusting them.&lt;/li&gt;
&lt;li&gt;Do not overload the judge with context. Keep it focused on the relevant input and output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the most important ideas here is that evaluators are an executable part of the spec for your project. Writing criteria that reflect your users and failure modes is essential because generic metrics rarely capture everything your product actually needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human in the Loop: When the Worst Case Matters
&lt;/h2&gt;

&lt;p&gt;Not all AI mistakes are equal. In high-stakes industries like healthcare, finance, or legal tech, a single failure can mean regulatory violations or real user harm. That is why teams in these domains invest heavily in clear ground-truth definitions, use human subject-matter experts as annotators, and apply human-in-the-loop workflows to refine their scoring.&lt;/p&gt;

&lt;p&gt;In these contexts, human review is not a nice-to-have. It is essential for catching hallucinations, establishing ground truth, and ensuring alignment with business, compliance, and user expectations. Automation misses nuance. Real people identify mistakes, label correct outputs, and make sure the final product actually meets human needs.&lt;/p&gt;

&lt;p&gt;Human-in-the-loop work comes in two forms. Human review uses internal experts to manually label, score, or audit outputs. It is useful for building high-quality ground-truth datasets, auditing edge cases, and calibrating model-based judges. One example is legal subject-matter experts defining exactly how a legal AI assistant should respond.&lt;/p&gt;

&lt;p&gt;User feedback is the implicit or explicit signal from end users during real usage. Thumbs up or down, flags, comments, corrections, and helpfulness ratings can trigger human review or flag production traces for dataset curation.&lt;/p&gt;

&lt;p&gt;The formula is simple: automated testing for scale plus human judgment for nuance creates a north-star experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spans: The Bridge Between Production and Testing
&lt;/h2&gt;

&lt;p&gt;A trace records one end-to-end execution of your application. Within it, a span represents a unit of work such as a model call, retrieval step, tool invocation, or business-logic function. Spans can be nested to show how the smaller operations contributed to the overall result. The exact names and boundaries depend on how you instrument the application.&lt;/p&gt;

&lt;p&gt;Why do traces matter for datasets? When your instrumentation records the relevant fields, traces can preserve the input, output, intermediate steps, and context behind real behavior. When something goes wrong, such as the AI rephrasing a user's question badly, you can save the relevant input and trace as the basis of a new test case. The failed production output is evidence of the problem, not the expected answer. Add a corrected reference, rubric, or explicit property that defines what success should look like, then use that curated case as a regression test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flywheel Effect
&lt;/h2&gt;

&lt;p&gt;This all comes together in a cycle worth internalizing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instrument the app and run it in production.&lt;/li&gt;
&lt;li&gt;Collect traces, operational metrics, evaluator signals, and user feedback.&lt;/li&gt;
&lt;li&gt;Find important examples, such as a user thumbs-down, policy failure, or unusual trace.&lt;/li&gt;
&lt;li&gt;Curate those examples into test cases with a corrected reference, rubric, or expected property.&lt;/li&gt;
&lt;li&gt;Fix the code, redeploy, and repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every turn of the flywheel makes your evals more realistic and your product more robust.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pcn1wmre176klbn6nws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pcn1wmre176klbn6nws.png" alt="The Production Eval Flywheel" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices: Playing Offense with Evals
&lt;/h2&gt;

&lt;p&gt;The biggest mindset shift is to use evals to play offense. Evals are not just a safety net for catching regressions. They are what lets you launch better products, faster and with confidence.&lt;/p&gt;

&lt;p&gt;A few principles follow from that. Great evals need to be intentionally designed, not bolted on. Treat datasets as maintained engineering assets: record provenance, version meaningful changes, deduplicate near-copies, protect sensitive data, and keep labels consistent as the collection grows. Prompt engineering is also evolving into context engineering. System instructions are only one part of what a production model sees; conversation history, retrieved documents, tool definitions and results, memory, and policy context can dominate the input. Evaluate the whole context assembly process, not just the prompt text.&lt;/p&gt;

&lt;p&gt;Finally, remember that everything changes when a new model comes out. Model-agnostic evals are your defense against the nondeterministic nature of LLMs. They let you swap models and release efficiently and intentionally. Optimize the entire evaluation system, not just the prompts. Once your evals are solid, you can even close the loop entirely and use them to automatically improve your prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Evals turn AI development from vibes into engineering. Start with a target, representative test cases, and evaluators that express what good means for your users. Run offline evals while you build and monitor selected quality signals after you ship. Curate production failures into regression cases, keep humans in the loop where the stakes are high, and treat your evaluation criteria as a living part of the product spec. Do that, and "did I improve or regress?" stops being a guess and becomes a question you can answer with evidence.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aiops</category>
      <category>programming</category>
      <category>evals</category>
    </item>
    <item>
      <title>Building a Multimodal Agentic Pipeline for Educational Content Ingestion</title>
      <dc:creator>Aditya Verma</dc:creator>
      <pubDate>Sat, 25 Jul 2026 07:28:13 +0000</pubDate>
      <link>https://dev.to/adityaverma/building-a-multimodal-agentic-pipeline-for-educational-content-ingestion-317f</link>
      <guid>https://dev.to/adityaverma/building-a-multimodal-agentic-pipeline-for-educational-content-ingestion-317f</guid>
      <description>&lt;p&gt;Educational publishers have decades of valuable content locked inside worksheets, textbooks, and scanned assessment papers. Converting it into structured, interactive learning material is harder than it looks: a single document can mix questions in multiple languages, inconsistent mathematical notation, diagrams that are essential to the question, multi-column layouts, and imperfect OCR. Doing this manually is slow and error-prone, and plain OCR only solves the easy part: it extracts text without understanding question boundaries, formulas, answer choices, or educational intent.&lt;/p&gt;

&lt;p&gt;The motivation is concrete. A structured question set ingested into Wayground works two ways: it can be printed as a proper classroom worksheet, or played live as a formative assessment. Publishers wanted both from the same source material, with every question tagged by Depth of Knowledge (DoK) so a teacher can control the rigor of what they hand out. That dual use is why structure is non-negotiable. A printed worksheet forgives loose formatting, but an interactive assessment needs clean question boundaries, machine-readable answers, and explicit metadata.&lt;/p&gt;

&lt;p&gt;We built a publisher content ingestion system that handles two related jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract existing questions from worksheets and assessment documents.&lt;/li&gt;
&lt;li&gt;Generate new questions from textbooks and other reference material.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both share the same foundation but need very different reasoning and quality control. This post walks through how each pipeline works and what we learned building them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why OCR Isn't Enough
&lt;/h2&gt;

&lt;p&gt;A PDF is a visual representation of a document, not a semantic one. Consider a worksheet containing the expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(x^2 - 4) / (x - 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A basic OCR system might produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x2 - 4
------
x - 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x^2 - 4 / x - 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These outputs are textually similar but mathematically different. The same ambiguity appears everywhere: chemistry superscripts and reaction arrows carry meaning, physics diagrams define the geometry needed to answer a question, and biology labels can be part of the question itself. Language adds another dimension: a Gujarati or Spanish worksheet may mix English scientific terminology, mathematical notation, and locally formatted instructions on one page.&lt;/p&gt;

&lt;p&gt;A reliable ingestion system therefore needs more than OCR. It needs a sequence of specialized reasoning steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  System Overview
&lt;/h2&gt;

&lt;p&gt;The platform is a FastAPI application with LangGraph orchestrating the two workflows. LangGraph carries a typed state object through each pipeline, holding raw text, detected subjects, extracted questions, and quality scores. This makes runs easy to inspect, pause, and retry, and keeps agents from relying on information hidden inside prompts.&lt;/p&gt;

&lt;p&gt;The supporting services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mistral.ai/" rel="noopener noreferrer"&gt;Mistral&lt;/a&gt; Document AI for OCR and document parsing&lt;/li&gt;
&lt;li&gt;GPT-4o for structured extraction, formula conversion, and image understanding&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://portkey.ai/" rel="noopener noreferrer"&gt;Portkey&lt;/a&gt; for model routing across providers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sympy.org/en/index.html" rel="noopener noreferrer"&gt;SymPy&lt;/a&gt; for deterministic mathematical verification&lt;/li&gt;
&lt;li&gt;PostgreSQL for document, question, image, and processing metadata&lt;/li&gt;
&lt;li&gt;A publishing layer that converts the internal representation into the platform schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwnk3hpv6uptj5af3qyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwnk3hpv6uptj5af3qyg.png" alt="system overview" width="800" height="859"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Extracting Existing Questions
&lt;/h2&gt;

&lt;p&gt;Extraction is not transcription. For each question, the system must reconstruct the author's intended structure: the stem, instructions, answer choices, correct answers, associated images, formulas, subject, language, and question type. We implemented this as an eight-stage sequential workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flecouxiyfosimmzvij2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flecouxiyfosimmzvij2m.png" alt="Extraction Workflow" width="800" height="835"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. OCR extraction
&lt;/h3&gt;

&lt;p&gt;Pulls raw text, page structure, images, and language signals, and deliberately preserves as much source information as possible. Cleaning too early destroys useful signals like column structure and the relationship between an image and nearby text.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Structure analysis
&lt;/h3&gt;

&lt;p&gt;Determines what kind of document this is (question numbering, section headings, multi-column layouts, repeating answer-choice formats) and picks a chunking strategy. Arbitrary token-based splitting can separate a question from its answer choices or detach a diagram from the text that references it. The useful question is not how many tokens fit in a context window, but what the smallest self-contained educational unit is.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Subject classification
&lt;/h3&gt;

&lt;p&gt;Detects the subjects present, which drives later processing: a chemistry document needs different normalization rules than a biology worksheet. It also flags whether the document contains formulas, so text-only documents skip formula processing entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Formula cleanup
&lt;/h3&gt;

&lt;p&gt;Converts inconsistent OCR output into standardized LaTeX. This stage must be conservative: its job is to repair representation, never to change mathematical meaning. Where confidence is low, it preserves the original expression and flags it for review instead of inventing a correction.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Text normalization
&lt;/h3&gt;

&lt;p&gt;Repairs broken whitespace, incorrect line breaks, split answer choices, repeated headers and footers, and encoding artifacts, while retaining references to the original source.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Structured question extraction
&lt;/h3&gt;

&lt;p&gt;Converts normalized content into a validated schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"question_text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is the value of x?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"question_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"multiple_choice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"correct_answer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mathematics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.91&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structured output here is critical. Free-form model responses are difficult to validate and dangerous to publish directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Language specialization
&lt;/h3&gt;

&lt;p&gt;Corrects spelling and language-specific OCR errors without translating or changing meaning. This matters for documents that mix a regional language with English terminology or non-Latin scripts. The system currently supports Gujarati and Spanish alongside English.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Final validation
&lt;/h3&gt;

&lt;p&gt;Checks that required fields are present, options are structurally valid, referenced images exist, LaTeX parses, questions are not empty or duplicated, and confidence meets the publishing threshold. The output is a set of structured questions with a quality report.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Multiple Agents Instead of One Big Prompt?
&lt;/h2&gt;

&lt;p&gt;Sending the whole document to one large prompt is simpler, and nearly impossible to debug. When the output is wrong, you cannot tell whether the failure came from OCR, layout understanding, question boundaries, formula parsing, or schema generation.&lt;/p&gt;

&lt;p&gt;Specialized stages give us three things: observability (every stage produces inspectable intermediate output), targeted retries (a failed formula conversion does not repeat OCR for the whole document), and independent improvement (the formula agent or validator can be upgraded without redesigning the pipeline).&lt;/p&gt;

&lt;p&gt;That said, not every stage needs an LLM. Deterministic code is preferable whenever the task can be solved reliably with rules, parsers, or mathematical libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Generating New Questions
&lt;/h2&gt;

&lt;p&gt;Generation has a different objective: use textbook content to create new questions that test understanding at specific cognitive levels. The workflow contains nine agents and four subject-specific generation modules, with a quality-gated retry loop: questions must score at least 75 against a rubric, with up to three generation attempts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5asuzn673qvl5ai4hl1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5asuzn673qvl5ai4hl1o.png" alt="Generation Workflow" width="800" height="992"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Content analysis
&lt;/h3&gt;

&lt;p&gt;Beyond identifying topics, the analyzer extracts core concepts, relationships between them, important values, and, most valuably, common student misconceptions. A high-quality distractor should represent a believable reasoning mistake, not a random incorrect value. When testing order of operations, a plausible wrong answer comes from evaluating addition before multiplication, because it reveals what the learner misunderstood.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cognitive-level planning
&lt;/h3&gt;

&lt;p&gt;Before generating anything, the system plans a distribution of questions across cognitive levels. At publishing time, each question maps to the Depth of Knowledge tag Wayground uses, so a worksheet can be assembled against an explicit rigor target instead of an implicit difficulty:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Intended capability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Recall a fact, formula, or definition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Apply a familiar procedure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Combine multiple concepts or reasoning steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Analyze, compare, or solve a non-routine problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Transfer knowledge to a novel situation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This planning step exists because without it, language models produce many questions that sound different but test the same shallow skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subject-specific generation
&lt;/h3&gt;

&lt;p&gt;A generic prompt is rarely sufficient across subjects, because correctness means something different in each:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subject&lt;/th&gt;
&lt;th&gt;What correctness requires&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mathematics&lt;/td&gt;
&lt;td&gt;Symbolic verification: answers are checked with SymPy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physics&lt;/td&gt;
&lt;td&gt;Numerical results plus unit and dimensional consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chemistry&lt;/td&gt;
&lt;td&gt;Equation, reaction, and terminology constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Biology&lt;/td&gt;
&lt;td&gt;Strong grounding in the source material, since most answers cannot be verified symbolically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Deterministic Answer Verification
&lt;/h2&gt;

&lt;p&gt;Language models are useful generators, but they should not be treated as calculators. For mathematical questions, the generated answer is independently solved with SymPy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr280p5wmguaxevorb0y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr280p5wmguaxevorb0y8.png" alt="answer verification sequence" width="800" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generator proposes; the verifier solves the problem independently. If they disagree, the question does not proceed to publishing. The same principle extends to unit validation, chemical equation balancing, and option uniqueness checks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Distractors from Known Mistakes
&lt;/h2&gt;

&lt;p&gt;This is my favorite part of the system. Instead of asking a language model to invent incorrect options, the system generates distractors by solving modified versions of the original problem with SymPy, where each modification encodes a specific mistake a student could plausibly make.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f(x) = (3x^2 + 1)^4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct derivative requires the chain rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f'(x) = 4(3x^2 + 1)^3 * 6x = 24x(3x^2 + 1)^3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distractor generator applies realistic mistake transformations (forgetting the chain rule, differentiating the inner function incorrectly, dropping the outer coefficient), and SymPy evaluates each altered procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A. 24x(3x^2 + 1)^3    correct chain rule
B. 4(3x^2 + 1)^3      forgot the inner derivative
C. 12x(3x^2 + 1)^3    inner derivative taken as 3x instead of 6x
D. 6x(3x^2 + 1)^3     dropped the outer coefficient
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fitm2b02wlzfhvxneu7s6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fitm2b02wlzfhvxneu7s6.png" alt="Derivative distractor paths" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The validator confirms each distractor is mathematically distinct from the correct answer and from the others, and does not simplify into the correct expression. The result is distractors that are realistic, deterministic, and traceable: the system can explain not only that an option is wrong, but which mistake produces it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quality-Gated Generation
&lt;/h2&gt;

&lt;p&gt;Every generated question is scored against a rubric covering correctness, grounding in the source material, clarity, cognitive-level alignment, distractor quality, and language quality. Questions below the threshold are retried, but instead of a bare "generate again," the validator returns structured reasons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"passed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cognitive_alignment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The question tests direct recall instead of the requested level 3 reasoning."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"distractor_quality"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Two answer choices are obviously unrelated to the concept."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feedback becomes input to the next generation attempt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extraction and Generation Are Different Products
&lt;/h2&gt;

&lt;p&gt;Although they share infrastructure, the two workflows should not be treated as one generic operation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Extraction&lt;/th&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary goal&lt;/td&gt;
&lt;td&gt;Reconstruct existing questions&lt;/td&gt;
&lt;td&gt;Create novel questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main risk&lt;/td&gt;
&lt;td&gt;Losing or changing source meaning&lt;/td&gt;
&lt;td&gt;Incorrect or shallow content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;Fidelity and schema correctness&lt;/td&gt;
&lt;td&gt;Correctness and cognitive alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retry strategy&lt;/td&gt;
&lt;td&gt;Reprocess the failed stage&lt;/td&gt;
&lt;td&gt;Regenerate using rubric feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic tools&lt;/td&gt;
&lt;td&gt;Formatting and structural checks&lt;/td&gt;
&lt;td&gt;Symbolic answer verification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This distinction shapes prompts, validation, metrics, and failure handling throughout the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;OCR is only the first step. Layout analysis, formula reconstruction, image association, and semantic extraction are separate problems.&lt;/li&gt;
&lt;li&gt;Preserve provenance. Without page numbers and source spans, reviewing an incorrect question becomes a search problem.&lt;/li&gt;
&lt;li&gt;Use models for interpretation, deterministic code for verification. Schema validation, math solving, deduplication, and retry limits do not need an LLM.&lt;/li&gt;
&lt;li&gt;Validate intermediate representations. Each stage needs its own contract. Waiting until final output makes failures impossible to isolate.&lt;/li&gt;
&lt;li&gt;Quality requires a feedback loop. Plan, generate, verify, score, and retry beats one-shot generation.&lt;/li&gt;
&lt;li&gt;Correctness is subject-specific. Symbolic proof in mathematics, unit checks in physics, source grounding in biology.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The current architecture is a solid foundation. The improvements I care most about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page-level provenance with bounding boxes, so a reviewer sees the exact source region beside each structured question.&lt;/li&gt;
&lt;li&gt;Hard gates instead of one aggregate score, so a question can never pass because strong writing compensates for a wrong answer.&lt;/li&gt;
&lt;li&gt;Confidence-based review routing: auto-approve the easy cases, send formula-heavy or low-confidence output to subject experts.&lt;/li&gt;
&lt;li&gt;Semantic deduplication across editions, teacher copies, and answer keys, where questions differ only in formatting or values.&lt;/li&gt;
&lt;li&gt;Cached document understanding and resumable execution, so a retry resumes from the failed stage instead of re-running OCR.&lt;/li&gt;
&lt;li&gt;An evaluation dataset with human-reviewed ground truth, because the metric that matters is cost per accepted question, not cost per token.&lt;/li&gt;
&lt;li&gt;Treating uploaded documents as untrusted input, with strict structured outputs so embedded text can never act as instructions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Turning educational PDFs into reliable questions is not a single-model problem. It is a document-understanding, reasoning, verification, and orchestration problem. The most important architectural decision was treating extraction and generation as pipelines of specialized stages rather than one large prompt: models interpret, deterministic tools verify, and quality gates decide what reaches publishing. The payoff is publisher content that lands in Wayground ready for both lives it needs to lead: printed as a worksheet or played as a formative assessment, with a DoK tag on every question. And with provenance, evaluation, and reviewer feedback in place, the same system keeps improving with every document it processes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>ocr</category>
      <category>python</category>
    </item>
  </channel>
</rss>
