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

🛠️ Разработка

Создание пользовательского инструментария

Инструментарий определен в одном файле Python, с верхней строкой документации с метаданными и классом Tools.

Пример верхней строки документации

"""
title: Инверсия строки
author: Ваше Имя
author_url: https://website.com
git_url: https://github.com/username/string-reverse.git
description: Этот инструмент вычисляет инверсию строки
required_open_webui_version: 0.4.0
requirements: langchain-openai, langgraph, ollama, langchain_ollama
version: 0.4.0
licence: MIT
"""

Класс Tools

Инструменты должны быть определены как методы внутри класса Tools, с необязательными подклассами Valves и UserValves, например:

class Tools:
def __init__(self):
"""Инициализация инструмента."""
self.valves = self.Valves()

class Valves(BaseModel):
api_key: str = Field("", description="Ваш ключ API")

def reverse_string(self, string: str) -> str:
"""
Инверсирует входную строку.
:param string: Строка для инверсии
"""
# пример использования клапанов
if self.valves.api_key != "42":
return "Неверный ключ API"
return string[::-1]

Аннотации типов

Каждый инструмент должен иметь аннотации типов для аргументов. Типы могут быть вложенными, такими как queries_and_docs: list[tuple[str, int]]. Эти аннотации типов используются для генерации JSON-схемы, которая отправляется модели. Инструменты без аннотаций типов работают с гораздо меньшей согласованностью.

Клапаны и UserValves - (необязательно, но настоятельно рекомендуется)

Клапаны и UserValves используются для указания настраиваемых настроек инструмента, подробнее о них можно прочитать на специальной странице Valves & UserValves.

Необязательные аргументы

Ниже приведен список необязательных аргументов, от которых могут зависеть ваши инструменты:

  • __event_emitter__: Генерация событий (см. следующий раздел)
  • __event_call__: То же, что и генератор событий, но может использоваться для взаимодействия пользователей
  • __user__: Словарь с информацией о пользователе. Он также содержит объект UserValves в __user__["valves"].
  • __metadata__: Словарь с метаданными чата
  • __messages__: Список предыдущих сообщений
  • __files__: Прикрепленные файлы
  • __model__: Словарь с информацией о модели

Просто добавьте их как аргументы к любому методу вашего класса Tool, как __user__ в приведенном выше примере.

Генераторы событий

Генераторы событий используются для добавления дополнительной информации в интерфейс чата. Аналогично выходным фильтрам, генераторы событий способны добавлять содержимое в чат. В отличие от выходных фильтров, они не способны удалять информацию. Кроме того, генераторы могут быть активированы на любом этапе во время инструмента.

Существует два различных типа генераторов событий:

Если кажется, что модель не может вызвать инструмент, убедитесь, что он включен (либо через страницу модели, либо через знак + рядом с полем ввода чата). Вы также можете изменить параметр Function Calling в разделе Advanced Params на странице модели с Default на Native.

Статус

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

await __event_emitter__(
{
"type": "status", # Здесь мы задаем тип
"data": {"description": "Сообщение, которое отображается в чате", "done": False, "hidden": False},
# Обратите внимание, что done равно False, что указывает на продолжение генерации статусов
}
)
Пример
async def test_function(
self, prompt: str, __user__: dict, __event_emitter__=None
) -> str:
"""
Это демонстрация

:param test: это тестовый параметр
"""

await __event_emitter__(
{
"type": "status", # Здесь мы задаем тип
"data": {"description": "Сообщение, которое отображается в чате", "done": False},
# Обратите внимание, что done равно False, что указывает на продолжение генерации статусов
}
)

# Выполните другую логику здесь
await __event_emitter__(
{
"type": "status",
"data": {"description": "Сообщение о завершении задачи", "done": True, "hidden": False},
# Обратите внимание, что done равно True, что указывает на завершение генерации статусов
# Вы также можете задать "hidden": True, если нужно удалить статус после возврата сообщения
}
)

