# How the Two-Stage Generation Pipeline Works in OpenMAIC

> Explore OpenMAIC's two-stage generation pipeline that transforms educational content into interactive classrooms, creating structured lesson outlines and rich scenes with engaging content.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: deep-dive
- Published: 2026-08-30

---

**OpenMAIC transforms raw educational content into interactive classrooms through a sequential two-stage generation pipeline that first produces structured lesson outlines and then constructs rich scenes with content and interactive actions.**

The [THU-MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC) repository implements this architecture to convert PDFs, PowerPoints, and text into AI-driven classroom experiences. Understanding this **two-stage generation pipeline** is essential for developers extending the platform or troubleshooting generation workflows.

## Architecture Overview

The system processes instructional material through distinct phases that separate content planning from presentation design.

### Stage 1: Outline Generation

In the first stage, the AI analyzes user inputs—whether text documents, PDFs, or presentations—and produces a structured **lesson outline**. This outline consists of ordered items that define the pedagogical flow of the lesson. This logic resides primarily in the `@openmaic/generation` package, which determines *what* content the lesson will cover.

### Stage 2: Scene Construction

For each outline item, the system builds a **rich scene** through two sub-steps:

1. **Content generation** - Creating slides, text, and media elements
2. **Action generation** - Adding interactive quizzes, simulations, and PBL (Problem-Based Learning) tasks

The completed scene is then persisted to the workspace. This stage determines *how* each outline item will be presented to learners.

## Pipeline Orchestration

The server-side module [`lib/server/classroom-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/classroom-generation.ts) orchestrates the entire workflow. It manages the transition from outline creation to scene generation through a sequential loop:

```typescript
// 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);
}

```

This orchestration ensures that each outline item is processed completely before moving to the next, while maintaining the ability to retry individual scenes independently.

## Scene Generation Implementation

The heavy lifting of scene construction lives in [`lib/server/scene-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/scene-generation.ts), specifically within the `buildSceneFromOutline` function. This function accepts an outline item and coordinates the content and action phases:

```typescript
// 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 applies fallbacks for missing data, generates language-specific text directives, and ensures that content creation succeeds before attempting action generation.

## Design Rationale

The **two-stage generation pipeline** employs this architecture for three critical reasons:

- **Modularity** - Outline logic can be modified or replaced without affecting scene generation code, allowing independent iteration of pedagogical planning versus presentation design.
- **Parallelism** - Once the outline is finalized, individual scenes can be generated and retried independently. If one scene fails, the system can regenerate that specific item without rebuilding the entire classroom.
- **Extensibility** - Additional phases such as media generation (images, video) and text-to-speech (TTS) are appended after the core two stages without breaking the existing pipeline contract.

## Practical Implementation Examples

### Generating a Complete Classroom

To initiate the pipeline from application code, use the `generateClassroom` function:

```typescript
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 Individual Scenes

For granular control over specific outline items, call `buildSceneFromOutline` directly:

```typescript
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 scene creation, persist the results using the StageAPI:

```typescript
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** separates lesson planning (outline generation) from presentation building (scene generation) to create interactive OpenMAIC classrooms.
- **Stage 1** produces structured lesson outlines via the `@openmaic/generation` package, determining what content to teach.
- **Stage 2** constructs rich scenes through `buildSceneFromOutline` in [`lib/server/scene-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/scene-generation.ts), first generating content then adding interactive actions.
- The orchestration logic in [`lib/server/classroom-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/classroom-generation.ts) manages the sequential processing of outline items into complete scenes.
- This architecture provides **modularity**, supports **independent retry logic**, and allows **extensibility** for post-processing steps like media generation.

## Frequently Asked Questions

### What triggers the two-stage generation pipeline in OpenMAIC?

The pipeline initiates when a user uploads instructional material—such as PDF documents, PowerPoint presentations, or plain text—through the `generateClassroom` function. This function calls the outline generation service to analyze the input and produce the initial lesson structure before proceeding to scene construction.

### How does OpenMAIC handle failures during scene generation?

The pipeline processes each outline item independently within a loop in [`lib/server/classroom-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/classroom-generation.ts). If `generateSceneContent` or `generateSceneActions` fails for a specific outline item, that scene can be retried without regenerating the entire classroom or other completed scenes, improving overall robustness.

### Can the two stages of the pipeline operate independently?

While the stages are **sequential**—scene generation requires a completed outline—the architecture supports modularity that allows outline logic to evolve separately from scene construction. Additionally, once an outline exists, individual scenes can be regenerated or modified independently, enabling parallel processing capabilities for performance optimization.

### Where is the scene content and action logic implemented?

The core scene building logic resides in [`lib/server/scene-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/scene-generation.ts), specifically within the `buildSceneFromOutline` function. This module handles both the **content phase** (slides, text, media) and the **actions phase** (quizzes, simulations), while [`lib/server/classroom-generation.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/classroom-generation.ts) orchestrates the overall workflow and persistence layers.