百人共学AI应用开发:Open WebUI+Ollama+RAG架构实战
1. 百人共学场景到底难在哪先说说这个项目的来龙去脉。去年年底我接手了一个内部共学项目的技术搭建工作参与人数大概在一百人上下背景五花八门——有刚入门的运营同学有写了几年代码的工程师也有完全不懂技术但特别爱提问的产品经理。大家要一起学的东西是AI应用开发从最基础的大模型调用到RAG知识库搭建再到Agent编排内容跨度不小。一开始我想得很简单不就是搭个聊天界面让大家问问题嘛Open WebUI加Ollama半小时搞定。结果真上手才发现一百个人同时用和一个人自己玩完全是两码事。第一个问题就是并发。Ollama默认的并行处理能力很有限几个人同时发请求后面的人就得排队等个十几秒是常态体验极差。第二个问题是知识库。共学项目需要把课程资料、参考文档、常见问题都喂给模型让大家能随时查但一百个人各自上传文件、各自建知识库管理起来就是灾难。第三个问题是权限和成本谁用了多少token谁问了什么哪些问题高频这些数据如果不记录后续优化根本无从下手。所以这个项目的核心不是“搭一个能聊天的界面”而是“搭一套能让一百个人稳定、高效、可管理地共学AI的系统”。关键词里的Open WebUI、Ollama、Svelte、RAG、知识库每一个都不是随便选的背后都有具体的取舍。下面我就把这套架构从设计思路到落地细节完整拆一遍。2. 整体架构设计与技术选型逻辑2.1 为什么是Open WebUI Ollama这个组合先说最核心的推理层。选Ollama而不是直接调云端API原因有三个。第一是数据隐私共学项目里大家会传一些内部资料走云端总归不放心。第二是成本可控一百个人如果都用云端API按token计费一个月下来账单能吓死人本地部署一次投入后续边际成本几乎为零。第三是教学价值共学项目本身就是要让大家理解大模型怎么跑起来的本地部署能让每个人看到模型加载、推理、显存占用的全过程这比调API有教育意义得多。Ollama的优势在于它把模型量化、加载、推理服务这些脏活累活都封装好了一条ollama run qwen2.5:7b就能跑起来对新手极其友好。而且它支持并发请求虽然默认并发数不高但可以通过环境变量调整。实测下来在一台32G内存、带一张24G显存的机器上跑一个7B的量化模型把OLLAMA_NUM_PARALLEL调到4同时服务二三十个轻量请求是没问题的。Open WebUI则是前端交互层的最佳选择。它本身就是一个功能完整的ChatGPT式界面支持多模型切换、对话历史、文件上传、RAG集成而且是用Svelte写的前端性能很好一百个人同时在线也不会卡。更重要的是它原生支持Ollama作为后端配置起来就是填个地址的事。关键词里提到的“open webui下载”“如何用docker安装open webui”这些热搜说明大家对这个组合的关注度很高我后面会给出具体的compose配置。2.2 Svelte在这个架构里扮演什么角色很多人看到Svelte会疑惑Open WebUI不是已经用Svelte写好了吗为什么还要单独提这里有两个层面的考虑。第一Open WebUI的前端虽然开箱即用但共学项目往往需要定制一些东西比如在界面上加一个“今日学习任务”的面板或者把课程资料的入口嵌进去。Open WebUI的前端代码就是Svelte写的你要改就得懂Svelte。第二我们后来单独做了一个学习进度看板用来展示每个人完成了哪些模块、问了哪些问题、知识库命中率如何这个看板就是用SvelteKit搭的因为它编译后体积极小加载快而且响应式写起来很顺手。Svelte的核心优势是“编译时框架”它不像React那样在运行时做虚拟DOM diff而是把状态更新直接编译成原生DOM操作。对于一百人共学这种场景前端要频繁展示实时数据谁在线、谁刚问了问题、知识库更新了哪些文档Svelte的响应式更新比React更轻量浏览器负担更小。而且Svelte的语法接近原生HTML对于共学项目里那些前端基础薄弱的同学来说改起来门槛更低。2.3 RAG和知识库为什么必须做怎么做共学项目最怕的就是大家问重复的问题。一百个人每个人问一遍“什么是RAG”模型就要回答一百遍既浪费算力又浪费时间。RAG检索增强生成就是解决这个问题的。它的原理不复杂把课程资料、FAQ、参考文档切块、向量化、存进向量数据库用户提问时先检索最相关的几个片段再把片段和问题一起喂给模型让模型基于这些片段回答。这样模型不用“记住”所有知识只需要“读懂”检索到的片段就行。但RAG的坑也很多。关键词里提到的“rag瓶颈”“rag hit rate”就是典型问题。检索命中率低模型答非所问切块策略不对上下文断裂向量模型选得不好语义相似度算不准。我在这个项目里试过好几种方案最后定下来的是用nomic-embed-text做向量化用Chroma做向量库切块大小512个token重叠128个token。这个组合在中文资料上的表现比较稳而且Chroma轻量不需要额外部署服务直接嵌在应用里就行。至于关键词里提到的“dify知识库流水线”“agentic rag”“graphrag”这些更高级的方案我也评估过。Dify确实功能强大但它的知识库流水线对于一百人共学来说有点重配置复杂而且和Open WebUI的集成不如原生RAG顺畅。GraphRAG适合处理实体关系复杂的知识图谱但我们的课程资料主要是线性文档用不上那么复杂的结构。所以最终选择了最朴素但最稳的方案Open WebUI内置的RAG功能配合Chroma和nomic-embed-text。3. 核心组件部署与配置实操3.1 Ollama的安装与并发调优Ollama的安装本身很简单官网有各平台的安装包。但关键词里“ollama下载慢”“ollama国内镜像源”这些热搜说明下载模型这一步经常卡住。我的经验是模型文件动辄几个G直接从官方源拉确实慢可以配置镜像源加速。具体做法是在启动Ollama服务前设置环境变量或者在~/.ollama/config.json里配置镜像地址。不过这里要注意镜像源的可用性会变化建议多准备几个备选。安装完之后关键的一步是调并发。默认情况下Ollama的OLLAMA_NUM_PARALLEL是1也就是一次只能处理一个请求。一百个人用这个值必须调大。我的设置是export OLLAMA_NUM_PARALLEL4 export OLLAMA_MAX_LOADED_MODELS2 export OLLAMA_KEEP_ALIVE30mOLLAMA_NUM_PARALLEL4表示同时处理4个请求OLLAMA_MAX_LOADED_MODELS2表示最多同时加载2个模型比如一个聊天模型加一个向量模型OLLAMA_KEEP_ALIVE30m表示模型在最后一次使用后保持30分钟不卸载避免频繁加载卸载带来的延迟。这里有个坑要提醒OLLAMA_NUM_PARALLEL不是越大越好。它受限于显存和内存每个并行请求都需要独立的KV Cache空间。7B模型在4位量化下每个请求大概需要1-2G显存4个并行就是4-8G加上模型本身的4G左右总共需要8-12G显存。如果你的显卡只有8G调到4就会OOM。我的建议是从2开始试观察显存占用逐步往上加。3.2 Open WebUI的Docker部署与中文配置Open WebUI官方推荐用Docker部署这也是最省心的方式。关键词里“用docker安装open webui”“绿联nas dxp4800 pro docker 部署 ollama open webui 的compose.yml脚本”这些搜索说明很多人是在NAS上部署的。我给出一个通用的compose配置version: 3.8 services: open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui ports: - 3000:8080 volumes: - ./open-webui-data:/app/backend/data environment: - OLLAMA_BASE_URLhttp://host.docker.internal:11434 - WEBUI_SECRET_KEYyour-secret-key-here - DEFAULT_LOCALEzh-CN extra_hosts: - host.docker.internal:host-gateway restart: unless-stopped这个配置里几个关键点OLLAMA_BASE_URL指向宿主机上的Ollama服务extra_hosts是为了让容器能访问宿主机的host.docker.internalDEFAULT_LOCALEzh-CN设置默认中文界面。WEBUI_SECRET_KEY一定要改不然会话不安全。部署完之后第一次访问需要注册管理员账号。这里有个细节Open WebUI默认第一个注册的用户就是管理员所以部署完要第一时间注册不然被别人抢了管理员权限就麻烦了。注册完之后在设置里把“允许新用户注册”关掉改成管理员手动邀请这样一百个人的账号才能可控。中文配置方面Open WebUI的界面本身支持多语言但模型回答的语言取决于你的提示词。我建议在系统提示词里明确写“请用中文回答”并且在知识库的文档里也尽量用中文这样检索和生成都是中文一致性更好。3.3 RAG知识库的搭建与切块策略知识库的搭建是重头戏。Open WebUI内置了RAG功能你可以在“工作空间”里创建知识库上传文档它会自动切块、向量化、存入Chroma。但默认的切块策略不一定适合中文资料需要手动调整。我的切块策略是这样的对于课程讲义这类结构化文档按标题层级切每个小节作为一个块块大小控制在300-500字。对于FAQ这类问答对每个问答作为一个独立的块不要合并。对于参考文档这类长文本用固定窗口切窗口512个token重叠128个token。重叠的作用是防止关键信息被切断比如一个概念的定义跨了两个块有重叠就能保证至少有一个块包含完整定义。向量模型我选的是nomic-embed-text它在中文语义相似度上的表现比默认的all-minilm好不少。配置方法是在Open WebUI的设置里把Embedding模型改成nomic-embed-text然后重新索引知识库。注意换向量模型后必须重新索引不然旧的向量和新模型不匹配检索会乱套。这里有个实测数据用默认切块和默认向量模型检索命中率大概在60%左右经常答非所问。换成512token切块加nomic-embed-text之后命中率提升到85%以上。这个提升非常明显值得花时间调。3.4 Svelte看板的开发与数据对接学习进度看板是我用SvelteKit单独做的主要展示三个数据每个人的学习进度、知识库的检索命中率、高频问题排行。数据来源是Open WebUI的API和Chroma的查询日志。SvelteKit的项目结构很清晰src/routes下每个文件夹就是一个页面page.svelte是页面组件page.server.js是服务端数据加载。我用page.server.js去调Open WebUI的API拿用户数据然后在page.svelte里用Svelte的响应式语法渲染。Svelte的$:语法特别好用比如$: filteredUsers users.filter(u u.progress 0.5)当users变化时filteredUsers自动更新不需要手动写监听。看板的部署很简单npm run build之后把build目录扔到Nginx里就行。因为SvelteKit支持SSR首屏加载很快一百个人同时打开也不会卡。4. 实操过程中的坑与排查记录4.1 Ollama并发上不去请求排队严重这是最早遇到的问题。一百个人同时用Ollama的请求队列排得老长后面的人等十几秒是常事。排查思路是这样的先看Ollama的日志发现请求是一个一个处理的说明OLLAMA_NUM_PARALLEL没生效。检查环境变量发现是在docker-compose里设置的但Ollama是直接装在宿主机上的环境变量没传进去。改成在宿主机的systemd服务里设置EnvironmentOLLAMA_NUM_PARALLEL4重启服务后生效。但调到4之后又出现了新问题显存不够模型加载失败。用nvidia-smi一看显存占满了。这时候要么换更小的模型要么降低并行数。我的选择是换模型从14B换到7B量化从8位换到4位显存占用从20G降到8G并行数就能开到4了。这里的关键是并发能力和模型大小是矛盾的一百人共学场景下7B模型加4位量化是性价比最高的选择。4.2 RAG检索答非所问命中率低这个问题困扰了我很久。用户问“RAG的切块策略怎么选”模型回答的却是“RAG的定义是什么”。排查下来发现两个原因一是切块太大一个块里包含了好几个主题检索时匹配到了块但匹配不到具体答案二是向量模型对中文支持不好语义相似度算不准。解决方法是重新切块加换向量模型。切块从1024token改成512token重叠从64改成128。向量模型从all-minilm换成nomic-embed-text。改完之后重新索引命中率从60%提升到85%。这里有个经验切块大小不是越小越好太小了上下文不完整模型没法基于片段回答。512token是个比较平衡的值大概相当于300-400个汉字能容纳一个完整的知识点。4.3 知识库更新后检索不到新内容有一次我上传了一批新的课程资料但用户提问时模型还是用旧资料回答。排查发现是Chroma的索引没有更新。Open WebUI在上传文档后会异步做向量化如果文档多向量化需要时间。而且如果向量化过程中有错误它不会报错只是静默失败。解决方法是上传后手动触发重新索引并且在Chroma的日志里确认向量数量增加了。还有一个坑是文档格式。Open WebUI支持PDF、Word、Markdown等格式但PDF的解析质量参差不齐。扫描版的PDF解析出来是乱码向量化后检索全是噪音。我的建议是尽量用Markdown或纯文本如果必须用PDF先用OCR工具转成文本再上传。4.4 常见问题速查表问题现象可能原因排查方法解决方案请求排队严重并发数太低查看Ollama日志调大OLLAMA_NUM_PARALLEL模型加载失败显存不足nvidia-smi查看显存换小模型或降低量化位数检索答非所问切块太大或向量模型差检查切块大小和向量模型改512token切块换nomic-embed-text新资料检索不到索引未更新查看Chroma向量数量手动触发重新索引PDF解析乱码扫描版PDF检查解析后的文本先用OCR转文本再上传界面卡顿前端资源加载慢浏览器开发者工具用SvelteKit做SSRNginx加缓存5. 一百人共学的运营经验与优化建议5.1 权限分级与账号管理一百个人不能都用同一个账号不然没法追踪谁问了什么。Open WebUI支持多用户管理员可以创建账号、分配角色。我的做法是分三级管理员我和几个助教、普通用户共学成员、只读用户旁听生。管理员可以管理知识库和模型普通用户可以提问和上传资料只读用户只能看不能问。这样既保证了管理可控又不会限制太多。账号创建用批量导入功能Open WebUI支持CSV导入把一百个人的邮箱和初始密码整理成CSV一键导入。导入后强制首次登录改密码避免弱密码问题。5.2 高频问题的沉淀与知识库迭代共学项目运行两周后我导出了所有对话记录统计了高频问题。排名前十的问题占了总提问量的40%比如“RAG是什么”“怎么调Ollama的并发”“知识库怎么更新”。这些问题我整理成FAQ文档补充进知识库并且把系统提示词改成“优先从知识库检索答案”。改完之后重复问题的回答速度明显提升因为模型直接命中知识库不需要重新推理。这个迭代过程很重要。知识库不是一次建好就完事要根据实际提问不断补充。我建议每周导出一次对话记录分析高频问题更新知识库。这样知识库会越来越准模型的负担也越来越轻。5.3 成本与性能的平衡一百人共学如果全用云端API按每人每天问20个问题、每个问题消耗1000token算一天就是200万token一个月6000万token按主流API的价格一个月要好几千块。本地部署虽然前期投入硬件但后续几乎零成本。我的硬件配置是一台二手服务器32G内存一张24G显存的显卡总投入不到一万块跑一年就回本了。性能方面7B模型加4位量化在24G显存上跑4并发响应时间在2-3秒左右对于共学场景完全够用。如果追求更快的响应可以上14B模型加8位量化但并发数要降到2而且需要更大的显存。我的建议是先用7B跑起来根据实际体验再决定要不要升级。5.4 后续扩展方向这套架构目前跑得挺稳但还有几个可以优化的方向。一是加缓存对于高频问题把答案缓存起来下次同样的问题直接返回缓存不走模型推理能大幅降低延迟。二是加监控用Prometheus加Grafana监控Ollama的请求量、响应时间、显存占用提前发现瓶颈。三是加Agent能力让模型能调用外部工具比如查课程表、查作业提交情况这样共学项目的自动化程度会更高。关键词里提到的“agentic rag”“agentscope 2.0 rag as service”这些方向我也在关注等这套基础架构稳定了可以考虑引入更高级的RAG方案。但现阶段稳定压倒一切先把一百个人的共学跑顺了再说。最后分享一个小技巧Open WebUI的模型列表可以自定义排序和分组把常用的模型放在最前面把向量模型隐藏起来这样用户界面更清爽不会因为模型太多而困惑。这个设置虽然小但对用户体验的提升很明显。