感谢您点开这篇文章:D,鼠鼠我是一个代码小白,下文是学习开源项目Open WebUI过程中的一点笔记记录,希望能帮助到你~
本人菜鸟,持续成长,能力不足有疏漏的地方欢迎一起探讨指正,比心心~
通过本文,您可以了解:
-
Open WebUI项目的基本信息和架构
-
通过ollama部署大模型、通过docker镜像和源码运行Open WebUI项目的方法
-
项目后端代码在多情景(普通提问、联网搜索提问、上传PDF文件且联网提问、上传PDF文件非联网提问)下的相关代码实现逻辑
-
RAG模块实现逻辑流程
目录
一、项目基本信息
二、运行项目源码
1、通过ollama部署大模型
1.1、安装ollma
1.2、配置ollama
1.3、下载模型
1.4、运行服务
命令行直接对话
REST API
2、搭建Open WebUI
2.1、通过docker部署
2.2、通过源码构建
编辑
三、项目结构
1、backend目录(后端代码)
1.1、start.sh
1.2、data目录
1.3、open_webui目录
1.3.1、main.py
中间件(应用于FastAPI应用中)
Task Endpoints
Pipelines Endpoints
Config Endpoints
OAuth Login & Callback
1.3.2、apps目录
1.3.2.1、webui/main.py
1.3.2.2、webui/models(重点,数据库实体)
1.3.2.3、openai/main.py
1.3.2.4、openai/chat_interceptor
1.3.3、retrieval目录
main.py
utils.py
2、src目录(前端代码)
四、特定情景下代码链路逻辑
情景1:用户在界面发送消息时,代码调用逻辑:
情景2:用户进行联网搜索提问“武汉今天天气如何”时,代码调用逻辑:
情景3.1:用户上传PDF文件,让其帮忙总结(联网搜索功能关闭),代码逻辑:
情景3.2:用户上传PDF文件,让其帮忙总结,(联网搜索功能开启),代码逻辑:
五、总结
-
Github:https://github.com/open-webui/open-webui
-
官方文档:https://docs.openwebui.com/getting-started/
-
代码版本:v0.3.32(2024.10.6)——本文学习版本,目前最新版本已更新至v0.3.35(截至2024.10.28)
作者本地环境:Ubuntu24.04,纯CPU
通过ollama部署大模型qwen2:7b作为模型端,通过Open WebUI提供用户chat服务。
ollama是大模型部署方案,对应docker,本质也是基于docker的容器化技术
1.1、安装ollma
官方地址:https://ollama.com/
开源地址:https://github.com/ollama/ollama
打开官网,点击Downloard,根据操作系统选择对应下载方式。
以Ubuntu24.04为例,通过下述命令下载:
如上,ollama已经成功安装。
1.2、配置ollama
通过编辑ollama.service进行配置:
-
更改HOST
由于Ollama的默认参数配置,启动时设置了仅本地访问,因此需要对HOST进行配置,开启监听任何来源IP。
-
更改模型存储路径
默认情况下,不同操作系统大模型存储的路径如下:
如果要修改模型文件的存储路径,设置如下:
如果因为指定的目录ollama用户及用户组没有相应权限,导致服务不能启动。可以通过授权给相应的目录权限解决问题:
-
应用配置
重载systemd并重启Ollama
配置完成后,访问测试。浏览器访问http://IP:11434/,出现Ollama is running代表成功。
1.3、下载模型
ollama的命令和docker操作命令非常相似。可通过shell窗口输入ollama查看相关命令:
由上可知ollama相关命令:
-
拉取qwen2-7b模型
可见,已成功拉取:
也可以自定义模型,所谓自定义模型就是不适用Ollama官方模型库中的模型,理论可以使用其他各类经过转换处理的模型,有从GGUF导入和从PyTorch或Safetensors导入两种方式。
所谓从从PyTorch或Safetensors导入Ollama,其实就是使用llama.cpp项目,对PyTorch或Safetensors类型的模型进行转换、量化处理成GGUF格式的模型,然后再用Ollama加载使用 。
参考:Ollama:一个在本地部署、运行大型语言模型的工具-CSDN博客
-
运行模型
运行模型并进行对话:
1.4、运行服务
命令行直接对话
如上,运行模型可以直接与模型进行对话。
REST API
运行模型后,执行ollama serve命令启动Ollama服务,然后就可以通过API形式进行模型调用。ollama serve会自动启动一个http服务,可以通过http请求模型服务。
参考官方API文档:https://github.com/ollama/ollama/blob/main/docs/api.md
生成回复
上述localhost也可以换成ip。
若要禁用流式,如下操作:
与模型聊天
也可以带历史记录
Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 WebUI,旨在完全离线操作。它支持各种 LLM 运行程序,包括 Ollama 和 OpenAI 兼容的 API。
-
Github:https://github.com/open-webui/open-webui
-
Open WebUI:https://docs.openwebui.com/
-
社区:https://openwebui.com/
2.1、通过docker部署
使用Docker部署安装Open WebUI。计算机已有ollama,使用以下命令:
访问http://IP:3000,创建一个账号(管理员)
登陆账号:
进入Open WebUI后,界面如下。在Settings中进行相关设置
管理员设置,设置外部连接:
设置连接后,在选择模型部分可见上面下载下来的千问模型:
选择模型即可进行对话:
2.2、通过源码构建
也可以通过本地运行项目源码进行搭建。(以Linux为例)
在鼠鼠我多次构建的过程中,有次有遇到一个错误,报错如下:
原因:涉及两方面,一是node.js 版本问题,如下图(官方最新文档要求),目前版本低于要求版本。
另一个方面——文件夹命名问题。原来的项目处于的一个文件夹为“openwebui(v0.3.32)”,其中包含括号和".",在后续代码执行中,由于路径中包含特殊字符(在这个案例中是括号 和 ),导致命令解释错误或者文件系统路径解析出现问题。在文件或目录名称中使用特殊字符,如括号、星号、问号、波浪线等,经常会导致这类问题,因为这些字符在 Unix 和 Linux 命令行中可能有特殊含义。
解决方法:将项目所处的目录进行重命名为“openwebui_v0_3_32”,即可解决。
Q:点击“+”功能只有“上传文件”,没有“联网搜索”,如何解决?
A:需要管理员在面板中进行设置搜索引擎,本质上是通过api调用:
整个代码语言构成分布如下,其中,Svelte 是一种现代的前端框架,用于构建高性能的Web应用程序。
项目文件如下所示,主要分为前端、后端、测试和部署脚本:
-
backend目录:后端代码目录,包含API服务、数据库操作等
-
cypress 目录:包含Cypress测试框架的配置和测试脚本,用于端到端测试
-
docs 目录:文档目录,包含项目说明、安全指南等。
-
kubernetes : 包含Kubernetes部署配置文件。
-
scripts : 包含各种脚本文件,用于自动化部署、测试或其他任务的脚本。
-
src :前端代码目录,存放Svelte组件和相关资源的地方。
-
static : 静态文件目录,如图片、CSS、客户端JavaScript等。
-
test/test_files/image_gen : 测试目录下的子目录,包含用于测试的图像生成器。
-
data文件夹:用于存储后端服务需要的数据文件,如数据库、文档等
-
open-webui文件夹:包含后端服务的主要代码和配置文件
-
dev.sh:用于本地开发环境的启动脚本
-
start.sh 和 start_windows.bat - 用于启动后端服务的脚本,分别适用于类Unix系统和Windows系统。
1.1、start.sh
启动脚本,最后会启动一个 Uvicorn 服务器,并通过这个命令来运行 open-webui/backend/open_webui/main.py 文件中的FastAPI的 app 应用对象,监听在指定的主机和端口上,并允许所有的转发 IP 地址。
1.2、data目录
-
cache - 用于存储应用程序的缓存数据。
-
functions - 包含一些后端服务使用的函数或脚本。
-
tools - 包含一些用于后端服务的工具或脚本。
-
uploads - 用于存储用户上传的文件。
-
vector_db - 用于存储向量数据库或类似的数据结构。
-
readme.txt - 包含文件夹的说明或使用指南。
-
webui.db - 后端服务使用的数据库文件。
1.3、open_webui目录
-
apps - 包含后端服务的应用程序逻辑。
-
data - 与主文件夹类似,用于存储后端服务需要的数据文件。
-
migrations - 包含数据库迁移脚本,用于数据库结构的版本控制。
-
static - 包含静态文件,如图片、CSS、JavaScript等。
-
test - 包含测试代码和测试用例。
-
utils - 包含一些后端服务使用的实用工具或函数。
-
init.py - Python模块初始化文件。
-
alembic.ini - Alembic数据库迁移工具的配置文件。
-
config.py - 后端服务的配置文件。
-
constants.py - 包含后端服务使用的常量。
-
env.py - 包含环境变量的配置。
-
main.py - 是后端服务的入口点或主程序。
1.3.1、main.py
中间件(应用于FastAPI应用中)
- ChatCompletionMiddleware类 :用于处理与聊天补全相关的请求,包括模型选择、过滤函数、工具函数调用和文件处理。
-
PipelineMiddleware类:对请求进行预处理和后处理。处理管道中的过滤器调用。
-
也添加中间件CORSMiddleware、SecurityHeadersMiddleware 以及 PipelineMiddleware 本身,分别负责处理跨域资源共享(CORS)、安全头部设置以及自定义的业务逻辑处理。
设置相关路由
-
@app.get("/api/models") : 用于获取模型的列表
-
@app.post("/api/chat/completed"):完整的聊天补全请求处理流程,包括模型验证、外部API调用、事件处理、全局和本地过滤器调用。
-
@app.post("/api/chat/actions/{action_id}"):用于处理特定动作的请求。它通过执行与动作ID关联的功能来响应聊天中的动作请求
Task Endpoints
路由
作用
GET请求端点/api/task/config
它返回当前应用的状态配置信息
POST请求端点/api/task/config/update
用于更新任务配置。只有管理员用户可以访问此端点,并且需要提供一个符合TaskConfigForm模型的JSON数据体来进行更新操作。
POST请求端点/api/task/title/completions
用于根据给定的提示生成标题
POST请求端点/api/task/query/completions
用于根据用户的对话历史生成搜索查询
POST请求端点/api/task/emoji/completions
用于根据文本内容生成相应的表情符号
POST请求端点/api/task/moa/completions
用于综合多个模型的响应生成最终答案
Pipelines Endpoints
@app.get("/api/pipelines/list"):通过调用get_openai_models函数获取模型列表,然后筛选出包含“pipelines”字段的响应,并返回相应的API URL和索引
Config Endpoints
@app.post("/api/pipelines/upload"):允许用户上传Python脚本文件作为管道。
接下来的几个段落分别定义了添加、删除管道以及获取管道详情等的端点;
并且定义了一系列API端点,用于管理和获取应用程序的配置信息。
OAuth Login & Callback
实现完整的OAuth登录和注册流程,包括客户端注册、会话管理、用户认证和JWT令牌生成等功能。
1.3.2、apps目录
1.3.2.1、webui/main.py
注册了多个路由处理器,处理不同类型api请求,如用户认证、文件上传、模型管理等。
定义相关核心函数:
-
get_status:根路由处理函数,返回应用的状态信息。
-
get_function_module:根据管道ID加载函数模块。
-
get_pipe_models:获取管道模型的详细信息。
-
execute_pipe:执行管道函数。
-
get_message_content:从不同的响应类型中获取消息内容。
-
process_line:处理聊天消息的每一行。
-
get_pipe_id:从表单数据中获取管道ID。
-
get_function_params:获取函数参数。
最后定义函数generate_function_chat_completion,实现聊天补全处理相关逻辑。
1.3.2.2、webui/models(重点,数据库实体)
(未完待续。。。。。。待整理)
1.3.2.3、openai/main.py
-
设置FastAPI应用、Middleware和依赖注入(中间件会在每次请求前执行,确保在访问模型端点之前已经加载了模型数据)。
-
设置api路由:
-
/config:提供了一个GET方法来返回当前的应用程序配置,包括是否启用OpenAI API的功能。
-
/config/update:接受一个POST请求,更新应用程序的配置,特别是启用或禁用OpenAI API的功能。
-
/urls和/keys:分别提供了GET方法来显示当前的OpenAI API URLs和Keys列表,以及POST方法来更新这些列表。
-
/audio/speech:这是一个音频处理的端点,接受用户的语音输入并生成对应的音频文件响应。
-
-
设置异步函数,例如fetch_url, cleanup_response, merge_models_lists, get_all_models_raw, get_all_models等。这些函数主要负责与外部API通信、处理JSON数据、合并模型列表等工作。
1.3.2.4、openai/chat_interceptor
实现一个简单的聊天系统拦截器,可以用于检查和处理特定的情况,例如不支持的URL或过长的上下文文本。
模块
实现
解析用户输入
get_message_text函数:从用户输入中提取文本内容
生成聊天响应
generate_chat_response函数:生成聊天响应,包括生成一个唯一的ID、创建时间、模型名称、选择内容和使用情况
拦截器列表
包含了一系列的拦截器实例
chat_interceptor_before_lark_doc_content和
chat_interceptor_after_lark_doc_content:
分别在处理飞书文档内容之前和之后使用的拦截器列表。
拦截器入口
遍历拦截器列表,并调用每个拦截器的 方法
intercept_chat_completion_before_lark_doc_content和intercept_chat_completion_after_lark_doc_content:
分别是在处理飞书文档内容之前和之后调用的拦截器入口函数。
拦截器类型
-
UnsupportedUrlChatCompletionInterceptor:
检查用户输入中是否包含不支持的URL,如果是,则返回默认回答。
-
LongContextTextChatCompletionInterceptor:
检查用户输入的文本是否过长,如果是,则返回默认回答。
拦截器调用
在发送聊天请求之前或之后,调用拦截器列表中的拦截器,每个拦截器都会检查请求,并决定是否拦截请求。
1.3.3、retrieval目录
-
loaders:从各种来源加载和处理文档内容,适用于需要跨多种文件格式工作的应用场景。
-
models:定义了用于检索任务的模型
-
vector:
-
包含与向量相关的文件,如和,用于处理向量数据库的连接和交互,以及向量化文本数据以用于相似性搜索。
-
文件可能包含与向量检索相关的主要逻辑。
-
-
web:
-
包含多个与Web相关的Python文件,如、等,这些文件用于实现与不同搜索引擎(如Brave Search、DuckDuckGo)的交互,以便从这些搜索引擎获取数据。
-
和文件可能包含Web应用的主要逻辑和辅助功能。
-
目录可能包含用于测试的示例数据。
-
-
utils.py:一个通用的工具文件,包含在整个应用中使用的辅助函数和类。
-
main.py:后端服务入口点,主要用于处理文档检索和向量数据库操作。
(下面的内容是旧版本v0.3.21中rag目录,即对应v0.3.32中retrieval目录,两版本肯定有差异,下面是之前学习旧版本的笔记,仅供参考)
main.py
配置和模型更新
-
定义 和 函数来更新嵌入和重排模型。
-
使用 获取嵌入函数,用于将文本转换为向量表示
API 路由和处理函数
-
定义了多个 API 路由和处理函数,例如:
-
:根路由,返回应用状态。
-
:返回嵌入模型的配置。
-
:返回重排模型的配置。
-
和 :更新嵌入和重排模型的配置。
-
:返回 RAG 应用的配置。
-
:更新 RAG 应用的配置。
-
和 :获取和更新查询模板和设置。
-
和 :处理文档和集合的查询请求。
-
和 :处理 YouTube 视频和网页内容的存储请求。
-
:处理网页搜索请求。
-
文档和网页处理
-
定义了 函数,根据文件类型选择适当的加载器(如 TikaLoader、TextLoader 等)。
-
定义了 和 函数,用于将数据存储到向量数据库中。
错误处理:
-
使用 处理错误情况,并返回错误信息。
辅助函数:
-
定义 、、 等辅助函数,用于加载和验证网页内容。
搜索功能:
-
定义 函数,用于通过不同的搜索引擎进行搜索。
安全加载器:
-
定义 类,用于增强错误处理,确保即使某些 URL 无法访问,系统仍然可以正常工作。
rag模块的作用流程:
utils.py
处理检索增强生成(RAG)任务的函数,主要涉及从不同数据源中提取和查询信息
-
query_doc 函数:用于从一个指定的集合中查询与给定查询最相关的文档。
-
query_doc_with_hybrid_search 函数:扩展了基本的查询功能,引入了混合搜索的概念。它不仅使用BM25Retriever进行初步筛选,还结合了ChromaRetriever进行更精确的搜索,并通过EnsembleRetriever组合两者的结果。此外,它还包括一个重排序步骤,通过RerankCompressor对结果进行进一步优化。
-
merge_and_sort_query_results 函数:用于合并多个查询结果,并对它们按相关性进行排序。它会将所有结果的距离、文档和元数据合并在一起,然后根据距离进行降序或升序排列,最后只保留前K个结果。
-
query_collection 和 query_collection_with_hybrid_search 函数:这两个函数分别实现了基于普通搜索和混合搜索的多集合查询。它们遍历一组集合名称,对每个集合执行相应的查询操作,并将结果合并和排序后返回。
-
rag_template 函数:用于替换模板字符串中的占位符,以便在生成的上下文中插入具体的查询和上下文内容。
-
get_embedding_function 函数:根据不同的嵌入引擎和模型生成对应的嵌入函数。
-
get_rag_context 函数:从文件列表和消息记录中提取与当前查询最相关的上下文。
-
get_model_path 函数:用于确定Hugging Face模型的本地路径。
-
generate_openai_embeddings 和 generate_openai_batch_embeddings 函数:用于调用OpenAI API生成文本的嵌入向量。前者处理单个文本输入,后者则可以处理一批文本输入,适用于批量处理的场景。
-
ChromaRetriever 类和 RerankCompressor 类:分别是LangChain库中原有的Retriever和DocumentCompressor的具体实现。ChromaRetriever负责从Chroma数据库中检索文档,而RerankCompressor则在检索到的文档基础上进行进一步的重排序。
。。。。。。(未完待续,鼠鼠后面有空会继续更新的惹)
-
lib:包含可重用的JavaScript或Svelte组件、工具函数、实用程序等
-
routes:包含Svelte路由文件,用于定义应用程序的页面路由。
-
app.css:包含全局样式表,定义了样式重置、通用样式或主题。
-
app.d.ts:TypeScript的声明文件,用于为项目提供类型定义。
-
app.html:项目的HTML模板文件,通常是应用程序的入口点。
-
tailwind.css:使用Tailwind CSS时的全局样式文件。
(由于前端不是鼠鼠我学习的重点,所以没在看前端部分了)
核心部分:
1、构建prompt和调用大模型:
构建prompt的apply_model_system_prompt_to_body函数细节:
调用大模型的post_streaming_url函数细节:
核心代码:
1、生成搜索查询:
2、执行搜索查询
核心代码:
1、接收处理保存用户上传的PDF文件
2、上述调用的处理文件的函数