🚰 管道函数:创建自定义“代理/模型”
欢迎阅读关于在 Open WebUI 中创建管道的指南!可以将管道理解为向 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 "你好,世界!"
管道类
- 定义:
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 "你好,世界!"
注意:始终将 Valves
放在 Pipe
类的顶部,接着是 __init__
和 pipe
函数。这种结构确保清晰和一致性。
使用管道创建多个模型
如果您希望管道在 Open WebUI 中创建多个模型,可以通过在 Pipe
类中定义 pipes
函数或变量来实现。这种设置,非正式地称为分支管道,使您的管道能够表示多个模型。
示例如下:
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}: 你好,世界!"
说明
-
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 :]
# 更新 body 中的模型 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()
如果 body 中的 "stream" 为 True:
return r.iter_lines()
else:
return r.json()
except Exception as e:
return f"错误: {e}"
详细说明
Valves 配置
NAME_PREFIX
:- 为 Open WebUI 显示的模型名称添加前缀。
- 默认值:
"OPENAI/"
。
OPENAI_API_BASE_URL
:- 指定 OpenAI API 的基础 URL。
- 默认值:
"https://api.openai.com/v1"
。
OPENAI_API_KEY
:- 用于认证的 OpenAI API 密钥。
- 默认值:
""
(空字符串,需提供)。
pipes
方法
-
用途: 获取可用的 OpenAI 模型并在 Open WebUI 中显示。
-
处理流程:
- 检查 API 密钥: 确保提供了 API 密钥。
- 获取模型: 使用 GET 请求从 OpenAI API 获取可用的模型。
- 过滤模型: 返回
id
中包含"gpt"
的模型。 - 错误处理: 如果出现问题,返回错误信息。
-
返回格式: 带有每个模型
id
和name
的字典列表。
pipe
方法
-
用途: 处理对选定 OpenAI 模型的请求并返回响应。
-
参数:
body
: 包含请求数据。__user__
: 包含用户信息(在此示例中未使用,但可用于认证或日志记录)。
-
处理流程:
- 准备请求头: 设置带有 API 密钥和内容类型的请求头。
- 提取模型 ID: 从选定的模型名称中提取实际模型 ID。
- 准备有效数据: 使用正确的模型 ID 更新 body。
- 发送 API 请求: 向 OpenAI API 的聊天完成端点发送 POST 请求。
- 处理流数据: 如果
stream
是True
,返回可迭代的行。 - 错误处理: 捕获异常并返回错 误信息。
扩展代理管道功能
您可以通过调整在 pipes
和 pipe
方法中的 API 端点、请求头以及逻辑,来支持其他服务提供商(如 Anthropic、Perplexity 等)。
使用内部 Open WebUI 功能
有时,您可能需要在管道中使用 Open WebUI 的内部功能。您可以直接从 open_webui
包导入这些功能。请注意,虽然这种更改可能性较小,但内部功能可能会因优化而发生变化,因此请始终参考最新文档。
以下是如何使用内部 Open WebUI 功能的示例:
from pydantic import BaseModel, Field
from fastapi import Request
from open_webui.models.users import Users
从 open_webui.utils.chat 导入 generate_chat_completion
类 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)
解释
-
导入内容:
- 从
open_webui.models.users
导入Users
:用于获取用户信息。 - 从
open_webui.utils.chat
导入generate_chat_completion
:使用内部逻辑生成聊天完成内容。
- 从
-
异步
pipe
函数:- 参数:
body
:模型的输入数据。__user__
:包含用户信息的字典。__request__
:FastAPI 的请求对象(generate_chat_completion
需要)。
- 处理流程:
- 获取用户对象:通过用户 ID 检索用户对象。
- 设置模型:指定要使用的模型。
- 生成完成内容:调用
generate_chat_completion
处理输入并生成输出。
- 参数:
重要提示
- 函数签名:请参考最新的 Open WebUI 代码库或文档以获取最准确的函数签名和参数。
- 最佳实践:始终妥善处理异常和错误,以确保用户体验流畅。
常见问题
问题 1:为什么要在 Open WebUI 中使用管道(Pipes)?
回答:Pipes 允许您通过自定义逻辑和处理为 Open WebUI 添加新的“模型”。它是一个灵活的插件系统,可以让您集成外部 API,自定义模型行为,以及在不修改核心代码库的情况下创建创新功能。
问题 2:什么是阀门(Valves),为什么它们很重要?
回答:Valves 是您 Pipe 的可配 置参数。它们类似于设置或者控制项,用于决定 Pipe 的运行方式。通过调整 Valves,您可以改变 Pipe 的行为,而无需修改底层代码。
问题 3:可以创建没有 Valves 的 Pipe 吗?
回答:是的,如果您的 Pipe 不需要任何持久化配置选项,您可以创建一个简单的没有 Valves 类的 Pipe。但是,包括 Valves 是为了更灵活和具备未来可扩展性的良好实践。
问题 4:使用 API 密钥时,如何确保 Pipe 的安全性?
回答:不要将敏感信息(例如 API 密钥)硬编码到您的 Pipe 中。相反,使用 Valves 来安全输入和存储 API 密钥。确保代码恰当地处理这些密钥,避免记录或暴露它们。
问题 5:pipe
和 pipes
函数之间有什么区别?
回答:
-
pipe
函数:处理输入数据并生成输出的主要函数。它处理单个模型的逻辑。 -
pipes
函数:允许您的 Pipe 表示多个模型,通过返回一个模型定义列表。每个模型将在 Open WebUI 中单独显示。
问题 6:如何在 Pipe 中处理错误?
回答:在 pipe
和 pipes
函数中使用 try-except 块捕获异常。返回有意义的错误信息或者优雅地处理错误,以确保用户可以了解问题所在。
问题 7:可以在 Pipe 中使用外部库吗?
回答:可以。根据需要导入和使用外部库。确保任何依赖项已在您的环境中正确安装和管理。
问题 8:如何测试我的 Pipe?
回答:通过在开发环境中运行 Open WebUI 并从界面中选择您的自定义模型来测试您的 Pipe。验证您的 Pipe 在各种输入和配置下是否按照预期运行。
问题 9:关于组织 Pipe 代码,有哪些最佳实践?
回答:以下是一些建议:
- 将
Valves
放在您的Pipe
类的顶部。 - 使用
__init__
方法初始化变量,尤其是self.valves
。 - 将
pipe
函数放在__init__
方法之后。 - 使用清晰且描述性的变量名。
- 添加代码注释以增加清晰度。
问题 10:在哪里可以找到最新的 Open WebUI 文档?
回答:访问官方 Open WebUI 仓库或文档网站,以获取最及时的信息,包括函数签名、示例以及可能的迁移指南。
总结
现在,您应该已经彻底了解如何在 Open WebUI 中创建和使用 Pipes。Pipes 提供了一种强大的方式来扩展和定制 Open WebUI 的功能,以满足您的特定需求。无论是集成外部 API、添加新模型,还是注入复杂逻辑,Pipes 都提供了实现这些功能的灵活性。
请记住:
- 在 Pipe 类中使用清晰且一致的结构。
- 利用 Valves 来实现可配置选项。
- 优雅地处理错误 以提升用户体验。
- 查阅最新的文档以获取更新或更改的信息。
祝编程愉快,尽情享受使用Pipes扩展您的Open WebUI吧!