OpenMAIC 技术架构文档

0 阅读9分钟

最近 GitHub 上面开源的 OpenMAIC 很火,我看了源码,很适合作为入门 Agent 的学习落地。今天给大家分享他的架构设计

目录


概述

OpenMAIC 是一个基于 AI 的智能课程生成平台,能够根据用户的自然语言需求自动生成完整的教学课件。系统采用三阶段流水线架构,依次生成课程大纲、场景内容和教学动作。

核心能力

  • 智能大纲生成:从自然语言需求自动推导课程结构
  • 多类型场景支持:幻灯片(slide)、测验(quiz)、互动(interactive)、项目式学习(pbl)
  • 多模态输入:支持 PDF 文档、图片、网络搜索结果作为上下文
  • 多模型支持:OpenAI、Anthropic Claude、Google Gemini、DeepSeek、Ollama 等
  • 流式输出:SSE 实时返回生成进度
  • 离线支持:IndexedDB 本地持久化

系统架构

┌─────────────────────────────────────────────────────────────────────────────────┐
│                              OpenMAIC 系统架构                                    │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                           用户界面层 (Frontend)                          │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │   │
│  │  │   首页      │  │  课堂页面   │  │  设置面板   │  │  代理工具栏  │    │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                          │
│                                      ▼                                          │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         状态管理层 (Zustand)                             │   │
│  │  useStageStore | useSettingsStore | useCanvasStore | useMediaStore      │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                          │
│                                      ▼                                          │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         API 路由层 (Next.js API Routes)                  │   │
│  │  /api/generate/scene-outlines-stream | scene-content | scene-actions    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                          │
│                                      ▼                                          │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                       核心业务层 (Generation Pipeline)                   │   │
│  │  outline-generator → scene-generator → scene-builder → action-parser    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                          │
│                                      ▼                                          │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         AI 服务层 (LLM Abstraction)                      │   │
│  │  callLLM() / streamLLM() → providers.ts → OpenAI/Claude/Gemini/...      │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                          │
│                                      ▼                                          │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                        数据持久层 (IndexedDB + LocalStorage)             │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

技术栈

前端框架

技术版本用途
Next.js16.1.2全栈 React 框架
React19.2.3UI 组件库
TypeScript5.x类型安全
Tailwind CSS4.x样式系统

状态管理

技术用途
Zustand全局状态管理
Immer不可变数据更新
DexieIndexedDB ORM

AI 集成

技术用途
Vercel AI SDK统一 LLM 调用接口
@ai-sdk/anthropicClaude 模型支持
@ai-sdk/openaiGPT 模型支持
@ai-sdk/googleGemini 模型支持
LangChain复杂 AI 工作流

文档处理

技术用途
pdf-parsePDF 文本提取
unpdfPDF 渲染
pptxgenjsPPT 生成
mammothWord 文档解析

核心模块

目录结构

OpenMAIC/
├── app/                          # Next.js App Router
│   ├── page.tsx                  # 首页(课程创建入口)
│   ├── layout.tsx                # 根布局
│   ├── classroom/[id]/           # 课堂播放页面
│   ├── generation-preview/       # 生成预览页面
│   └── api/                      # API 路由
│       ├── generate/             # 生成相关 API
│       │   ├── scene-outlines-stream/  # 大纲流式生成
│       │   ├── scene-content/          # 场景内容生成
│       │   ├── scene-actions/          # 教学动作生成
│       │   ├── image/                  # AI 图片生成
│       │   ├── video/                  # AI 视频生成
│       │   └── tts/                    # 语音合成
│       ├── chat/                 # 对话 API
│       ├── parse-pdf/            # PDF 解析
│       └── web-search/           # 网络搜索
│
├── lib/                          # 核心业务逻辑
│   ├── ai/                       # AI 服务层
│   │   ├── llm.ts                # 统一 LLM 调用封装
│   │   └── providers.ts          # 模型提供商配置
│   ├── generation/               # 生成流水线
│   │   ├── outline-generator.ts  # 大纲生成器
│   │   ├── scene-generator.ts    # 场景内容生成器
│   │   ├── scene-builder.ts      # 场景构建器
│   │   ├── action-parser.ts      # 动作解析器
│   │   └── prompts/              # Prompt 模板系统
│   │       ├── templates/        # 模板文件
│   │       ├── snippets/         # 可复用片段
│   │       └── loader.ts         # 模板加载器
│   ├── store/                    # Zustand 状态管理
│   ├── types/                    # TypeScript 类型定义
│   └── utils/                    # 工具函数
│
├── components/                   # React 组件
│   ├── generation/               # 生成相关组件
│   ├── stage/                    # 课堂舞台组件
│   ├── slide-renderer/           # 幻灯片渲染器
│   ├── settings/                 # 设置面板
│   └── ui/                       # 基础 UI 组件
│
├── configs/                      # 配置文件
└── public/                       # 静态资源

