AI 应用开发与项目实战学习笔记
适合目标:8 小时内建立 AI 应用开发全景图,覆盖 LLM、向量数据库、SSE 流式输出、TTS、ASR、Skills、结构化输出、RAG、项目实战与高频面试题。
学习重点:不是只会调 API,而是能把模型、检索、工具调用、语音能力、前端渲染和业务工作流串成一个完整应用。
学习原则:先理解链路,再学单点;先掌握“为什么这样设计”,再记接口;先会做 MVP,再谈大而全。
说明:你提到的
soe我先按SSE / 流式输出来整理。如果你原本指的是别的缩写,我后面可以再单独补一节。
目录
- 学习总览
- AI 应用开发全景图
- LLM 集成核心
- Embedding 与向量数据库
- SSE 流式输出、Realtime、TTS、ASR
- Skills、Tool Calling 与工作流设计
- 项目实战:AI 生成 LeaferJS 课件 JSON
- 技术选型与模块拆分
- 高频面试题
- 更好记的学习方法
- 8 小时学习节奏建议
- 一页速记总结
- 背诵口诀
1. 学习总览
1.1 AI 应用开发到底在学什么
很多人学 AI 应用时,容易停留在这一步:
会发一个 prompt,拿回一段文本。
但真实项目里,AI 应用开发远不止这样,它要解决的是:
- 如何让模型稳定理解用户需求
- 如何给模型补充业务上下文
- 如何让模型调用工具而不是只会“说”
- 如何把输出变成程序可直接消费的数据
- 如何处理流式、语音、检索、缓存、权限、成本和监控
所以,AI 应用开发的本质不是“接一下模型”,而是:
把模型变成系统中的一个智能节点,并与检索、工具、前端、数据库、语音能力一起组成一条完整业务链路。
1.2 你可以把 AI 应用看成什么
把 AI 应用压缩成一句话:
输入 -> 理解 -> 补充上下文 -> 决策 -> 调工具 -> 结构化输出 -> 渲染/执行 -> 反馈
也就是说,一次 AI 交互往往不是单轮文本生成,而是一条流水线:
- 用户输入文本、语音或图片
- 系统做上下文拼装
- 模型判断要不要查资料、调工具、走工作流
- 模型返回结构化结果
- 程序把结果渲染成页面、JSON、音频或业务动作
1.3 这份笔记的主线
主线 1:LLM 解决“理解、生成、决策”
- 理解用户意图
- 生成文本或结构化内容
- 决定是否调用工具
主线 2:向量数据库解决“找上下文”
- 给模型补知识
- 做相似内容召回
- 让模型不只依赖参数记忆
主线 3:SSE / Realtime / TTS / ASR 解决“交互体验”
- 让回答边生成边展示
- 让语音输入输出更自然
- 让 AI 应用从“静态问答”升级成“实时交互”
主线 4:Skills 解决“模型如何真正做事”
- 查询知识
- 生成组件
- 调用业务能力
- 写入数据库或渲染数据
主线 5:项目实战解决“如何把这些能力组织成产品”
- 数据结构怎么设计
- 后端链路怎么组织
- 前端怎么渲染
- 如何保证生成结果稳定
1.4 核心记忆主线
把 AI 应用开发记成一句话:
模型负责思考,检索负责补知识,Skills 负责执行,结构化输出负责落地,前端负责呈现。
再压缩成五个词:
模型、检索、工具、结构、渲染
2. AI 应用开发全景图
2.1 一个完整 AI 应用通常由哪些模块组成
| 模块 | 作用 | 典型输入输出 |
|---|---|---|
| LLM | 理解、生成、决策 | 文本输入 -> 文本/结构化输出 |
| Embedding | 把文本变向量 | 文本 -> 向量 |
| 向量数据库 | 相似检索 | 向量 -> TopK 相关内容 |
| RAG | 检索增强生成 | 用户问题 + 召回文档 -> 更可靠答案 |
| SSE / Realtime | 流式展示、实时交互 | 增量 token / 音频帧 |
| TTS | 文本转语音 | 文本 -> 音频 |
| ASR | 语音转文本 | 音频 -> 文本 |
| Skills / Tools | 让模型调用业务能力 | 模型意图 -> 程序动作 |
| 结构化输出 | 让结果可编程 | prompt -> JSON / Schema |
| 前端渲染 | 页面、图形、课件展示 | JSON -> UI / Canvas / LeaferJS |
2.2 AI 应用和普通 Web 应用最大的区别
普通 Web 应用更偏:
固定逻辑 + 固定界面 + 固定接口
AI 应用更偏:
不确定输入 + 模型推理 + 检索上下文 + 工具协作 + 结果校验
也就是说,AI 应用会新增这些挑战:
- 输出不稳定
- 成本与延迟波动
- prompt 质量直接影响产品效果
- 工具调用和状态管理更复杂
- 需要评估、回放、追踪和观测
2.3 一个通用 AI 应用架构
你可以先记住这个通用架构:
Client -> API Server -> Prompt Builder -> Retriever -> Model -> Tool Router -> Validator -> Renderer / Business Action
拆开理解:
- Client:输入问题、播放流式结果、展示界面
- API Server:鉴权、限流、组织上下文
- Prompt Builder:构造系统指令、上下文、示例
- Retriever:从向量库召回知识
- Model:进行生成或决策
- Tool Router:根据模型意图调用 Skills
- Validator:检查 JSON 合法性和业务约束
- Renderer / Business Action:渲染结果或执行操作
2.4 面试里怎么概括 AI 应用开发
标准答法可以这样说:
AI 应用开发本质上是在传统应用架构中加入模型推理、上下文检索、工具调用和结构化输出能力,让系统从固定逻辑扩展为“可理解、可生成、可决策、可执行”的应用。
3. LLM 集成核心
这一部分是 AI 应用开发的中心。你不需要先背所有模型名,而要先理解:模型在系统里扮演什么角色,以及该如何稳定调用它。
3.1 LLM 在项目里通常承担什么角色
LLM 最常见的三类角色:
生成者:写文案、写总结、写 JSON理解者:做分类、提取字段、识别意图调度者:判断要不要调用工具、选哪个工具、按什么顺序执行
所以,模型并不只是“回答问题”,它还可以是:
一个语言驱动的决策层
3.2 新项目里优先记哪类 API
学习时你可以先把 OpenAI 相关能力分成三层:
| 能力 | 适合场景 | 记忆重点 |
|---|---|---|
| Responses API | 大多数文本、多模态、结构化、工具调用场景 | 新项目优先记它 |
| Realtime API | 低延迟语音对话、双向实时流 | 语音应用重点 |
| Chat Completions | 旧项目兼容或历史代码 | 了解即可,不作为主线 |
当前官方文档的主线已经围绕 Responses API / Streaming / Realtime / Structured Outputs / Function Calling 组织,所以学习新项目时优先围绕这条主线建立认知。
学习阶段怎么记模型选择
为了方便记忆,你可以先按任务类型记:
- 复杂推理、复杂生成:优先高能力主模型
- 日常文本生成、结构化输出:优先更轻量的通用模型
- 向量检索:使用专门的 embedding 模型
- TTS:使用语音合成模型
- ASR:使用语音转写模型
学习时不用一开始就死背所有模型名,但要形成这个意识:
文本、向量、语音,不一定是同一个模型。
前后端安全边界怎么记
这一点非常重要:
- 正式 API Key 只应该放在服务端
- 浏览器不要直接持有标准密钥
- 实时语音场景通常使用后端下发的临时令牌
- 所有调用最好经过你自己的业务后端做鉴权、限流和审计
一句话记忆:
模型能力可以在前端展示,但密钥和真实调用链路应由后端控制。
3.3 一次最基本的 LLM 调用长什么样
示例:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const response = await client.responses.create({
model: "gpt-5.4-mini",
input: "用一句话解释什么是向量数据库",
});
console.log(response.output_text);
看这段代码时,你脑子里要立刻有这个模型:
client:和平台通信model:选哪个模型input:给模型的输入response.output_text:最终文本结果
3.4 LLM 调用最常见的四种模式
模式 1:普通文本生成
适合:
- 问答
- 总结
- 改写
- 文案生成
模式 2:结构化输出
适合:
- 生成 JSON
- 信息抽取
- 组件配置
- 表单字段解析
模式 3:工具调用
适合:
- 查询知识库
- 调用数据库
- 生成页面组件
- 执行业务动作
模式 4:多轮状态延续
适合:
- 对话助手
- 复杂任务拆解
- 长链路生成
3.5 为什么“结构化输出”比“让模型自己写 JSON”更可靠
很多初学者会这样写:
请返回一个 JSON,不要有多余文字。
这能用,但稳定性不够,因为:
- 模型可能多说解释
- 字段名可能漂移
- 数组和对象层级可能不一致
- 一旦输出不合法,程序就崩
更好的做法是:
使用 Structured Outputs + JSON Schema
这样做的价值是:
- 限定字段结构
- 减少自由发挥
- 程序更容易直接消费
- 更适合组件生成、表单抽取、工作流输入
3.6 一个结构化输出示例
const response = await client.responses.create({
model: "gpt-5.4-mini",
input: "生成一个标题页组件配置",
text: {
format: {
type: "json_schema",
name: "slide_component",
schema: {
type: "object",
properties: {
type: { type: "string" },
title: { type: "string" },
subtitle: { type: "string" },
},
required: ["type", "title"],
additionalProperties: false,
},
},
},
});
这里最关键的记忆点是:
type: "json_schema":告诉模型按 Schema 输出required:哪些字段必须有additionalProperties: false:禁止乱加字段
3.7 工具调用是什么
工具调用可以理解成:
模型不只是“说应该怎么做”,而是告诉系统“请帮我调用这个工具去做”。
例如:
- 用户说“生成一页课程封面”
- 模型判断应该调用
create_title_slide - 系统执行这个 skill
- 返回组件 JSON
- 模型再基于结果继续组织最终输出
3.8 Tool Calling 的本质
本质上,Tool Calling 解决的是:
模型只负责决策,真正执行交给程序。
这是非常重要的架构思想,因为:
- 模型擅长理解和规划
- 程序擅长确定性执行
- 把二者分开,系统更稳定
3.9 tool_choice 要解决什么问题
工具很多时,你要考虑:
- 让模型自己决定是否调用
- 强制调用某个工具
- 禁止调用工具,只做文本返回
也就是说,tool_choice 控制的是:
模型在这次请求里能不能调工具,以及调哪个工具。
3.10 多轮状态怎么记
多轮对话或长流程任务里,要理解一个关键点:
模型本身不是持久数据库,状态要靠应用层管理。
常见做法:
- 前端保存会话 ID
- 后端保存对话记录、业务状态、用户资料
- 模型请求时附带历史上下文
- 或使用
previous_response_id继续串联前后轮次
3.11 提示词不是“文案”,而是“接口设计”
很多人把 Prompt 理解成“写几句话”。
更准确的理解是:
Prompt 是给模型设计输入协议。
一个好的 Prompt,应该包含:
- 角色和任务
- 输入变量
- 输出格式
- 约束条件
- 示例
- 失败时的兜底策略
3.12 LLM 集成的常见错误
- 让前端直接持有正式 API Key
- 把所有业务逻辑都塞到 prompt 里
- 不做结构化校验
- 不做重试和超时控制
- 不记录 prompt、响应和工具调用链路
- 让模型直接生成最终生产数据而不做二次验证
3.13 一句话压缩 LLM 集成
模型负责理解与决策,结构化输出负责可编程,工具调用负责可执行,应用层负责状态和稳定性。
4. Embedding 与向量数据库
这部分是 RAG 的基础。只要你理解“文本为什么能被拿去做相似搜索”,向量数据库就不会神秘。
4.1 什么是 Embedding
Embedding 可以理解成:
把文本、图片、音频等非结构化内容,映射成一串数字向量。
这串向量不是给人看的,而是给机器做“相似度计算”的。
4.2 为什么需要 Embedding
因为模型和数据库要做这件事:
不是找字面一样,而是找语义接近。
例如:
- “二分查找”
- “折半查找”
虽然词不完全一样,但语义接近,向量空间里它们通常也会比较近。
4.3 Embedding 的基本调用
const embedding = await client.embeddings.create({
model: "text-embedding-3-small",
input: "二分查找适用于有序数组",
});
const vector = embedding.data[0].embedding;
记忆点:
- 文本进来
- 向量出去
- 向量会被存进向量数据库
4.4 向量数据库是做什么的
向量数据库主要解决三件事:
- 存向量
- 按相似度检索向量
- 配合 metadata 过滤
它不是普通关系数据库的替代品,而是:
专门为相似搜索和语义检索准备的检索层。
4.5 一个完整 RAG 链路
RAG 可以记成:
切分 -> 向量化 -> 入库 -> 查询向量化 -> 相似检索 -> 拼接上下文 -> 再问模型
展开来看:
- 把文档切成 chunk
- 给每个 chunk 生成 embedding
- 写入向量数据库
- 用户提问时,对问题也做 embedding
- 去库里找最相似的 TopK chunk
- 把这些 chunk 拼到 prompt 里
- 再让模型回答
4.6 为什么不能把所有知识直接塞给模型
原因很简单:
- 上下文窗口有限
- 成本会很高
- 长文本噪声多
- 每次都全塞,效率差
所以更合理的做法是:
按需召回,而不是全量灌输
4.7 向量数据库常见字段
一般一条数据会包含:
idvectorpayload / metadatasourcechunk_textdoc_idchunk_index
例如:
{
"id": "chunk_1024",
"vector": [0.12, -0.33, 0.88],
"metadata": {
"docId": "course_js_01",
"chapter": "闭包",
"level": "beginner",
"type": "knowledge"
},
"text": "闭包是函数与其词法环境的组合"
}
4.8 切分策略很重要
RAG 效果不只是模型决定的,chunk 切分非常关键。
常见切分方式:
- 固定长度切分
- 按段落切分
- 按标题层级切分
- 语义切分
切分要注意:
- 不要太短,语义碎
- 不要太长,噪声大
- 要保留上下文连续性
- 可以适当 overlap
4.9 检索不是越多越好
很多人会误以为:
TopK 越大越全面
其实不是。TopK 太大时可能会:
- 引入噪声
- 稀释关键证据
- 提高 token 成本
- 降低回答聚焦度
所以 RAG 的重点不是“多”,而是:
召回准
4.10 metadata 过滤为什么重要
metadata 可以让检索更可控。
例如:
- 只查某个课程
- 只查某个学科
- 只查组件模板
- 只查某个用户的私人资料
这对 AI 课件项目尤其重要,因为你可能要把知识块、模板块、组件块分开检索。
4.11 RAG 和微调的区别
RAG
- 动态补充知识
- 更新知识不需要重新训练
- 适合文档问答、知识库、模板召回
微调
- 调整模型风格或任务行为
- 更适合稳定格式、专业语气、固定任务
- 更新成本更高
一句话区分:
RAG 补知识,微调改习惯。
4.12 向量数据库选型怎么记
你可以先用场景记,而不是死背产品:
| 类型 | 适合场景 | 记忆方式 |
|---|---|---|
pgvector |
你本来就用 Postgres,想快速把向量和业务数据放一起 | 关系库一体化 |
| Qdrant | 检索能力清晰、工程接入友好、适合应用层快速落地 | 独立向量检索服务 |
| Milvus | 大规模、高性能、分布式向量检索场景 | 重型高规模方案 |
学习阶段不用纠结“哪家绝对最好”,先记:
轻量一体化用 pgvector,独立检索服务看 Qdrant,超大规模看 Milvus。
4.13 AI 课件项目里向量数据库能做什么
在你说的课件生成场景里,向量数据库非常有用:
- 检索知识库内容,生成更准确课件
- 检索历史优质课件结构
- 检索组件模板和布局示例
- 检索教师个人风格和常用措辞
- 检索某类题型或图示模板
4.14 一句话压缩向量数据库
Embedding 负责把内容变成可比较的向量,向量数据库负责把相似内容快速找回来。
5. SSE 流式输出、Realtime、TTS、ASR
这一部分决定用户体验。一个 AI 产品,如果只能等几十秒再一次性吐结果,体验会非常差;如果能边生成边展示、边说边听,产品感会立刻提升。
5.1 为什么需要流式输出
一次完整生成可能会比较慢,特别是:
- 回答很长
- 需要检索和工具调用
- 要生成多页课件
如果用户一直空等,会感觉:
系统卡了
所以流式输出的核心价值是:
- 更快感知到结果
- 更好的交互体验
- 方便分段渲染
- 便于展示生成过程
5.2 SSE 是什么
SSE 即 Server-Sent Events,可以理解成:
服务器不断把增量内容往客户端推。
在 AI 文本生成里,它很适合:
- token 流式展示
- 进度消息推送
- 生成步骤回显
5.3 一个基本流式示例
const stream = await client.responses.create({
model: "gpt-5.4-mini",
input: "请分三点解释 RAG",
stream: true,
});
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta);
}
}
记忆点:
stream: true- 后端拿到一连串事件
- 前端按事件增量渲染
5.4 SSE 和 WebSocket 的区别
| 技术 | 通信方向 | 适合场景 |
|---|---|---|
| SSE | 服务器 -> 客户端单向推送 | 文本流式输出、状态消息 |
| WebSocket | 双向通信 | 实时协作、低延迟语音、实时控制 |
一句话区分:
文本流式优先 SSE,实时双向交互看 WebSocket / Realtime。
5.5 Realtime API 适合什么
Realtime 更适合:
- 低延迟语音对话
- 连续语音输入输出
- 实时中断、打断、继续说
- 语音 Agent
学习时可以先记:
- 浏览器端实时语音更适合 WebRTC
- 服务端中间层更适合 WebSocket
5.6 TTS 是什么
TTS 即 Text To Speech,文本转语音。
它在 AI 应用里常见用途:
- 把回答读出来
- 给课件生成讲解音频
- 做 AI 老师、AI 主播、AI 导航助手
5.7 TTS 的关键关注点
- 音色是否自然
- 延迟是否可接受
- 语速、情感、停顿是否可控
- 是否支持流式音频
- 成本和并发是否可控
5.8 一个基础 TTS 示例
const speech = await client.audio.speech.create({
model: "gpt-4o-mini-tts",
voice: "coral",
input: "欢迎来到二分查找课程",
instructions: "语速平稳,适合教学解说",
});
在课件场景里,TTS 可以用于:
- 每页自动生成讲解音频
- 一键播放当前页内容
- 导出音频版课程
5.9 ASR 是什么
ASR 即 Automatic Speech Recognition,自动语音识别。
也就是:
把用户说的话转成文字。
5.10 ASR 适合哪些场景
- 语音输入 prompt
- 语音编辑课件
- 会议纪要转写
- 教师口述生成课件
5.11 一个基础 ASR 示例
import fs from "fs";
const transcription = await client.audio.transcriptions.create({
file: fs.createReadStream("teacher.mp3"),
model: "gpt-4o-mini-transcribe",
response_format: "text",
});
console.log(transcription);
5.12 TTS 和 ASR 的关系怎么记
很简单:
- TTS:
字 -> 声 - ASR:
声 -> 字
再压缩成一句:
TTS 负责说,ASR 负责听。
5.13 语音 AI 应用的一条常见链路
用户说话 -> ASR 转文本 -> LLM 理解与决策 -> Tool / RAG -> 文本结果 -> TTS 播放
如果是更实时的模式,则会演化成:
语音流输入 -> Realtime -> 增量理解 -> 增量输出 -> 语音流播放
5.14 流式处理中常见坑
- 前端把流式片段当完整 JSON 解析
- 流断开后没有重试和恢复机制
- 没有区分“中间态”和“最终完成态”
- 后端不做 flush,前端感知不到增量
- 一边流式展示,一边又试图直接写最终数据库,导致状态错乱
5.15 课件项目里该如何用流式
推荐这样拆:
规划阶段:先流式展示“正在规划课件”组件生成阶段:逐页、逐组件返回状态渲染阶段:每页生成完立即预览音频阶段:每页单独生成 TTS
这样用户的感受会很好,因为不是“一直等”,而是“不断看到进度和结果”。
5.16 一句话压缩语音与流式
SSE 负责边生成边看,Realtime 负责边说边听,TTS 负责输出声音,ASR 负责接收声音。
6. Skills、Tool Calling 与工作流设计
这部分是 AI 应用从“会说话”走向“会做事”的关键。
6.1 这里的 Skills 应该怎么理解
在这份笔记里,Skills 不是泛指“能力”,而是:
被模型调用的、具有明确输入输出的业务工具或组件工厂。
比如:
search_course_knowledgecreate_title_slidecreate_timeline_componentgenerate_teacher_voiceoversave_courseware
6.2 为什么要设计 Skills,而不是全让模型自由生成
因为纯 prompt 方式有这些问题:
- 输出不稳定
- 不容易复用
- 不方便校验
- 不好观察和追踪
- 很难沉淀业务能力
而 Skills 的优势是:
- 输入输出可定义
- 逻辑可复用
- 可监控、可测试
- 容易做版本管理
- 更适合复杂项目长期维护
6.3 Skill 的设计原则
原则 1:单一职责
一个 Skill 最好只干一类事。
例如:
create_text_blockcreate_quiz_block
比一个超大 generate_anything 更稳定。
原则 2:输入明确
Skill 的参数要清晰:
- 字段名稳定
- 类型稳定
- 必填项明确
原则 3:输出确定
Skill 返回结果最好是:
- 稳定 JSON
- 可验证结构
- 不带多余文案
原则 4:可观测
你要知道:
- 谁调用了它
- 传了什么参数
- 调用成功没有
- 延迟多少
- 返回什么结果
6.4 Tool Calling 和 Workflow 的关系
Tool Calling 解决的是:
一次请求里模型如何调用工具
Workflow 解决的是:
多步任务如何按顺序组织
例如生成课件时:
- 先生成目录
- 再生成每一页规划
- 再生成每一页组件
- 再验证 JSON
- 再渲染和存储
这就是一个工作流,而不是一次单纯的工具调用。
6.5 为什么复杂 AI 项目一定要“拆步骤”
因为一步到位生成整个复杂产物,容易出现:
- token 太长
- 结构失控
- 局部错误拖垮整体
- 无法增量修复
更合理的设计是:
规划 -> 分页 -> 分组件 -> 校验 -> 编译 -> 渲染
6.6 Skills 的常见分层方式
你可以把 Skills 分成三层:
| 层级 | 作用 | 例子 |
|---|---|---|
| 数据技能 | 查数据、查文档、查模板 | search_docs, search_components |
| 生成技能 | 生成局部结构 | create_title_block, create_chart_block |
| 动作技能 | 触发业务动作 | save_project, publish_courseware |
6.7 一套适合课件项目的 Skills
你这个项目里,可以先设计这几个核心 Skills:
plan_coursewaresearch_knowledgesearch_layout_templatescreate_title_slidecreate_bullet_slidecreate_timeline_slidecreate_quiz_slidecreate_chart_componentvalidate_slide_schemacompile_to_leafer_jsongenerate_tts_voiceoversave_courseware
6.8 Skills 和组件库是什么关系
你可以这样理解:
- 组件库定义“有哪些组件”
- Skills 负责“按业务参数生成这些组件的 JSON”
也就是说:
组件库是积木,Skill 是搭积木的方法。
6.9 为什么最好让 Skills 产出“中间 DSL”,而不是直接产出最终渲染 JSON
这是项目里最重要的架构点之一。
如果让模型直接输出最终 LeaferJS JSON,会有几个风险:
- 字段太多,容易漂移
- 绝对坐标容易乱
- 主题样式难统一
- 不方便切换渲染引擎
- 难做自动修复
更好的做法是:
先产出业务中间 DSL,再由程序编译成 LeaferJS JSON
6.10 什么是中间 DSL
DSL 即领域专用结构。
例如你可以定义:
{
"slideType": "title",
"title": "二分查找",
"subtitle": "用有序数组快速定位目标值",
"theme": "light-edu",
"notes": "开场 15 秒解释应用场景"
}
这比直接生成一堆 x / y / width / fill / fontSize 更好控制。
6.11 为什么 DSL 更适合长期演进
因为它让系统层次更清楚:
- 模型只关心业务语义
- 编译器负责转成具体渲染格式
- 样式系统统一控制视觉
- 未来可以从 LeaferJS 切到别的引擎
6.12 一句话压缩 Skills
Skill 是被模型调用的业务工具;复杂项目里,Skill 最好生成中间 DSL,而不是直接生成最终渲染数据。
7. 项目实战:AI 生成 LeaferJS 课件 JSON
这一部分就是把前面所有知识串起来,做成一个真实项目。你提到的方向很适合拿来做作品集和面试项目,因为它同时覆盖了生成式 AI、结构化输出、前端渲染、组件化和工作流设计。
7.1 项目目标怎么定义
一句话目标:
用户通过自然语言描述教学主题,AI 自动生成课件结构、每页组件配置,并编译成可由 LeaferJS 渲染的 JSON 课件。
更完整一点可以是:
- 输入课程主题或教学需求
- AI 生成课件大纲
- AI 为每一页选择合适布局和组件
- Skills 生成每页组件 DSL
- 系统将 DSL 编译为 LeaferJS JSON
- 前端即时预览,可再编辑、重生成、配音
7.2 这个项目为什么有价值
因为它同时体现了:
- AI 内容生成
- 结构化输出
- Tool Calling / Skills
- 向量检索
- 前端图形渲染
- 语音输入输出
- 产品化工作流
面试官通常会觉得这是个“像真项目”的题目,而不是只会做聊天机器人。
7.3 最推荐的系统链路
推荐链路如下:
用户描述 -> 课件规划模型 -> 检索知识/模板 -> Slide Planner -> Skills 生成每页 DSL -> Schema 校验 -> Leafer Compiler -> 前端预览 -> 局部重生成 -> 保存 / 导出 / 配音
7.4 为什么不要一步让 AI 直接生成整份最终课件 JSON
因为这样做的风险非常大:
- 整体结构过长,容易截断
- 一页出错会污染整份结果
- 难以局部重做
- 样式不统一
- 坐标布局容易混乱
更合理的方案是:
- 先规划页级结构
- 再生成页内组件 DSL
- 再用编译器转成 LeaferJS JSON
7.5 一个推荐的分层架构
第 1 层:用户输入层
接收:
- 文本描述
- 语音描述
- 上传资料
- 课程模板选择
第 2 层:规划层
模型负责:
- 识别课程主题
- 判断适合几页
- 规划每页类型
- 决定哪些页需要图表、时间线、问答、总结
第 3 层:检索层
检索:
- 知识库
- 历史课件样例
- 布局模板
- 组件模板
- 教师个人风格
第 4 层:技能生成层
Skills 生成:
- 每页 DSL
- 每个组件参数
- 讲解词草稿
第 5 层:编译与校验层
负责:
- JSON Schema 校验
- 版式约束检查
- 编译成 LeaferJS JSON
- 修正越界布局
第 6 层:渲染与编辑层
负责:
- 用 LeaferJS 渲染页面
- 支持拖拽编辑
- 支持单页重生成
- 支持导出、播放、保存
7.6 你应该设计两套 JSON,而不是一套
这是整个项目最关键的设计。
第一套:业务 DSL
给模型和 Skills 用,表达“这一页是什么内容”。
第二套:渲染 JSON
给 LeaferJS 用,表达“这一页怎么画出来”。
这两个层次分开后,系统会非常清楚。
7.7 一份推荐的业务 DSL 结构
{
"coursewareId": "cw_binary_search_001",
"topic": "二分查找",
"theme": "light-edu",
"slides": [
{
"id": "slide_1",
"slideType": "title",
"title": "二分查找",
"subtitle": "在有序数组中快速定位目标值",
"notes": "开场介绍应用场景"
},
{
"id": "slide_2",
"slideType": "two-column",
"title": "核心思路",
"components": [
{
"componentType": "bulletList",
"items": [
"每次取中间值比较",
"缩小搜索区间",
"前提是数组有序"
]
},
{
"componentType": "codeBlock",
"language": "js",
"code": "while (left <= right) { ... }"
}
]
}
]
}
7.8 一份推荐的 LeaferJS 渲染 JSON 结构
下面这份更偏“最终渲染层”:
{
"tag": "Leafer",
"width": 1280,
"height": 720,
"children": [
{
"tag": "Rect",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"fill": "#F8FAFC"
},
{
"tag": "Text",
"x": 80,
"y": 70,
"width": 1120,
"text": "二分查找",
"fontSize": 40,
"fontWeight": "bold",
"fill": "#111827"
},
{
"tag": "Text",
"x": 80,
"y": 130,
"width": 1120,
"text": "在有序数组中快速定位目标值",
"fontSize": 22,
"fill": "#4B5563"
}
]
}
学习时要记住:
LLM 更适合生成 DSL,程序更适合生成最终坐标和样式。
7.9 LeaferJS 这类渲染层要注意什么
根据官方 JSON 文档,App 元素本身不直接导入导出,通常导出 app.tree 的数据,再用 app.tree.set(...) 导入。
这说明一个很重要的工程点:
前端渲染层要有自己的导入导出适配,不要把模型输出直接硬塞给渲染实例。
7.10 项目里最重要的几个数据模型
数据模型 1:Courseware
表示整份课件。
常见字段:
idtopicthemeslidesauthorIdstatus
数据模型 2:Slide
表示单页。
常见字段:
idslideTypetitlecomponentsnotesvoiceoverStatus
数据模型 3:ComponentSpec
表示一页里的某个组件。
常见字段:
componentTypepropslayoutSlotpriority
数据模型 4:Template
表示课件模板或布局模板。
常见字段:
templateIdnamethemeTokensallowedComponentssampleDsl
7.11 推荐的生成流程
步骤 1:课件规划
模型先输出:
- 总页数
- 每页标题
- 每页类型
- 每页核心内容
这一步只做“大纲规划”,不要直接出最终组件。
步骤 2:知识与模板检索
根据每页主题去检索:
- 课程知识块
- 相似课件页
- 布局模板
- 对应组件示例
步骤 3:Skills 生成每页 DSL
例如:
create_title_slidecreate_definition_slidecreate_code_example_slidecreate_quiz_slide
步骤 4:Schema 校验
检查:
- 字段是否齐全
- 类型是否正确
- 组件是否在白名单
- 文本长度是否超限
步骤 5:布局编译
把 DSL 编译成:
- 组件坐标
- 字体样式
- 颜色主题
- 页级背景
最终产出 LeaferJS JSON。
步骤 6:渲染与反馈
前端渲染后可以:
- 让用户局部修改
- 局部重生成单个组件
- 对单页重新配图或配音
7.12 为什么“局部重生成”很重要
用户常常不是整份课件都不满意,而是:
- 这页标题不好
- 这块图表不合适
- 这页太密了
- 这页讲解词太长
如果没有局部重生成,体验会很差。
所以你要设计:
- 重新生成单页
- 重新生成单个组件
- 重新生成配音文本
7.13 一组非常实用的 Skills 设计
Skill 1:plan_courseware
输入:
- 主题
- 目标用户
- 课时长度
- 风格要求
输出:
- 页数
- 每页主题
- 每页 slideType
Skill 2:create_slide_components
输入:
slideType- 本页内容
- 布局模板
- 主题样式
输出:
components[]
Skill 3:search_slide_examples
输入:
- 当前页主题
- 组件类型
输出:
- 相似课件案例
- 高质量布局样例
Skill 4:compile_to_leafer_json
输入:
- 页级 DSL
- 主题 token
- 画布尺寸
输出:
- LeaferJS JSON
Skill 5:generate_voiceover
输入:
- 当前页标题
- 组件内容
- 讲解风格
输出:
- 解说词
- TTS 音频链接
7.14 提示词设计该怎么做
你这个项目里,Prompt 最好分层写。
规划 Prompt
负责输出课件目录和页级意图。
组件生成 Prompt
负责输出组件 DSL。
讲解词 Prompt
负责输出配音文案。
修复 Prompt
负责修复校验失败的 JSON。
这样做的好处是:
- 每一步目标更单一
- 更方便排查问题
- 更方便做 A/B 测试
7.15 为什么一定要做 JSON 校验和自动修复
因为模型输出不可能 100% 稳定。
所以实际项目里至少要做:
- JSON Schema 校验
- 字段默认值填充
- 超长文本裁剪
- 坐标越界修复
- 不合法组件替换为兜底组件
这一步很关键,因为它决定:
AI 输出能不能真正进入生产链路
7.16 最佳实践:模型不要直接负责版式坐标
让模型直接生成精确坐标,一般不是个好主意。
因为模型更擅长:
- 语义组织
- 层级规划
- 内容选择
程序更擅长:
- 计算布局
- 保证边距
- 控制字号
- 保证响应式和统一视觉
所以:
模型负责“放什么”,布局引擎负责“放哪里”。
7.17 项目里向量数据库怎么用最值
你这个项目中,向量数据库最值得存这几类内容:
- 教材知识 chunk
- 历史优秀课件页
- 组件模板描述
- 教师个人风格样例
- 常见图示讲法
推荐检索策略:
- 先按
courseId / subject / grade过滤 - 再做相似检索
- 召回后做轻量 rerank
7.18 加入 TTS / ASR 后,项目会更像产品
你可以增加这几个高级功能:
- 教师口述主题,ASR 转文本生成课件
- 每页自动生成讲解音频
- AI 老师朗读当前页
- 语音指令“把第二页改成时间线布局”
7.19 一个适合面试展示的完整故事线
你可以这样讲你的项目:
这是一个 AI 课件生成系统。用户输入课程描述后,系统先通过模型规划页级结构,再结合向量检索召回教材知识和布局模板,随后由一组 Skills 生成每页组件 DSL,经过 Schema 校验和布局编译后产出 LeaferJS 可渲染 JSON。前端支持逐页预览、局部重生成和 TTS 配音,后端则负责流式输出、检索、工具编排和结果持久化。
如果你能把这段话讲顺,面试里会很加分。
7.20 一句话压缩项目方案
不要让模型一步吐最终课件,而要让模型规划、让 Skills 生成 DSL、让编译器生成 LeaferJS JSON。
8. 技术选型与模块拆分
8.1 一个适合 MVP 的技术栈
前端
- React / Next.js 或 React + Vite
- LeaferJS 负责课件渲染与编辑
- Zustand / Redux 管理编辑状态
- EventSource 或 fetch stream 处理流式输出
后端
- Node.js + NestJS / Express
- OpenAI SDK
- SSE 接口和任务编排层
- JSON Schema 校验层
数据层
- PostgreSQL 存业务数据
pgvector或独立向量库存 embedding- Redis 做缓存、队列和会话状态
- OSS / S3 存音频、图片、导出文件
8.2 一个适合 MVP 的接口设计
POST /api/courseware/planPOST /api/courseware/generate-slidePOST /api/courseware/compileGET /api/courseware/stream/:taskIdPOST /api/courseware/asrPOST /api/courseware/ttsPOST /api/courseware/regenerate-component
8.3 前后端职责怎么分
前端负责
- 输入描述
- 展示生成进度
- 预览 LeaferJS 画面
- 局部编辑和重生成
- 音频播放和录音
后端负责
- 鉴权
- 调模型
- 检索知识
- 执行 Skills
- 校验 JSON
- 存储结果
8.4 推荐的版本迭代路线
V1:最小可用版
只做:
- 文本输入
- 生成课件大纲
- 生成 3-4 种固定 slideType
- 编译成 LeaferJS JSON
- 前端预览
V2:增强版
增加:
- 流式生成
- 向量检索
- 单页重生成
- 组件局部编辑
V3:产品版
增加:
- TTS 配音
- ASR 语音输入
- 教师风格记忆
- 课件模板市场
8.5 成本与性能要怎么考虑
AI 项目里一定要考虑:
- 长 prompt 成本
- 检索次数
- 多步工作流调用次数
- TTS / ASR 额外成本
- 流式连接占用
常见优化:
- 先规划再分页生成,避免一次超长输出
- 模板复用,减少重复生成
- 缓存 embedding 和检索结果
- 把高频稳定内容做成规则或模板,不要每次都问模型
8.6 评估指标应该怎么定
项目落地后,至少看这些指标:
- 课件首版生成成功率
- JSON 校验通过率
- 首次渲染成功率
- 平均生成时长
- 单页重生成时长
- 用户修改次数
- TTS 生成成功率
8.7 一句话压缩技术选型
前端负责体验和渲染,后端负责模型、检索、技能编排和校验,数据层负责知识、状态和资源持久化。
9. 高频面试题
9.1 什么是 AI 应用开发
可以答:
AI 应用开发是在传统应用架构中加入模型推理、检索增强、工具调用和结构化输出能力,让系统能够理解用户意图、生成内容并触发业务动作。
9.2 LLM 集成时,为什么不能只靠 Prompt
可以答:
因为纯 Prompt 方式在复杂项目里稳定性不足,通常还需要结构化输出、工具调用、状态管理和结果校验来保证系统可控。
9.3 Structured Outputs 为什么比“请返回 JSON”更好
可以答:
因为 Structured Outputs 能约束字段结构并提高 schema 一致性,程序可以更稳定地直接消费结果,而不是赌模型每次都手写出合法 JSON。
9.4 RAG 是什么
可以答:
RAG 是检索增强生成,先从外部知识库召回相关内容,再把这些内容拼进上下文中辅助模型回答,从而提升准确率和时效性。
9.5 向量数据库和关系数据库有什么区别
可以答:
关系数据库更擅长精确查询和事务处理,向量数据库更擅长基于 embedding 做相似搜索和语义检索,两者通常是协作关系而不是替代关系。
9.6 为什么要做 chunk 切分
可以答:
因为原始文档通常太长,必须切成更适合检索的语义片段,切分质量会直接影响 RAG 的召回效果。
9.7 SSE 和 WebSocket 的区别是什么
可以答:
SSE 适合服务端单向推送,比如文本流式输出;WebSocket 适合双向实时通信,比如低延迟语音交互和实时控制。
9.8 Tool Calling 的价值是什么
可以答:
它让模型从只会生成文本,升级为能决定并触发程序动作。模型负责决策,程序负责确定性执行。
9.9 Skills 应该怎么设计
可以答:
Skills 最好单一职责、输入输出清晰、结构稳定、可观测,并尽量生成中间 DSL 而不是直接生成最终渲染层数据。
9.10 为什么课件项目里要设计中间 DSL
可以答:
因为 DSL 更贴近业务语义,更稳定、更容易校验,也方便统一主题样式和后续切换渲染引擎。最终坐标和样式更适合由程序编译生成。
9.11 为什么不能直接让模型生成最终 LeaferJS JSON
可以答:
因为最终渲染 JSON 结构冗长、字段多、对布局细节要求高,模型直接生成容易漂移和越界。更稳的方案是模型生成 DSL,程序做布局编译。
9.12 AI 项目里如何控制成本
可以答:
- 拆步骤,减少一次超长生成
- 缓存 embedding 和检索结果
- 模板化固定内容
- 对高频简单任务用更轻量模型
- 对失败流程做局部重试,而不是整链路重跑
9.13 TTS 和 ASR 在项目里分别有什么作用
可以答:
TTS 负责把文本结果转成语音输出,ASR 负责把用户语音转成文本输入,它们配合后可以形成完整的语音交互链路。
9.14 如果让你设计一个 AI 课件生成系统,你会怎么做
推荐答法:
- 先定义课件业务 DSL
- 设计页级规划模型
- 接入知识库和模板检索
- 用 Skills 生成每页组件结构
- 做 JSON Schema 校验与自动修复
- 编译为 LeaferJS JSON 渲染
- 增加单页重生成、TTS 和 ASR 能力
10. 更好记的学习方法
10.1 用一条链路记住 AI 应用
把所有内容压成这条链:
输入 -> 检索 -> 推理 -> 调工具 -> 输出结构 -> 渲染 -> 反馈
10.2 用“谁负责什么”来记
- LLM:理解与决策
- Embedding:把内容变向量
- 向量库:找相似内容
- Skills:执行工具能力
- Schema:约束输出结构
- LeaferJS:渲染画面
- TTS:说出来
- ASR:听进来
10.3 用对比法记忆
对比 1:RAG vs 微调
- RAG:补知识
- 微调:改风格和习惯
对比 2:SSE vs WebSocket
- SSE:单向流
- WebSocket:双向实时
对比 3:DSL vs 最终渲染 JSON
- DSL:业务语义层
- 渲染 JSON:画布执行层
对比 4:Prompt vs Skills
- Prompt:告诉模型怎么想
- Skills:让模型知道怎么做
10.4 用口诀记
模型会想,工具会做RAG 补知识,微调改习惯TTS 负责说,ASR 负责听SSE 先看结果,Realtime 先做交互模型出 DSL,程序做布局
10.5 最有效的记忆方式是输出
你至少要做到:
- 能口头讲清 AI 应用链路
- 能画出课件项目架构图
- 能手写一个 DSL JSON
- 能回答 10 个面试题
如果能做到这四点,就不只是“看过”,而是“掌握了”。
11. 8 小时学习节奏建议
第 1 小时:建立总框架
目标:
- 先理解 AI 应用开发全景图
- 记住“模型、检索、工具、结构、渲染”五个关键词
- 明白这不是单纯调 API
第 2-3 小时:集中突破 LLM、结构化输出、Tool Calling
重点:
- Responses API
- Structured Outputs
- Tool Calling
- Prompt 分层设计
- 状态管理思路
这两个小时的目标是:
- 能说明模型在系统里扮演什么角色
- 能解释为什么要结构化输出
- 能说出 Prompt 和 Skills 的区别
第 4 小时:集中突破 Embedding、向量数据库、RAG
重点:
- Embedding 是什么
- RAG 链路
- chunk 切分
- metadata 过滤
- 向量库选型认知
输出目标:
能画出一条 RAG 流程图
第 5 小时:集中突破 SSE、Realtime、TTS、ASR
重点:
- SSE 流式展示
- Realtime 场景
- TTS 与 ASR 的位置
- 文本应用和语音应用的链路差异
输出目标:
能区分 SSE、WebSocket、Realtime
第 6-7 小时:完整看懂课件项目方案
重点:
- 为什么需要 DSL
- 为什么要 Skills
- 为什么要编译层
- 为什么要局部重生成
- 为什么检索知识和模板
输出目标:
能不看笔记讲清 AI 课件项目架构
第 8 小时:冲刺复盘
做三件事:
- 默写一页速记总结
- 回答面试题
- 用 5 分钟讲一遍你的项目方案
12. 一页速记总结
12.1 AI 应用核心链路
输入 -> 检索 -> 推理 -> 调工具 -> 结构化输出 -> 渲染/执行
12.2 LLM 核心定位
- 理解用户意图
- 生成文本或 JSON
- 决策是否调用工具
12.3 向量数据库核心定位
- 存向量
- 做相似检索
- 给 RAG 提供上下文
12.4 语音与流式核心定位
- SSE:边生成边展示
- Realtime:低延迟双向实时交互
- TTS:文本转语音
- ASR:语音转文本
12.5 Skills 核心定位
- 把业务能力封装成可调用工具
- 输入输出结构明确
- 最好生成中间 DSL
12.6 课件项目核心设计
- 先规划页级结构
- 再生成每页组件 DSL
- 再编译为 LeaferJS JSON
- 前端支持预览和局部重生成
12.7 最重要的一句话
不要让模型直接控制最终渲染层,让模型负责语义和结构,让程序负责布局和稳定性。
13. 背诵口诀
13.1 总口诀
模型来想,检索来补,工具来做,结构来稳,前端来显。
13.2 RAG 口诀
先切再向量,检索找证据,拼进上下文,再让模型答。
13.3 流式与语音口诀
SSE 边看边出,Realtime 边说边回,TTS 负责说,ASR 负责听。
13.4 项目口诀
先规划,再分页;先 DSL,再编译;先校验,再渲染。
13.5 面试口诀
回答 AI 项目题时,尽量按这个顺序说:
- 业务目标
- 系统链路
- 数据结构
- 工具与检索
- 稳定性与优化
只要你按这个顺序说,回答就会比较完整。
附:这份笔记最值得反复看的三部分
第一次学习
重点看:
- AI 应用开发全景图
- LLM 集成核心
- 向量数据库与 RAG
第二次复习
重点看:
- Skills 设计
- AI 课件项目方案
- 技术选型与模块拆分
第三次冲刺
只看:
- 一页速记总结
- 背诵口诀
- 高频面试题
如果你能把这三部分不看笔记讲出来,说明你已经真正掌握了这套内容。