チャットボックスを超えて:ローカルLLMを現実の世界に繋ぐ
OllamaとOpen-WebUIを使用してローカルLLMを実行することは、プライバシーを重視する開発者にとっての定番の構成となっています。これはChatGPTのような体験を再現しながら、すべてのトークンを自身のハードウェア内に保持できます。しかし、スタンドアロンのLLMは往々にして孤立したサイロになりがちです。PostgreSQLデータベースをクエリすることも、現在のJiraチケットのステータスを知ることもできず、独自の企業スタイルガイドを強制することもできません。
Open-WebUI Pipelinesは、プログラム可能なミドルウェアとして機能することでこのギャップを埋めます。これらは会話の「インターセプター(遮断機)」のようなものだと考えてください。プロンプトがモデルに届く前に機密データを削除したり、モデルの出力が画面に表示される前にフォーマットを整えたりすることができます。規制の厳しい環境でこれらをデプロイしてきた私の経験では、パイプラインはAIアシスタントがその役割を逸脱しないようにするための最も信頼できる方法です。
パイプライン・アーキテクチャの仕組み
パイプラインはセカンダリサービスとして機能します。通常、Open-WebUIインスタンスと並んで軽量なDockerコンテナ内で動作します。「送信」をクリックすると、Open-WebUIはAPIコールを介してメッセージのペイロードをパイプラインサーバーに送信します。このセットアップによるオーバーヘッドは通常50ms未満であり、ユーザーにとっては瞬時に切り替わったように感じられます。
パイプラインの3つの柱
- Pipeクラス: これがエントリポイントです。Open-WebUIが認識し、インターフェースにロードするPythonクラスです。
- Valves(バルブ): 設定ダッシュボードとして機能します。TavilyやLangChainなどのサービスのAPIキーをハードコードする代わりに、Valvesとして定義します。これらはUI設定のテキストフィールドとして表示され、迅速な更新が可能です。
- Filters(フィルタ)とActions(アクション): フィルタはテキストストリームをリアルタイムで修正します。アクションは、特定のトピックが言及されたときにSlack通知を送信するなど、特定のイベントをトリガーします。
パイプラインエンジンの起動
Pythonを書く前に、パイプラインエンジンを実行させる必要があります。Dockerを使用している場合は、単一のコマンドで公式イメージを起動できます。このコンテナはスクリプトを監視し、変更を保存するたびに自動的にリロードします。
docker run -d -p 9099:9099 --add-host=host.docker.internal:host-gateway -v pipelines:/app/pipelines --name pipelines ghcr.io/open-webui/pipelines:main
/app/pipelinesディレクトリに移動したPythonファイルは自動的に検出されます。新しいロジックをOpen-WebUIのダッシュボードに反映させるためにコンテナを再起動する必要すらありません。
実践チュートリアル:PIIサニティフィルタの構築
LLMが内部プロジェクト名を漏洩するのを防ぐフィルタを構築しましょう。「Project-X」や「Internal-Vault」のような機密用語を、ユーザーの目に触れる前に編集済みのプレースホルダーに置き換えます。
1. スクリプトの作成
security_filter.pyという名前のファイルを作成します。UI設定を定義するためにPydanticを使用します。これにより、技術者でないユーザーでもブラウザから直接、制限ワードリストを更新できるようになります。
from typing import List, Optional, Union, Generator
from pydantic import BaseModel, Field
class Pipeline:
class Valves(BaseModel):
# これらのフィールドはOpen-WebUIの設定として表示されます
blacklisted_terms: str = Field(default="Project-X,Internal-Vault,Top-Secret")
replacement_label: str = Field(default="[削除済み]")
def __init__(self):
self.type = "filter"
self.name = "セキュリティ・スクラブ・フィルタ"
self.valves = self.Valves()
async def outlet(self, body: dict, user: Optional[dict] = None) -> dict:
# これはLLMがレスポンスを生成した後に実行されます
terms = self.valves.blacklisted_terms.split(",")
content = body.get("messages", [])[-1].get("content", "")
for term in terms:
clean_term = term.strip()
if clean_term in content:
content = content.replace(clean_term, self.valves.replacement_label)
body["messages"][-1]["content"] = content
return body
2. 外部APIへの接続
パイプラインは「仮想モデル」としても機能します。単なるフィルタリングだけでなく、クエリを外部ツールにルーティングすることもできます。例えば、ユーザーが天気の更新を求めた場合、パイプラインはOpenWeather APIを呼び出してデータを直接返し、標準のLLM生成をバイパスすることができます。
import requests
class Pipeline:
def __init__(self):
self.name = "ライブデータ・アシスタント"
async def pipe(self, body: dict, user: Optional[dict] = None) -> str:
last_message = body.get("messages", [])[-1].get("content", "").lower()
if "ハノイの天気" in last_message:
# 実際のシナリオでは、ここでセキュアなAPIコールを使用してください
return "現在のハノイの気温は28℃、湿度は80%です。"
return "現時点ではハノイの気象データのみにアクセス可能です。"
本番環境からの教訓
私は社内チームのために、これらのワークフローの改良に数ヶ月を費やしてきました。ローカルの実験から20人が使用するツールへと移行するには、安定性と速度に重点を置く必要があります。
非同期呼び出しを優先する
外部APIに対して標準のPython requestsを使用しないでください。これはメインスレッドをブロックします。APIの応答に3秒かかる場合、UI全体が全員に対してフリーズしてしまいます。インターフェースの軽快さを保つために、async/awaitを備えたhttpxを使用してください。
堅牢なエラーフォールバックの構築
APIは失敗するものです。パイプラインがクラッシュすると、Open-WebUIは一般的な「Server Error」を返し、ユーザーを失望させます。常にロジックを try-except ブロックで囲んでください。ツールが失敗した場合は、役立つメッセージを返すか、クエリをLlama 3のようなローカルのバックアップモデルにルーティングするようにパイプラインをプログラムしましょう。
Valvesでロジックのポータビリティを維持する
シークレット情報をハードコードしないでください。データベース文字列からAPIトークンまで、すべてに Valves クラスを使用してください。これにより、個人の資格情報を公開することなく、.py スクリプトをチームと共有できます。チームメンバーは、設定 > パイプライン メニューに自分のキーを入力するだけで済みます。
結論
Open-WebUI Pipelinesは、基本的なチャットインターフェースを強力なオーケストレーションレイヤーへと変貌させます。数行のPythonを書くだけで、ローカルAIとデータの対話方法を変えることができます。まずは簡単なテキストフィルタから始めて、感覚を掴んでください。その統合の容易さを実感できれば、AIを真に有用なものにする複雑なマルチツールワークフローの構築を開始できるはずです。

