AI Lesson Generation
Published Jul 4, 2026
AI Lesson Generation is the heart of Praxis924 — it's how a bare topic becomes a finished, quality-checked lesson without you writing a word. This guide takes you all the way from an empty subject to a published lesson: four sections, interactive exercises, and — if you want it — grounding in your own dataset. Budget about ten minutes of clicking, plus generation time.
What you'll need
- An admin account. Admins are seeded on startup and land on
/admin. - At least one LLM provider key in your
.env—GROQ_API_KEY,GEMINI_API_KEY, orHF_TOKEN. - The stack running (
docker compose up -d).
Note: With no provider key, generation still "works" but produces deterministic placeholder text. It's fine for a dry run and useless for anything you'll publish — set at least one key first.
The mental model (30 seconds)
Everything in Praxis924 is organised as Technology → Framework → Lesson. A Technology is the broad subject (say, Python). A Framework is a track inside it (say, Async Python). A Lesson is a single unit — and the lesson is what the AI generates. Every lesson has four sections (main explanation, practical walkthrough, key principles, summary) plus a set of exercises. Hold that hierarchy in your head and the rest of this is just filling it in.
Step 1 — Create a Technology
In the admin console, open Technologies → New Technology and give it a name and short description. This is just the container that groups related tracks — nothing generates here yet.
Step 2 — Add a Framework
Open your new technology and create a Framework inside it. Set its learning level and display order so it sits in the right place on the learner's roadmap. Frameworks are where lessons live, and — importantly — where you attach a dataset if you want grounded content.
Step 3 (optional, but this is the trust multiplier) — Ground it with your own data
By default the AI writes from its general training. If you want lessons grounded in specific material — your internal docs, a particular library version, a proprietary dataset — attach a Data Source to the framework and upload your text (plain or alpaca-style is fine).
Praxis924 chunks the file, embeds each chunk via Hugging Face, and stores the vectors in pgvector. During generation it retrieves the most relevant chunks by meaning and cites them in the lesson.
Tip: Grounding is what turns "plausible AI text" into "answers from your actual source." Skip it for general topics; use it for anything proprietary or version-specific — it's the single biggest lever on trust.
Step 4 — Design the syllabus
On the framework page, click Generate Syllabus. The model designs an ordered, basics-to-advanced outline and creates one draft lesson per topic. Nothing is written yet — these are empty placeholders with a title and a position in the sequence.
Read the outline before moving on. Delete drafts you don't want, reorder anything that's out of sequence. Five minutes here saves you regenerating content later.
Step 5 — Generate a lesson
Open a draft and click Generate (or use Generate All on the framework to batch every draft at once). It's worth knowing exactly what happens, because it explains both the quality and the occasional failure:
- Build the grounded source — the top-K dataset chunks if the framework has a data source, otherwise the lesson's own raw content.
- Write the four sections, one at a time.
- Run the review loop on each section — the AI scores its own draft, and anything below 7/10 is sent back for improvement, up to two rounds. You never see the weak first draft.
- Generate the exercises — multiple-choice, fill-in-the-blank, and calculation.
- Persist everything with citations and flip the status to
generated.
The whole pipeline runs as a durable workflow, so if the server restarts mid-generation it resumes from the last finished step instead of starting over.
Note: A lesson moves through pending → generating → generated (or failed). A failed lesson is always safe to re-run — it won't duplicate anything.
Step 6 — Review, then fill any gaps
Read what came back. If a section is empty or an exercise type is missing — usually because a provider hit a quota partway through — click Fill Gaps. This regenerates only the missing pieces, and makes zero LLM calls if the lesson is already complete, so it's safe and cheap to click as many times as you like. It also strips out any placeholder text, so an outage can never quietly persist itself as real content.
Step 7 — Publish
When you're happy, switch the lesson's status from draft to published. It now appears in /learn for every learner — the four sections, inline sources, exercises, an AI-graded coding challenge, and Lucy (the AI teacher) available alongside it.
When generation fails — and it will, sometimes
Free-tier LLM quotas run out. These are the usual ones and how to clear them:
| Symptom | Cause | Fix |
|---|---|---|
| HF 402 · Gemini 429 "limit:0" · Groq 429 TPM | Provider quota exhausted | Wait for the reset, or add another provider key — the system fails over Groq → Gemini → HF automatically |
Lesson stuck on generating after a restart | Interrupted workflow | It resumes on boot; if it's truly stuck, just click Generate again |
| A section reads like filler | No provider key set | Add a key, then click Fill Gaps |
Warning: The grounded source is deliberately capped (~3000 characters) because it's re-sent in every prompt. That cap protects your tokens-per-minute budget — bigger context is not better here.
What you just built
One published lesson a learner can read, practice, get AI-graded on, and interrogate with Lucy — generated in minutes, quality-gated by the review loop, and grounded in your own data if you chose to attach it. Repeat Steps 4–7, or hit Generate All, and you've got an entire framework.
Where to go next
- Batch a whole framework with Generate All.
- Attach a dataset and regenerate to watch grounding and citations kick in.
- Export the result to the portable content pool to version or share your curriculum.