ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

当开源教育平台遇上 AI:领课教育如何用大模型辅助生成课程大纲

当开源教育平台遇上 AI:领课教育如何用大模型辅助生成课程大纲 领课教育Roncoo Education是一套开源的分布式在线教育系统Spring Boot 3.5 Spring Cloud Alibaba前端 Vue 3 Element Plus。最近的版本里我们给系统接入了大语言模型LLM能力其中最典型的场景就是AI 辅助生成教学大纲课程编辑在富文本编辑器里选择教学大纲类型输入一句需求描述AI 便以打字机效果流式输出一份结构完整的大纲草稿确认后一键插入课程简介。一、设计目标协议抽象而不是厂商绑定接入大模型第一个要回答的问题是绑哪家如果为每家厂商写一套 SDK 调用后续换模型、换服务商就要动业务代码。领课教育的选择是按协议抽象而不是按厂商抽象。目前主流大模型 API 归结为三种协议协议代表服务商OpenAI 兼容协议/chat/completionsOpenAI、通义千问、DeepSeek、Kimi、讯飞星火等Anthropic Messages 协议/messagesClaude 系列OpenAI Responses 协议/responsesOpenAI 新版接口这套划分落在枚举LlmPlatformEnum中publicenumLlmPlatformEnum{/** OpenAI 及兼容协议适用于OpenAI、阿里百炼/通义千问、DeepSeek、月之暗面等 */OPENAI_COMPATIBLE(1,OpenAI兼容协议,openai_compatible%,OPENAI_COMPATIBLE),/** Anthropic Messages 协议适用于Claude 系列 */ANTHROPIC_MESSAGES(2,Anthropic Messages协议,anthropic%,ANTHROPIC_MESSAGES),/** OpenAI Responses API适用于OpenAI 新版 Responses 接口 */OPENAI_RESPONSES(3,OpenAI Responses协议,openai_responses%,OPENAI_RESPONSES);}与之配套的配置类Llm同样只保留协议维度的字段llmPlatform协议类型、aiApiKey、aiBaseUrl、aiModel、temperature、maxTokens、timeout。这意味着换服务商只需在系统配置里改一个 baseUrl 和 model业务代码零改动。想从 OpenAI 切到 DeepSeek把aiBaseUrl指向https://api.deepseek.com即可因为两者都走 OpenAI 兼容协议。配置存在系统配置表里由SysConfigCommonBiz.getSysConfig(Llm.class)统一读取管理员在后台系统配置页面即可完成所有 LLM 参数的调整。二、核心抽象LlmFace 接口与路由所有协议实现都收敛到一个接口LlmFace提供同步调用、流式调用、连接测试三个方法。以 OpenAI 兼容协议实现为例底层直接复用了Spring AI的OpenAiChatModel省去手写 HTTP 与 SSE 解析的体力活Component(valueOPENAI_COMPATIBLE)publicclassOpenAiCompatibleLlmImplimplementsLlmFace{OverridepublicFluxStringchatStream(LlmRequestrequest,Llmconfig){OpenAiChatModelchatModelbuildChatModel(request,config);returnchatModel.stream(newPrompt(toMessages(request))).mapNotNull(resp-{if(resp.getResult()null||resp.getResult().getOutput()null){returnnull;}returnresp.getResult().getOutput().getText();}).filter(StringUtils::hasText);}privateOpenAiChatModelbuildChatModel(LlmRequestrequest,Llmconfig){OpenAiApiopenAiApiOpenAiApi.builder().baseUrl(StringUtils.hasText(config.getAiBaseUrl())?config.getAiBaseUrl():DEFAULT_BASE_URL).apiKey(config.getAiApiKey()).build();// ... model / temperature / maxTokens 按 请求 配置 默认值 的优先级解析}}注意Component(value OPENAI_COMPATIBLE)这个细节——Bean 名称与LlmPlatformEnum的mode字段一一对应。于是路由层LlmHelper不需要写任何 if-else直接利用 Spring 的集合注入特性ComponentpublicclassLlmHelper{privatefinalMapString,LlmFacellmFaceMap;publicLlmHelper(MapString,LlmFacellmFaceMap){// Spring 自动注入所有 LlmFace 实现this.llmFaceMapllmFaceMap;}publicLlmFacegetLlmFace(Llmconfig){LlmPlatformEnumplatformEnumLlmPlatformEnum.byCode(config.getLlmPlatform());returnllmFaceMap.get(platformEnum.getMode());}publicFluxStringchatStream(LlmRequestrequest,Llmconfig){request.setStream(true);returngetLlmFace(config).chatStream(request,config);}}新增一种协议比如未来接入某家新的国产大模型私有协议只需要新增一个LlmFace实现类加一个枚举值LlmHelper和所有业务代码都不用碰。这是典型的开闭原则落地。三、AI 写作任务两段式设计与 aiToken业务入口在系统服务的AdminAiWriteController/system/admin/ai/write拆成两个接口POST /create创建写作任务返回一次性aiTokenGET /completions凭aiToken通过 SSE 流式获取 AI 输出。为什么要拆两步而不是一个接口直接流式返回因为流式接口走的是EventSourceGET 请求不适合携带 JSON body。于是任务参数先落 Redis换回一个短时 tokenpublicResultStringcreate(AdminAiWriteCreateReqreq){LlmllmsysConfigCommonBiz.getSysConfig(Llm.class);if(llmnull||!StringUtils.hasText(llm.getAiApiKey())){returnResult.error(AI功能未配置请在系统配置中设置 aiApiKey);}StringaiTokenIdUtil.fastSimpleUUID();StringtaskDatareq.getWriteType()||req.getUserPrompt();cacheRedis.set(AI_TOKEN_PREFIXaiToken,taskData,AI_TOKEN_EXPIRE_MINUTES,TimeUnit.MINUTES);returnResult.success(aiToken);}aiToken有效期 10 分钟、一次性使用天然规避了请求参数被篡改和重放的问题——这也是把 AI 能力暴露给管理后台时的一个安全细节。四、课程大纲的提示词工程系统把 AI 写作场景抽象成WriteTypeEnum通用写作、课程简介、文章撰写、营销文案、教学大纲。每种类型对应一段专职的系统提示词System Prompt这是决定输出质量的关键一层privateStringbuildSystemPrompt(WriteTypeEnumwriteType){returnswitch(writeType){caseCOURSE_INTRO-你是一位专业的在线教育课程文案撰写专家。请根据用户的要求撰写吸引人的课程简介突出课程价值、学习收益和目标受众。使用Markdown格式输出。;caseSYLLABUS-你是一位专业的教学设计专家。请根据用户的要求设计详细的教学大纲包含课程目标、章节安排、知识点和学习目标。使用Markdown格式输出。;// ...};}针对教学大纲提示词明确约束了四个产出要素课程目标、章节安排、知识点、学习目标——这正是教学设计Instructional Design中大纲的标准骨架而不是让模型随意发挥。用户侧只需输入一句自然语言比如“面向零基础学员的 Spring Boot 入门课30 学时包含实战项目”模型返回的大纲会自带章节层级、每章知识点列表和学习目标Markdown 格式与前端渲染天然契合。五、SSE 流式输出让 AI “边想边说”大纲类内容动辄上千字如果等模型全部生成完再返回用户要盯着空白页面十几秒。系统采用SSEServer-Sent Events流式输出模型每吐出一个 token 片段就立刻推给浏览器。这里有个容易踩坑的细节SSE 协议规定每条消息以\n\n结尾如果模型输出内容本身含换行符会直接破坏协议分帧。领课教育的解法是在服务端对内容做转义编码publicstaticStringstreamToResponse(FluxStringflux,HttpServletResponseresponse)throwsIOException{response.setContentType(text/event-stream);response.setCharacterEncoding(UTF-8);PrintWriterwriterresponse.getWriter();flux.doOnNext(content-{// content 中的换行编码为 \\n避免破坏 SSE 协议格式writer.write(data: encodeForSse(content)\n\n);writer.flush();}).doOnComplete(()-writer.write(data: [DONE]\n\n)).blockLast();}publicstaticStringencodeForSse(Stringcontent){returncontent.replace(\\,\\\\).replace(\n,\\n).replace(\r,);}流结束以data: [DONE]标记出错则以data: [ERROR]开头推送错误信息前端据此区分三种状态。六、前端编辑器里长出来的 AI 入口AI 能力的最终落点是管理后台的富文本编辑器。领课教育前端基于 WangEditor 做了深度定制AI 写作被注册为编辑器工具栏上的一个菜单按钮点击后弹出AiForm对话框选择写作类型教学大纲 → 输入需求 → 点击创作开始 → 打字机效果流式渲染 → 插入下方核心交互由一个通用的 SSE composableuseEventStream驱动内置了 80ms 节流渲染避免每个 token 都触发一次 Markdown 重排const{start,loading:isBeginning,isComplete}useEventStream({onChunk:(text){// 后端将换行符编码为 \n 字面量推送此处还原后再渲染constdecodedtext.replace(/\\n/g,\n).replace(/\\r/g,)messageList.valuesafeMarkdownRender(preprocessMarkdown(decoded))// 自动滚动到底部},onError:()ElMessage.error(AI写作繁忙请稍后重试)})consthandleAiasync(){constaiTokenawaitsystemApi.aiWriteCreate(formModel)// 第一步创建任务awaitstart(()systemApi.aiWriteCompletions({aiToken}))// 第二步SSE 流式接收}用户确认后内容经dangerouslyInsertHtml插入编辑器当前光标处与人工撰写的内容无缝混合编辑consthandleAiCallback(val){aiVisible.valuefalseif(val){editorRef.value.restoreSelection()editorRef.value.dangerouslyInsertHtml(val)// AI 内容插入光标处}}而这个编辑器正是课程编辑页views/course/update/index.vue中简介字段所用的组件——也就是说AI 生成的教学大纲可以直接成为课程详情页的一部分也可以作为讲师后续录制课程视频时的章节蓝图。七、架构小结回头看整条链路管理员配置 LLM协议 baseUrl apiKey model │ ▼ WangEditor「AI写作」按钮 → AiForm选择教学大纲 输入需求 │ ▼ POST /system/admin/ai/write/create ──→ Redis 存任务返回 aiToken10 分钟有效 │ ▼ GET /system/admin/ai/write/completions?aiTokenxxx │ ▼ LlmHelper 按协议路由 → LlmFace 实现Spring AI→ 大模型流式响应 │ ▼ LlmUtil SSE 转义输出 → 前端 useEventStream 节流渲染 Markdown → 插入编辑器几个值得借鉴的工程决策协议抽象优于厂商抽象——三种协议覆盖了当前几乎全部主流大模型换服务商是配置变更而非代码变更两段式任务设计——aiToken一次性、短时效兼顾了 EventSource 的技术约束与接口安全提示词与场景绑定——教学设计专家的角色设定 四要素约束把通用大模型变成了垂直场景的专用工具SSE 内容转义——一行encodeForSse解决了流式输出中最常见的分帧事故AI 深度嵌入既有工作流——不是独立页面而是编辑器工具栏上的一个按钮学习成本几乎为零。AI 不会替代讲师但可以把讲师从搭大纲骨架这类结构性劳动中解放出来让人的精力聚焦在真正需要专业判断的内容打磨上。这或许就是 AI 与教育系统结合最务实的姿势。
返回列表