跳到主要内容

🔧 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 的类里。你也可以添加可选的 Valves 和 UserValves 子类:

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 显式声明它们,并优先选择稳定、轻量且维护活跃的依赖。对于重量级依赖,要评估安装时间、镜像体积与多副本环境下的一致性成本。

Valves 与 UserValves​

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

可选注入参数​

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

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

其中 __oauth_token__ 是代表用户调用外部 API 的推荐方式。它通常包含 access_token、id_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 全量内容快照。前端会把这些快照当作“权威内容”直接替换消息正文,因此你之前通过 message、chat:message、replace 等事件写进去的内容会闪一下然后被覆盖。

最佳实践​

  • 需要实时反馈时,优先使用 status
  • 需要用户确认或输入时,使用 confirmation、input
  • 需要文件、通知、引用时,使用对应兼容事件
  • 不要把 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 的核心行为