๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

๐Ÿšฐ Pipe Function: Create Custom "Agents/Models"

Open WebUI์—์„œ **ํŒŒ์ดํ”„(Pipes)**๋ฅผ ๋งŒ๋“œ๋Š” ๊ฐ€์ด๋“œ์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! ํŒŒ์ดํ”„๋Š” Open WebUI์— ์ƒˆ๋กœ์šด ๋ชจ๋ธ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ๊ฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” ํŒŒ์ดํ”„๊ฐ€ ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  Open WebUI ๋ชจ๋ธ์— ์‚ฌ์šฉ์ž ์ •์˜๋œ ๋กœ์ง๊ณผ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ๋งŒ์˜ ํŒŒ์ดํ”„๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ๋น„์œ ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์„ธ๋ถ€์‚ฌํ•ญ์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋‹ค๋ฃจ์–ด ํฌ๊ด„์ ์ธ ์ดํ•ด๋ฅผ ๋„์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„ ์†Œ๊ฐœโ€‹

Open WebUI๋ฅผ ๋ฐฐ๊ด€ ์‹œ์Šคํ…œ์œผ๋กœ ์ƒ์ƒํ•ด๋ณด์„ธ์š”. ๋ฐ์ดํ„ฐ๊ฐ€ ํŒŒ์ดํ”„์™€ ๋ฐธ๋ธŒ๋ฅผ ํ†ตํ•ด ํ๋ฆ…๋‹ˆ๋‹ค. ์ด ๋น„์œ ์—์„œ:

  • ํŒŒ์ดํ”„(Pipes): ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅผ ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ๋ฅผ ์†Œ๊ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ •์˜๋œ ๋กœ์ง๊ณผ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ๋ฐธ๋ธŒ(Valves): ํŒŒ์ดํ”„๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅด๋Š” ๋ฐฉ์‹์„ ์ œ์–ดํ•˜๋Š” ์กฐ์ • ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ฅผ ๋งŒ๋“ค๋ฉด 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) # ์ด๋Š” ๊ตฌ์„ฑ ์˜ต์…˜๊ณผ ์ž…๋ ฅ ๋ณธ๋ฌธ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค
return "Hello, World!"

Pipe ํด๋ž˜์Šคโ€‹

  • ์ •์˜: Pipe ํด๋ž˜์Šค๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๋กœ์ง์„ ์ •์˜ํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
  • ๋ชฉ์ : Open WebUI ๋‚ด์—์„œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์ฒญ์‚ฌ์ง„ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐธ๋ธŒ(Valves): ํŒŒ์ดํ”„ ๊ตฌ์„ฑํ•˜๊ธฐโ€‹

  • ์ •์˜: Valves๋Š” Pipe ๋‚ด๋ถ€์˜ ํด๋ž˜์Šค์ด๋ฉฐ BaseModel์„ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.
  • ๋ชฉ์ : ํŒŒ์ดํ”„ ์‚ฌ์šฉ ์ค‘ ์ง€์† ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ์˜ต์…˜(๋งค๊ฐœ๋ณ€์ˆ˜)์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ: ์œ„ ์ฝ”๋“œ์—์„œ๋Š” MODEL_ID๊ฐ€ ๊ธฐ๋ณธ ๋นˆ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง„ ๊ตฌ์„ฑ ์˜ต์…˜์ž…๋‹ˆ๋‹ค.

๋น„์œ : ๋ฐธ๋ธŒ๋Š” ์‹ค์ œ ์„ธ์ƒ์—์„œ ๋ฌผ์˜ ํ๋ฆ„์„ ์ œ์–ดํ•˜๋Š” ํŒŒ์ดํ”„ ์‹œ์Šคํ…œ์˜ ์†์žก์ด์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํŒŒ์ดํ”„์—์„œ ๋ฐธ๋ธŒ๋Š” ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„๊ณผ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์‚ฌ์šฉ์ž๋“ค์ด ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

