Differentiate lessons within a curriculum unit - #300
Conversation
Every lesson of a unit was generated from the same grammar points and vocabulary sets, with no knowledge of its siblings and with lesson_type used only as a label. The model had no differentiation signal, so consecutive lessons of a unit repeated the same explanation, the same example sentences and the same common mistakes. Lesson generation now receives two additional signals: - The lessons already generated for the same unit are condensed into a capped summary (titles, types, explanation excerpts, example sentences, vocabulary, common traps) and injected as delimited data the new lesson must not reuse. The router builds the list from the lessons it already loaded for the plan, so no extra query is needed, and keeps it current when several lessons of a unit are generated in one request. - The declared lesson_type selects an instruction block describing what the explanation, the exercise mix and the vocabulary of a grammar, vocabulary, reading, writing, listening or review lesson must emphasise. Unknown types fall back to a generic block, and review lessons keep recycling the unit material but with new sentences and contexts. The output JSON schema is unchanged.
|
Thanks for putting this together, the overall approach looks solid. I found four concrete correctness issues that I think should be addressed before merging:
The context wiring, unit scoping, same-request context updates, and backward-compatible generator signature otherwise look correct. |
Collect the unit vocabulary from every previous lesson instead of only the six that get a detailed summary. Scope the minimum share of grammar-targeting exercises to the lesson type, so a vocabulary lesson can ask for lexical exercises without contradicting the strict constraints. Stop claiming the student worked through the listed lessons, since a sibling can still be pending. Skip explanation blocks that are not lists, which the lesson schema still allows.
|
All four addressed.
New tests cover the unit vocabulary beyond the detailed window, the per-type grammar ratio, the
|
|
Thanks! |
Closes #295.
Problem
Every lesson of a unit is generated from the same
grammar_pointsandvocabulary_set_ids, the prompt carries no information about the lessons already generated for that unit, andlesson_typeappears only as a label echoed back into the output JSON. With no differentiation signal and no memory of the siblings, the model produces the same explanation, the same example sentences and the same "common mistakes" list for lesson after lesson.Change
Lesson generation receives two additional signals.
Sibling-lesson context.
build_previous_lessons_summary()condenses the already generated lessons of the same unit into a capped summary — at most the 6 most recent lessons, each with title, type, a truncated explanation excerpt, up to 3 example sentences, up to 6 vocabulary words and up to 2 common traps, followed by the vocabulary already introduced in the unit. It is injected into the prompt inside a<<<PREVIOUS_LESSONSblock described as data only, with explicit instructions not to reuse the example sentences, the explanation angle, the situations or the traps. A unit's first lesson gets no block at all.The router builds that list from the lessons it already loads for the plan, so
GET /todaymakes no extra query, and it appends lessons generated earlier in the same request so several lessons of one unit generated together still see each other.Per-type behaviour.
lesson_typenow selects an instruction block stating what the explanation, the exercise mix and the vocabulary of agrammar,vocabulary,reading,writing,listeningorreviewlesson must emphasise. Unknown types fall back to a generic block.reviewkeeps recycling the unit material by design, so its reuse rule is inverted — recycling is expected, but the sentences, contexts and exercises must be new.The output JSON schema is untouched; only the instructions around it change.
Tests
tests/test_prompts.py— per-type blocks differ, unknown type falls back, the sibling block is delimited and present only when there is history, review keeps the recycling policy.tests/test_lesson_generator.py— summary extraction, caps, vocabulary de-duplication, truncation and malformed-content tolerance, plus the prompt actually receiving the sibling context.tests/test_study_plan.py—GET /todaypasses the unit's earlier lessons to the generator, including a lesson generated moments earlier in the same request.Full backend suite: 986 passed, coverage 85%.
Docs
specs/prompts.instructions.md,specs/services.instructions.mdandspecs/study-plan.instructions.mdare updated.CHANGELOG.mdandspecs/version.mdare intentionally left untouched — releases and version bumps look like maintainer territory, and version edits would conflict across parallel PRs.Not covered here
The "unexpected error" when opening a later lesson of a unit out of sequence, mentioned in the issue, is not addressed. It blocked my verification but is a separate matter.