Open WebUI Python 工具
工具是一个 Python 文件。Open WebUI 会 exec 这个文件,实例化 Tools(),并将每个公共方法转化为模型可以调用的函数。这组公共方法就是工具的表面——你忘记加 _ 前缀的辅助函数,就是模型会调用的函数。
文档字符串不是注释。它的第一个块成为发送给模型的函数描述,每一行 :param name: 成为参数描述。文档字符串就是提示词。
文件
"""
title: 包查询
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="是否包含已废弃的发布版本")
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": "特定版本;省略则获取最新发布"}}}}
框架无法展示的规则
- 第一行必须是三个双引号
"""。 注释、导入或空行在上面会使整个前置元数据不可见——requirements永远不会安装,静默失败。 - 用前导
_保持辅助函数不出现在表面上。Tools上的其他所有公共内容——包括继承来的——都是模型可调用的函数。 - 仅使用 reST 风格文档字符串。
: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、文件)、valve 输入类型(password、select、multiselect、dynamic options)、返回文件或嵌入 HTML,以及不再起作用的继承标志。