__init__ ๋ฉ”์„œ๋“œโ€‹

  • ์ •์˜: Pipe ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.
  • ๋ชฉ์ : ํŒŒ์ดํ”„์˜ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ํ•„์š”ํ•œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์ตœ์  ์‹ค์ฒœ: ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋ฉฐ self.valves๋ฅผ ์ฃผ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
def __init__(self):
self.valves = self.Valves()

pipe ํ•จ์ˆ˜โ€‹

  • ์ •์˜: ์‚ฌ์šฉ์ž ์ •์˜ ๋กœ์ง์ด ์ž๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
  • ๋งค๊ฐœ๋ณ€์ˆ˜:
    • body: ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ์ž…๋‹ˆ๋‹ค.
  • ๋ชฉ์ : ์‚ฌ์šฉ์ž ์ •์˜ ๋กœ์ง์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
def pipe(self, body: dict):
# ๋กœ์ง์ด ์—ฌ๊ธฐ์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค
print(self.valves, body) # ์ด๋Š” ๊ตฌ์„ฑ ์˜ต์…˜๊ณผ ์ž…๋ ฅ ๋ณธ๋ฌธ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค
return "Hello, World!"

์ฐธ๊ณ : ํ•ญ์ƒ Valves๋ฅผ Pipe ํด๋ž˜์Šค์˜ ์ƒ๋‹จ์— ์œ„์น˜์‹œํ‚ค๊ณ , ๊ทธ ๋’ค์— __init__์„ ๋‘๋ฉฐ pipe ํ•จ์ˆ˜๋ฅผ ์œ„์น˜์‹œํ‚ต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋Š” ๋ช…ํ™•์„ฑ๊ณผ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.


ํŒŒ์ดํ”„๋ฅผ ํ†ตํ•ด ๋‹ค์ค‘ ๋ชจ๋ธ ์ƒ์„ฑํ•˜๊ธฐโ€‹

Open WebUI ๋‚ด์—์„œ ๋‹ค์ค‘ ๋ชจ๋ธ์„ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ์ด๋Š” Pipe ํด๋ž˜์Šค ์•ˆ์— pipes ํ•จ์ˆ˜ ๋˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•จ์œผ๋กœ์จ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„ค์ •์€ ๋น„๊ณต์‹์ ์œผ๋กœ **๋‹ค์ค‘ ๋ถ„๋ฐฐ๊ธฐ(manifold)**๋ผ ๋ถˆ๋ฆฌ๋ฉฐ, ํŒŒ์ดํ”„๊ฐ€ ์—ฌ๋Ÿฌ ๋ชจ๋ธ์„ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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) # ๊ตฌ์„ฑ ์˜ต์…˜๊ณผ ์ž…๋ ฅ ๋ณธ๋ฌธ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค
model = body.get("model", "")
return f"{model}: Hello, World!"

์„ค๋ช…โ€‹

  • pipes ํ•จ์ˆ˜:

    • ๋”•์…”๋„ˆ๋ฆฌ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ ๋”•์…”๋„ˆ๋ฆฌ๋Š” ๊ณ ์œ ํ•œ id์™€ name ํ‚ค๋ฅผ ๊ฐ€์ง„ ๋ชจ๋ธ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
    • ์ด๋Ÿฌํ•œ ๋ชจ๋ธ์€ ๊ฐœ๋ณ„์ ์œผ๋กœ Open WebUI ๋ชจ๋ธ ์„ ํƒ๊ธฐ์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์—…๋ฐ์ดํŠธ๋œ pipe ํ•จ์ˆ˜:

    • ์„ ํƒ๋œ ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ์˜ˆ์—์„œ๋Š” ๋ฐ˜ํ™˜ ๋ฌธ์ž์—ด์— ๋ชจ๋ธ ์ด๋ฆ„์„ ํฌํ•จ์‹œํ‚ต๋‹ˆ๋‹ค.

์˜ˆ์‹œ: OpenAI ํ”„๋ก์‹œ ํŒŒ์ดํ”„โ€‹

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 :]

