Open WebUI Pythonツール
ツールは1つのPythonファイルです。Open WebUIはファイルをexecし、Tools()をインスタンス化して、すべての公開メソッドをモデルが呼び出せる関数に変換します。この公開メソッドの集合がツールの表面(surface)です——_を接頭辞として付け忘れたヘルパーは、モデルが呼び出す関数になってしまいます。
docstringは単なるコメントではありません。最初のブロックがモデルに送られる関数説明となり、各:param name:行がパラメータ説明になります。docstringこそがプロンプトです。
ファイル
"""
title: Package Lookup
author: you
description: 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="PyPI JSON APIのルート",
)
class UserValves(BaseModel):
include_yanked: bool = Field(default=False, description="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:
"""
PyPI上のPythonパッケージを検索し、メタデータを返します。
:param name: パッケージ名(例: `httpx`)
:param version: 特定のバージョン。省略時は最新リリース
:return: サマリー、最新バージョン、ホームページ、ライセンスを含むJSON
"""
if __event_emitter__:
await __event_emitter__(
{"type": "status", "data": {"description": f"{name}を取得中...", "done": False}}
)
try:
data = await self._fetch(name, version)
except httpx.HTTPStatusError as e:
return f"PyPIがパッケージ'{name}'に対してステータスコード{e.response.status_code}を返しました。"
except Exception as e:
return f"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()
このファイルは、モデルに対して以下の仕様を正確に生成します——ファイル内の他の部分は到達できません:
{"name": "get_package",
"description": "PyPI上のPythonパッケージを検索し、メタデータを返します。",
"parameters": {"type": "object", "required": ["name"], "properties": {
"name": {"type": "string", "description": "パッケージ名(例: `httpx`)"},
"version": {"type": "string", "description": "特定のバージョン。省略時は最新リリース"}}}}
スケルトンコードでは示せないルール
- 1行目は正確に
"""であること。 コメントやインポート、空行が上にあるとフロントマター全体が見えなくなり——requirementsがインストールされず、警告も出ません。 - ヘルパーは先頭に
_を付けて公開面に出さない。Tools上のその他すべての公開要素(継承されたものも含む)は、モデルが呼び出せる関数となります。 - reST形式のdocstringのみ使用可能。
:param name: テキストはモデルに届きますが、GoogleスタイルのArgs:ブロックは何も届きません。 - モデル向けの全パラメータに型ヒントを付ける。 型ヒントからJSONスキーマが生成されます。型ヒントはインポート時に解決可能でなければならず、解決できないアノテーションはツールの保存に失敗します。
- 注入される
__dunder__パラメータにはすべてデフォルト値を設定する。 Open WebUIは利用可能な場合のみこれらを提供し、モデルからは見えません——スキーマからは除去されます。 __init__は引数を取らず、self.valves = self.Valves()を設定する。 この行がないと、管理者が設定したバルブ値は無視されます。- すべてのメソッドは
async defで定義する。 同期メソッドはイベントループ上でインライン実行され、サーバーをブロックします。ブロッキング処理はawait asyncio.to_thread(...)に委譲してください。 - 文字列を返す(
dictやlistは自動的にJSONダンプされます)。例外を発生させるのではなく、読みやすいエラーメッセージを返してください——発生した例外はそのままstr()でモデルに届きます。 - 進捗は
statusイベントで、回答は戻り値で伝える。 4つのコンテンツイベント(message、chat:message、chat:message:delta、replace)は、ネイティブモード(唯一サポートされるモード)では補完スナップショットによって上書きされます。
検証
python scripts/check_tool.py mytool.py
このスクリプトはstdlibのみに依存しますが、ツールファイルを実行するため、ツール自身のインポートが解決可能である必要があります——上記のファイルの場合はuv run --with httpx --with pydantic python scripts/check_tool.py mytool.pyとします。
このスクリプトはサーバーの読み込みと仕様生成を再現します。2つの条件が成立する必要があります:スクリプトが正常に終了すること、そして表示されるツールの公開面のすべての名前が、モデルに呼び出させる意図を持ったものであること。
その後、ファイルをWorkspace > Toolsに貼り付けます。ツールIDはファイル内ではなくそこで設定され、小文字のPython識別子でなければなりません。
リファレンス
完全な注入パラメータ一覧、イベントエミッターカタログ(status、citation、notification、confirmation、input、ファイル)、バルブの入力タイプ(パスワード、セレクト、マルチセレクト、動的オプション)、ファイルや埋め込みHTMLの返却方法、および使用されなくなった継承フラグについては、references/REFERENCE.mdを参照してください。