逆元装置 ▍ INVERSION

丽·芙

CONSTRUCT — LIV
▍
意识海深度 · 回廊稳定
逆元装置 · 待机中
指挥官链接 · 未认证

从OpenWebUI到校园定制:RAG知识库私有化部署与角色权限改造

公開日: 2026-06-15 00:00 1603文字 9 min read

この投稿は「日本語」では表示できません。元の投稿を表示しています。
基于OpenWebUI源码进行校园场景改造的工程技术笔记——如何隐藏开发者入口、设计访客临时会话、部署本地Ollama服务和构建校园RAG知识库。

改造的起点:OpenWebUI 是什么

OpenWebUI 是目前最活跃的开源 LLM 聊天界面之一,提供了一套完整的功能栈:多模型支持(Ollama + OpenAI API)、文档上传与 RAG 检索、聊天历史管理、用户权限系统、插件市场。

但对于校园场景,这套功能太”重”了。普通学生不需要 Workspace、Models、Prompts、Functions、Pipelines——他们只需要一个干净的对话框。

改造的核心思路是:保留 OpenWebUI 的模型接入和知识库能力,砍掉面向开发者的 UI,换上校园场景的交互。

前端改造:SvelteKit 路由权限分离

OpenWebUI 前端基于 SvelteKit(已迁移到 Svelte 5 runes 语法)。路由结构大致如下:

src/routes/
├── (app)/          # 主应用路由
│   ├── +layout.svelte
│   ├── chat/       # 聊天界面
│   ├── workspace/  # 知识库工作区
│   ├── admin/      # 管理后台
│   └── models/     # 模型管理
└── auth/           # 登录认证

路由守卫实现

通过 SvelteKit 的 +layout.server.ts 实现服务端路由守卫:

// src/routes/(app)/+layout.server.ts
import { redirect } from '@sveltejs/kit'

export const load = async ({ url, locals }) => {
  const user = locals.user
  const isAdminRoute = url.pathname.startsWith('/admin')

  if (isAdminRoute) {
    if (!user || user.role !== 'admin') {
      throw redirect(307, '/auth/admin-login')
    }
  }

  return { user }
}

组件条件渲染

前端导航和侧边栏通过用户角色控制可见性:

