Skip to main content
Functions in Open WebUI allow you to extend your language models with custom Python code that can be called during conversations. This enables your models to perform actions, fetch data, and integrate with external services.

Overview

Functions provide:
  • Native Python code execution
  • Built-in code editor in the workspace
  • Function calling and tool use capabilities
  • Filter functions to modify messages
  • Admin and user-level configuration
Functions are stored in the database and loaded dynamically at runtime. Admin users can create and manage functions through the web interface.

Creating Functions

Through the Web Interface

1

Navigate to Workspace

Go to Workspace → Functions in the Open WebUI interface
2

Create New Function

Click Create New Function and enter:
  • ID: Unique identifier (alphanumeric and underscores only)
  • Name: Display name for the function
  • Description: What the function does
3

Write Function Code

Use the built-in editor to write your Python function:
"""
title: Example Function
description: A simple example function
author: Your Name
version: 1.0.0
"""

class Function:
    def __init__(self):
        pass
    
    def __call__(self, user_message: str, **kwargs) -> str:
        return f"Processed: {user_message}"
4

Save and Enable

Save the function and toggle it active to make it available

Via API

Create functions programmatically:
import requests

url = "http://localhost:8080/api/functions/create"
payload = {
    "id": "my_function",
    "name": "My Function",
    "content": '''
class Function:
    def __call__(self, user_message: str) -> str:
        return f"Echo: {user_message}"
''',
    "meta": {
        "description": "Echoes the user message",
        "manifest": {}
    }
}

response = requests.post(url, json=payload)

Function Types

Open WebUI supports two main types of functions:

Action Functions

Perform operations and return results:
import requests
from datetime import datetime

class Function:
    def __init__(self):
        self.name = "get_weather"
        self.description = "Get current weather for a city"
    
    def __call__(self, city: str, **kwargs) -> dict:
        # Call weather API
        response = requests.get(
            f"https://api.weather.com/v1/current",
            params={"city": city}
        )
        return response.json()

Filter Functions

Modify messages before and after model processing:
class Function:
    type = "filter"  # Mark as filter function
    
    def inlet(self, messages: list, user: dict, **kwargs) -> list:
        """Process messages before sending to model"""
        # Add timestamp to each message
        for msg in messages:
            msg["timestamp"] = datetime.now().isoformat()
        return messages
    
    def outlet(self, messages: list, user: dict, **kwargs) -> list:
        """Process messages after model response"""
        # Log the conversation
        print(f"Conversation for {user['email']}: {len(messages)} messages")
        return messages

Valves Configuration

Valves allow functions to have configurable parameters:
from pydantic import BaseModel, Field

class Function:
    class Valves(BaseModel):
        api_key: str = Field(
            default="",
            description="API key for external service"
        )
        temperature: float = Field(
            default=0.7,
            description="Model temperature",
            ge=0.0,
            le=2.0
        )
        max_tokens: int = Field(
            default=1000,
            description="Maximum tokens"
        )
    
    def __init__(self):
        self.valves = self.Valves()
    
    def __call__(self, prompt: str, **kwargs) -> str:
        # Use valve values
        api_key = self.valves.api_key
        temp = self.valves.temperature
        # Your function logic here
        return f"Using temp={temp}"

User Valves

Allow individual users to configure function parameters:
from pydantic import BaseModel, Field

class Function:
    class UserValves(BaseModel):
        personal_api_key: str = Field(
            default="",
            description="Your personal API key"
        )
        preferred_language: str = Field(
            default="en",
            description="Preferred response language"
        )
    
    def __init__(self):
        self.user_valves = {}
    
    def __call__(self, user_message: str, __user__: dict, **kwargs) -> str:
        user_id = __user__["id"]
        valves = self.user_valves.get(user_id, self.UserValves())
        
        # Use user-specific configuration
        lang = valves.preferred_language
        return f"Response in {lang}: {user_message}"

Managing Functions

List Functions

import requests

response = requests.get("http://localhost:8080/api/functions/")
functions = response.json()

Get Function by ID

response = requests.get("http://localhost:8080/api/functions/id/my_function")
function = response.json()

Update Function

import requests

url = "http://localhost:8080/api/functions/id/my_function/update"
payload = {
    "content": """# Updated code here""",
    "meta": {"description": "Updated description"}
}

response = requests.post(url, json=payload)

Toggle Function

Enable or disable a function:
response = requests.post(
    "http://localhost:8080/api/functions/id/my_function/toggle"
)

Delete Function

response = requests.delete(
    "http://localhost:8080/api/functions/id/my_function/delete"
)

Import from URL

Load functions from GitHub or other sources:
import requests

url = "http://localhost:8080/api/functions/load/url"
payload = {
    "url": "https://github.com/user/repo/blob/main/my_function.py"
}

response = requests.post(url, json=payload)
function_data = response.json()
GitHub URLs are automatically converted to raw URLs. Both blob and tree URLs are supported.

Function Examples

import sqlite3
from typing import List, Dict

class Function:
    def __init__(self):
        self.name = "query_database"
        self.description = "Query the local database"
    
    def __call__(self, query: str, **kwargs) -> List[Dict]:
        conn = sqlite3.connect('app.db')
        cursor = conn.cursor()
        
        cursor.execute(query)
        columns = [desc[0] for desc in cursor.description]
        results = [
            dict(zip(columns, row))
            for row in cursor.fetchall()
        ]
        
        conn.close()
        return results
import requests
from pydantic import BaseModel, Field

class Function:
    class Valves(BaseModel):
        api_key: str = Field(default="", description="API Key")
        base_url: str = Field(
            default="https://api.example.com",
            description="API Base URL"
        )
    
    def __init__(self):
        self.valves = self.Valves()
    
    def __call__(self, endpoint: str, params: dict = None, **kwargs) -> dict:
        headers = {"Authorization": f"Bearer {self.valves.api_key}"}
        url = f"{self.valves.base_url}/{endpoint}"
        
        response = requests.get(url, headers=headers, params=params)
        return response.json()
import re
from typing import List

class Function:
    def __init__(self):
        self.name = "extract_emails"
        self.description = "Extract email addresses from text"
    
    def __call__(self, text: str, **kwargs) -> List[str]:
        email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
        emails = re.findall(email_pattern, text)
        return list(set(emails))  # Remove duplicates

Global vs Local Functions

Functions can be toggled between global and local scope:
import requests

# Toggle global scope (available to all users)
response = requests.post(
    "http://localhost:8080/api/functions/id/my_function/toggle/global"
)
Global functions are available to all users. Ensure they don’t expose sensitive data or operations.

Best Practices

  1. Error Handling: Always wrap function logic in try-except blocks
  2. Type Hints: Use Python type hints for better documentation
  3. Validation: Validate inputs before processing
  4. Security: Never hardcode sensitive credentials
  5. Performance: Keep functions lightweight and fast
  6. Documentation: Include clear docstrings and metadata

Next Steps

  • Learn about Tools for extended functionality
  • Explore Pipelines for request/response filtering
  • Configure Skills for reusable capabilities