跳至主要内容

🚰 管道函數:建立自訂「代理/模型」

歡迎來到有關在 Open WebUI 中建立 管道 的指南!將管道想像成往 Open WebUI 添加新模型的一種方式。在本文中,我們將逐步解析管道是什麼、它如何運作,以及如何建立自己的管道以向 Open WebUI 模型添加自定義邏輯和處理方式。我們將使用清晰的比喻並詳細講解每個部分,確保您深入理解。

管道簡介

把 Open WebUI 想像成一個 管道系統,其中數據通過管道和閥門流動。在這個比喻中:

  • 管道 像是 插件,可引入新的數據流通路,讓您加入自定義邏輯和處理。
  • 閥門 是管道中可配置的部分,用來控制數據如何流動。

通過創建管道,您基本上是在 Open WebUI 框架內打造具有特定行為的自訂模型。


理解管道結構

首先從管道的基本框架開始,以理解其結構:

from pydantic import BaseModel, Field

class Pipe:
class Valves(BaseModel):
MODEL_ID: str = Field(default="")

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

def pipe(self, body: dict):
# 邏輯寫在這裡
print(self.valves, body) # 打印配置選項和輸入的 body
return "Hello, World!"

Pipe 類

  • 定義Pipe 類是您定義自訂邏輯的地方。
  • 目的:充當插件的藍圖,決定其在 Open WebUI 中的行為。

Valves:配置管道

  • 定義ValvesPipe 類中的嵌套類,繼承自 BaseModel
  • 目的:它包含配置選項(參數),可在使用管道時持久化。
  • 範例:在上面的程式碼中,MODEL_ID 是一個帶有默認空字符串的配置選項。

比喻:把 Valves 想像成現實世界管道系統上的旋鈕,用來控制水的流動。在您的管道中,Valves 用戶可以調整設置,影響數據流動和處理方式。

__init__ 方法

  • 定義Pipe 類的構造器方法。
  • 目的:初始化管道的狀態並設置任何必要的組件。
  • 最佳實踐:保持簡單;主要在這裡初始化 self.valves
def __init__(self):
self.valves = self.Valves()

pipe 函數

  • 定義:核心函數,是您自定義邏輯所在的位置。
  • 參數
    • body: 一個包含輸入數據的字典。
  • 目的:使用您的自訂邏輯處理輸入數據並返回結果。
def pipe(self, body: dict):
# 邏輯寫在這裡
print(self.valves, body) # 打印配置選項和輸入的 body
return "Hello, World!"

注意:請始終將 Valves 放在 Pipe 類的頂部,接著是 __init__,然後是 pipe 函數。這種結構可以確保清晰性和一致性。


使用管道創建多個模型

如果您希望管道在 Open WebUI 中創建 多個模型,可以通過在 Pipe 類中定義 pipes 函數或變數來實現。這種設置,非正式地稱為 歧管,讓您的管道能夠表示多個模型。

以下是具體操作:

from pydantic import BaseModel, Field

class Pipe:
class Valves(BaseModel):
MODEL_ID: str = Field(default="")

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

def pipes(self):
return [
{"id": "model_id_1", "name": "model_1"},
{"id": "model_id_2", "name": "model_2"},
{"id": "model_id_3", "name": "model_3"},
]

def pipe(self, body: dict):
# 邏輯寫在這裡
print(self.valves, body) # 打印配置選項和輸入的 body
model = body.get("model", "")
return f"{model}: Hello, World!"

說明

  • pipes 函數

    • 返回一個字典列表。
    • 每個字典表示一個具有唯一 idname 鍵的模型。
    • 這些模型會個別顯示在 Open WebUI 的模型選擇器中。
  • 更新後的 pipe 函數

    • 根據選擇的模型處理輸入。
    • 在此範例中,返回的字符串中包含模型名稱。

範例:OpenAI Proxy 管道

接下來是一個實際範例,我們將創建一個管道來代理請求到 OpenAI API。該管道將從 OpenAI 獲取可用模型,並允許用戶通過 Open WebUI 與它們互動。

from pydantic import BaseModel, Field
import requests

class Pipe:
class Valves(BaseModel):
NAME_PREFIX: str = Field(
default="OPENAI/"
description="要添加在模型名稱之前的前綴。",
)
OPENAI_API_BASE_URL: str = Field(
default="https://api.openai.com/v1",
description="用於訪問 OpenAI API 端點的基本 URL。",
)
OPENAI_API_KEY: str = Field(
default="",
description="用於驗證對 OpenAI API 的請求的 API 密鑰。",
)

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