# ๋ณธ๋ฌธ์—์„œ ๋ชจ๋ธ 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. ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ: ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜ํ™˜ ํ˜•์‹: ๊ฐ ๋ชจ๋ธ์— ๋Œ€ํ•ด id ๋ฐ name์„ ํฌํ•จํ•˜๋Š” ์‚ฌ์ „ ๋ฆฌ์ŠคํŠธ.

pipe ํ•จ์ˆ˜โ€‹

  • ๋ชฉ์ : ์„ ํƒํ•œ OpenAI ๋ชจ๋ธ์— ๋Œ€ํ•œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ๋งค๊ฐœ๋ณ€์ˆ˜:

    • body: ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
    • __user__: ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค (์ด ์˜ˆ์ œ์—์„œ๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š์ง€๋งŒ ์ธ์ฆ ๋˜๋Š” ๋กœ๊ทธ์— ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Œ).
  • ์ ˆ์ฐจ:

    1. ํ—ค๋” ์ค€๋น„: API ํ‚ค์™€ ์ฝ˜ํ…์ธ  ์œ ํ˜•์œผ๋กœ ํ—ค๋”๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    2. ๋ชจ๋ธ ID ์ถ”์ถœ: ์„ ํƒํ•œ ๋ชจ๋ธ ์ด๋ฆ„์—์„œ ์‹ค์ œ ๋ชจ๋ธ ID๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
    3. ํŽ˜์ด๋กœ๋“œ ์ค€๋น„: ์˜ฌ๋ฐ”๋ฅธ ๋ชจ๋ธ ID์™€ ํ•จ๊ป˜ ๋ณธ๋ฌธ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
    4. API ์š”์ฒญ ์‹คํ–‰: OpenAI API์˜ ์ฑ„ํŒ… ์™„์„ฑ ์—”๋“œํฌ์ธํŠธ์— POST ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
    5. ์ŠคํŠธ๋ฆฌ๋ฐ ์ฒ˜๋ฆฌ: stream์ด True์ด๋ฉด ๋ผ์ธ์˜ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    6. ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ: ์˜ˆ์™ธ๋ฅผ ํฌ์ฐฉํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ก์‹œ ํŒŒ์ดํ”„ ํ™•์žฅโ€‹

Anthropic, Perplexity ๋“ฑ์˜ ์ถ”๊ฐ€ ์„œ๋น„์Šค ์ œ๊ณต์ž๋ฅผ ์ง€์›ํ•˜๋„๋ก ์ด ํ”„๋ก์‹œ Pipe๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด, pipes ๋ฐ pipe ํ•จ์ˆ˜ ๋‚ด์—์„œ API ์—”๋“œํฌ์ธํŠธ, ํ—ค๋” ๋ฐ ๋กœ์ง์„ ์กฐ์ •ํ•˜์„ธ์š”.


๋‚ด๋ถ€ 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
open_webui.utils.chat์—์„œ generate_chat_completion ๊ฐ€์ ธ์˜ค๊ธฐ

ํด๋ž˜์Šค 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)

์„ค๋ช…โ€‹

  • Imports:

    • Users from open_webui.models.users: ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด.
    • generate_chat_completion from open_webui.utils.chat: ๋‚ด๋ถ€ ๋กœ์ง์„ ์‚ฌ์šฉํ•ด ์ฑ„ํŒ… ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด.
  • ๋น„๋™๊ธฐ pipe ํ•จ์ˆ˜:

    • ๋งค๊ฐœ๋ณ€์ˆ˜:
      • body: ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ.
      • __user__: ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ.
      • __request__: FastAPI์˜ ์š”์ฒญ ๊ฐ์ฒด (generate_chat_completion์— ํ•„์š”).
    • ํ”„๋กœ์„ธ์Šค:
      1. ์‚ฌ์šฉ์ž ๊ฐ์ฒด ๊ฐ€์ ธ์˜ค๊ธฐ: ID๋ฅผ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉ์ž ๊ฐ์ฒด๋ฅผ ๊ฒ€์ƒ‰.
      2. ๋ชจ๋ธ ์„ค์ •: ์‚ฌ์šฉ๋  ๋ชจ๋ธ ์ง€์ •.
      3. ๋‹ต๋ณ€ ์ƒ์„ฑ: generate_chat_completion ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ถœ๋ ฅ ์ƒ์„ฑ.

