Перейти к основному содержимому

🚰 Функция 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.

  • Процесс:

    1. Проверка API-ключа: Удостоверяется, что API-ключ предоставлен.
    2. Получение моделей: Выполняет GET-запрос к API OpenAI для получения доступных моделей.
    3. Фильтрация моделей: Возвращает модели, в которых в id присутствует "gpt".
    4. Обработка ошибок: В случае проблемы возвращает сообщение об ошибке.
  • Формат возврата: Список словарей с id и name для каждой модели.

Функция pipe

  • Цель: Обрабатывает запрос к выбранной модели OpenAI и возвращает ответ.

  • Параметры:

    • body: Содержит данные запроса.
    • __user__: Содержит информацию о пользователе (не используется в данном примере, но может быть полезна для аутентификации или логгирования).
  • Процесс:

    1. Подготовка заголовков: Настраивает заголовки с API-ключом и типом контента.
    2. Извлечение идентификатора модели: Извлекает фактический идентификатор модели из имени модели.
    3. Подготовка данных: Обновляет тело запроса с корректным идентификатором модели.
    4. Выполнение API-запроса: Отправляет POST-запрос к конечной точке чата API OpenAI.
    5. Обработка потоков: Если stream равен True, возвращает итератор строк.
    6. Обработка ошибок: Обрабатывает исключения и возвращает сообщение об ошибке.

Расширение 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).
    • Процесс:
      1. Получение объекта пользователя: Извлекает объект пользователя с использованием его ID.
      2. Установка модели: Указывает модель, которая будет использоваться.
      3. Генерация завершения: Вызывает generate_chat_completion для обработки входных данных и создания выходных.

Важные примечания

  • Сигнатуры функций: Обратитесь к последнему исходному коду Open WebUI или документации для наиболее точных сигнатур функций и параметров.
  • Лучшие практики: Всегда аккуратно обрабатывайте исключения и ошибки, чтобы обеспечить плавный пользовательский опыт.

Часто задаваемые вопросы

В1: Почему я должен использовать Pipe в Open WebUI?

О: Pipe позволяет вам добавлять новую "модель" с пользовательской логикой и обработкой в Open WebUI. Это гибкая система плагинов, которая позволяет интегрировать внешние API, настраивать поведение моделей и создавать инновационные функции без изменения основного кода.


В2: Что такое Valves и почему они важны?

О: Valves — это настраиваемые параметры вашего Pipe. Они функционируют как настройки или элементы управления, определяющие, как работает ваш Pipe. Настраивая Valves, вы можете изменять поведение Pipe без модификации базового кода.


В3: Могу ли я создать Pipe без Valves?

О: Да, вы можете создать простой Pipe без определения Valves, если вашему Pipe не требуются никакие параметры конфигурации. Однако добавление Valves — это хорошая практика для гибкости и масштабируемости в будущем.


В4: Как я могу убедиться, что мой Pipe безопасен при использовании API-ключей?

О: Никогда не прописывайте конфиденциальную информацию, например API-ключи, напрямую в код Pipe. Вместо этого используйте Valves для ввода и безопасного хранения API-ключей. Убедитесь, что ваш код обрабатывает эти ключи соответствующим образом и избегает их логирования или утечки.


В5: В чем разница между функциями pipe и pipes?

О:

  • Функция pipe: Основная функция, где обрабатываются входные данные и генерируется выход. Она отвечает за логику для одной модели.

  • Функция pipes: Позволяет вашему Pipe представлять несколько моделей, возвращая список определений моделей. Каждая модель будет представлена отдельно в Open WebUI.


В6: Как обработать ошибки в моем Pipe?

О: Используйте блоки try-except внутри своих функций pipe и pipes, чтобы перехватывать исключения. Возвращайте понятные сообщения об ошибке или обработайте ошибки таким образом, чтобы пользователи понимали, что произошло.


В7: Могу ли я использовать внешние библиотеки в своем Pipe?

О: Да, вы можете импортировать и использовать внешние библиотеки по мере необходимости. Убедитесь, что все зависимости правильно установлены и управляются в вашей среде.


В8: Как протестировать мой Pipe?

О: Тестируйте ваш Pipe, запуская Open WebUI в среде разработки и выбирая вашу кастомную модель в интерфейсе. Убедитесь, что Pipe ведет себя ожидаемым образом с различными входными данными и настройками.


В9: Есть ли лучшие практики организации кода моего Pipe?

О: Да, следуйте этим рекомендациям:

  • Разместите Valves в верхней части класса Pipe.
  • Инициализируйте переменные в методе __init__, в первую очередь self.valves.
  • Разместите функцию pipe после метода __init__.
  • Используйте четкие и описательные имена переменных.
  • Комментируйте ваш код для обеспечения ясности.

В10: Где я могу найти последнюю документацию Open WebUI?

О: Посетите официальный репозиторий или сайт документации Open WebUI для получения самой свежей информации, включая сигнатуры функций, примеры и руководства по миграции, если произошли изменения.


Заключение

К настоящему моменту вы должны иметь полное представление о том, как создавать и использовать Pipe в Open WebUI. Pipe предоставляет мощный способ расширения и настройки возможностей Open WebUI в соответствии с вашими конкретными потребностями. Независимо от того, интегрируете ли вы внешние API, добавляете новые модели или вводите сложную логику, Pipe предоставляет необходимую гибкость.

Не забывайте:

  • Использовать четкую и последовательную структуру в ваших классах Pipe.
  • Использовать Valves для настраиваемых опций.
  • Аккуратно обрабатывать ошибки для улучшения пользовательского опыта.
  • Ознакомьтесь с последней документацией, чтобы узнать об обновлениях или изменениях.

Приятного программирования и наслаждайтесь расширением вашего Open WebUI с помощью Pipes!