🚰 管道函数:创建自定义“代理/模型”
欢迎来到本指南,我们将介绍如何在 Open WebUI 中创建管道(Pipes)。可以将管道视为一种向 Open WebUI 添加新模型的方式。本文档将详细解释什么是管道、它是如何工作的,以及如何创建自己的管道以向 Open WebUI 模型添加自定义逻辑和处理过程。我们将使用清晰的比喻并逐步讲解每一个细节,确保你能够全面理解。
管道简介
想象一下,Open WebUI 就像一个管道系统,数据通过管道和阀门流动。在这个类比中:
- 管道就像插件,允许你引入新的数据流动路径,从而可以注入自定义逻辑和处理过程。
- 阀门是管道中的可配置部分,控制数据如何流经管道。
通过创建一个管道,你实际上是在构建一个具有特定行为的自定义模型,所有这些都在 Open WebUI 框架内完成。
理解管道结构
让我们从一个基本的管道版本开始,了解其结构:
from pydantic import BaseModel, Field
class Pipe:
class Valves(BaseModel):
MODEL_ID: str = Field(default="")
def __init__(self):
self.valves = self.Valves()
def pipe(self, body: dict):
# 逻辑代码写在这里
print(self.valves, body) # 这将打印配置选项和输入体
return "Hello, World!"
管道类
- 定义:
Pipe
类是你定义自定义逻辑的地方。 - 用途: 作为插件的蓝图,决定了它在 Open WebUI 中的行为。
阀门:配置你的管道
- 定义:
Valves
是Pipe
类中的一个嵌套类,继承自BaseModel
。 - 用途: 包含跨管道使用的配置选项(参数)。
- 示例: 在上面的代码中,
MODEL_ID
是一个默认为空字符串的配置选项。
比喻: 可以把阀门想象成现实世界中的管道系统的旋钮,控制水流的方向。在你的管道中,阀门允许用户调整设置,影响数据的流动和处理方式。
__init__
方法
- 定义:
Pipe
类的构造方法。 - 用途: 初始化管道的状态并设置必要的组件。
- 最佳实践: 保持简洁;主要在这里初始 化
self.valves
。
def __init__(self):
self.valves = self.Valves()
pipe
函数
- 定义: 核心函数,包含你的自定义逻辑。
- 参数:
body
: 包含输入数据的字典。
- 用途: 使用自定义逻辑处理输入数据,并返回结果。
def pipe(self, body: dict):
# 逻辑代码写在这里
print(self.valves, body) # 这将打印配置选项和输入体
return "Hello, World!"
注意: 始终将 Valves
放在 Pipe
类的顶部,接着是 __init__
方法,然后是 pipe
函数。这种结构确保了清晰和一致性。
使用管道创建多个模型
如果你希望你的管道能在 Open WebUI 中创建多个模型,可以通过在 Pipe
类中定义一个 pipes
函数或变量来实现。这种设置通常被称为多通路(manifold),允许你的管道 代表多个模型。
以下是具体做法:
from pydantic import BaseModel, Field
class Pipe:
class Valves(BaseModel):
MODEL_ID: str = Field(default="")
def __init__(self):
self.valves = self.Valves()
def pipes(self):
return [
{"id": "model_id_1", "name": "model_1"},
{"id": "model_id_2", "name": "model_2"},
{"id": "model_id_3", "name": "model_3"},
]
def pipe(self, body: dict):
# 逻辑代码写在这里
print(self.valves, body) # 打印配置选项和输入体
model = body.get("model", "")
return f"{model}: Hello, World!"
解释
-
pipes
函数:- 返回一个字典列表。
- 每个字典代表一个带有唯一
id
和name
键的模型。 - 这些模型将在 Open WebUI 的模型选择器中单独显示。
-
更新后的
pipe
函数:- 根据选定的模型处理输入。
- 在这个例子中,它会在返回的字符串中包含模型名称。
示例:OpenAI 代理管道
接下来,我们来看一个实际的例子,创建一个代理请求到 OpenAI API 的管道。该管道将获取可用的 OpenAI 模型 ,并允许用户通过 Open WebUI 与它们交互。
from pydantic import BaseModel, Field
import requests
class Pipe:
class Valves(BaseModel):
NAME_PREFIX: str = Field(
default="OPENAI/",
description="在模型名称前添加的前缀。",
)
OPENAI_API_BASE_URL: str = Field(
default="https://api.openai.com/v1",
description="访问 OpenAI API 端点的基本 URL。",
)
OPENAI_API_KEY: str = Field(
default="",
description="用于认证请求到 OpenAI API 的 API 密钥。",
)
def __init__(self):
self.valves = self.Valves()
def pipes(self):
if self.valves.OPENAI_API_KEY:
try:
headers = {
"Authorization": f"Bearer {self.valves.OPENAI_API_KEY}",
"Content-Type": "application/json",
}
r = requests.get(
f"{self.valves.OPENAI_API_BASE_URL}/models", headers=headers
)
models = r.json()
return [
{
"id": model["id"],
"name": f'{self.valves.NAME_PREFIX}{model.get("name", model["id"])}',
}
for model in models["data"]
if "gpt" in model["id"]
]
except Exception as e:
return [
{
"id": "error",
"name": "获取模型时出错。请检查您的 API 密钥。",
},
]
else:
return [
{
"id": "error",
"name": "未提供 API 密钥。",
},
]
def pipe(self, body: dict, __user__: dict):
print(f"pipe:{__name__}")
headers = {
"Authorization": f"Bearer {self.valves.OPENAI_API_KEY}",
"Content-Type": "application/json",
}
# 从模型名称中提取模型 ID
model_id = body["model"][body["model"].find(".") + 1:]
# 更新请求体中的模型 ID
payload = {**body, "model": model_id}
try:
r = requests.post(
url=f"{self.valves.OPENAI_API_BASE_URL}/chat/completions",
json=payload,
headers=headers,
stream=True,
)
r.raise_for_status()
if body.get("stream", False):
return r.iter_lines()
else:
return r.json()
except Exception as e:
return f"错误: {e}"
详细分解
阀门配置
NAME_PREFIX
:- 在 Open WebUI 中显示的模型名称前添加前缀。
- 默认值:
"OPENAI/"
。
OPENAI_API_BASE_URL
:- 指定 OpenAI API 的基本 URL。
- 默认值:
"https://api.openai.com/v1"
。
OPENAI_API_KEY
:- 用于认证请求到 OpenAI API 的 API 密钥。
- 默认值:
""
(空字符串;必须提供)。
pipes
函数
-
用途: 获取可用的 OpenAI 模型并在 Open WebUI 中展示。
-
流程:
- 检查 API 密钥: 确保提供了 API 密钥。
- 获取模型: 发起 GET 请求到 OpenAI API 获取可用模型。
- 过滤模型: 返回 ID 中包含
"gpt"
的模型。 - 错误处理: 如果有问题,返回错误信息。
-
返回格式: 包含每个模型的
id
和name
的字典列表。
pipe
函数
-
用途: 处理对选定 OpenAI 模型的请求并返回响应。
-
参数:
body
: 包含请求数据的字典。__user__
: 包含用户信息的字典(在此示例中未使用,但可用于身份验证或日志记录)。
-
流程:
- 准备头部信息: 设置包含 API 密钥和内容类型的头部信息。
- 提取模型 ID: 从选定的模型名称中提取实际的模型 ID。
- 准备负载: 更新请求体中的正确模型 ID。
- 发起 API 请求: 向 OpenAI API 的聊天补全端点发送 POST 请求。
- 处理流式传输: 如果
stream
为True
,则返回行迭代器。 - 错误处理: 捕获异常并返回错误消息。
扩展代理管道
你可以修改此代理管道,支持其他服务提供商如 Anthropic、Perplexity 等,只需调整 API 端点、头部信息和 pipes
和 pipe
函数中的逻辑即可。
使用内部 Open WebUI 函数
有时,你可能希望在管道中直接使用 Open WebUI 的内部函数。你可以从 open_webui
包中导入这些函数。请注意,虽然不太可能,但内部函数可能会因优化目的而发生变化,因此始终参考最新的文档。
以下是如何使用内部 Open WebUI 函数的方法:
from pydantic import BaseModel, Field
from fastapi import Request
from open_webui.models.users import Users
from open_webui.utils.chat import generate_chat_completion
class Pipe:
def __init__(self):
pass
async def pipe(
self,
body: dict,
__user__: dict,
__request__: Request,
) -> str:
# 使用更新后的签名调用统一端点
user = Users.get_user_by_id(__user__["id"])
body["model"] = "llama3.2:latest"
return await generate_chat_completion(__request__, body, user)
解释
-
导入:
Users
来自open_webui.models.users
: 用于获取用户信息。generate_chat_completion
来自open_webui.utils.chat
: 用于使用内部逻辑生成聊天补全。
-
异步
pipe
函数:- 参数:
body
: 模型的输入数据。__user__
: 包含用户信息的字典。__request__
: FastAPI 的请求对象(由generate_chat_completion
需要)。
- 流程:
- 获取用户对象: 使用用户 ID 获取用户对象。
- 设置模型: 指定要使用的模型。
- 生成补全: 调用
generate_chat_completion
处理输入并生成输出。
- 参数:
重要提示
- 函数签名: 参考最新的 Open WebUI 代码库或文档以获取最准确的函数签名和参数。
- 最佳实践: 始终优雅地处理异常和错误,以确保用户体验顺畅。