def pipes(self):
if self.valves.OPENAI_API_KEY:
try:
headers = {
"Authorization": f"Bearer {self.valves.OPENAI_API_KEY}",
"Content-Type": "application/json",
}

r = requests.get(
f"{self.valves.OPENAI_API_BASE_URL}/models", headers=headers
)
models = r.json()
return [
{
"id": model["id"],
"name": f{self.valves.NAME_PREFIX}{model.get("name", model["id"])},
}
for model in models["data"]
if "gpt" in model["id"]
]

except Exception as e:
return [
{
"id": "error",
"name": "獲取模型時出錯。請檢查您的 API 密鑰。",
},
]
else:
return [
{
"id": "error",
"name": "未提供 API 密鑰。",
},
]

def pipe(self, body: dict, __user__: dict):
print(f"pipe:{__name__}")
headers = {
"Authorization": f"Bearer {self.valves.OPENAI_API_KEY}",
"Content-Type": "application/json",
}

# 從模型名稱中提取模型 ID
model_id = body["model"][body["model"].find(".") + 1 :]

# 更新 body 中的模型 ID
payload = {**body, "model": model_id}
try:
r = requests.post(
url=f"{self.valves.OPENAI_API_BASE_URL}/chat/completions",
json=payload,
headers=headers,
stream=True,
)

r.raise_for_status()

if body.get("stream", False):
return r.iter_lines()
else:
return r.json()
except Exception as e:
return f"錯誤: {e}"

詳細解析

Valves 設定

  • NAME_PREFIX:
    • 添加一個前綴到 Open WebUI 中顯示的模型名稱。
    • 預設值: "OPENAI/"
  • OPENAI_API_BASE_URL:
    • 指定 OpenAI API 的基本 URL。
    • 預設值: "https://api.openai.com/v1"
  • OPENAI_API_KEY:
    • 您的 OpenAI API 驗證密鑰。
    • 預設值: "" (空字串;必須提供)。

pipes 函數

  • 用途: 獲取可用的 OpenAI 模型並使其在 Open WebUI 中可用。

  • 過程:

    1. 檢查 API 密鑰: 確保已提供 API 密鑰。
    2. 獲取模型: 向 OpenAI API 發送一個 GET 請求以檢索可用的模型。
    3. 篩選模型: 返回 id 中包含 "gpt" 的模型。
    4. 錯誤處理: 如果出現問題,返回錯誤訊息。
  • 返回格式: 包含每個模型的 idname 的字典列表。

pipe 函數

  • 用途: 處理對選定 OpenAI 模型的請求並返回回應。

  • 參數:

    • body: 包含請求數據。
    • __user__: 包含用戶資訊(本範例中未使用,但在驗證或記錄時可能有用)。
  • 過程:

    1. 準備標頭: 使用 API 密鑰和內容類型設置標頭。
    2. 提取模型 ID: 從選定的模型名稱中提取實際的模型 ID。
    3. 準備載荷: 更新 body 以包括正確的模型 ID。
    4. 發送 API 請求: 向 OpenAI API 的聊天完成端點發送 POST 請求。
    5. 處理流式傳輸: 如果 streamTrue,返回行的可迭代對象。
    6. 錯誤處理: 捕獲異常並返回錯誤訊息。

擴展代理 Pipe

您可以調整此代理 Pipe 以支持其他服務提供商,例如 Anthropic、Perplexity 等,方法是調整 API 端點、標頭和 pipespipe 函數中的邏輯。


使用 Open WebUI 的內部函數

有時,您可能需要在 Pipe 中利用 Open WebUI 的內部函數。您可以直接從 open_webui 套件中導入這些函數。請注意,儘管不太可能,但內部函數可能會因優化目的而更改,因此請務必參考最新的文檔。

以下是您可以使用 Open WebUI 內部函數的方法:

from pydantic import BaseModel, Field
from fastapi import Request

from open_webui.models.users import Users
from open_webui.utils.chat import generate_chat_completion

class Pipe:
def __init__(self):
pass

async def pipe(
self,
body: dict,
__user__: dict,
__request__: Request,
) -> str:
# 使用統一端點與更新後的簽名
user = Users.get_user_by_id(__user__["id"])
body["model"] = "llama3.2:latest"
return await generate_chat_completion(__request__, body, user)