์ค‘์š”ํ•œ ์ฐธ๊ณ ์‚ฌํ•ญโ€‹

  • ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜: ์ตœ์‹  Open WebUI ์ฝ”๋“œ๋ฒ ์ด์Šค ๋˜๋Š” ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ€์žฅ ์ •ํ™•ํ•œ ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  • ์ตœ์‹  ๊ด€ํ–‰: ์˜ˆ์™ธ์™€ ์˜ค๋ฅ˜๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜์—ฌ ์›ํ™œํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋ณด์žฅํ•˜์„ธ์š”.

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธโ€‹

Q1: ์™œ Open WebUI์—์„œ Pipe๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?โ€‹

A: Pipe๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Open WebUI์— ์‚ฌ์šฉ์ž ์ •์˜ ๋…ผ๋ฆฌ ๋ฐ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด "๋ชจ๋ธ"์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์™ธ๋ถ€ API๋ฅผ ํ†ตํ•ฉํ•˜๊ณ , ๋ชจ๋ธ ๋™์ž‘์„ ์ˆ˜์ •ํ•˜๋ฉฐ, ํ•ต์‹ฌ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ํ˜์‹ ์ ์ธ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.


Q2: Valves๋ž€ ๋ฌด์—‡์ด๋ฉฐ ์™œ ์ค‘์š”ํ•œ๊ฐ€์š”?โ€‹

A: Valves๋Š” Pipe์˜ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์„ค์ • ๋˜๋Š” ์ปจํŠธ๋กค๊ณผ ๊ฐ™์œผ๋ฉฐ Pipe๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. Valves๋ฅผ ์กฐ์ •ํ•˜๋ฉด ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ Pipe์˜ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Q3: Valves ์—†์ด Pipe๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‚˜์š”?โ€‹

A: ๋„ค, ์ง€์†์ ์ธ ๊ตฌ์„ฑ ์˜ต์…˜์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ Pipe์˜ ๊ฒฝ์šฐ Valves ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๊ณ  ๊ฐ„๋‹จํ•œ Pipe๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Flexibility์™€ ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ์„ ์œ„ํ•ด Valves๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ด€ํ–‰์ž…๋‹ˆ๋‹ค.


Q4: API ํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ Pipe์˜ ๋ณด์•ˆ์„ ์–ด๋–ป๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?โ€‹

A: API ํ‚ค์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ ˆ๋Œ€ Pipe์— ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  Valves๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API ํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ž…๋ ฅํ•˜๊ณ  ์ €์žฅํ•˜์„ธ์š”. ์ด๋Ÿฌํ•œ ํ‚ค๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜ ๋…ธ์ถœ์‹œํ‚ค์ง€ ์•Š๋„๋ก ํ•˜์„ธ์š”.


Q5: pipe ํ•จ์ˆ˜์™€ pipes ํ•จ์ˆ˜์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?โ€‹

A:

  • pipe ํ•จ์ˆ˜: ์ฃผ ๋ชจ๋ธ์˜ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•˜๋Š” ์ฃผ์š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‹จ์ผ ๋ชจ๋ธ์˜ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • pipes ํ•จ์ˆ˜: ์—ฌ๋Ÿฌ ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ •์˜ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•จ์œผ๋กœ์จ Pipe๊ฐ€ ์—ฌ๋Ÿฌ ๋ชจ๋ธ์„ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ชจ๋ธ์€ Open WebUI์—์„œ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.


Q6: Pipe์—์„œ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€?โ€‹

A: pipe ๋ฐ pipes ํ•จ์ˆ˜ ๋‚ด์—์„œ try-except ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์™ธ๋ฅผ ํฌ์ฐฉํ•˜์„ธ์š”. ์˜๋ฏธ ์žˆ๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๋ฅผ ๊ฒ€์ฆํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์„ธ์š”.


