Fill Gaps, Don't Regenerate
Published Jul 6, 2026
AI lesson generation is a multi-step pipeline, and multi-step pipelines get interrupted. A free-tier quota runs out mid-run, a provider 429s, the box restarts. When that happens you end up with a lesson that is mostly there: three of four sections written, exercises half-populated, status stuck short of generated. Fill Gaps is the repair tool for exactly this situation. It looks at what a lesson already has, figures out what is missing, and regenerates only those pieces — the missing sections and the missing exercise kinds — while leaving the good content untouched. If nothing is missing, it makes zero LLM calls. This is a how-to for admins who own the /admin content console.
What you'll need
- Admin access to the
/adminconsole (routes are guarded byrequire_admin). - A lesson that has been through generation at least once and came back partial — usually you'll notice it because some sections are blank, exercises are thin, or the lesson never reached
generated. - At least one working LLM provider key configured (
NVIDIA_API_KEY→GROQ_API_KEY→GEMINI_API_KEY→HF_TOKEN, first configured wins). Without a key the system emits deterministic placeholder content, which is not what you want to persist.
Note: Fill Gaps is the right tool for a partial lesson. If you want to rebuild a lesson from scratch — different angle, new dataset — use full generation instead. Fill Gaps deliberately preserves what already exists.
How to run Fill Gaps
- Open the admin console at
/adminand navigate down the hierarchy: Technology → Framework → the lesson (ContentItem) you want to repair. - Read the current state. A healthy lesson has all four sections —
main_explanation,practical_explanation,key_principles,summary— each with a review score, plus exercises across themcq,fill_blank, andcalculationkinds. Look for blanks: an empty section, a missing exercise type, ageneration_statusthat never reachedgenerated. - Click Fill Gaps. This calls
POST /admin/content/{id}/fill-gaps. The service inspects the lesson, builds the list of missing sections and missing exercise kinds, and generates only those. Existing sections and their scores are left exactly as they are. - Wait for it to finish. Because it only touches gaps, a nearly-complete lesson finishes fast and cheap — it is regenerating one or two things, not sixteen.
- Verify. Refresh the lesson and confirm the previously-empty sections now have content and a review score, the exercise kinds are all present, and the status has advanced. When everything is in place, publish to move the lesson from
drafttopublishedso learners see it in/learn.
What it does under the hood
Fill Gaps is intentionally token-frugal, because tokens are the scarce resource on free tiers:
- It counts the gaps first. If the lesson is already complete, the missing-list is empty and the endpoint returns having made 0 LLM calls. Running it on a finished lesson is safe and essentially free — a no-op.
- It regenerates only what's missing. A single blank section costs one section's worth of generation, not a full four-section rebuild. The same goes for exercises: only the absent kinds are produced.
- It filters out placeholder junk. If a prior run left fallback/placeholder text behind (the deterministic content emitted when a provider is unavailable), Fill Gaps treats that as a gap and refuses to persist the junk — so an outage never leaves permanent filler baked into the lesson.
When it goes wrong
Most "failures" here are quota, not bugs. The pipeline raises LLMUnavailableError when the provider is down or throttled, which leaves the lesson re-runnable — you lose nothing by trying again.
| Symptom | Likely cause | What to do |
|---|---|---|
| Fill Gaps did nothing / returned instantly | Lesson already complete — 0 LLM calls by design | Nothing to fix; publish it |
| Still missing sections after a run | Provider quota hit again mid-fill (e.g. Groq TPM, Gemini limit:0, HF 402) | Wait for the window to reset, or configure another provider key, then click Fill Gaps again |
| A section came back as obvious filler | No working provider key at run time | Add a valid key; Fill Gaps filters placeholders, so re-run to replace them |
Status still not generated | One or more gaps remain | Re-run until the missing-list is empty |
Tip: Because Fill Gaps is idempotent and cheap when complete, the safe habit after any interrupted bulk generate is simply to click it again. It converges — each run closes whatever gaps the last one couldn't, and stops calling the LLM the moment the lesson is whole.
What you get
A lesson brought to full completeness without paying to regenerate the parts that were already good — four scored sections, all exercise kinds present, no placeholder text, ready to move from draft to published. Practically, Fill Gaps turns a quota interruption from a "start over" event into a "click once more" event, which is what makes bulk generation across a whole framework survivable on a free tier. Next: once your lessons are generated and published, run a Fill Gaps pass across the framework as a cheap final sweep before publishing, and consider exporting the finished set to the content pool so the curriculum is portable.