openmaic-classroom
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenMAIC — Multi-Agent Interactive Classroom
OpenMAIC — 多Agent交互式课堂
Skill by ara.so — Daily 2026 Skills collection.
OpenMAIC (Open Multi-Agent Interactive Classroom) is a Next.js 16 / React 19 / TypeScript platform that converts any topic or document into a full interactive lesson. A multi-agent pipeline (LangGraph 1.1) generates slides, quizzes, HTML simulations, and project-based learning activities delivered by AI teachers and AI classmates with voice (TTS) and whiteboard support.
由ara.so开发的Skill — 属于Daily 2026 Skills合集。
OpenMAIC(开源多Agent交互式课堂)是基于Next.js 16 / React 19 / TypeScript构建的平台,可将任意主题或文档转换为完整的交互式课程。其多Agent流水线(LangGraph 1.1)可生成幻灯片、测验、HTML模拟场景和项目式学习活动,由AI教师和AI同学通过语音(TTS)和白板功能进行授课。
Project Stack
技术栈
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19, Tailwind CSS 4 |
| Agent orchestration | LangGraph 1.1 |
| Language | TypeScript 5 |
| Package manager | pnpm >= 10 |
| Runtime | Node.js >= 20 |
| 层级 | 技术 |
|---|---|
| 框架 | Next.js 16(App Router) |
| UI | React 19, Tailwind CSS 4 |
| Agent编排 | LangGraph 1.1 |
| 编程语言 | TypeScript 5 |
| 包管理器 | pnpm >= 10 |
| 运行时 | Node.js >= 20 |
Installation
安装步骤
bash
git clone https://github.com/THU-MAIC/OpenMAIC.git
cd OpenMAIC
pnpm installbash
git clone https://github.com/THU-MAIC/OpenMAIC.git
cd OpenMAIC
pnpm installEnvironment Configuration
环境配置
bash
cp .env.example .env.localEdit — at minimum one LLM provider key is required:
.env.localenv
undefinedbash
cp .env.example .env.local编辑文件 — 至少需要配置一个LLM提供商的密钥:
.env.localenv
undefinedLLM Providers (configure at least one)
LLM Providers (configure at least one)
OPENAI_API_KEY=$OPENAI_API_KEY
ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY
GOOGLE_API_KEY=$GOOGLE_API_KEY
OPENAI_API_KEY=$OPENAI_API_KEY
ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY
GOOGLE_API_KEY=$GOOGLE_API_KEY
Recommended default model (Gemini 3 Flash = best speed/quality balance)
Recommended default model (Gemini 3 Flash = best speed/quality balance)
DEFAULT_MODEL=google:gemini-3-flash-preview
DEFAULT_MODEL=google:gemini-3-flash-preview
Optional: MinerU for advanced PDF/table/formula parsing
Optional: MinerU for advanced PDF/table/formula parsing
PDF_MINERU_BASE_URL=https://mineru.net
PDF_MINERU_API_KEY=$MINERU_API_KEY
PDF_MINERU_BASE_URL=https://mineru.net
PDF_MINERU_API_KEY=$MINERU_API_KEY
Optional: access code for hosted mode
Optional: access code for hosted mode
ACCESS_CODE=$OPENMAIC_ACCESS_CODE
undefinedACCESS_CODE=$OPENMAIC_ACCESS_CODE
undefinedProvider Config via YAML (alternative to env vars)
基于YAML的提供商配置(环境变量的替代方案)
Create in the project root:
server-providers.ymlyaml
providers:
openai:
apiKey: $OPENAI_API_KEY
anthropic:
apiKey: $ANTHROPIC_API_KEY
google:
apiKey: $GOOGLE_API_KEY
deepseek:
apiKey: $DEEPSEEK_API_KEY
# Any OpenAI-compatible endpoint
custom:
baseURL: https://your-proxy.example.com/v1
apiKey: $CUSTOM_API_KEY在项目根目录创建文件:
server-providers.ymlyaml
providers:
openai:
apiKey: $OPENAI_API_KEY
anthropic:
apiKey: $ANTHROPIC_API_KEY
google:
apiKey: $GOOGLE_API_KEY
deepseek:
apiKey: $DEEPSEEK_API_KEY
# Any OpenAI-compatible endpoint
custom:
baseURL: https://your-proxy.example.com/v1
apiKey: $CUSTOM_API_KEYRunning the App
运行应用
bash
undefinedbash
undefinedDevelopment
开发环境
pnpm dev
pnpm dev
Production build
生产环境构建
pnpm build && pnpm start
pnpm build && pnpm start
Type checking
类型检查
pnpm tsc --noEmit
pnpm tsc --noEmit
Linting
代码检查
pnpm lint
---pnpm lint
---Docker Deployment
Docker部署
bash
cp .env.example .env.localbash
cp .env.example .env.localEdit .env.local with your API keys
编辑.env.local文件配置你的API密钥
docker compose up --build
docker compose up --build
---
---Vercel Deployment
Vercel部署
bash
undefinedbash
undefinedFork the repo, then import at https://vercel.com/new
Fork该仓库,然后在https://vercel.com/new导入
Set env vars in Vercel dashboard:
在Vercel控制台设置环境变量:
OPENAI_API_KEY or ANTHROPIC_API_KEY or GOOGLE_API_KEY
OPENAI_API_KEY 或 ANTHROPIC_API_KEY 或 GOOGLE_API_KEY
DEFAULT_MODEL (optional, e.g. google:gemini-3-flash-preview)
DEFAULT_MODEL(可选,例如google:gemini-3-flash-preview)
One-click deploy button is available in the README; it pre-fills env var descriptions automatically.
---
README中提供了一键部署按钮,可自动预填充环境变量说明。
---Lesson Generation Pipeline
课程生成流程
OpenMAIC uses a two-stage pipeline:
| Stage | Description |
|---|---|
| Outline | AI analyzes topic/document and produces a structured lesson outline |
| Scenes | Each outline item is expanded into a typed scene: |
OpenMAIC采用两阶段流水线:
| 阶段 | 描述 |
|---|---|
| 大纲生成 | AI分析主题/文档,生成结构化课程大纲 |
| 场景生成 | 大纲中的每个条目会被扩展为特定类型的场景: |
Scene Types
场景类型
| Type | Description |
|---|---|
| AI teacher lectures with TTS narration, spotlight, laser pointer |
| Single/multiple choice or short-answer with AI grading |
| HTML-based simulation (physics, flowcharts, etc.) |
| Project-Based Learning — choose a role, collaborate with agents |
| 类型 | 描述 |
|---|---|
| AI教师通过TTS旁白、高亮、激光笔进行授课 |
| 单选题/多选题/简答题,由AI自动评分 |
| 基于HTML的模拟场景(物理实验、流程图等) |
| 项目式学习 — 选择角色,与Agent协作完成项目 |
API Usage — Generating a Classroom
API使用 — 生成课堂
REST: Start Generation Job
REST:启动生成任务
typescript
// POST /api/generate
const response = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
topic: 'Quantum Entanglement',
// Optional: attach document content
document: markdownString,
// Optional: model override
model: 'google:gemini-3-flash-preview',
}),
});
const { jobId } = await response.json();typescript
// POST /api/generate
const response = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
topic: 'Quantum Entanglement',
// Optional: attach document content
document: markdownString,
// Optional: model override
model: 'google:gemini-3-flash-preview',
}),
});
const { jobId } = await response.json();REST: Poll Job Status
REST:轮询任务状态
typescript
// GET /api/generate/status?jobId=<jobId>
const poll = async (jobId: string) => {
while (true) {
const res = await fetch(`/api/generate/status?jobId=${jobId}`);
const data = await res.json();
if (data.status === 'completed') {
console.log('Classroom URL:', data.classroomUrl);
break;
}
if (data.status === 'failed') {
throw new Error(data.error);
}
// status === 'pending' | 'running'
await new Promise(r => setTimeout(r, 3000));
}
};typescript
// GET /api/generate/status?jobId=<jobId>
const poll = async (jobId: string) => {
while (true) {
const res = await fetch(`/api/generate/status?jobId=${jobId}`);
const data = await res.json();
if (data.status === 'completed') {
console.log('Classroom URL:', data.classroomUrl);
break;
}
if (data.status === 'failed') {
throw new Error(data.error);
}
// status === 'pending' | 'running'
await new Promise(r => setTimeout(r, 3000));
}
};REST: Export Slides
REST:导出幻灯片
typescript
// GET /api/export/pptx?classroomId=<id>
const exportPptx = async (classroomId: string) => {
const res = await fetch(`/api/export/pptx?classroomId=${classroomId}`);
const blob = await res.blob();
const url = URL.createObjectURL(blob);
// trigger download
const a = document.createElement('a');
a.href = url;
a.download = 'lesson.pptx';
a.click();
};
// GET /api/export/html?classroomId=<id>
const exportHtml = async (classroomId: string) => {
const res = await fetch(`/api/export/html?classroomId=${classroomId}`);
const html = await res.text();
return html;
};typescript
// GET /api/export/pptx?classroomId=<id>
const exportPptx = async (classroomId: string) => {
const res = await fetch(`/api/export/pptx?classroomId=${classroomId}`);
const blob = await res.blob();
const url = URL.createObjectURL(blob);
// trigger download
const a = document.createElement('a');
a.href = url;
a.download = 'lesson.pptx';
a.click();
};
// GET /api/export/html?classroomId=<id>
const exportHtml = async (classroomId: string) => {
const res = await fetch(`/api/export/html?classroomId=${classroomId}`);
const html = await res.text();
return html;
};OpenClaw Integration
OpenClaw集成
OpenMAIC ships a skill for OpenClaw, enabling classroom generation from Feishu, Slack, Discord, Telegram, etc.
OpenMAIC附带了OpenClaw的Skill,支持从飞书、Slack、Discord、Telegram等平台生成课堂。
Install the Skill
安装Skill
bash
undefinedbash
undefinedVia ClawHub (recommended)
推荐通过ClawHub安装
clawhub install openmaic
clawhub install openmaic
Manual install
手动安装
mkdir -p ~/.openclaw/skills
cp -R /path/to/OpenMAIC/skills/openmaic ~/.openclaw/skills/openmaic
undefinedmkdir -p ~/.openclaw/skills
cp -R /path/to/OpenMAIC/skills/openmaic ~/.openclaw/skills/openmaic
undefinedConfigure OpenClaw
配置OpenClaw
Edit :
~/.openclaw/openclaw.jsonjsonc
{
"skills": {
"entries": {
"openmaic": {
"config": {
// Hosted mode — get access code from https://open.maic.chat/
"accessCode": "$OPENMAIC_ACCESS_CODE",
// Self-hosted mode — local repo + server URL
"repoDir": "/path/to/OpenMAIC",
"url": "http://localhost:3000"
}
}
}
}
}编辑文件:
~/.openclaw/openclaw.jsonjsonc
{
"skills": {
"entries": {
"openmaic": {
"config": {
// 托管模式 — 从https://open.maic.chat/获取访问码
"accessCode": "$OPENMAIC_ACCESS_CODE",
// 自托管模式 — 本地仓库+服务器地址
"repoDir": "/path/to/OpenMAIC",
"url": "http://localhost:3000"
}
}
}
}
}OpenClaw Skill Lifecycle
OpenClaw Skill生命周期
| Phase | What Happens |
|---|---|
| Clone | Detect existing checkout or clone fresh |
| Startup | Choose |
| Provider Keys | Guide user to edit |
| Generation | Submit async job, poll, return classroom link |
| 阶段 | 操作内容 |
|---|---|
| 克隆 | 检测现有仓库或克隆新仓库 |
| 启动 | 选择 |
| 提供商密钥 | 引导用户编辑 |
| 生成任务 | 提交异步任务,轮询状态,返回课堂链接 |
Custom Scene Development Pattern
自定义场景开发模式
Scenes are typed React components. To add a new scene type:
typescript
// types/scene.ts
export type SceneType = 'slides' | 'quiz' | 'interactive' | 'pbl' | 'custom';
export interface CustomScene {
type: 'custom';
title: string;
content: string;
// your fields
metadata: Record<string, unknown>;
}typescript
// components/scenes/CustomScene.tsx
'use client';
import { type CustomScene } from '@/types/scene';
interface Props {
scene: CustomScene;
onComplete: () => void;
}
export function CustomSceneComponent({ scene, onComplete }: Props) {
return (
<div className="flex flex-col gap-4 p-6">
<h2 className="text-2xl font-bold">{scene.title}</h2>
<div dangerouslySetInnerHTML={{ __html: scene.content }} />
<button
className="mt-4 rounded-lg bg-blue-600 px-6 py-2 text-white"
onClick={onComplete}
>
Continue
</button>
</div>
);
}场景是带类型的React组件。要添加新的场景类型:
typescript
// types/scene.ts
export type SceneType = 'slides' | 'quiz' | 'interactive' | 'pbl' | 'custom';
export interface CustomScene {
type: 'custom';
title: string;
content: string;
// your fields
metadata: Record<string, unknown>;
}typescript
// components/scenes/CustomScene.tsx
'use client';
import { type CustomScene } from '@/types/scene';
interface Props {
scene: CustomScene;
onComplete: () => void;
}
export function CustomSceneComponent({ scene, onComplete }: Props) {
return (
<div className="flex flex-col gap-4 p-6">
<h2 className="text-2xl font-bold">{scene.title}</h2>
<div dangerouslySetInnerHTML={{ __html: scene.content }} />
<button
className="mt-4 rounded-lg bg-blue-600 px-6 py-2 text-white"
onClick={onComplete}
>
Continue
</button>
</div>
);
}Multi-Agent Interaction Modes
多Agent交互模式
| Mode | Trigger | Description |
|---|---|---|
| Classroom Discussion | Automatic | Agents proactively start discussions; user can jump in or get called on |
| Roundtable Debate | Scene config | Multiple agent personas debate a topic with whiteboard illustrations |
| Q&A | User asks question | AI teacher responds with slides, diagrams, or whiteboard drawings |
| Whiteboard | During any scene | Agents draw equations, flowcharts, or concept diagrams in real time |
| 模式 | 触发方式 | 描述 |
|---|---|---|
| 课堂讨论 | 自动触发 | Agent主动发起讨论,用户可加入或被邀请参与 |
| 圆桌辩论 | 场景配置触发 | 多个不同角色的Agent围绕主题辩论,同时在白板上绘图说明 |
| 问答环节 | 用户提问触发 | AI教师通过幻灯片、图表或白板绘图进行解答 |
| 白板协作 | 任意场景中触发 | Agent实时绘制公式、流程图或概念图 |
MinerU Advanced Document Parsing
MinerU高级文档解析
For complex PDFs with tables, formulas, or scanned images:
env
undefined对于包含表格、公式或扫描件的复杂PDF:
env
undefinedUse MinerU hosted API
使用MinerU托管API
PDF_MINERU_BASE_URL=https://mineru.net
PDF_MINERU_API_KEY=$MINERU_API_KEY
PDF_MINERU_BASE_URL=https://mineru.net
PDF_MINERU_API_KEY=$MINERU_API_KEY
Or self-hosted MinerU instance (Docker)
或自托管MinerU实例(Docker)
PDF_MINERU_BASE_URL=http://localhost:8888
Without MinerU, OpenMAIC falls back to standard PDF text extraction.
---PDF_MINERU_BASE_URL=http://localhost:8888
如果未启用MinerU,OpenMAIC会回退到标准PDF文本提取功能。
---Supported LLM Providers & Model Strings
支持的LLM提供商及模型字符串
typescript
// Model string format: "provider:model-name"
const models = {
// Google (recommended)
geminiFlash: 'google:gemini-3-flash-preview', // best speed/quality
geminiPro: 'google:gemini-3.1-pro', // highest quality
// OpenAI
gpt4o: 'openai:gpt-4o',
gpt4oMini: 'openai:gpt-4o-mini',
// Anthropic
claude4Sonnet: 'anthropic:claude-sonnet-4-5',
claude4Haiku: 'anthropic:claude-haiku-4-5',
// DeepSeek
deepseekChat: 'deepseek:deepseek-chat',
// OpenAI-compatible (custom base URL)
custom: 'custom:your-model-name',
};typescript
// Model string format: "provider:model-name"
const models = {
// Google (recommended)
geminiFlash: 'google:gemini-3-flash-preview', // best speed/quality
geminiPro: 'google:gemini-3.1-pro', // highest quality
// OpenAI
gpt4o: 'openai:gpt-4o',
gpt4oMini: 'openai:gpt-4o-mini',
// Anthropic
claude4Sonnet: 'anthropic:claude-sonnet-4-5',
claude4Haiku: 'anthropic:claude-haiku-4-5',
// DeepSeek
deepseekChat: 'deepseek:deepseek-chat',
// OpenAI-compatible (custom base URL)
custom: 'custom:your-model-name',
};Export Formats
导出格式
| Format | Endpoint | Notes |
|---|---|---|
PowerPoint | | Fully editable slides |
Interactive | | Self-contained HTML page |
| 格式 | 接口 | 说明 |
|---|---|---|
PowerPoint | | 可完全编辑的幻灯片 |
交互式 | | 独立HTML页面 |
Common Patterns
常见使用模式
Generate a Classroom from a Document String
从文档字符串生成课堂
typescript
const generateFromDocument = async (markdownContent: string, topic: string) => {
const res = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
topic,
document: markdownContent,
model: process.env.DEFAULT_MODEL ?? 'google:gemini-3-flash-preview',
}),
});
const { jobId } = await res.json();
// Poll until done
let classroomUrl: string | null = null;
while (!classroomUrl) {
await new Promise(r => setTimeout(r, 4000));
const status = await fetch(`/api/generate/status?jobId=${jobId}`).then(r => r.json());
if (status.status === 'completed') classroomUrl = status.classroomUrl;
if (status.status === 'failed') throw new Error(status.error);
}
return classroomUrl;
};typescript
const generateFromDocument = async (markdownContent: string, topic: string) => {
const res = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
topic,
document: markdownContent,
model: process.env.DEFAULT_MODEL ?? 'google:gemini-3-flash-preview',
}),
});
const { jobId } = await res.json();
// 轮询直到完成
let classroomUrl: string | null = null;
while (!classroomUrl) {
await new Promise(r => setTimeout(r, 4000));
const status = await fetch(`/api/generate/status?jobId=${jobId}`).then(r => r.json());
if (status.status === 'completed') classroomUrl = status.classroomUrl;
if (status.status === 'failed') throw new Error(status.error);
}
return classroomUrl;
};Check Provider Health
检查提供商健康状态
typescript
// GET /api/providers
const checkProviders = async () => {
const res = await fetch('/api/providers');
const { providers } = await res.json();
// providers: Array<{ name: string; available: boolean; models: string[] }>
return providers.filter((p: { available: boolean }) => p.available);
};typescript
// GET /api/providers
const checkProviders = async () => {
const res = await fetch('/api/providers');
const { providers } = await res.json();
// providers: Array<{ name: string; available: boolean; models: string[] }>
return providers.filter((p: { available: boolean }) => p.available);
};Troubleshooting
故障排查
| Problem | Solution |
|---|---|
| Set at least one of |
| Generation hangs at outline stage | Check API key quota; try switching to |
| TTS not working | TTS requires a browser with Web Speech API support; check browser console for errors |
| PDF parsing produces garbled text | Enable MinerU by setting |
| Vercel timeout during generation | Increase function timeout in |
| Docker build fails | Ensure |
| OpenClaw skill not found | Run |
| Upgrade Node.js to >= 20 ( |
| Port 3000 already in use | Set |
| 问题 | 解决方案 |
|---|---|
| 在 |
| 大纲生成阶段卡住 | 检查API密钥配额;尝试切换到 |
| TTS无法工作 | TTS需要浏览器支持Web Speech API;检查浏览器控制台的错误信息 |
| PDF解析结果乱码 | 通过在 |
| Vercel部署时生成任务超时 | 在 |
| Docker构建失败 | 确保 |
| OpenClaw Skill找不到 | 运行 |
Node < 20时 | 将Node.js升级到>=20版本( |
| 端口3000已被占用 | 在 |
Key File Structure
核心文件结构
OpenMAIC/
├── app/ # Next.js App Router pages & API routes
│ ├── api/
│ │ ├── generate/ # POST lesson generation, GET status
│ │ ├── export/ # pptx / html export endpoints
│ │ └── providers/ # LLM provider health check
│ └── classroom/ # Classroom viewer pages
├── components/
│ ├── scenes/ # Slide, Quiz, Interactive, PBL components
│ ├── whiteboard/ # Real-time whiteboard rendering
│ └── agents/ # Agent avatar & TTS components
├── lib/
│ ├── agents/ # LangGraph agent graph definitions
│ ├── providers/ # LLM provider abstractions
│ └── generation/ # Outline + scene generation pipeline
├── skills/
│ └── openmaic/ # OpenClaw skill definition
├── server-providers.yml # Optional YAML provider config
├── .env.example # Environment variable template
└── docker-compose.yml # Docker deployment configOpenMAIC/
├── app/ # Next.js App Router页面及API路由
│ ├── api/
│ │ ├── generate/ # 课程生成POST接口、状态查询GET接口
│ │ ├── export/ # pptx/html导出接口
│ │ └── providers/ # LLM提供商健康检查接口
│ └── classroom/ # 课堂查看页面
├── components/
│ ├── scenes/ # 幻灯片、测验、交互式模拟、项目式学习组件
│ ├── whiteboard/ # 实时白板渲染组件
│ └── agents/ # Agent头像及TTS组件
├── lib/
│ ├── agents/ # LangGraph Agent图定义
│ ├── providers/ # LLM提供商抽象层
│ └── generation/ # 大纲+场景生成流水线
├── skills/
│ └── openmaic/ # OpenClaw Skill定义
├── server-providers.yml # 可选的YAML提供商配置文件
├── .env.example # 环境变量模板
└── docker-compose.yml # Docker部署配置