Herramientas Python de Open WebUI
Una herramienta es un archivo Python. Open WebUI exec el archivo, instancia Tools() y convierte
cada método público en una función que el modelo puede llamar. Ese conjunto de métodos públicos es la
superficie de la herramienta — un ayudante que olvidaste prefijar con _ es una función que el modelo llamará.
El docstring no es un comentario. Su primer bloque se convierte en la descripción de la función enviada al
modelo, y cada línea :param nombre: se convierte en una descripción de parámetro. El docstring es el prompt.
El archivo
"""
title: Búsqueda de Paquetes
author: tú
description: Busca un paquete en 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="Raíz de la API JSON de PyPI",
)
class UserValves(BaseModel):
include_yanked: bool = Field(default=False, description="Incluir versiones retiradas")
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:
"""
Busca un paquete Python en PyPI y devuelve sus metadatos.
:param name: El nombre del paquete, p.ej. `httpx`
:param version: Una versión específica; omitir para la última versión
:return: JSON con resumen, última versión, página de inicio y licencia
"""
if __event_emitter__:
await __event_emitter__(
{"type": "status", "data": {"description": f"Obteniendo {name}...", "done": False}}
)
try:
data = await self._fetch(name, version)
except httpx.HTTPStatusError as e:
return f"PyPI devolvió {e.response.status_code} para el paquete '{name}'."
except Exception as e:
return f"No se pudo contactar 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 cliente:
response = await cliente.get(f"{self.valves.base_url}/{path}")
response.raise_for_status()
return response.json()
Ese archivo genera exactamente esta especificación para el modelo — nada más en el archivo es accesible:
{"name": "get_package",
"description": "Busca un paquete Python en PyPI y devuelve sus metadatos.",
"parameters": {"type": "object", "required": ["name"], "properties": {
"name": {"type": "string", "description": "El nombre del paquete, p.ej. `httpx`"},
"version": {"type": "string", "description": "Una versión específica; omitir para la última versión"}}}}
Reglas que el esqueleto no puede mostrar
- La línea 1 es exactamente
""". Un comentario, una importación o una línea en blanco arriba hace que todo el frontmatter sea invisible — entoncesrequirementsnunca se instala, silenciosamente. - Mantén los ayudantes fuera de la superficie con un guion bajo
_inicial. Todo lo demás público enTools— incluyendo cualquier cosa heredada — es una función que el modelo puede llamar. - Solo docstrings reST.
:param nombre: textollega al modelo; un bloque estilo GoogleArgs:no llega a nada. - Añade tipo a cada parámetro que ve el modelo. Las anotaciones generan el esquema JSON. Las anotaciones deben resolverse en tiempo de importación; una anotación irresoluble hace que guardar la herramienta falle por completo.
- Asigna un valor predeterminado a cada parámetro
__dunder__inyectado. Open WebUI los proporciona solo donde los tiene, y el modelo nunca los ve — se eliminan del esquema. __init__no toma argumentos y estableceself.valves = self.Valves(). Sin esa línea, los valores de válvula configurados por el administrador se pierden.- Cada método es
async def. Un método síncrono se ejecuta en el bucle de eventos y bloquea el servidor; empuja trabajo bloqueante a través deawait asyncio.to_thread(...). - Devuelve una cadena (un
dictolistse convierte a JSON por ti). Devuelve un mensaje de error legible en lugar de lanzar una excepción — una excepción lanzada llega al modelo como sustr()simple. - El progreso va a través de eventos
status; la respuesta va a través del valor de retorno. Los cuatro eventos de contenido (message,chat:message,chat:message:delta,replace) son sobrescritos por instantáneas de finalización en modo Nativo, que es el único modo compatible.
Verificar
python scripts/check_tool.py mi_herramienta.py
El script es solo de la biblioteca estándar, pero ejecuta el archivo de la herramienta, por lo que las importaciones propias de la herramienta deben resolverse —
uv run --with httpx --with pydantic python scripts/check_tool.py mi_herramienta.py para el archivo anterior.
Reproduce la carga del servidor y la generación de especificaciones. Dos barras, ambas deben cumplirse: sale limpio, y cada nombre en la superficie de la herramienta impresa es uno que pretendes que el modelo llame.
Luego pega el archivo en Workspace > Tools. El id de la herramienta se establece allí, no en el archivo, y debe ser un identificador Python en minúsculas.
Referencia
Lee references/REFERENCE.md para la lista completa de parámetros inyectados, el catálogo
de emisores de eventos (status, citation, notification, confirmation, input, archivos), tipos de entrada de válvulas
(contraseña, selección, selección múltiple, opciones dinámicas), devolución de archivos o HTML incrustado y los
indicadores heredados que ya no hacen nada.