How the Two-Stage Generation Pipeline Works in OpenMAIC
OpenMAIC converts raw instructional material into interactive classrooms through a two-stage generation pipeline that first creates a structured lesson outline, then builds rich interactive scenes with content and actions for each outline item.
The OpenMAIC platform transforms static educational content into dynamic, AI-driven learning experiences. At the core of this transformation is a two-stage generation pipeline that systematically processes user inputs—whether text, PDF, or PowerPoint—and generates structured, interactive lesson environments. This architecture, implemented in the THU-MAIC/OpenMAIC repository, separates content planning from scene construction to maximize modularity and reliability.
Stage 1: Outline Generation
The pipeline begins with outline generation, handled by the external @openmaic/generation package. During this stage, the AI analyzes the user’s input material and produces a structured lesson outline—an ordered list of outline items that define the pedagogical flow of the lesson. This stage determines what content needs to be taught without specifying how it will be presented.
The outline serves as the contract between the two stages. Once generated, it becomes the immutable blueprint that the second stage uses to construct individual learning scenes.
Stage 2: Scene Construction
For every item in the generated outline, the pipeline executes scene generation to create how the content is presented. This stage operates independently for each outline entry and consists of two distinct sub-steps: content creation and action layering.
The Content Phase
First, the system invokes generateSceneContent to fabricate the visual and textual elements of the scene. This includes generating slides, explanatory text, and media references. The function accepts the outline item and an AI call wrapper to produce the raw educational material.
The Actions Phase
Next, the pipeline calls generateSceneActions to layer interactivity onto the content. This step adds quizzes, simulations, problem-based learning (PBL) tasks, and other interactive elements that transform static content into engaging learning experiences. The actions are generated with awareness of the content created in the previous sub-step.
Pipeline Orchestration in classroom-generation.ts
The high-level coordination of the two-stage generation pipeline resides in lib/server/classroom-generation.ts. This module orchestrates the transition from outline to completed classroom by iterating through each outline entry and triggering the scene construction workflow.
// lib/server/classroom-generation.ts (excerpt)
for (const [index, safeOutline] of outlines.entries()) {
// 1️⃣ Generate scene content
const content = await generateSceneContent(...);
// 2️⃣ Generate scene actions
const actions = await generateSceneActions(...);
// 3️⃣ Persist the scene
const sceneId = createSceneWithActions(safeOutline, content, actions, api);
}
The loop processes outline items sequentially, calling the scene generation service for each entry before persisting the completed scene via createSceneWithActions.
Scene Assembly in scene-generation.ts
The heavy lifting of scene construction is encapsulated in lib/server/scene-generation.ts within the buildSceneFromOutline function. This function manages the two sub-steps and assembles the final scene object.
// lib/server/scene-generation.ts (excerpt)
export async function buildSceneFromOutline(
outline,
aiCall,
stageId,
assignedImages,
imageMapping,
languageModel,
visionEnabled,
ctx,
agents,
) {
const safeOutline = applyOutlineFallbacks(outline, !!languageModel, { logger });
const langText = buildLanguageText(languageDirective, safeOutline.languageNote);
// ── CONTENT PHASE ──
const content = await generateSceneContent(safeOutline, aiCall, { … });
if (!content) return null;
// ── ACTIONS PHASE ──
const actions = await generateSceneActions(safeOutline, content, aiCall, { … });
// Return a fully‑formed scene ready for persistence
return buildCompleteScene(safeOutline, content, actions, stageId);
}
The function accepts comprehensive parameters including the outline object, LLM call wrapper, stage ID, image mappings, and agent configurations. It applies fallbacks for missing data, generates content, generates actions, and returns a complete scene ready for persistence.
Design Benefits of the Two-Stage Architecture
Separating outline generation from scene construction provides three critical advantages:
- Modularity – Outline logic can be updated or swapped without modifying scene generation code, allowing independent evolution of pedagogical strategy and presentation technology.
- Parallelism – Once the outline is finalized, individual scenes can be generated and retried independently, improving robustness against transient AI failures.
- Extensibility – Additional processing phases—such as media generation (images, video) and text-to-speech (TTS) synthesis—can be appended after the core two stages without breaking the existing pipeline.
Implementation Examples
Generating a Complete Classroom
To initiate the full pipeline from application code, invoke the generateClassroom function:
import { generateClassroom } from '@/lib/server/classroom-generation';
// `input` contains the raw user material (PDF, text, etc.)
const result = await generateClassroom({
input,
stageId: 'stage-123',
onProgress: ({ step, progress }) =>
console.log(`🔄 ${step} – ${progress}%`),
});
console.log('✅ Classroom ready at', result.url);
Building a Single Scene
For granular control over individual scene creation, use buildSceneFromOutline directly:
import { buildSceneFromOutline } from '@/lib/server/scene-generation';
import { callLLM } from '@/lib/ai/llm';
const scene = await buildSceneFromOutline(
outlineItem, // a SceneOutline from the generated outline
callLLM, // LLM call wrapper
'stage-123', // current stage ID
pdfImages, // optional images extracted from PDFs
imageMapping, // optional mapping for those images
languageModel, // optional model for PBL loop fallback
);
if (scene) {
console.log('🖼️ Scene built:', scene.title);
}
Persisting Generated Scenes
After constructing content and actions, persist the scene using the API layer:
import { StageAPI } from '@/lib/api/stage-api';
import { createSceneWithActions } from '@/lib/server/scene-generation';
const sceneId = createSceneWithActions(
outline,
content,
actions,
StageAPI, // concrete API implementation
);
if (sceneId) {
console.log('💾 Scene stored with ID:', sceneId);
}
Summary
- The two-stage generation pipeline in OpenMAIC separates content planning (outline generation) from interactive presentation (scene generation).
- Stage 1 uses the
@openmaic/generationpackage to create structured lesson outlines from raw user inputs. - Stage 2 processes each outline item through
lib/server/scene-generation.ts, first generating content viagenerateSceneContent, then adding interactivity viagenerateSceneActions. - The orchestration logic in
lib/server/classroom-generation.tsmanages the sequential processing of outlines and the persistence of completed scenes. - This architecture enables independent scaling, retry logic, and post-processing enhancements like media generation and TTS.
Frequently Asked Questions
What is the purpose of separating outline and scene generation?
The separation ensures that the pedagogical structure (what to teach) is finalized before any presentation assets (how to teach it) are created. This prevents content drift, allows different AI models to handle planning versus presentation, and enables scene-level retries without regenerating the entire lesson plan.
Can individual scenes be regenerated without rebuilding the entire classroom?
Yes. Because the outline serves as an immutable contract, the buildSceneFromOutline function in lib/server/scene-generation.ts can be called for a single outline item independently. This allows the system to reattempt scene generation for specific sections that fail or require updates without reprocessing the entire pipeline.
What types of actions can be generated in the second stage?
The actions phase generates interactive elements including quizzes, simulations, problem-based learning (PBL) tasks, and other engagement mechanisms. These actions are contextualized by the content generated in the preceding phase, ensuring that interactions remain pedagogically relevant to the specific outline item.
How does the pipeline handle errors during scene generation?
The pipeline implements fallback logic via applyOutlineFallbacks and null checks after content generation. If generateSceneContent returns null, the function exits early without attempting action generation. This defensive programming prevents partial scene creation and allows the orchestration layer in classroom-generation.ts to retry failed scenes individually or log errors for specific outline items while continuing processing of other items.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →