Ferramentas Python do Open WebUI
Uma ferramenta é um arquivo Python. O Open WebUI executa o arquivo, instancia Tools(), e transforma
cada método público em uma função que o modelo pode chamar. Esse conjunto de métodos públicos é a
superfície da ferramenta — um auxiliar que você esqueceu de prefixar com _ se torna uma função que o modelo chamará.
A docstring não é um comentário. Seu primeiro bloco se torna a descrição da função enviada ao
modelo, e cada linha :param nome: se torna uma descrição de parâmetro. A docstring é o prompt.
O arquivo
"""
title: Consulta de Pacote
author: você
description: Consulta um pacote no PyPI
requirements: httpx
version: 0.1.0
licence: MIT
"""
import json
from typing import Any, Callable, Optional
import httpx
from pydantic import BaseModel, Field
class Tools:
class Valves(BaseModel):
base_url: str = Field(
default="https://pypi.org/pypi",
description="Raiz da API JSON do PyPI",
)
class UserValves(BaseModel):
include_yanked: bool = Field(default=False, description="Incluir versões yanked")
def __init__(self):
self.valves = self.Valves()
async def get_package(
self,
name: str,
version: Optional[str] = None,
__user__: Optional[dict] = None,
__event_emitter__: Optional[Callable[[dict], Any]] = None,
) -> str:
"""
Consulta um pacote Python no PyPI e retorna seus metadados.
:param name: O nome do pacote, ex. `httpx`
:param version: Uma versão específica; omita para a versão mais recente
:return: JSON com resumo, versão mais recente, página inicial e licença
"""
if __event_emitter__:
await __event_emitter__(
{"type": "status", "data": {"description": f"Buscando {name}...", "done": False}}
)
try:
data = await self._fetch(name, version)
except httpx.HTTPStatusError as e:
return f"PyPI retornou {e.response.status_code} para o pacote '{name}'."
except Exception as e:
return f"Não foi possível acessar o PyPI: {e}"
info = data.get("info", {})
return json.dumps(
{"name": info.get("name"), "version": info.get("version"), "summary": info.get("summary")},
ensure_ascii=False,
)
async def _fetch(self, name: str, version: Optional[str]) -> dict:
path = f"{name}/{version}/json" if version else f"{name}/json"
async with httpx.AsyncClient(timeout=15) as client:
response = await client.get(f"{self.valves.base_url}/{path}")
response.raise_for_status()
return response.json()
Esse arquivo gera exatamente esta especificação para o modelo — nada mais no arquivo é acessível:
{"name": "get_package",
"description": "Consulta um pacote Python no PyPI e retorna seus metadados.",
"parameters": {"type": "object", "required": ["name"], "properties": {
"name": {"type": "string", "description": "O nome do pacote, ex. `httpx`"},
"version": {"type": "string", "description": "Uma versão específica; omita para a versão mais recente"}}}}
Regras que o esqueleto não mostra
- A linha 1 é exatamente
""". Um comentário, um import ou uma linha em branco acima dela torna todo o frontmatter invisível —requirementsentão nunca é instalado, silenciosamente. - Mantenha auxiliares fora da superfície com um
_inicial. Qualquer outra coisa pública emTools— incluindo qualquer coisa herdada — é uma função que o modelo pode chamar. - Apenas docstrings reST.
:param nome: textoalcança o modelo; um blocoArgs:no estilo Google não alcança nada. - Adicione dicas de tipo a todo parâmetro voltado ao modelo. As dicas geram o esquema JSON. As dicas devem ser resolvíveis no momento da importação; uma anotação não resolvível faz com que salvar a ferramenta falhe imediatamente.
- Dê um padrão a cada parâmetro
__dunder__injetado. O Open WebUI os fornece apenas onde os possui, e o modelo nunca os vê — eles são removidos do esquema. __init__não aceita argumentos e defineself.valves = self.Valves(). Sem essa linha, os valores de válvula configurados pelo administrador são descartados.- Todo método é
async def. Um método síncrono é executado inline no loop de eventos e bloqueia o servidor; empurre trabalhos bloqueantes através deawait asyncio.to_thread(...). - Retorne uma string (um
dictoulisté convertido para JSON automaticamente). Retorne uma mensagem de erro legível em vez de levantar uma exceção — uma exceção levantada chega ao modelo como seustr()simples. - O progresso passa por eventos
status; a resposta passa pelo valor de retorno. Os quatro eventos de conteúdo (message,chat:message,chat:message:delta,replace) são sobrescritos por snapshots de conclusão no modo Nativo, que é o único modo suportado.
Verificar
python scripts/check_tool.py mytool.py
O script depende apenas da biblioteca padrão, mas executa o arquivo da ferramenta, portanto as importações da ferramenta
precisam ser resolvíveis — uv run --with httpx --with pydantic python scripts/check_tool.py mytool.py para o arquivo acima.
Ele reproduz a carga do servidor e a geração de esquemas. Duas barras, ambas devem ser cumpridas: a saída é limpa, e cada nome na superfície da ferramenta impressa é um que você pretendia que o modelo chamasse.
Em seguida, cole o arquivo em Espaço de Trabalho > Ferramentas. O id da ferramenta é definido lá, não no arquivo, e deve ser um identificador Python em minúsculas.
Referência
Leia references/REFERENCE.md para a lista completa de parâmetros injetados, o catálogo do emissor de eventos (status, citation, notification, confirmation, input, arquivos), tipos de entrada de válvula (senha, seleção, multisseleção, opções dinâmicas), retorno de arquivos ou HTML embutido, e as
flags herdadas que não fazem mais nada.