except Exception as e:
await __event_emitter__(
{
"type": "status",
"data": {"description": f"Произошла ошибка: {e}", "done": True},
}
)

return f"Сообщите пользователю: {e}"

Сообщение

Этот тип используется для добавления сообщения в LLM на любом этапе в инструменте. Это означает, что вы можете добавлять сообщения, вставлять изображения и даже отображать веб-страницы до, после или во время ответа LLM.

await __event_emitter__(
{
"type": "message", # Мы задаем здесь тип
"data": {"content": "Это сообщение будет добавлено в чат."},
# Обратите внимание, что для типа message нам НЕ нужно устанавливать условие done
}
)
Пример
async def test_function(
self, prompt: str, __user__: dict, __event_emitter__=None
) -> str:
"""
Это демонстрация

:param test: это тестовый параметр
"""

await __event_emitter__(
{
"type": "message", # Мы задаем здесь тип
"data": {"content": "Это сообщение будет добавлено в чат."},
# Обратите внимание, что для типа message нам НЕ нужно устанавливать условие done
}
)

except Exception as e:
await __event_emitter__(
{
"type": "status",
"data": {"description": f"Произошла ошибка: {e}", "done": True},
}
)

return f"Сообщите пользователю: {e}"

Ссылки

Этот тип используется для предоставления ссылок или ссылочной информации в чате. Вы можете использовать его, чтобы указать содержание, источник и любые соответствующие метаданные. Ниже приведен пример, как передать событие ссылки:

await __event_emitter__(
{
"type": "citation",
"data": {
"document": [content],
"metadata": [
{
"date_accessed": datetime.now().isoformat(),
"source": title,
}
],
"source": {"name": title, "url": url},
},
}
)

Если вы отправляете несколько ссылок, вы можете итерировать по ним и вызывать эмиттер несколько раз. При реализации пользовательских ссылок убедитесь, что вы установили self.citation = False в методе __init__ вашего класса Tools. В противном случае встроенные ссылки заменят те, которые вы передали. Например:

def __init__(self):
self.citation = False

Внимание: если вы установите self.citation = True, это заменит все пользовательские ссылки, которые вы отправите, автоматически сгенерированной ссылкой на возврат. Отключив эту функцию, вы сможете полностью управлять своими собственными ссылками.

Пример
class Tools:
class UserValves(BaseModel):
test: bool = Field(
default=True, description="тест"
)

def __init__(self):
self.citation = False

async def test_function(
self, prompt: str, __user__: dict, __event_emitter__=None
) -> str:
"""
Это демонстрация, которая просто создает ссылку

:param test: это тестовый параметр
"""

await __event_emitter__(
{
"type": "citation",
"data": {
"document": ["Это сообщение будет добавлено в чат как ссылка при клике"],
"metadata": [
{
"date_accessed": datetime.now().isoformat(),
"source": title,
}
],
"source": {"name": "Название контента", "url": "http://ссылка-на-цитирование"},
},
}
)

Внешние пакеты

В метаданных определения Tools вы можете указывать настраиваемые пакеты. Когда вы нажимаете Сохранить, строка будет разобрана, и pip install будет выполнен для всех требований сразу.

Имейте в виду, что поскольку pip используется в том же процессе, что и Open WebUI, UI будет полностью неотзывчивым во время установки.

Меры по предотвращению конфликтов пакетов с требованиями Open WebUI не принимаются. Это означает, что указание требований может сломать Open WebUI, если вы не будете осторожны. Вы можете попытаться обойти это, указав open-webui в качестве требования.

Пример
"""
title: myToolName
author: myName
funding_url: [любая ссылка здесь будет отображаться за кнопкой 'Сердце' для пользователей, чтобы выразить вам поддержку]
version: 1.0.0
# версия отображается в UI, чтобы помочь пользователям отслеживать обновления.
license: GPLv3
description: [рекомендуется]
requirements: package1>=2.7.0,package2,package3
"""