关键模块说明

1. AI 服务层 (lib/ai/)

llm.ts - 统一 LLM 调用封装

// 调用示例
import { callLLM, streamLLM } from '@/lib/ai/llm';

// 同步调用
const result = await callLLM({
  model: languageModel,
  system: systemPrompt,
  prompt: userPrompt,
  maxOutputTokens: 4096,
}, 'scene-content');

// 流式调用
const stream = streamLLM({
  model: languageModel,
  system: systemPrompt,
  prompt: userPrompt,
}, 'scene-outlines-stream');

for await (const chunk of stream.textStream) {
  console.log(chunk);
}

providers.ts - 模型提供商配置

支持以下提供商:

  • OpenAI (GPT-4o, GPT-4-turbo, o1, o3)
  • Anthropic (Claude 4.6, Claude 4.5)
  • Google (Gemini 2.5, Gemini 3.x)
  • DeepSeek (DeepSeek V3, R1)
  • Qwen (通义千问)
  • Kimi (Moonshot)
  • GLM (智谱)
  • Ollama (本地模型)

2. 生成流水线 (lib/generation/)

outline-generator.ts - 大纲生成

  • 输入:用户需求文本、PDF 内容、图片描述
  • 输出:SceneOutline[] 场景大纲数组
  • 特点:使用 SSE 流式返回,支持增量解析 JSON

scene-generator.ts - 场景内容生成

  • 输入:单个 SceneOutline
  • 输出:完整场景内容(elements/questions/html)
  • 特点:根据 type 分发到不同的内容生成器

prompts/ - Prompt 模板系统

prompts/
├── templates/                    # 完整提示词模板
│   ├── requirements-to-outlines/ # 大纲生成
│   │   ├── system.md
│   │   └── user.md
│   ├── slide-content/            # 幻灯片内容
│   ├── quiz-content/             # 测验内容
│   ├── interactive-html/         # 互动内容
│   └── ...
├── snippets/                     # 可复用片段
│   ├── json-format.md
│   └── ...
└── loader.ts                     # 模板加载和变量插值

课程生成流程

详细讲解:juejin.cn/spost/76307…

三阶段流水线

┌─────────────────────────────────────────────────────────────────────────────────┐
                           课程生成三阶段流程                                      
├─────────────────────────────────────────────────────────────────────────────────┤
                                                                                 
  用户输入                                                                        
  requirement: "帮我创建一个关于光合作用的初中生物课程,时长20分钟"                  
  language: "zh-CN"                                                              
  pdfFile: [可选] 教材PDF                                                        
                                                                                 
                                                                                
                                                                                
  ╔═══════════════════════════════════════════════════════════════════════════╗ 
                      Stage 1: 需求  场景大纲                     
  ╠═══════════════════════════════════════════════════════════════════════════╣ 
    API: POST /api/generate/scene-outlines-stream                             
    流程: 解析输入  构建Prompt  调用LLM  流式返回JSON                       
    输出: SceneOutline[]                                                       
  ╚═══════════════════════════════════════════════════════════════════════════╝ 
                                                                                
                                                                                
  ╔═══════════════════════════════════════════════════════════════════════════╗ 
                   Stage 2: 大纲  场景内容               
  ╠═══════════════════════════════════════════════════════════════════════════╣ 
    API: POST /api/generate/scene-content (每个大纲独立调用)                   
    流程: 根据type选择prompt  生成内容  解析JSON                             
    输出: GeneratedSlideContent | GeneratedQuizContent | ...                   
  ╚═══════════════════════════════════════════════════════════════════════════╝ 
                                                                                
                                                                                
  ╔═══════════════════════════════════════════════════════════════════════════╗ 
                   Stage 3: 内容  教学动作                     
  ╠═══════════════════════════════════════════════════════════════════════════╣ 
    API: POST /api/generate/scene-actions                                      
    流程: 分析内容  生成讲解动作  添加动画触发                                
    输出: Action[] (教学动作序列)                                              
  ╚═══════════════════════════════════════════════════════════════════════════╝ 
                                                                                
                                                                                
                              最终输出: 完整课堂 (Stage)                          
                                                                                 
└─────────────────────────────────────────────────────────────────────────────────┘

Stage 1 详解:大纲生成

入口文件: app/api/generate/scene-outlines-stream/route.ts