解釋

  • 導入內容:

    • open_webui.models.users 導入 Users: 用於獲取用戶資訊。
    • open_webui.utils.chat 導入 generate_chat_completion: 用於使用內部邏輯生成聊天內容。
  • 異步 pipe 函數:

    • 參數:
      • body: 模型的輸入數據。
      • __user__: 包含用戶資訊的字典。
      • __request__: 來自 FastAPI 的請求對象 (由 generate_chat_completion 需要)。
    • 流程:
      1. 獲取用戶對象: 使用用戶的 ID 獲取用戶對象。
      2. 設置模型: 指定要使用的模型。
      3. 生成完成結果: 調用 generate_chat_completion 處理輸入並生成輸出。

重要說明

  • 函數簽名: 請參閱最新的 Open WebUI 代碼庫或文檔,以獲取最準確的函數簽名和參數。
  • 最佳實踐: 始終妥善處理異常和錯誤以確保用戶體驗順暢。

常見問題

問題 1: 為什麼要在 Open WebUI 中使用 Pipes?

: Pipes 讓您能夠為 Open WebUI 添加具有自定義邏輯和處理的新"模型"。這是一種靈活的插件系統,使您能夠整合外部 API,自定義模型行為,以及創建創新的功能,而無需更改核心代碼庫。


問題 2: Valves 是什麼,為什麼它們很重要?

: Valves 是 Pipe 的可配置參數。它們類似於設置或控制器,決定 Pipe 的運作方式。通過調整 Valves,您可以在不修改底層代碼的情況下更改 Pipe 的行為。


問題 3: 我可以創建沒有 Valves 的 Pipe 嗎?

: 可以,如果您的 Pipe 不需要任何持久的配置選項,您可以創建一個簡單的 Pipe 而不定義 Valves 類。然而,包含 Valves 是一種靈活和未來可擴展的好方法。


問題 4: 如何在使用 API 密鑰時確保我的 Pipe 是安全的?

: 千萬不要在 Pipe 中硬編碼敏感資訊如 API 密鑰。相反,使用 Valves 安全地輸入和存儲 API 密鑰。確保您的代碼妥善處理這些密鑰,避免記錄或暴露它們。


問題 5: pipepipes 函數有什麼區別?

:

  • pipe 函數: 處理輸入數據並生成輸出的主要函數。它處理單個模型的邏輯。

  • pipes 函數: 允許您的 Pipe 表示多個模型,通過返回一個模型定義列表。每個模型都將在 Open WebUI 中單獨顯示。


問題 6: 如何在我的 Pipe 中處理錯誤?

: 在 pipepipes 函數中使用 try-except 塊來捕獲異常。返回有意義的錯誤消息或優雅地處理錯誤,以確保用戶了解發生了什麼問題。


問題 7: 我可以在我的 Pipe 中使用外部庫嗎?

: 可以,您可以根據需要導入並使用外部庫。確保在您的環境中正確安裝和管理任何依賴項。


問題 8: 如何測試我的 Pipe?

: 通過在開發環境中運行 Open WebUI 並從界面中選擇您的自定義模型來測試您的 Pipe。驗證您的 Pipe 在各種輸入和配置下是否按照預期運行。


問題 9: 有關組織我的 Pipe 代碼的最佳實踐嗎?

: 是的,請遵循以下指南:

  • Valves 放在 Pipe 類的頂部。
  • __init__ 方法中初始化變量,主要是 self.valves
  • __init__ 方法之後放置 pipe 函數。
  • 使用清晰且描述性強的變量名稱。
  • 注釋您的代碼以提高可讀性。

問題 10: 我在哪裡可以找到最新的 Open WebUI 文檔?

: 請訪問官方的 Open WebUI 存儲庫或文檔站點,以獲取包括函數簽名、示例和遷移指南 (如果發生變更) 在內的最新資訊。


結論

現在,您應該對如何在 Open WebUI 中創建和使用 Pipes 有了深入的瞭解。Pipes 提供了一種強大的方法來擴展和自定義 Open WebUI 的功能,以適應您的具體需求。無論您是在整合外部 API,添加新模型還是注入複雜邏輯,Pipes 都提供了實現它的靈活性。

請記住:

  • 在您的 Pipe 類中使用清晰且一致的結構
  • 利用 Valves 作為可配置選項。
  • 優雅地處理錯誤 以改善用戶體驗。
  • 查閱最新的文件以瞭解所有更新或變更。

祝開發順利,並享受使用 Pipes 擴展您的 Open WebUI 的樂趣!