気軽に試せるラップトップ環境で、チャットbotを提供するオールインワンの生成AI環境構築から始め、Kubernetesを活用した本格的なGPUクラスタの構築やモデルのファインチューニングまで解説する本連載。今回は、OpenAIが公開したオープンウェイトモデル「gpt-oss」を活用したAIエージェント構築方法を解説します。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
OpenAIのオープンウェイトリーズニングモデル「gpt-oss」が2025年8月5日にリリースされました。gpt-ossは、自律的に状況を判断し、能動的に意思決定をして行動するエージェント能力が飛躍的に向上しています。そのため、MCP(Model Context Protocol)を活用することで、ローカル環境でOpenAIの生成AI(人工知能)モデルと他のツールをきちんと連携させることができます。
そこで本稿では、gpt-ossを活用するユースケースの一つとして、前回の記事で構築したGPUクラスタ環境にgpt-ossをデプロイし、「Open WebUI」と「mcp-grafana」を連携させ、KubernetesのGPU環境とPodのGrafanaのメトリクス/ログをチャット操作で取得し、AIエージェントによりトラブルシューティングを自動化する手順を紹介します。
GPUクラスタ環境はKubernetesと、Kubernetesに新たに追加された「Dynamic Resource Allocation」(DRA)を活用しています。詳細については、下記の記事を参考にしてください。
またOpen WebUIやMCPの詳細については、本連載の過去記事を参考にしてください。
本題に入る前に、OpenAIにより公開されたgpt-ossの特徴を整理します。
gpt-ossは20B(約200億)と120B(約1200億)の2サイズが公開されています。推論でのアクティブパラメーターは120Bで約5.1B、20Bで約3.6Bであり、推論時に利用するパラメーターを抑えつつ高性能を実現しています。Artificial Analysisのレポートでも、少ないパラメーター数で高い性能を発揮することが確認できます。
このアーキテクチャにより、少ないリソースで高速に動作するようになっており、特に20Bのモデルは16GBのVRAMを搭載した家庭用GPUや24GB以上のRAMを持つAppleシリコンを搭載したMacなどでも実用的な速度で実行させることができます。
生成AIモデルが持ち得ない情報を利用してタスクを実行したり、他のアプリケーションを操作したりする際に、Tool Calling(ツール呼び出し、Function Callingとも)の性能が重要になってきています。gpt-ossはツール呼び出しの性能が高く、AIエージェントの構築、実装にも役立つモデルとなっています。
下図は、AIが小売業の業務で、APIやデータベース、検索エンジンなどの外部ツールを適切に利用して、小売業特有の課題を解決できるかどうかを測定するベンチマーク「Tau-Bench Retail」の結果を示したものです。gpt-ossの結果は、一時期、OpenAIのフラグシップ推論モデルだった「OpenAI o3」に匹敵する性能となっています。
MCPサーバをきちんと利用してくれるモデルとなると、従来は商用モデルしか選択肢がありませんでした。gpt-ossはMCPを実用的に利用できるオープンウェイトモデルとして注目されています。
ChatGPTの登場当初、爆弾の製造方法を回答するなど、本来回答すべきでないような危険な事項に対する回答が話題となりました。こうした背景を踏まえ、OpenAIは悪意のある質問に対して回答を抑制する技術を開発し、その技術をgpt-ossにも取り込んでいます。
gpt-ossでは、モデル自身の安全性のみでなく、ファインチューニングで悪意のある目的で知識を追加させた際、能力を低下するような仕組みが備わっています。
OpenAIは、2019年に革新的な生成AIモデルを公開して誰でも利用できるようにしました。これにより、他社の競争が加速し、Metaの「LLaMA」、Googleの「Gemma」などのオープンウェイトモデルが各社からリリースされる流れを生み出しました。
OpenAI APIのようにLLM(大規模言語モデル)操作の標準となるAPIを策定し、生成AIにおけるオープンエコシステムをリードし続けています。こうした中で、gpt-ossが公開された背景には「生成AI技術におけるリーダーシップを取り続ける」という意味が込められていると、筆者は考えています。
ここからは、gpt-ossを活用し、Open WebUIとGrafanaを連携させて、チャットベースでメトリクスやログを調べたり、障害を解析したりできる活用法を解説していきます。
生成AIからGrafanaを操作できるようにするために、本稿では「mcp-grafana」を利用しています。mcp-grafanaを生成AIと組み合わせると、次のようなことができます。
ここからは1と2について紹介します。
mcp-grafanaは、Grafanaエコシステムへのアクセスを提供するMCPサーバです。執筆時点での最新バージョン(v0.7.2)では、ダッシュボード、データソース、Prometheus/Lokiクエリ、アラート、オンコール、インシデント管理、Sift調査、Pyroscopeプロファイリング、ナビゲーションなど、Grafanaの包括的な機能にアクセスできます。
mcp-grafanaは活発に開発されており、2025年7月にリリースされた0.6.2からはGrafana Enterpriseと組み合わせることで、サービスアカウントのRBAC(ロールベースのアクセス制御)によるアクセス制御や、mTLS(mutual Transport Layer Security)によってクライアント/サーバで相互認証した暗号化通信をするといった、より高度な運用ができるようになってきています。
なお、mcp-grafanaの利用にはGrafana 9.0以降が必要です。
今回構築する分析システムは、前回構築したKubernetesのGPU+モニタリング環境を利用します。概要は下記の通りです。
コンポーネント | 説明 |
---|---|
Open WebUI | gpt-ossと対話するためのチャットインタフェースです。mcp-grafanaを利用しながらタスクを実行するエージェント的な機能もgpt-ossと連携させています |
Ollama | gpt-ossを実行します。ユーザーの要求に対して回答を生成したり、ツール(ここではGrafana)呼び出し要求をしたりします |
mcp-grafana | Grafanaの機能をAIエージェントに公開するMCPです |
動作のポイントは、次の通りです。
Open WebUIでMCPを利用するには、従来はmcpoにより、stdio方式のMCPサーバをOpenAPI(OpenAIではないことに注意!)によるREST APIに変換する必要がありました。
Open WebUI 0.6.31以降からStreamable HTTP方式のMCP対応が追加され、mcpoがなくても直接接続できるようになりました。ただしstdio方式のMCPに接続するには、mcpoや次回紹介するAI Gatewayが必要です。
mcpoによるOpenAPIへの変換はOpen WebUI固有の方式となるため、stdio方式のMCPを利用する場合は、今後、AI Gatewayを利用してstdioからStreamable HTTPへ変換して利用することが推奨されます。AI Gatewayについては次回紹介します。
本稿で利用する環境を下記の手順で構築します。
構築に必要なスクリプトはGitHubからも取得できますので、ぜひ利用してください。
本連載第3回でも、GPUを利用したOpen WebUIの構築方法を紹介しました。今回は、KubernetesのDRA Driverで管理されるGPUを利用します。またデスクトップPCでも実行することを前提にリソース消費を抑える設定を行っていましたが、ここでは、性能がフルに発揮できる設定で構築します。Helmでインストール手順は紹介するので、まずは下記のvalues.yamlを用意します。
ingress: enabled: true host: null # 特定のホスト名でWebページにアクセスするには上記hostの値をopen-webui.localのようにホスト名のFQDNにする。 # host: "open-webui.local" extraEnvVars: # デバッグメッセージの出力設定 - name: GLOBAL_LOG_LEVEL value: "DEBUG" - name: OLLAMA_DEBUG value: "1" # Arenaモデルの無効化 - name: ENABLE_EVALUATION_ARENA_MODELS value: "false" # Ollama(推論エンジン)の設定 ollama: enabled: true persistentVolume: # 永続化ストレージを利用 enabled: true size: 300Gi resources: limits: cpu: "8" memory: 64Gi gpu: enabled: true draEnabled: true number: 1 # 利用するGPUの個数
なお、values.yaml内の下記の設定(CPUコア数、メモリ、GPU数〈number〉)はお使いの環境により、値を変更してください。
resources: limits: cpu: "8" memory: 64Gi gpu: ... number: 1
helmを実行してインストールします。
helm upgrade -i --version 8.9.0 --create-namespace open-webui open-webui/open-webui -n open-webui -f values.yaml
values.yamlでGPUの設定をしていれば、GPUはモデルによる推論をするOllamaのPodに自動的に設定されます。下記のコマンドで、ResourceClaimTemplateとResourceClaimが生成されているのが確認できます。
$ kubectl get resourceclaimtemplate -n open-webui NAME AGE gpu-template 45s $ kubectl get resourceclaim -n open-webui NAME STATE AGE ollama-0-shared-gpu-bz8pz allocated,reserved 4d4h
また、Podの中でResourceClaimTemplateを利用してGPUを確保していることも確認できます。
kubectl get pod ollama-xxxxx -oyaml -n open-webui ... resourceClaims: - name: shared-gpu resourceClaimTemplateName: gpu-template ...
Ingressを導入していれば、hostsファイルに、KubernetesノードのIPでopen-webui.localにアクセスできるように設定することで、WebブラウザからOpen WebUIに直接アクセスできるようになります。
[KubernetesのノードのIP] open-webui.local
次に、mcp-grafanaを構築します。下記の手順で構築します。
mcp-grafanaの利用には、Grafanaへ接続するためのサービストークンが必要となるので取得します。
まずはGrafanaにログインし、左のペインのAdministration > Users and access > Service accountsから、Add Service Accountでアカウントを作成します。
続いて、作成したサービスアカウントを選択し、Add service tokenからトークンを取得します。
最後に、取得したトークンをコピーしてメモします。
GrafanaにMCPインタフェースを追加するmcp-grafanaをインストールします。なお、ツール名はmcp-grafanaですが、Helmチャートではgrafana-mcpとしてデプロイされます。つまり、次のように区別されます。
この対応関係を理解しておくと、後の設定手順で混乱を防げます。
Grafana接続情報の設定
Grafanaの接続URLと、先ほど取得したGrafanaのAPIキーを環境変数で設定します。
export GRAFANA_URL="http://lgtm-grafana.monitoring.svc.cluster.local:80" export GRAFANA_API_KEY="glsa_xxxx"
grafana-mcpチャートのインストール準備
grafana-mcpのHelmチャートをインストールする前に、以下のvalues.yamlを作成します。ここでは不要なツールカテゴリーを無効化し、MCPがStreamable HTTPで通信できるように設定します。
# --- 無効化したいツールカテゴリー disabledCategories: - oncall - admin - incident - alerting - sift - pyroscope - asserts # --- Streamable HTTP を有効化(:8000で待受) extraArgs: - -t - streamable-http - --address=0.0.0.0:8000 - --debug
mcp-grafanaでは、--disableオプションにより、指定したカテゴリー(admin,search,dashboard,datasources,prometheus,incident,loki,alerting,oncall,sift,pyroscope,asserts)のツールを無効にできます。不要なツールを無効化することで、誤ったツール呼び出しを減らし、生成AIによるツール利用の精度を向上させることができます。
カテゴリーごとのツールのリストは、0.7.1バージョンのものを本稿末尾に添付しておくので、参考にしてください。最新情報は、mcp-grafanaのサイトをご確認ください。
チャートのインストール
以下のコマンドでgrafana-mcpチャートをインストールします。
helm repo add grafana https://grafana.github.io/helm-charts helm repo update helm upgrade -i grafana-mcp grafana/grafana-mcp \ --version 0.1.3 \ --namespace open-webui --create-namespace \ -f values.yaml \ --set-string grafana.url="$GRAFANA_URL" \ --set-string grafana.apiKey="$GRAFANA_API_KEY"
動作確認
以下のコマンドを実行し、Open WebUIコンテナ内からmcp-grafanaのエンドポイントが正常に応答することを確認します。
$ kubectl exec -n open-webui -it open-webui -- bash $ curl -sS -X POST "http://grafana-mcp.grafana-mcp.svc.cluster.local:8000/mcp" \ -H 'Accept: application/json, text/event-stream' \ -H 'Content-Type: application/json' \ --data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | jq .
{ "jsonrpc": "2.0", "id": 2, "result": { ...(省略)...
ここからは、Open WebUI上の作業になります。WebブラウザからOpen WebUIの画面にアクセスします。Ingressとhostsファイルが正しく設定されていれば、http://open-webui.local/にアクセスすると、Open WebUIの画面が表示されます。
アクセスしたサイトから管理者アカウントの作成とサインインをしてください。分からない場合は、本連載第2回で手順を記載しているのでご覧ください。
Open WebUI画面の左下のユーザーをクリックして、管理者パネル > 設定 > External Toolsから+ボタンを選択してmcp-grafanaを設定します。
下記を設定し、ツールサーバを追加します。
項目 | 設定値 |
---|---|
種類 | MCP(Streamable HTTP) |
URL | http://grafana-mcp.open-webui.svc.cluster.local:8000/mcp |
認証 | Bearer : dummy(本来ならmcp-grafanaのAPIキーだがキーを設定しない場合、適当な値を入れる) |
ID | mcp-grafana |
名前 | mcp-grafana |
可視性 | 公開 |
入力後、接続テストアイコンをクリックし、「接続が成功しました」と表示されると正しく接続されています(下図)。
画面下の「保存」をクリックして設定を保存すれば、設定は完了です。
今回、mcp-grafana導入時に認証のAPIキーを設定していませんが、APIキーを利用しない場合でも執筆時点(Open WebUI v0.6.32)ではダミーのAPIキーが必要なことに注意してください。
「ユーザ名」をクリックして、「設定」 > 「一般」 > 「詳細パラメーター」から、モデルパラメーターを設定します。
パラメーター | 値 | 説明 |
---|---|---|
Function Calling | ネイティブ | モデルがTool Callingをサポートしている場合、標準インタフェースを利用するようネイティブを設定する |
think(Ollama) | オン | モデルの思考プロセスを有効化する |
num_ctx | 20000 | コンテキストのサイズ。大きくしてより多くのテキストを処理できるようにする |
num_gpu | 999 | GPUのVRAMに載せるモデルのレイヤー。999にして全てのレイヤーをGPUに載せるようにする |
Function Callingについては、チャット画面右上の「設定」アイコンからFunction Callingの設定をすることもできます。
Open WebUIのチャット画面から、gpt-oss:120bをプルして取得します。Open WebUI上部の「モデルを選択」から、検索欄に使用したいモデル名(gpt-oss:120b)を入力して、サジェストに表示されるollama.comからモデルをプルします。
MCPを利用するには、モデルがツールを利用するTool Callingに対応している必要があります。Ollamaの場合、下記のコマンドでTool Callingに対応しているかどうか確認できます。
$ ollama show okamototk/gemma-2-llama-swallow:9b ... Capabilities completion tools
toolsと表示されていれば、Tool Callingに対応しています。なお、著名なモデルでもTool Callingに対応していても性能がいまひとつなモデルが多い印象です。gpt-ossの他には「Qwen3」「GLM 4.5(Air)」などもTool Callingの性能が高く注目されています。興味がある人は試してみてください。
Open WebUI上でMCPサーバを利用するには、チャット画面「+」からMCPサーバを選択します。
上記のようにmcp-grafanaとtimeのトグルが表示されることを確認し、mcp-grafanaとtimeを有効にすると、モデルがMCPサーバを利用できるようになります。
この状態で、「現在の時刻を教えてください」と入力します。
tool_get_current_time_postがコールされ、結果と、結果を受けたモデルの応答(現在、2025年7月31日21時40分です、など)が表示されれば、MCPサーバは正しく動作しています。
利用されたツール名をクリックすると、MCPサーバとのメッセージの通信内容を確認できます。
mcp-grafanaを効果的に利用するには、プロンプトテンプレートを設定します。左下のユーザーアイコン > 設定 > 一般 > システムプロンプトから、下記のシステムプロンプトを設定します。
あなたは優れた洞察力を持つ監視アシスタントです - mcp-grafanaを利用して、モニタリング基盤にアクセスすることができます - mcp-grafanaだけでなく、他のFunction Callも効果的に駆使してください - 出力する自然言語は最小限で、日本語で簡潔に回答してください - 得られたログやJSONを出力されることは望んでいません - APIで取得した結果によりコンテキストサイズを超える場合は結果を要約してください
設定画面は下記の通りです。
システムプロンプトを利用しなくても動作しますが、設定することにより、より効果的にGrafanaのタスクを実行できるようになります。
さて、登録したmcp-grafanaを利用してメトリクスを検索してみましょう。チャットのテキストボックスの「+」からmcp-grafanaとtimeプラグインを有効にします。
下記の通り入力します。
過去1時間のメトリクスから負荷が高い3つのPodを教えてください。
下記のような応答が出力されました(注:問い合わせごとに出力内容は異なります)。
負荷が高いPodとして3つのPodを回答しました。CPU使用率が表示されていないので、CPU使用率を明示的に指定して検索します。
過去1時間でCPUの使用率がもっとも高い上位3つのPodとそのメトリクスを教えて
今度は、CPUの使用率も一緒に教えてくれました。
ここで、動作を見ていきましょう。最初の問い合わせの結果を見ると、MCPサーバが下記のように呼び出されているのが分かります。
tool_XXXは、mcp-grafanaが提供するツール名です。この時、下記のように動作していました。
1. tool_list_datasource_post
2. tool_list_prometheus_metrics_names_post
3. tool_query_prometheus_post
4. tool_query_prometheus_post
それぞれ、思考とツール名をクリックすると詳細を見ることができます。例えば、思考をクリックすると、下記のような思考が表示されます。
We need top 3 pods with high load over past hour. Load could be CPU usage. Use metric container_cpu_usage_seconds_total rate. Query Prometheus: rate(container_cpu_usage_seconds_total{job="..."}[5m]) maybe. Need to get per pod sum. Use query: sum by (pod) (rate(container_cpu_usage_seconds_total[5m])) . Then get top 3. Use query_type=instant? Could use range? For top pods over past hour, we can use instant at now with rate over last 5m. Use query_type=instant. Let's execute.
3つの負荷が高いPodを検索するのにPromQLのクエリ(rate(container....total[5m]))を作成して、実行しようとしている様子が分かります。
またツールをクリックすると、ツール呼び出しの詳細を確認できます。下記のMCPツール呼び出しの例では、負荷が高いPod3つを取得するクエリを実行し、結果を取得しているのが分かります。
{ // tool_query_prometheus_postに渡されたパラメーター "datasourceUid": "prom", "endTime": "", "expr": "topk(3, sum by (pod) (rate(container_cpu_usage_seconds_total[5m])))", "queryType": "instant", "startTime": "now", "stepSeconds": 0 } [ // 上記入力に対するgrafana-mcpの出力値(負荷が高いPod3つ) { "metric": { "pod": "open-webui-ollama-f556866cf-ln6v9" }, "value": [ 1755047581.294, "1.0392317966869316" ] }, { "metric": { "pod": "k8s-monitoring-alloy-operator-6d4d55d7c9-dvtb5" }, "value": [ 1755047581.294, "0.09001269068883878" ] }, { "metric": { "pod": "kube-apiserver-node1a-1" }, "value": [ 1755047581.294, "0.0895756641445195" ] } ]
次に、Kubernetesのイベントログを検索してみましょう。新しいチャットを開き、mcp-grafanaとtimeツールを同様に有効にして、下記のように質問してみます。
過去15分間でKubernetesのイベントステータスを調査してください
特定のPodでエラーが発生していることをレポートしてくれました。続いて、次のように入力し、原因の特定をしてみます。
simple-application名前空間のPod simple-application-645b54d7b-zljb4(node1a-1)のログから、失敗原因を特定して
次のような回答があり、イメージ名が誤っている可能性を指摘してくれました。
このように、MCPを活用することで、生成AIモデルを活用して障害原因の特定も自動化する取り組みが始められるようになりつつあります。
ローカル環境で利用できるオープンウェイトモデルでも、高度なタスクをこなせるようになってきたことがお分かりいただけたでしょうか。Open WebUIは、Ollamaの他に、OpenAIやOpen Routerで提供されるクラウドモデルを利用することもできます。
高機能なローカルモデルを使うのが難しい人でも簡単にMCPサーバによる高度な機能拡張を試すことができます。ぜひ、本稿を参考にさまざまなオープンウェイトモデルやMCPサーバを試してみてください。
mcp-grafanaでは以下のツールが利用可能です。mcp-grafanaを利用する際に、これらのツールがあることを理解していると、指示する際の参考になります。
青字で示しているのがツールのカテゴリーです。カテゴリーの後ろにあるかっこは、そのカテゴリーのツールを無効化する際のキーワードとして利用します(例:Dashboardカテゴリーのツールを無効化する場合は--disable-dashboardと指定します)。
関数(引数) | 説明 |
---|---|
Dashboards(dashboard) | |
search_dashboards(name) | ダッシュボードを検索します |
get_dashboard_by_uid(uid) | UIDからダッシュボードの詳細を取得します |
update_dashboard(dashboard_json) | ダッシュボードを作成または更新します |
get_dashboard_panel_queries(dashboard_uid) | ダッシュボードパネルのクエリとデータソース情報を取得します |
get_dashboard_property() | JSONPathを使用してダッシュボードの一部を取得します |
get_dashboard_summary() | 完全なダッシュボードのJSONではなく、コンパクトなダッシュボードの概要を取得します |
Datasources(datasource) | |
list_datasources() | データソースの一覧を取得します |
get_datasource_by_uid(uid) | UIDからデータソースの詳細を取得します |
get_datasource_by_name(name) | 名前からデータソースの詳細を取得します |
Prometheus(prometheus) | |
query_prometheus(query, datasource, start, end, step) | PromQLクエリを実行します |
list_prometheus_metric_metadata(metric) | メトリクスのメタデータを取得します |
list_prometheus_metric_names() | 利用可能なメトリクス名の一覧を取得します |
list_prometheus_label_names(selector) | ラベル名の一覧を取得します |
list_prometheus_label_values(label, selector) | ラベル値の一覧を取得します |
Loki(loki) | |
query_loki_logs(query, datasource, start, end, limit) | LogQLによるログクエリを実行します |
list_loki_label_names() | ログラベル名の一覧を取得します |
list_loki_label_values(label) | ログラベル値の一覧を取得します |
query_loki_stats(query, datasource, start, end) | ログストリームの統計情報を取得します |
Alerting(alerting) | |
list_alert_rules() | アラートルールの一覧を取得します |
get_alert_rule_by_uid(uid) | UIDからアラートルールの詳細を取得します |
list_contact_points() | 通知コンタクトポイントの一覧を取得します |
OnCall(oncall) | |
list_oncall_schedules() | オンコールスケジュールの一覧を取得します |
get_oncall_shift(schedule_id, time) | オンコールシフトの詳細を取得します |
get_current_oncall_users(schedule_id) | 現在のオンコール担当者を取得します |
list_oncall_teams() | オンコールチームの一覧を取得します |
list_oncall_users() | オンコールユーザーの一覧を取得します |
list_alert_groups(page,id,routeId,integrationId,state,teamId,startedAt,labels,name) | アラートグループ一覧を取得します |
get_alert_group(alertGroupId) | IDで指定したアラートグループを取得 |
Incidents(incident) | |
list_incidents() | インシデントの一覧を取得します |
create_incident(title, description) | インシデントを作成します |
add_activity_to_incident(incident_id, activity) | インシデントにアクティビティーを追加します |
get_incident(incident_id) | インシデントの詳細を取得します |
Sift Investigations(sift) | |
list_sift_investigations(limit) | Sift調査の一覧を取得します |
get_sift_investigation(uuid) | UUIDからSift調査の詳細を取得します |
get_sift_analysis(investigation_uuid, analysis_id) | Sift分析結果を取得します |
find_error_pattern_logs(query, datasource, start, end) | ログからエラーパターンを検出します |
find_slow_requests() | 遅いリクエストを検出します |
Pyroscope Profiling(pyroscope) | |
list_pyroscope_label_names(selector) | Pyroscopeラベル名の一覧を取得します |
list_pyroscope_label_values(label, selector) | Pyroscopeラベル値の一覧を取得します |
list_pyroscope_profile_types() | 利用可能なプロファイルタイプの一覧を取得します |
fetch_pyroscope_profile(query, profile_type, start, end) | プロファイルデータを取得します |
Admin(admin) | |
list_teams() | チームの一覧を取得します |
list_users_by_org() | 組織内のユーザー一覧を取得します |
Asserts(asserts) | |
get_assertions(entity) | エンティティのアサーション要約を取得します |
Navigation(navigation) | |
generate_deeplink | Grafanaリソースの正確なディープリンクURLを生成します |
Copyright © ITmedia, Inc. All Rights Reserved.