// 请求体结构
interface OutlineRequest {
  requirements: UserRequirements;
  pdfText?: string;           // PDF 提取的文本
  pdfImages?: PdfImage[];     // PDF 提取的图片
  imageMapping?: ImageMapping; // 图片ID -> base64 URL
  researchContext?: string;   // 网络搜索结果
  agents?: AgentInfo[];       // 教师 Agent 信息
}

// 响应 (SSE 事件流)
// event: { type: 'outline', data: SceneOutline, index: number }
// event: { type: 'done', outlines: SceneOutline[] }
// event: { type: 'error', error: string }

Prompt 构建流程:

  1. 加载模板文件 templates/requirements-to-outlines/
  2. 变量插值:
    • {{requirement}} → 用户需求文本
    • {{language}} → 课程语言
    • {{pdfContent}} → PDF 文本内容
    • {{availableImages}} → 可用图片描述
    • {{researchContext}} → 网络搜索结果
  3. 处理图片:
    • Vision 模型:前 N 张图片直接传给模型
    • 非 Vision 模型:转换为文本描述

Stage 2 详解:内容生成

入口文件: app/api/generate/scene-content/route.ts

根据 outline.type 分发到不同生成器:

type模板输出类型
slideslide-content/GeneratedSlideContent
quizquiz-content/GeneratedQuizContent
interactiveinteractive-html/ + interactive-scientific-model/GeneratedInteractiveContent
pbl特殊处理GeneratedPBLContent

Stage 3 详解:动作生成

入口文件: app/api/generate/scene-actions/route.ts

生成的动作类型:

动作类型说明
speak语音讲解
highlight元素高亮
show显示元素
hide隐藏元素
pointer指针移动
animation触发动画

数据模型

核心类型定义

用户需求 (lib/types/generation.ts)

interface UserRequirements {
  requirement: string;        // 自由文本需求
  language: 'zh-CN' | 'en-US';
  userNickname?: string;      // 学生昵称(个性化)
  userBio?: string;           // 学生背景(个性化)
  webSearch?: boolean;        // 是否启用网络搜索
}

场景大纲 (lib/types/generation.ts)

interface SceneOutline {
  id: string;
  type: 'slide' | 'quiz' | 'interactive' | 'pbl';
  title: string;
  description: string;
  keyPoints: string[];
  teachingObjective?: string;
  estimatedDuration?: number;
  order: number;
  language?: 'zh-CN' | 'en-US';

  // 图片引用
  suggestedImageIds?: string[];

  // AI 生成媒体请求
  mediaGenerations?: MediaGenerationRequest[];

  // 类型特定配置
  quizConfig?: QuizConfig;
  interactiveConfig?: InteractiveConfig;
  pblConfig?: PBLConfig;
}

完整场景 (lib/types/stage.ts)

interface Scene {
  id: string;
  stageId: string;
  title: string;
  type: 'slide' | 'quiz' | 'interactive' | 'pbl';
  order: number;

  // 场景内容
  elements?: PPTElement[];      // 幻灯片元素
  questions?: QuizQuestion[];   // 测验问题
  html?: string;                // 互动 HTML

  // 教学动作
  actions: Action[];

  // 元数据
  duration?: number;
  thumbnail?: string;
}

教学动作 (lib/types/action.ts)

interface Action {
  id: string;
  type: ActionType;
  timing: number;           // 触发时间 (ms)
  duration?: number;        // 持续时间 (ms)
  targetId?: string;        // 目标元素 ID
  content?: string;         // 讲解文本
  params?: Record<string, unknown>;  // 额外参数
}

AI 服务集成

模型配置 (lib/ai/providers.ts)

export const PROVIDERS: Record<ProviderId, ProviderConfig> = {
  openai: {
    type: 'openai',
    name: 'OpenAI',
    models: [
      {
        id: 'gpt-4o',
        name: 'GPT-4o',
        contextWindow: 128000,
        outputWindow: 16384,
        capabilities: { vision: true },
      },
      // ...
    ],
  },
  anthropic: {
    type: 'anthropic',
    name: 'Anthropic',
    models: [
      {
        id: 'claude-sonnet-4-6-20250514',
        name: 'Claude Sonnet 4.6',
        contextWindow: 200000,
        outputWindow: 64000,
        capabilities: { vision: true, thinking: true },
      },
      // ...
    ],
  },
  // ...
};

Thinking 模式支持

系统支持为支持深度思考的模型启用 Thinking 模式:

// 调用时启用 thinking
await callLLM(params, 'source', undefined, {
  enabled: true,
  budgetTokens: 10240,
});