<!-- 普通用户只看到极简导航 -->
{#if user?.role === 'admin'}
  <Sidebar>
    <NavItem href="/chat">对话</NavItem>
    <NavItem href="/workspace">知识库</NavItem>
    <NavItem href="/admin">管理后台</NavItem>
  </Sidebar>
{:else}
  <!-- 访客/学生:无侧边栏,仅顶部最小导航 -->
  <MinimalHeader>
    <span>ZCST Campus AI</span>
    <AdminLoginLink />
  </MinimalHeader>
{/if}

改造原则:不删除代码,而是用条件渲染隐藏。这样后续升级 OpenWebUI 时,只需合并路由和布局文件,不会丢失功能。

后端鉴权:FastAPI 中间件

前端隐藏只是第一层。后端必须独立鉴权——不能假设”用户看不到按钮就调不到 API”:

# backend/open_webui/routers/admin.py
from fastapi import Depends, HTTPException

async def admin_required(user = Depends(get_current_user)):
    if user.role != "admin":
        raise HTTPException(status_code=403, detail="Admin access required")
    return user

@router.get("/admin/stats")
async def get_stats(user = Depends(admin_required)):
    return get_system_stats()

核心原则:管理员路由 = 前端隐藏 + 后端鉴权。两者缺一不可。

临时会话设计

校园场景和通用聊天工具有个关键差异:不是所有用户都需要被记住。访客(家长、考生、外来人员)应该用完即走;学生日常提问也不需要长期保存上下文。

# backend/open_webui/routers/chats.py

@router.post("/chat/guest")
async def guest_chat(request: ChatRequest):
    session_id = str(uuid.uuid4())
    context = await rag_search(request.message, top_k=5)

    response = await llm.chat(
        messages=[{
            "role": "system",
            "content": f"你是珠海科技学院的校园助手。参考以下资料回答:\n{format_context(context)}"
        }, {
            "role": "user",
            "content": request.message
        }]
    )

    return {
        "session_id": session_id,
        "answer": response,
        "sources": [c.metadata for c in context]
    }

本地模型部署:Ollama

对于校园场景,Ollama 本地部署有几个优势:

  1. 零 API 费用:不需要按 token 付费,对学生和学校预算友好
  2. 数据不外传:所有提问和文档都留在本地服务器上
  3. 离线可用:不依赖外部网络

Docker Compose 一键部署:

# docker-compose.yaml
services:
  zcst-campus-ai:
    build: .
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama

  ollama:
    image: ollama/ollama:latest
    volumes:
      - ollama_data:/root/.ollama
    command: >
      sh -c "ollama serve & sleep 5 && ollama pull qwen2.5:7b && wait"

volumes:
  ollama_data:

模型选型建议

模型参数量最低显存校园场景建议
qwen2.5
7B8GB通用问答,中文表现好
qwen2.5
14B16GB更复杂的推理
llama3.1
8B8GB备选,英文稍优
deepseek-r1
8B8GB需要推理链路的场景

如果服务器资源有限,7B 模型配合 RAG 知识库已能满足大部分校园问答需求。RAG 弥补了小模型在特定领域知识上的不足。

RAG 知识库构建

校园知识库的文档来源多样:PDF 通知、公众号文章(HTML)、新生手册(Word)、招生简章(网页)。OpenWebUI 内置了文档解析和向量化能力,需要做的是组织文档结构:

knowledge_base/
├── 招生就业/
│   ├── 2026年招生简章.pdf
│   └── 历年分数线.pdf
├── 生活服务/
│   ├── 食堂窗口指南.md
│   ├── 宿舍管理规定.pdf
│   └── 校园交通指南.md
├── 学习支持/
│   ├── 图书馆使用指南.pdf
│   └── 创新创业基地入驻流程.md
└── 办事指南/
    ├── 学生证补办流程.md
    └── 校园卡充值方式.md

分目录管理的好处是:RAG 检索时可以按目录过滤,学生问”食堂”相关问题时优先检索生活服务下的文档,避免被创新创业、招生等内容干扰。

安全清单

校园场景的 AI 助手面临几个特殊风险:

风险措施
Prompt injection(越狱)System prompt 中强调”仅回答校园相关问题”,拒绝执行代码、角色扮演
知识库投毒仅管理员可上传文档,上传后需要审核才能索引
Cookie/Token 泄露访客 token 设短过期时间(30分钟),不具管理员权限
敏感信息外泄学校内部文件不上传知识库,仅索引已公开的校园资料
模型幻觉所有回答标注知识来源,不确定的信息明确告知”建议咨询相关部门”

对我自己的启发

做这个改造最大的收获,反而不是技术上的。

从 OpenWebUI 到 ZCST Campus AI,本质上做的是减法——不是加功能,而是把不需要的藏起来;不是搞万能 AI,而是让它专注做好一件事。SvelteKit 的路由守卫、FastAPI 的中间件鉴权、Docker Compose 的一键部署——这些技术手段本身不复杂,难的是做出”砍什么、留什么”的判断。

之前做始影琯朗的时候,设计思路是”加”——十个角色、多层记忆、消息总线,恨不得把所有能力都塞进去。而校园助手让我学会了”减”——一个学生打开页面,不需要知道什么是 RAG、什么是向量检索、什么是模型路由。他只需要问”食堂几点开门”,然后得到一个靠谱的答案。

这大概是做产品和技术最大的区别:技术让我们能做什么,产品让我们知道不做什么。

如果你也在做类似的校园或者企业内部 AI 助手改造,希望这篇文章能提供一些参考。