☰
百人共学AI应用开发:Open WebUI+Ollama+RAG架构实战
2026/9/30 15:22:29 网站建设 项目流程

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_PARALLEL=4 export OLLAMA_MAX_LOADED_MODELS=2 export OLLAMA_KEEP_ALIVE=30m

OLLAMA_NUM_PARALLEL=4表示同时处理4个请求,OLLAMA_MAX_LOADED_MODELS=2表示最多同时加载2个模型(比如一个聊天模型加一个向量模型),OLLAMA_KEEP_ALIVE=30m表示模型在最后一次使用后保持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_URL=http://host.docker.internal:11434 - WEBUI_SECRET_KEY=your-secret-key-here - DEFAULT_LOCALE=zh-CN extra_hosts: - "host.docker.internal:host-gateway" restart: unless-stopped

这个配置里几个关键点:OLLAMA_BASE_URL指向宿主机上的Ollama服务,extra_hosts是为了让容器能访问宿主机的host.docker.internal,DEFAULT_LOCALE=zh-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服务里设置Environment="OLLAMA_NUM_PARALLEL=4",重启服务后生效。

但调到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做SSR,Nginx加缓存

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的模型列表可以自定义排序和分组,把常用的模型放在最前面,把向量模型隐藏起来,这样用户界面更清爽,不会因为模型太多而困惑。这个设置虽然小,但对用户体验的提升很明显。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询