🚰 Функция Pipe: Создайте собственных "агентов/модели"
Добро пожаловать в этот гид по созданию Pipe в Open WebUI! Представьте Pipe как способ добавления новой модели в Open WebUI. В этом документе мы расскажем, что такое Pipe, как он работает и как создать свой собственный, добавив индивидуальную л огику и обработку в модели Open WebUI. Мы будем использовать ясные метафоры и подробно объяснять каждый шаг, чтобы вы получили полное понимание.
Введение в Pipe
Представьте Open WebUI как систему водопровода, где данные текут через трубы и клапаны. В этой аналогии:
- Трубы (Pipes) — это как плагины, которые позволяют внедрять новые пути для передачи данных, добавляя собственную логику и обработку.
- Клапаны (Valves) — это настраиваемые части трубы, контролирующие поток данных через неё.
Создавая Pipe, вы фактически создаёте индивидуальную модель с нужным поведением в рамках Open WebUI.
Структура Pipe
Начнем с базового, минимального варианта Pipe, чтобы понять его структуру:
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
- Определение: Класс
Pipe
— это место, где определяется ваша собственная логика. - Цель: Служит чертежом для вашего плагина, определяя его поведение в Open WebUI.
Valves: Настройка трубы
- Определение:
Valves
— вложенный класс внутриPipe
, наследуемый отBaseModel
. - Цель: Содержит параметры конфигурации (переменные), которые сохраняются при использовании вашего Pipe.
- Пример: В приведенном выше коде
MODEL_ID
— это параметр конфигурации с пустой строкой по умолчанию.
Метафора: Представьте клапаны как ручки на трубопроводной системе, контролирующие поток воды. В вашем Pipe клапаны позволяют пользователям регулировать настройки, влияющие на поток данных и обработку.
Метод __init__
- Определение: Конструктор класса
Pipe
. - Цель: Инициализирует состояние 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
. Такая структура обеспечивает ясность и последовательность.
Создание нескольких моделей с помощью Pipe
Что, если вы хотите создать несколько моделей с помощью Pipe в Open WebUI? Вы можете добиться этого, задав функцию или переменную pipes
внутри вашего класса Pipe
. Эта настройка, неформально называемая манифолд, позволяет вашему Pipe представлять несколько моделей.
Вот как это делается:
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 Proxy Pipe
Теперь рассмотрим практический пример, в котором мы создадим Pipe, проксирующий запросы к API OpenAI. Этот Pipe будет извлекать доступные модели из 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="Базовый URL для доступа к конечным точкам API OpenAI.",
)
OPENAI_API_KEY: str = Field(
default="",
description="Ключ API для аутентификации запросов к API OpenAI.",
)
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",
}
# Извлечение идентификатора модели из имени модели
model_id = body["model"][body["model"].find(".") + 1 :]
# Обновление идентификатора модели в теле запроса
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}"
Детальный разбор
Конфигурация Valves
NAME_PREFIX
:- Добавляет префикс к именам моделей, отображаемым в Open WebUI.
- По умолчанию:
"OPENAI/"
.
OPENAI_API_BASE_URL
:- Указывает базовый URL для API OpenAI.
- По умолчанию:
"https://api.openai.com/v1"
.
OPENAI_API_KEY
:- Ваш API-ключ для аутентификации.
- По умолчанию:
""
(пустая строка; должен быть указан).
Функция pipes
-
Цель: Получает доступные модели OpenAI и делает их доступными в Open WebUI.
-
Процесс:
- Проверка API-ключа: Удостоверяется, что API-ключ предоставлен.
- Получение моделей: Выполняет GET-запрос к API OpenAI для получения доступных моделей.
- Фильтрация моделей: Возвращает модели, в которых в
id
присутствует"gpt"
. - Обработка ошибок: В случае проблемы возвращает сообщение об ошибке.
-
Формат возврата: Список словарей с
id
иname
для каждой модели.
Функция pipe
-
Цель: Обрабатывает запрос к выбранной модели OpenAI и возвращает ответ.
-
Параметры:
body
: Содержит данные запроса.__user__
: Содержит информацию о пользователе (не используется в данном примере, но может быть полезна для аутентификации или логгирования).
-
Процесс:
- Подготовка заголовков: Настраивает заголовки с API-ключом и типом контента.
- Извлечение идентификатора модели: Извлекает фактический идентификатор модели из имени модели.
- Подготовка данных: Обновляет тело запроса с корректным идентификатором модели.
- Выполнение API-запроса: Отправляет POST-запрос к конечной точке чата API OpenAI.
- Обработка потоков: Если
stream
равенTrue
, возвращает итератор строк. - Обработка ошибок: Обрабатывает исключения и возвращает сообщение об ошибке.
Расширение Proxy Pipe
Вы можете модифицировать этот Proxy Pipe для поддержки дополнительных поставщиков услуг, таких как Anthropic, Perplexity и другие, настраивая конечные точки API, заголовки и логику в функциях pipes
и pipe
.
Использование внутренних функций Open WebUI
Иногда вы можете захотеть использовать внутренние функции Open WebUI в рамках вашего Pipe. Вы можете импортировать эти функции напрямую из пакета 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 или документации для наиболее точных сигнатур функций и параметров.
- Лучшие практики: Всегда аккуратно обрабатывайте исключения и ошибки, чтобы обеспечить плавный пользовательский опыт.