Q7: Pipe์—์„œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?โ€‹

A: ๋„ค, ํ•„์š”ํ•  ๊ฒฝ์šฐ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋‚ด์—์„œ ๋ชจ๋“  ์ข…์†์„ฑ์ด ์ ์ ˆํžˆ ์„ค์น˜๋˜๊ณ  ๊ด€๋ฆฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.


Q8: Pipe๋ฅผ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๋‚˜์š”?โ€‹

A: ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ Open WebUI๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ชจ๋ธ์„ ์„ ํƒํ•˜์—ฌ Pipe๋ฅผ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”. Pipe๊ฐ€ ๋‹ค์–‘ํ•œ ์ž…๋ ฅ ๋ฐ ์„ค์ •์—์„œ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.


Q9: Pipe ์ฝ”๋“œ๋ฅผ ์กฐ์งํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?โ€‹

A: ๋„ค, ๋‹ค์Œ ์ง€์นจ์„ ๋”ฐ๋ฅด์„ธ์š”:

  • Valves๋ฅผ Pipe ํด๋ž˜์Šค์˜ ์ƒ๋‹จ์— ์œ„์น˜์‹œํ‚ค์„ธ์š”.
  • __init__ ๋ฉ”์„œ๋“œ์—์„œ ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์„ธ์š”, ์ฃผ๋กœ self.valves๋ฅผ.
  • __init__ ๋ฉ”์„œ๋“œ ๋‹ค์Œ์— pipe ํ•จ์ˆ˜๋ฅผ ๋ฐฐ์น˜ํ•˜์„ธ์š”.
  • ๋ช…ํ™•ํ•˜๊ณ  ์„ค๋ช…์ ์ธ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์ฝ”๋“œ๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์„์„ ์ž‘์„ฑํ•˜์„ธ์š”.

Q10: ์ตœ์‹  Open WebUI ๋ฌธ์„œ๋Š” ์–ด๋””์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‚˜์š”?โ€‹

A: ๊ณต์‹ Open WebUI ์ €์žฅ์†Œ ๋˜๋Š” ๋ฌธ์„œ ์‚ฌ์ดํŠธ๋ฅผ ๋ฐฉ๋ฌธํ•˜์—ฌ ๊ฐ€์žฅ ์ตœ์‹  ์ •๋ณด, ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜, ์˜ˆ์ œ ๋ฐ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.


๊ฒฐ๋ก โ€‹

์ด์ œ Open WebUI์—์„œ Pipe๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ฒ ์ €ํžˆ ์ดํ•ดํ•˜์…จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Pipe๋Š” Open WebUI์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๊ณ  ๋งž์ถคํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ API๋ฅผ ํ†ตํ•ฉํ•˜๋“ , ์ƒˆ๋กœ์šด ๋ชจ๋ธ์„ ์ถ”๊ฐ€ํ•˜๋“ , ๋ณต์žกํ•œ ๋…ผ๋ฆฌ๋ฅผ ์‚ฝ์ž…ํ•˜๋“ , Pipe๋Š” ์ด๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์–ตํ•˜์„ธ์š”:

  • Pipe ํด๋ž˜์Šค์—์„œ ๋ช…ํ™•ํ•˜๊ณ  ์ผ๊ด€๋œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์„ ์œ„ํ•ด Valves๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”.
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜๋ฅผ ์‹ ์ค‘ํžˆ ์ฒ˜๋ฆฌํ•˜์„ธ์š”.
  • ์ตœ์‹  ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š” ์—…๋ฐ์ดํŠธ๋‚˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋”ฉ์„ ์ฆ๊ธฐ์‹œ๊ณ , Pipes๋กœ Open WebUI๋ฅผ ํ™•์žฅํ•˜๋Š” ์žฌ๋ฏธ๋ฅผ ๋ˆ„๋ฆฌ์„ธ์š”!