Open WebUI Python-Tools
Ein Tool ist eine Python-Datei. Open WebUI führt die Datei mit exec aus, instanziiert Tools() und macht jede öffentliche Methode zu einer Funktion, die das Modell aufrufen kann. Diese Menge öffentlicher Methoden ist die Oberfläche des Tools – ein Helfer, den Sie mit _ zu versehen vergessen haben, wird zu einer vom Modell aufrufbaren Funktion.
Der Docstring ist kein Kommentar. Sein erster Block wird zur Funktionsbeschreibung, die an das Modell gesendet wird, und jede :param name:-Zeile wird zur Parameterbeschreibung. Der Docstring ist der Prompt.
Die Datei
"""
title: Paketabfrage
author: du
description: Ein Paket auf PyPI nachschlagen
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="PyPI JSON-API-Wurzel",
)
class UserValves(BaseModel):
include_yanked: bool = Field(default=False, description="Zurückgezogene Veröffentlichungen einbeziehen")
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:
"""
Suche ein Python-Paket auf PyPI und gib seine Metadaten zurück.
:param name: Der Paketname, z. B. `httpx`
:param version: Eine bestimmte Version; weglassen für die neueste Version
:return: JSON mit Zusammenfassung, neuester Version, Homepage und Lizenz
"""
if __event_emitter__:
await __event_emitter__(
{"type": "status", "data": {"description": f"Rufe {name} ab...", "done": False}}
)
try:
data = await self._fetch(name, version)
except httpx.HTTPStatusError as e:
return f"PyPI gab Status {e.response.status_code} für Paket '{name}' zurück."
except Exception as e:
return f"PyPI nicht erreichbar: {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()
Diese Datei erzeugt genau diese Spezifikation für das Modell – nichts anderes in der Datei ist erreichbar:
{"name": "get_package",
"description": "Suche ein Python-Paket auf PyPI und gib seine Metadaten zurück.",
"parameters": {"type": "object", "required": ["name"], "properties": {
"name": {"type": "string", "description": "Der Paketname, z. B. `httpx`"},
"version": {"type": "string", "description": "Eine bestimmte Version; weglassen für die neueste Version"}}}}
Regeln, die das Skelett nicht zeigen kann
- Zeile 1 ist genau
""". Ein Kommentar, ein Import oder eine Leerzeile darüber macht die gesamte Frontmatter unsichtbar – dann installiert sichrequirementsniemals, und zwar lautlos. - Halte Helfer von der Oberfläche fern mit einem führenden
_. Alles andere Öffentliche anTools– einschließlich geerbter Methoden – ist eine Funktion, die das Modell aufrufen kann. - Nur reST-Docstrings.
:param name: texterreicht das Modell; ein Google-styleArgs:-Block erreicht nichts. - Typisiere jeden modellseitigen Parameter. Die Typannotationen erzeugen das JSON-Schema. Annotationen müssen zum Importzeitpunkt auflösbar sein; eine nicht auflösbare Annotation führt dazu, dass das Speichern des Tools sofort fehlschlägt.
- Gib jedem injizierten
__dunder__-Parameter einen Standardwert. Open WebUI liefert sie nur dort, wo sie vorhanden sind, und das Modell sieht sie nie – sie werden aus dem Schema entfernt. __init__nimmt keine Argumente entgegen und setztself.valves = self.Valves(). Ohne diese Zeile gehen die vom Administrator konfigurierten Ventilwerte verloren.- Jede Methode ist
async def. Eine synchrone Methode läuft inline auf der Ereignisschleife und blockiert den Server; verschiebe blockierende Arbeit durchawait asyncio.to_thread(...). - Gib einen String zurück (ein
dictoderlistwird für dich in JSON umgewandelt). Gib eine lesbare Fehlermeldung zurück, anstatt eine Exception zu werfen – eine ausgelöste Exception erreicht das Modell als deren rohestr()-Darstellung. - Fortschritt erfolgt über
status-Ereignisse; die Antwort erfolgt über den Rückgabewert. Die vier Inhalt-Ereignisse (message,chat:message,chat:message:delta,replace) werden durch Vervollständigungs-Schnappschüsse im nativen Modus überschrieben, dem einzigen unterstützten Modus.
Verifizieren
python scripts/check_tool.py meinwerkzeug.py
Das Skript benötigt nur die Standardbibliothek, führt aber die Tool-Datei aus, daher müssen die eigenen Importe des Tools aufgelöst werden können – uv run --with httpx --with pydantic python scripts/check_tool.py meinwerkzeug.py für die obige Datei.
Es reproduziert das Laden des Servers und die Spezifikationserzeugung. Zwei Balken, beide müssen halten: Es beendet sich sauber, und jeder Name in der gedruckten Tool-Oberfläche ist einer, den das Modell aufrufen soll.
Füge dann die Datei in Arbeitsbereich > Tools ein. Die Tool-ID wird dort festgelegt, nicht in der Datei, und muss ein kleingeschriebener Python-Bezeichner sein.
Referenz
Lies references/REFERENCE.md für die vollständige Liste der injizierten Parameter, den Ereignis-Emitter-Katalog (status, citation, notification, confirmation, input, Dateien), Ventil-Eingabetypen (Passwort, Auswahl, Mehrfachauswahl, dynamische Optionen), das Zurückgeben von Dateien oder eingebettetem HTML und die geerbten Flags, die nichts mehr bewirken.