跳到主要内容

🔧 Tool 开发

⚠️ 关键安全警告

Workspace Tools 会在你的服务器上执行任意 Python 代码。 只应从可信来源安装,导入前必须审阅代码,并且只能把 Workspace 访问权限交给可信管理员。允许用户创建或导入 Tool,基本等同于给了他们服务器 shell 权限。完整背景见 Plugin Security Warning

编写自定义 Toolkit

Toolkit 通常定义在一个 Python 文件中,包含顶部 metadata docstring 和一个 Tools 类。

为未来兼容性优先使用 async

Tool 方法通常都应该定义成 async。 OPL 数据空间后端正逐步向全异步执行迁移;同步函数未来可能阻塞执行,甚至失效。

顶部 docstring 示例

"""
title: String Inverse
author: Your Name
author_url: https://website.com
git_url: https://github.com/username/string-reverse.git
description: This tool calculates the inverse of a string
required_open_webui_version: 0.4.0
requirements: langchain-openai, langgraph, ollama, langchain_ollama
version: 0.4.0
licence: MIT
"""

Tools

所有 Tool 方法都必须定义在名为 Tools 的类里。你也可以添加可选的 ValvesUserValves 子类:

class Tools:
    def __init__(self):
        self.valves = self.Valves()

    class Valves(BaseModel):
        api_key: str = Field("", description="Your API key here")

    async def reverse_string(self, string: str) -> str:
        """
        Reverses the input string.
        :param string: The string to reverse
        """
        if self.valves.api_key != "42":
            return "Wrong API key"
        return string[::-1]

类型标注

每个 Tool 参数都应该有类型标注。 OPL 数据空间会用这些标注来生成发送给模型的 JSON Schema。没有类型标注的 Tool 虽然也可能运行,但一致性会明显变差。

外部依赖

如果你的 Tool 依赖第三方 Python 包,请通过顶部 frontmatter 里的 requirements 显式声明它们,并优先选择稳定、轻量且维护活跃的依赖。对于重量级依赖,要评估安装时间、镜像体积与多副本环境下的一致性成本。

ValvesUserValves

它们用来定义 Tool 的可配置项。详细说明见 Valves & UserValves

可选注入参数

Tool 方法还可以声明以下可选参数:

  • __event_emitter__:发送事件
  • __event_call__:需要与用户交互时使用
  • __user__:当前用户信息,含 __user__["valves"]
  • __metadata__:聊天元数据
  • __messages__:历史消息
  • __files__:附加文件
  • __model__:模型信息
  • __oauth_token__:用户有效的 OAuth Token 载荷

其中 __oauth_token__ 是代表用户调用外部 API 的推荐方式。它通常包含 access_tokenid_token 等字段,避免再去做 cookie 抓取或手工刷新 token。

在 Tool 中使用 OAuth Token

import httpx
from typing import Optional

class Tools:
    async def get_user_profile_from_external_api(
        self, __oauth_token__: Optional[dict] = None
    ) -> str:
        if not __oauth_token__ or "access_token" not in __oauth_token__:
            return "Error: User is not authenticated via OAuth or token is unavailable."

        access_token = __oauth_token__["access_token"]

        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json"
        }

        try:
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    "https://api.my-service.com/v1/profile",
                    headers=headers
                )
                response.raise_for_status()
                return f"API Response: {response.json()}"
        except httpx.HTTPStatusError as e:
            return f"Error: Failed to fetch data from API. Status: {e.response.status_code}"
        except Exception as e:
            return f"An unexpected error occurred: {e}"

Event Emitters

Event Emitter 可以在 Tool 执行期间向聊天界面附加状态、通知、引用等额外信息。和 Filter outlet 不同,Event Emitter 更适合做实时 UI 反馈。

按 Native 模式来设计 Tool

Default Mode 已经是遗留模式,不再支持新开发。请按 Tool Calling Modes 中的 Native(Agentic)Mode 设计 Tool。下面的兼容矩阵保留了 Default 行为,只是为了帮助维护历史 Tool。

Native / Default 两种函数调用模式下,Event Emitter 的兼容性并不相同:

  • Native Mode:唯一推荐模式,但事件面较小
  • Default Mode:事件更全,但模式本身已不再支持

模式配置

  1. 管理员级:Admin Panel → Settings → Models → Model Specific Settings → Advanced Parameters → Function Calling
  2. 按请求:聊天里的 Chat Controls → Advanced Params

兼容性矩阵

事件类型Default ModeNative Mode结论
status完整支持完整支持推荐使用
message完整支持会被覆盖不兼容
chat:completion完整支持可工作,但可能覆盖内容部分兼容
chat:message:delta完整支持会被覆盖不兼容
chat:message完整支持会被覆盖不兼容
replace完整支持会被覆盖不兼容
chat:message:files / files完整支持完整支持兼容
chat:message:error完整支持完整支持兼容
chat:message:follow_ups完整支持完整支持兼容
chat:title / chat:tags完整支持完整支持兼容
chat:tasks:cancel完整支持完整支持兼容
citation / source完整支持完整支持兼容
notification完整支持完整支持兼容
confirmation完整支持完整支持兼容
execute完整支持完整支持兼容
input完整支持完整支持兼容

为什么 Native 模式会破坏某些事件

在 Native 模式下,服务端会反复发送 chat:completion 全量内容快照。前端会把这些快照当作“权威内容”直接替换消息正文,因此你之前通过 messagechat:messagereplace 等事件写进去的内容会闪一下然后被覆盖。

最佳实践

  • 需要实时反馈时,优先使用 status
  • 需要用户确认或输入时,使用 confirmationinput
  • 需要文件、通知、引用时,使用对应兼容事件
  • 不要把 Tool 的核心 UX 建立在 Native 不兼容的事件类型上

status 事件:最可靠的方式

status 在 Default 和 Native 两种模式下都可靠,是最推荐的事件类型。

await __event_emitter__({
    "type": "status",
    "data": {
        "description": "Loading data file...",
        "done": False,
        "hidden": False
    }
})

字段说明:

  • description:展示给用户的状态文字
  • done:是否已完成
  • hidden:完成后是否自动隐藏

排查事件问题

如果你发现:

  • Tool 发出的内容一闪而过
  • message / replace 像是没生效
  • 只有 status 能稳定显示

大概率是因为当前在 Native 模式下使用了不兼容的消息类事件。

处理方式:

  1. 改成兼容事件类型
  2. 在 Tool 里按模式降级 UX
  3. 不要再要求用户切回 Default 模式来满足新 Tool 的核心行为