Open WebUI Python 도구
도구는 하나의 Python 파일입니다. Open WebUI는 파일을 exec하고 Tools()를 인스턴스화한 다음,
모든 public 메서드를 모델이 호출할 수 있는 함수로 변환합니다. 이 public 메서드들의 집합이
도구의 표면(surface) 입니다. _ 접두사를 붙이지 않은 헬퍼는 모델이 호출할 함수가 됩니다.
docstring은 주석이 아닙니다. 첫 번째 블록은 모델에 전달되는 함수 설명이 되고,
각 :param name: 줄은 파라미터 설명이 됩니다. docstring이 프롬프트입니다.
파일
"""
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="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": "특정 버전; 생략 시 최신 릴리스"}}}}
기본 구조에서 보여주지 못하는 규칙
- 첫 번째 줄은 정확히
"""여야 합니다. 주석, import, 또는 빈 줄이 위에 있으면 전체 프론트매터가 보이지 않게 됩니다. 그러면requirements가 조용히 설치되지 않습니다. - 헬퍼는
_접두사로 표면에서 숨기세요.Tools의 다른 모든 public 요소(상속된 것 포함)는 모델이 호출할 수 있는 함수입니다. - reST docstring만 사용하세요.
:param name: text는 모델에 도달하지만, Google 스타일의Args:블록은 아무것도 도달하지 않습니다. - 모델이 사용하는 모든 파라미터에 타입 힌트를 제공하세요. 힌트는 JSON 스키마를 생성합니다. 힌트는 import 시점에 해석 가능해야 하며, 해석 불가능한 어노테이션은 도구 저장을 즉시 실패시킵니다.
- 모든 주입된
__dunder__파라미터에 기본값을 제공하세요. Open WebUI는 해당 파라미터가 있는 곳에서만 제공하며, 모델은 이를 절대 보지 못합니다. 스키마에서 제거됩니다. __init__는 인자를 받지 않고self.valves = self.Valves()를 설정해야 합니다. 이 줄이 없으면 관리자가 구성한 밸브 값이 무시됩니다.- 모든 메서드는
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
이 스크립트는 표준 라이브러리만 사용하지만, 도구 파일을 실행하므로 도구 자체의 import가 해결되어야 합니다. 위 파일의 경우 uv run --with httpx --with pydantic python scripts/check_tool.py mytool.py를 사용하세요.
이 스크립트는 서버의 로드 및 스펙 생성을 재현합니다. 두 가지 조건이 모두 충족되어야 합니다: 깨끗하게 종료되고, 출력된 도구 표면의 모든 이름이 모델이 호출하도록 의도한 것이어야 합니다.
그런 다음 파일을 Workspace > Tools에 붙여넣으세요. 도구 ID는 파일이 아닌 해당 위치에서 설정되며, 소문자 Python 식별자여야 합니다.
참고
주입된 파라미터 전체 목록, 이벤트 이미터 카탈로그(status, citation, notification, confirmation, input, 파일), 밸브 입력 타입(비밀번호, 선택, 다중 선택, 동적 옵션), 파일 또는 임베디드 HTML 반환, 더 이상 아무 기능도 하지 않는 상속된 플래그에 대해서는 references/REFERENCE.md를 읽으세요.