Open WebUI Python 工具
一個工具就是一個 Python 檔案。Open WebUI 會 exec 該檔案,實例化 Tools(),並將每個公開方法轉換為模型可呼叫的函式。這組公開方法就是工具的表面 (surface)——你忘了加上 _ 前綴的輔助函式,就會變成模型可以呼叫的函式。
Docstring 不是註解。它的第一個區塊會變成傳送給模型的函式描述,而每一行 :param name: 則會變成參數描述。Docstring 就是提示詞。
檔案範例
"""
title: Package Lookup
author: you
description: Look up a package on 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="包含已棄用的發行版")
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 行必須剛好是
"""。 註解、匯入陳述或空行都會讓整個 frontmatter 變得不可見——此時requirements永遠不會被安裝,而且靜默失敗。 - 使用前導
_讓輔助函式遠離表面。 其他所有Tools上的公開內容——包括任何繼承而來的——都是模型可以呼叫的函式。 - 僅使用 reST 風格的 docstring。
:param name: text才能傳遞給模型;Google 風格的Args:區塊則完全無效。 - 對每個模型可見的參數加上型別提示。 型別提示會產生 JSON Schema。型別提示必須在匯入時就能解析;無法解析的標註會直接導致工具儲存失敗。
- 為每個注入的
__dunder__參數提供預設值。 Open WebUI 只在有該參數的地方才提供值,而模型永遠看不到它們——它們會從 schema 中被移除。 __init__不接受任何引數,並設定self.valves = self.Valves()。 沒有這行程式碼,管理員設定的 valve 值就會被丟棄。- 每個方法都必須是
async def。 同步方法會在事件迴圈中內聯執行,並阻塞伺服器;請透過await asyncio.to_thread(...)將阻塞性工作推出去。 - 回傳一個字串(
dict或list會自動幫你轉成 JSON)。回傳一個可讀的錯誤訊息,而不是拋出例外——拋出的例外會以其原始的str()形式傳遞給模型。 - 進度透過
status事件傳遞;答案透過回傳值傳遞。 四個內容事件(message,chat:message,chat:message:delta,replace)在原生模式(唯一支援的模式)下會被完成快照覆寫。
驗證
python scripts/check_tool.py mytool.py
該腳本僅使用標準函式庫,但它會執行工具檔案,因此工具自身的匯入必須能成功解析——對於上面的檔案,請使用 uv run --with httpx --with pydantic python scripts/check_tool.py mytool.py。
它會複製伺服器的載入與規格生成流程。兩個條件都必須成立:程式能正常退出,並且在印出的工具表面中的每個名稱都是你預期模型呼叫的。
然後將檔案貼到 Workspace > Tools。工具 ID 是在那裡設定的,而不是在檔案中,且必須是小寫的 Python 識別字。
參考資料
請參閱 references/REFERENCE.md 以取得完整的注入參數列表、事件發射器目錄(status, citation, notification, confirmation, input, 檔案)、閥值輸入類型(密碼、下拉選單、多選、動態選項)、回傳檔案或內嵌 HTML,以及那些不再有任何作用的繼承旗標。