// 或全局禁用
LLM_THINKING_DISABLED=true

多模态输入

// Vision 模型直接传递图片
const result = await callLLM({
  model: languageModel,
  system: systemPrompt,
  messages: [{
    role: 'user',
    content: [
      { type: 'text', text: userPrompt },
      { type: 'image', image: base64Url },
    ],
  }],
});

API 接口

生成相关 API

接口方法说明
/api/generate/scene-outlines-streamPOSTSSE 流式生成大纲
/api/generate/scene-contentPOST生成单个场景内容
/api/generate/scene-actionsPOST生成教学动作
/api/generate/imagePOSTAI 图片生成
/api/generate/videoPOSTAI 视频生成
/api/generate/ttsPOST文本转语音

其他 API

接口方法说明
/api/parse-pdfPOST解析 PDF 文档
/api/web-searchPOST执行网络搜索
/api/chatPOST课堂对话
/api/classroomGET/POST课堂数据管理

请求头约定

生成 API 通过请求头传递配置:

x-provider-id: openai
x-model-id: gpt-4o
x-image-generation-enabled: true
x-video-generation-enabled: false

状态管理

useStageStore (lib/store/stage.ts)

管理课堂核心状态:

interface StageState {
  // 课堂信息
  stage: Stage | null;

  // 场景列表
  scenes: Scene[];
  currentSceneId: string | null;

  // 生成状态
  generatingOutlines: SceneOutline[];
  outlines: SceneOutline[];
  generationStatus: 'idle' | 'generating' | 'paused' | 'completed' | 'error';

  // 操作方法
  setStage: (stage: Stage) => void;
  addScene: (scene: Scene) => void;
  updateScene: (sceneId: string, updates: Partial<Scene>) => void;
  // ...
}

useSettingsStore (lib/store/settings.ts)

管理用户配置:

interface SettingsState {
  // 模型配置
  providerId: ProviderId;
  modelId: string;
  providersConfig: ProvidersConfig;

  // 功能配置
  pdfProviderId: PDFProviderId;
  webSearchProviderId: WebSearchProviderId;

  // 操作方法
  setModel: (providerId: ProviderId, modelId: string) => void;
  // ...
}

数据持久化

IndexedDB Schema (lib/utils/database.ts)

// 使用 Dexie ORM
const db = new Dexie('OpenMAIC');

db.version(1).stores({
  // 课堂数据
  stages: 'id, createdAt, updatedAt',
  stageScenes: 'stageId, sceneId',
  stageOutlines: 'stageId',

  // 媒体缓存
  pdfImages: 'id, sessionId',
  generatedImages: 'id, stageId',
  generatedVideos: 'id, stageId',

  // 用户配置
  settings: 'key',
});

存储策略

数据类型存储位置生命周期
用户配置LocalStorage持久
课堂数据IndexedDB持久
PDF 图片IndexedDB会话级
生成缓存IndexedDB按课堂

扩展开发指南

添加新的场景类型

  1. lib/types/generation.ts 添加类型定义
  2. lib/generation/prompts/templates/ 创建新的 prompt 模板
  3. lib/generation/scene-generator.ts 添加生成逻辑
  4. components/scene-renderers/ 创建渲染组件

添加新的 LLM 提供商

  1. lib/ai/providers.ts 添加提供商配置
  2. lib/types/provider.ts 添加类型定义
  3. 测试 callLLM / streamLLM 兼容性

自定义 Prompt 模板

模板支持变量插值和片段复用:

<!-- templates/custom/system.md -->
# Custom Generator

{{snippet:json-format}}

## Variables
- Topic: {{topic}}
- Language: {{language}}
import { buildPrompt, PROMPT_IDS } from '@/lib/generation/prompts';

const prompts = buildPrompt('custom-generator', {
  topic: 'My Topic',
  language: 'zh-CN',
});

附录:关键文件索引

功能文件路径
首页入口app/page.tsx
课堂播放app/classroom/[id]/page.tsx
大纲生成 APIapp/api/generate/scene-outlines-stream/route.ts
内容生成 APIapp/api/generate/scene-content/route.ts
动作生成 APIapp/api/generate/scene-actions/route.ts
LLM 封装lib/ai/llm.ts
提供商配置lib/ai/providers.ts
大纲生成器lib/generation/outline-generator.ts
场景生成器lib/generation/scene-generator.ts
Prompt 加载器lib/generation/prompts/loader.ts
类型定义lib/types/generation.ts, lib/types/stage.ts
状态管理lib/store/stage.ts, lib/store/settings.ts
数据库lib/utils/database.ts