
在实际教育类项目中课程视频上传、学习进度记录、作业批改和权限管理往往比功能清单本身复杂得多。开源的 AI 原生学习平台 LearnOS 提供了一种新思路把类似 Coursera 的课程、测验、进度跟踪和 AI 辅助能力安装到本地服务器让团队或学校自行掌控数据与部署方式。下面围绕 LearnOS 的设计目标梳理自托管学习平台的核心组件、Docker Compose 最小部署过程、AI 能力接入方式以及从学习环境到生产环境的排查与落地清单。如果你正在评估“如何在自己服务器上搭建在线学习系统”或者想理解“AI 原生”到底意味着什么可以按这个链路走一遍。1. LearnOS 是什么为什么要在本地跑一个“AI 原生的 Coursera”1.1 从 Coursera 的旁听模式说起用过 Coursera 的人大多知道免费旁听audit模式不付费也能看课程视频和阅读材料但不能交作业、拿证书。这个模式的本质是平台把课程内容、作业批改和认证服务做了分层。用户获得的是什么、平台保留的是什么通常由商业规则决定。而 LearnOS 这类自托管学习平台则完全不同课程资源、用户学习记录、作业结果和 AI 对话记录都放在自己的服务器上平台本身不再充当内容权限的“中间商”。换句话说如果你给 LearnOS 配置了一门课程并设置所有注册用户都可以直接浏览材料那它就自带“免费旁听”能力。这种能力不是靠平台赠送的“旁听券”实现的而是因为你拥有整个系统内容可见性由自己决定。对学校内部培训、企业内部课程团队和小型教育机构来说这种模式比订阅 SaaS 平台更可控。1.2 AI Native 不等于“塞一个聊天机器人”很多项目号称接入了 AI实际上只是在原有界面上加了一个对话框。AI 原生则不同系统从内容推荐、课程生成到答疑和批改的整个链路都用模型能力驱动。例如新用户注册后系统根据用户填写的学习目标自动生成课程学习路径。用户观看视频过程中AI 可以基于当前字幕内容回答上下文相关问题。测验结束后系统按错误类型推送针对性练习而不是只看分数。课程作者输入主题和难度后系统自动给出章节大纲、测验题和资料链接。这些能力在传统学习管理系统里要分别开发且不知道用户到底卡在哪里。AI 原生平台真正的变化是学习数据不再只用来展示“学了百分之几”而是变成模型决策的输入。用户下一步学什么、看什么资料、做什么练习可以由模型实时计算。1.3 本地运行的核心价值本地部署最大的价值是隐私、成本和可扩展性。隐私企业内部培训资料、员工学习记录和对话数据不需要上传到第三方平台安全审计和合规控制更容易实施。成本平台不按用户数或课程数收取 SaaS 订阅费模型服务也可以选择本地推理或者第三方 API按自己的预算灵活切换。可扩展性课程格式、认证规则、AI 提示词、部署规模都可以自己改。开源项目只要遵循许可证要求你就能基于它做二次开发。代价同样明显需要自己维护服务、数据库、备份和升级还要设计模型接口的限流、熔断和成本控制。LearnOS 给你的不是“买来即用”的托管产品而是一套可以控制、也需要负责的软件系统。2. 部署前先把组件拆清楚自托管学习平台的通用架构2.1 五类核心组件无论 LearnOS 最终采用什么技术栈一个可运行的自托管学习平台通常都要包含下面五类组件。把它们拆清楚后再部署遇到故障时就能快速定位问题在哪一层。组件作用说明前端应用用户浏览器看到的页面负责课程列表、播放器、测验收卷、学习进度展示后端 API处理登录、课程、作业、进度等业务逻辑提供 REST 或 GraphQL 接口是系统核心数据库持久化用户、课程、学习记录常见选型 PostgreSQL、MySQL需要备份对象存储保存视频、文档、图片可以使用 MinIO、S3、本地目录很多项目也会用磁盘挂载AI 网关统一调用 LLM 模型接口支持 OpenAI 兼容协议方便切换本地模型和云端模型部分项目还会引入 Redis 做缓存和任务队列用来处理视频转码、邮件通知、异步 AI 请求等任务。部署时不需要在一开始就把所有组件都搭起来但至少要明白改动一个配置会影响到哪一层。2.2 环境与硬件要求在跑 LearnOS 之前先确认本机或服务器的环境。下面是一份通用的参考值不是 LearnOS 官方最低配置落地前要以项目 README 或 Docker 镜像说明为准。CPU2 核起步推荐 4 核。视频转码和 AI 模型推理对 CPU 消耗很大。内存4GB 能够做基本功能验证8GB 跑得更稳。磁盘30GB 起步。课程视频和对象存储数据会快速增长。操作系统Linux 服务器最稳妥macOS 适合本地开发Windows 建议使用 WSL 2。Docker需要安装 Docker Engine 和 Docker Compose 插件版本尽量保持较新。如果计划在本地同时运行 7B 参数的开放模型内存至少 16GB物理内存不够时要考虑显存。多数 AI 推理框架会提供 CPU 量化模式但速度会明显下降。建议先使用云端 OpenAI 兼容接口跑通功能再根据性能和成本决定是否切换到本地模型。2.3 学习环境与生产环境的差异很多人在本机用 Docker 启动服务后以为部署到服务器只需复制命令。实际上学习环境和生产环境的关注点完全不同下面这张表可以帮助你提前对齐。维度学习环境生产环境访问范围localhost 或内网需要 HTTPS、域名、反向代理密钥管理写在.env里使用密钥管理系统或容器 secret数据库掉数据可接受必须自动备份、定期恢复演练模型服务使用公开测试 Key需要限流、配额、成本监控日志后台实时看集中收集到日志平台或文件系统升级直接 pull 最新镜像锁版本、先备份、灰度发布学习环境的目标是“跑通”生产环境的目标是“可持续运行”。如果你只是在本地试用 LearnOS可以跳过部分安全加固但只要准备对外开放环境差异必须从第一天考虑。3. 使用 Docker Compose 做最小部署3.1 项目结构与 .env为了让配置集中管理先创建一个独立的项目目录并准备环境变量文件。下面是一个可用于演示的目录结构mkdir -p learnos-deploy cd learnos-deploy touch .env docker-compose.yml.env文件里保存数据库密码、API 密钥和模型接口信息。注意.env不要提交到 Git因为里面包含敏感信息。如果项目仓库已经提供.env.example可以直接复制为.env再修改。# .env POSTGRES_USERlearnos POSTGRES_PASSWORDchange_me_in_production POSTGRES_DBlearnos DATABASE_URLpostgres://learnos:change_me_in_productiondb:5432/learnos JWT_SECRETplease_replace_with_long_random_string AI_API_KEYyour_model_platform_key这里的DATABASE_URL中的主机名db是 Docker Compose 服务名只能用于容器内部访问。宿主机上的数据库客户端如果要用则需要把db换成localhost并映射端口。3.2 Docker Compose 配置示例由于开源项目不断迭代下面这个 compose 文件不是 LearnOS 官方文件而是一个“自托管学习平台通常需要的服务骨架”。如果你拿到的项目确实使用 Node.js 后端和 PostgreSQL这个模板能直接作为起点如果项目技术栈不同也要保留db - api - web的依赖关系。version: 3.9 services: db: image: postgres:16-alpine environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine command: [redis-server, --appendonly, yes] volumes: - redisdata:/data api: image: ${LEARNOS_API_IMAGE:-learnos/api:dev} command: [sh, -c, npx prisma migrate deploy node dist/main.js] env_file: - .env environment: DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}db:5432/${POSTGRES_DB} REDIS_URL: redis://redis:6379 depends_on: db: condition: service_healthy redis: condition: service_started ports: - 3000:3000 web: image: ${LEARNOS_WEB_IMAGE:-learnos/web:dev} depends_on: - api ports: - 8080:80 volumes: pgdata: redisdata:这段配置的第一个关键是健康检查。db服务只有在pg_isready返回成功后api才会启动避免后端启动时数据库还没就绪。第二个关键是env_file所有业务环境变量统一从.env注入到容器的环境变量中。第三个关键是镜像名称我使用了learnos/api:dev和learnos/web:dev作为示意图真实镜像名可能是 Docker Hub 或 GHCR 上不同的地址。部署前一定要先到仓库查看官方 compose 文件不要直接把占位镜像名用于生产。3.3 启动、健康检查和首次访问配置完成后先拉取镜像并启动服务docker compose pull docker compose up -d查看服务状态docker compose ps当你看到api和web的状态是Up且没有Restarting时说明容器已经启动。再用健康检查验证前端页面curl -I http://localhost:8080如果返回HTTP/1.1 200 OK说明 web 服务可以访问。随后在浏览器打开http://localhost:8080应该能看到 LearnOS 的首页、登录页或初始化页面。如果 8080 端口已经被占用可以修改 compose 文件中的8080:80例如改成18080:80再重新启动。端口映射以宿主机端口:容器端口的格式书写修改宿主机端口不会影响容器内部逻辑。3.4 创建第一门课程并验证“免费旁听”流程进入系统后第一件事是找到管理员账号。很多开源项目会在首次启动时通过环境变量指定管理员邮箱和密码或者提供一个初始化命令。如果项目提供种子脚本可以执行docker compose exec api npm run seed如果项目没有种子脚本就手动在后台注册一个账号然后到数据库或管理接口里把它提升为管理员。这个过程不要跳过因为 LearnOS 的内容管理功能一般只对管理员开放。创建课程时至少需要填写课程标题、简介、分类并上传课程封面。真正的内容通常由章、节、视频、文档和测验构成。你需要把一门课程设置为“所有登录用户可见”这样注册用户进入课程后可以直接浏览学习材料不需要额外的报名流程。这个行为在体验上就等同于 Coursera 的免费旁听模式——用户放弃的只是证书和评分服务但核心学习材料不会被平台墙壁阻挡。验证旁听流程时可以用第二个普通用户注册登录查看课程列表进入课程页面打开一个视频或文档确认页面没有出现付费解锁或无权访问提示。这一步很重要因为课程权限配置往往在“管理员看得见”和“普通用户看得见”之间出现差异。4. 接入 AI 能力配置模型、推荐与课程生成4.1 通过环境变量接入 OpenAI 兼容接口AI 原生平台的价值需要通过模型服务体现。目前很多开源项目都兼容 OpenAI 接口协议这意味着只要模型服务能提供/v1/chat/completions接口就可以接入。常见选项包括云端 OpenAI 兼容服务配置一个 API Key 即可。本地推理框架例如 Ollama、vLLM、LM Studio。内网部署的模型网关统一转发到多个模型源。在.env中常见的配置项类似这样AI_PROVIDERopenai_compatible AI_BASE_URLhttps://api.example.com/v1 AI_MODELgpt-4o-mini AI_API_KEYsk-xxxx如果你在本地使用 Ollama 跑模型则需要把AI_BASE_URL设为容器的宿主机地址。由于容器内的localhost指向容器自己不是宿主机因此不能直接写http://localhost:11434/v1。在 Linux 上可以使用http://host.docker.internal:11434/v1在 Docker Desktop 中通常也能使用http://host.docker.internal:11434/v1。不同系统的解析方式略有差异这一点是接入本地模型最常遇到的坑。4.2 课程推荐与学习路径接入模型后最直观的 AI 能力是课程推荐。传统推荐系统需要构建用户画像、物品画像和交互矩阵而 AI 原生平台可以用文本向量和自然语言直接完成。一个简化的思路是把每门课程的标题、简介、标签拼成文本用 Embedding 模型转成向量用户每完成一门课程也把表现记录转成文本再生成一个用户侧向量系统通过余弦相似度返回最匹配的课程列表。这个流程放在需要的时候做成异步任务不需要用户等待模型计算。如果你只是想验证一条更简单的链路可以在课程详情页添加一个“AI 推荐下一步”按钮。前端把当前课程 ID 发给后端后端把这个课程的内容摘要和用户近期学习记录拼进 Prompt调用聊天接口返回 3 门推荐课程。示例逻辑如下import os import requests def recommend_next_course(course_context, user_recent_learning): payload { model: os.getenv(AI_MODEL), messages: [ { role: system, content: 你是一名课程推荐助手。根据用户最近学习的内容和当前课程信息推荐下一步学习课程并说明理由。 }, { role: user, content: f当前课程{course_context}\n用户最近学习{user_recent_learning} } ], temperature: 0.3 } resp requests.post( f{os.getenv(AI_BASE_URL)}/chat/completions, headers{Authorization: fBearer {os.getenv(AI_API_KEY)}}, jsonpayload, timeout30 ) resp.raise_for_status() return resp.json()[choices][0][message][content]这个函数的核心在于把系统提示、课程上下文和用户状态放在同一个 Prompt 中。temperature设置为 0.3是为了让推荐结果更稳定避免每次打开页面得到完全不同的答案。生产环境还要加上超时和重试防止模型服务变慢拖垮整个页面接口。4.3 自动出题和答疑的调用链路课程作者可以利用 AI 快速生成测验题。输入一段课程正文和题目数量模型可以返回 JSON 格式的题目。此时要关注两件事一是模型返回结果的格式解析二是题目质量的人工审核。如果项目后端使用 Python可以从一个通用接口调用模型然后用json.loads把返回内容解析成题目数组。示例import json def generate_quiz(text, num_questions3): prompt f根据下面的课程内容生成 {num_questions} 道选择题返回 JSON 数组。 每道题包含 question, options, answer_index。 课程内容 {text[:2000]} # 调用模型服务的代码省略 result_text call_llm(prompt) return json.loads(result_text)这里最常见的问题是模型返回的 JSON 可能被解释性文字包裹例如“好的这是题目”后面才是 JSON。解析时会直接报错。稳妥的做法是要求模型只输出 JSON并在代码中截取第一个[到最后一个]的片段再解析。答疑的链路可以这样设计用户提问后后端先从课程资料中检索相关段落再把段落和问题一起送给模型。这样模型回答时有依据也不容易产生幻觉。这一流程通常被称为“检索增强生成RAG”对学习平台来说非常实用。最小实现并不复杂先把课程内容切分成块用向量数据库或内存列表保存用户提问时找到最相似的内容块拼入 Prompt。5. 验证结果从登录到日志一条检查链路5.1 功能验证清单完成部署后不要只验证首页能不能打开。下面是一份适合自托管学习平台的快速验收清单注册一个普通用户并登录。在管理员后台创建课程、章节和测验。以普通用户身份进入课程浏览视频或文档。提交一次测验确认系统可以保存结果。触发一次 AI 答疑确认模型回复能出现在界面上。退出登录确认未登录用户不能访问课程管理页面。重启学习环境docker compose restart确认数据没有丢失。任何一个环节失败都要记录下来。功能验证不是为了应付测试而是为了让你知道日志中哪些报错是“预期内”的哪些是“配置错误”的。5.2 常见问题与排查表部署 LearnOS 类项目时下面这些问题出现频率较高。每个问题都按照“现象、可能原因、检查方式、处理建议”整理成表方便快速定位。问题现象可能原因检查方式处理建议docker compose up启动后 api 反复重启数据库尚未就绪或迁移命令失败docker compose logs -f api查看迁移日志给 db 加 healthcheck等待数据库健康后再启动 api浏览器访问页面显示 502web 服务无法连接 apidocker compose exec web curl http://api:3000/health检查 api 实际监听端口和 web 反向代理配置登录后页面一直转圈前端调用的 API 地址不正确打开浏览器开发者工具查看 Network 报错修改前端环境变量中的 API 地址为实际后端地址上传课程视频失败对象存储没有正确创建 bucket查看 api 日志中的存储错误信息创建 bucket 并给服务配置正确的 Access Key/SecretAI 答疑超时模型服务地址不通或模型响应太慢在 api 容器内 curl 模型接口检查host.docker.internal映射或增大超时时间普通用户也能看到课程管理入口前端路由没有做权限控制检查角色字段和路由守卫逻辑后端接口必须校验角色不能只靠前端隐藏按钮修改环境变量后不生效没有重建容器只 restart 了容器docker compose ps看启动时间修改.env后需要docker compose up -d --force-recreate5.3 日志与监控线索容器模式下的日志排查比裸进程更方便因为所有服务的标准输出都被 Docker 收集起来了。docker compose logs -f api看到EADDRINUSE说明端口被占用看到connection refused说明依赖服务没起来看到migrate相关错误说明数据库版本或迁移脚本有问题。AI 调用相关的日志通常会打印模型名称、状态码和耗时。如果项目本身不打印这些关键信息建议在部署时通过反向代理或日志插件补充。资源占用用下面的命令查看docker stats如果内存长期接近上限说明需要调大机器内存或减少并发任务。如果 AI 推理占满 GPU还需要为模型服务单独设置显存限制和排队机制。6. 从本地跑到生产环境安全、备份、升级6.1 不要把密钥写进 docker-compose在本地开发时为了省事你可能会把密码、JWT 密钥和 API Key 直接写在 compose 文件里。生产环境绝对不能这样做因为 compose 文件很可能被复制进仓库导致密钥泄露。正确做法是使用.env文件并把.env加入.gitignore。使用 Docker secret 或系统级环境变量管理敏感信息。定期轮换JWT_SECRET、数据库密码和模型 API Key。对数据库端口不要随意映射到公网。如果服务器已经被暴露到公网第一件事是确认数据库没有映射到0.0.0.0:5432。否则攻击者可能直接尝试连接 PostgreSQL 端口。6.2 数据备份与迁移学习平台的数据比容器重要得多。容器可以随时删除重建课程内容和用户学习记录一旦丢失很难恢复。备份动作至少要覆盖数据库和对象存储两部分。PostgreSQL 备份命令可以在宿主机上执行也可以进入容器执行docker compose exec db pg_dump -U learnos -d learnos -F c -f /tmp/learnos.dump docker compose cp db:/tmp/learnos.dump ./backups/对象存储如果是 MinIO使用mc命令同步如果只是挂在宿主机目录直接备份对应目录即可。备份完成后要定期测试恢复流程。没有验证过的备份等于没有备份。恢复数据库的流程大致是先启动一个空的数据库容器再用pg_restore导入备份文件。恢复前要备份当前数据避免恢复失败后连旧数据都找不到。6.3 版本升级与回滚开源项目迭代很快升级前必须查看发布说明确认是否有破坏性变更。升级的大概流程备份当前数据库和持久化数据。记录当前镜像版本例如learnos/api:v0.3.2。修改镜像标签到新版本。执行docker compose pull拉取新镜像。启动新版本并查看日志。如果出现异常改回旧镜像标签再docker compose up -d。回滚操作本身很简单但数据库迁移可能不是可逆的。部分项目在升级时会自动执行数据库迁移如果迁移已经修改了表结构直接回滚到旧镜像可能导致版本不匹配。因此升级前要确认迁移是否向后兼容或者数据库是否已有备份。7. 最佳实践清单与扩展方向7.1 部署前检查清单每次部署或升级前可以按下面这份清单逐项确认。虽然看起来琐碎但能避免绝大多数低级故障。[ ] 确定域名、端口和访问协议尽早配置 HTTPS。[ ] 检查 Docker 版本和 Compose 插件可用。[ ] 从官方仓库获取最新的 compose 文件和镜像标签。[ ] 修改默认密码、Secret 和 API Key且不提交到 Git。[ ] 确认数据库和对象存储有独立 volume容器删除后数据不丢。[ ] 测试健康检查接口是否正常返回。[ ] 验证普通用户注册、课程访问、测验提交三条主链路。[ ] 配置日志滚动和磁盘空间告警。[ ] 制定备份任务并在一个临时环境演练恢复。7.2 内容生产和教育场景扩展方向LearnOS 解决了平台层问题但真正决定一个学习平台价值的还是课程内容。基于自有服务器你可以扩展出很多适合实际教学的场景课程内容标准化引入 SCORM 或 xAPI 规范让现有课件能复用。多语言课程集成翻译接口用 AI 生成字幕和课件翻译。企业培训增加部门分组、训练营、证书模板和培训完成报表。课堂教学LTI 集成可以对接学校现有的 LMS例如 Canvas、Moodle。移动端适配优先确认 PWA 是否可用再考虑原生小程序或 App。不要一开始就做所有功能。建议先跑通“课程-测验-AI 答疑”这条最小闭环再根据真实用户反馈逐步增加功能。7.3 开发者参与开源项目的切入点如果你打算研究 LearnOS 源码而不是只做部署可以先从这几个入口入手阅读项目 README 和docker-compose.yml搞清楚服务如何连接。找到数据库模型定义文件理解用户、课程、章节、测验之间的关系。运行测试命令看看项目是否自带单元测试和集成测试。从“小 bug”或“文档缺失”开始提交 PR而不是一开始就改核心业务逻辑。给开源项目提交代码前要查看贡献指南确认代码风格、提交信息和测试要求。对学习项目来说最好的参与方式是先写一份部署笔记然后对照源码去修正自己理解错误的地方。这样既能帮助社区也能真正学到架构设计。如果你只是想在本地验证自托管学习平台先按默认配置跑通流程如果未来要用于团队培训或学校教育务必把备份、权限控制和模型成本作为第一优先级。项目是否叫 LearnOS 并不重要重要的是你能否把课程内容、学习数据和模型决策的主动权掌握在自己手中。