Outils Python Open WebUI
Un outil est un fichier Python unique. Open WebUI exécute le fichier, instancie Tools(), et transforme
chaque méthode publique en une fonction que le modèle peut appeler. Cet ensemble de méthodes publiques constitue la
surface de l'outil — une aide que vous avez oublié de préfixer par _ devient une fonction que le modèle appellera.
La docstring n'est pas un commentaire. Son premier bloc devient la description de la fonction envoyée au
modèle, et chaque ligne :param nom: devient une description de paramètre. La docstring est l'invite.
Le fichier
"""
title: Recherche de paquet
author: vous
description: Rechercher un paquet sur 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="Racine de l'API JSON PyPI",
)
class UserValves(BaseModel):
include_yanked: bool = Field(default=False, description="Inclure les versions supprimées")
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:
"""
Rechercher un paquet Python sur PyPI et retourner ses métadonnées.
:param name: Le nom du paquet, ex. `httpx`
:param version: Une version spécifique ; omettre pour la dernière version
:return: JSON avec résumé, dernière version, page d'accueil et licence
"""
if __event_emitter__:
await __event_emitter__(
{"type": "status", "data": {"description": f"Récupération de {name}...", "done": False}}
)
try:
data = await self._fetch(name, version)
except httpx.HTTPStatusError as e:
return f"PyPI a retourné {e.response.status_code} pour le paquet '{name}'."
except Exception as e:
return f"Impossible de contacter 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()
Ce fichier génère exactement cette spécification pour le modèle — rien d'autre dans le fichier n'est accessible :
{"name": "get_package",
"description": "Rechercher un paquet Python sur PyPI et retourner ses métadonnées.",
"parameters": {"type": "object", "required": ["name"], "properties": {
"name": {"type": "string", "description": "Le nom du paquet, ex. `httpx`"},
"version": {"type": "string", "description": "Une version spécifique ; omettre pour la dernière version"}}}}
Règles que le squelette ne peut pas montrer
- La ligne 1 est exactement
""". Un commentaire, une importation ou une ligne vide au-dessus rend tout le frontmatter invisible —requirementsne s'installe alors jamais, en silence. - Gardez les aides hors de la surface avec un préfixe
_. Tout le reste de ce qui est public surTools— y compris tout ce qui est hérité — est une fonction que le modèle peut appeler. - Docstrings reST uniquement.
:param nom: texteatteint le modèle ; un blocArgs:de style Google n'atteint rien. - Type-hint chaque paramètre exposé au modèle. Les indications génèrent le schéma JSON. Les indications doivent être résolubles au moment de l'importation ; une annotation insoluble rend l'enregistrement de l'outil immédiatement impossible.
- Donnez à chaque paramètre
__dunder__injecté une valeur par défaut. Open WebUI ne les fournit que là où il les a, et le modèle ne les voit jamais — ils sont retirés du schéma. __init__ne prend aucun argument et définitself.valves = self.Valves(). Sans cette ligne, les valeurs de valve configurées par l'administrateur sont perdues.- Chaque méthode est
async def. Une méthode synchrone s'exécute en ligne sur la boucle d'événements et bloque le serveur ; poussez le travail bloquant viaawait asyncio.to_thread(...). - Retournez une chaîne (un
dictou unelistest converti en JSON pour vous). Retournez un message d'erreur lisible plutôt que de lever une exception — une exception levée atteint le modèle sous forme de son simplestr(). - La progression passe par les événements
status; la réponse passe par la valeur de retour. Les quatre événements de contenu (message,chat:message,chat:message:delta,replace) sont écrasés par les instantanés de complétion en mode Natif, qui est le seul mode pris en charge.
Vérifier
python scripts/check_tool.py moutil.py
Le script ne dépend que de la bibliothèque standard, mais il exécute le fichier outil, donc les imports propres à l'outil
doivent être résolus — uv run --with httpx --with pydantic python scripts/check_tool.py moutil.py pour le fichier ci-dessus.
Il reproduit le chargement et la génération de spécifications du serveur. Deux barres, les deux doivent tenir : il se termine proprement, et chaque nom dans la surface de l'outil imprimée est celui que vous vouliez que le modèle appelle.
Ensuite, collez le fichier dans Workspace > Tools. L'identifiant de l'outil est défini là, pas dans le fichier, et doit être un identifiant Python en minuscules.
Référence
Lisez references/REFERENCE.md pour la liste complète des paramètres injectés, le catalogue
d'émetteurs d'événements (status, citation, notification, confirmation, input, fichiers), les types d'entrée de valve
(mot de passe, sélection, sélection multiple, options dynamiques), le retour de fichiers ou de HTML intégré, et les
indicateurs hérités qui ne font plus rien.