Docker Model Runner で AI チャットボットをゼロから作成する方法

この記事では、Docker Model Runner と Prometheus、Grafana、Jaeger といった強力な可観測性ツールを活用して、本番環境レベルの生成 AI チャットボットをビルドする方法をご紹介します。

開発者が AI 搭載アプリケーションを開発する際によく直面する課題を整理し、それに対して Docker Model Runner がどのように解決策を提供できるのかを解説。そのうえで、チャットボットのビルド プロセスをステップバイステップでご紹介します。ビルド後には、リアルタイムのモニタリングやストリーミング応答、そしてモダンな React ベースの UI まで含めた、ローカルで動作するチャットボットの完成形をご確認いただけます。

生成 AI 開発における現在の課題

生成 AI (GenAI) はソフトウェア開発の在り方を大きく変えつつありますが、AI 搭載アプリの開発にはいくつかの大きなハードルがあります。

まず、開発環境が断片化していること。さまざまなライブラリやフレームワーク、プラットフォームを組み合わせる必要がありますが、それらは元々連携を前提に設計されていないため、統合に手間がかかります。

次に、大規模言語モデルを効率よく動かすためには特殊なハードウェア構成が必要であり、それが環境ごとに異なる点です。AI モデルの実行環境が、アプリケーション コードの実行環境 (たとえば Docker など) と切り離されているため、コードとモデルで別々の環境を維持しなければならないという負担が生まれています。

さらに、モデルの保存、バージョン管理、提供に関する標準的な方法が存在しないため、デプロイが一貫せず、チーム間での連携が困難になります。クラウドベースの AI サービスに依存すると、利用量に応じて予測しにくいコストが発生するうえに、機密性の高いデータを外部に送信することによるセキュリティやプライバシーのリスクも伴います。

これらの課題が組み合わさることで、開発者体験は損なわれ、企業が AI 導入を加速させたいタイミングでの実験、検証やイノベーションが停滞する原因となっているのです。

Docker がこの課題をどう解決するか

Docker Model Runner は、AI モデルの実行を Docker コンテナーのワークフローに直接統合することで、こうした課題を根本から解決します。

図 1: 従来の複雑なマルチステップの GenAI セットアップと、Docker Model Runner によるシンプルなワンコマンドのワークフローとの比較図

多くの開発者が、コンテナー化された AI モデルを活用しており、統合されたワークフロー、コスト管理、データのプライバシーといった恩恵を受けています。Docker Model Runner は、これらの利点をさらに強化し、モデルの取り扱いをより簡単かつ効率的にします。

Model Runner は、Docker のインターフェースを維持しながらホストマシン上でモデルをネイティブに実行できるため、開発体験を大幅に向上させます。

Docker Model Runner の主な特長

  • シンプルなモデル実行。複雑なセットアップ不要。Docker CLI コマンド 1 つでローカル実行が可能
  • ハードウェア アクセラレーション。コンテナーによるオーバーヘッドなしで GPU リソースに直接アクセス
  • 統合された開発ワークフロー。既存の Docker ツールや開発手法とシームレスに連携
  • 標準化されたパッケージング。既存のレジストリを使って OCI アーティファクトとしてモデルを配布可能
  • コスト管理。ローカル実行により予測しにくい API コストを回避
  • データプライバシーの確保。外部 API を使わず、機密データを自社インフラ内に留めることが可能

このアプローチにより、AI 搭載アプリケーションの開発とテストのあり方が根本的に変化します。ローカル環境での開発が、より高速、安全、効率的になります。

Docker で AI チャットボットを作る方法

このガイドでは、Docker Model Runner を活用して、高機能なチャットインターフェースを備えた GenAI アプリケーションをビルドします。また、モデルのパフォーマンスを監視、最適化するための高度な可観測性ツールも組み込みます。

プロジェクト概要

このプロジェクトでは、以下を実装します。

  • React/TypeScript によるレスポンシブなチャット UI (ストリーミング応答付き)
  • Docker Model Runner と連携する Go 製バックエンド サーバー
  • メトリクス ログ トレースを含む包括的な可観測性の導入
  • リアルタイムで AI モデルのパフォーマンスを監視する仕組み

アーキテクチャ

このアプリケーションは、以下の主要コンポーネントで構成されています。

  1. フロントエンドがチャット メッセージをバックエンド API に送信
  2. バックエンドがメッセージを整形し、Model Runner に送信
  3. LLM (大規模言語モデル) が入力を処理し、応答を生成
  4. バックエンドが生成されたトークンを順次フロントエンドにストリーミング
  5. フロントエンドが受信したトークンをリアルタイムに表示
  6. 各プロセスで可観測性コンポーネントがメトリクス、ログ、トレースを収集
図 2: フロントエンド、バックエンド、Model Runner、および Prometheus、Grafana、Jaeger などの可観測性ツール間のデータフローを示すアーキテクチャ図

プロジェクト構成

このプロジェクトは、以下のような構成になっています。

tree -L 2
.
├── Dockerfile
├── README-model-runner.md
├── README.md
├── backend.env
├── compose.yaml
├── frontend
..
├── go.mod
├── go.sum
├── grafana
│   └── provisioning
├── main.go
├── main_branch_update.md
├── observability
│   └── README.md
├── pkg
│   ├── health
│   ├── logger
│   ├── metrics
│   ├── middleware
│   └── tracing
├── prometheus
│   └── prometheus.yml
├── refs
│   └── heads
..
 
 
21 directories, 33 files

前提条件

始める前に、以下の環境が整っていることを確認してください。

  • Docker Desktop (バージョン 4.40 以降)
  • Docker Model Runner が有効化されていること
  • AI モデルを効率よく実行するためのメモリ (16GB 以上)
  • Go に関する基本的な知識 (バックエンド開発用)
  • React と TypeScript の基礎知識 (フロントエンド開発用)

はじめに

アプリケーションを実行するには、以下の手順を行います。

1. リポジトリをクローンします。

git clone 
https://github.com/dockersamples/genai-model-runner-metrics

cd genai-model-runner-metrics

2. Docker Desktop で Model Runner を有効にします。

  • 「Settings (設定)」 > 「Features in Development (開発中の機能)」 > 「Beta」タブへ移動
  • 「Docker Model Runner」を有効化
  • 「Apply and Restart (適用して再起動)」を選択
図 3: Docker Desktop の Beta 機能設定パネルのスクリーンショット。Docker AI、Docker Model Runner、および TCP サポートが有効化されている様子。

モデルのダウンロード

このデモでは Llama 3.2 モデルを使用しますが、お好みのモデルに置き換えることも可能です。

3. 以下のコマンドでモデルをダウンロードします。

docker model pull ai/llama3.2:1B-Q8_0

コンテナーの一覧を確認するのと同様に、Docker Dashboard の「Models」セクションからダウンロード済みの AI モデルを管理できます。ここでは、モデルの詳細情報やストレージ使用状況の確認、ローカルにある AI モデルのライブラリ管理が可能です。

図 4: Docker ダッシュボードの表示。ローカルにダウンロードされた AI モデルが、サイズ、パラメータ数、量子化方式などの詳細情報とともに表示されている様子。

4. アプリケーションを起動します。

docker compose up -d --build
図 5: Docker ダッシュボードに表示された、起動中のコンテナ一覧。Jaeger、Prometheus、バックエンド、フロントエンド、および genai-model-runner-metrics などが含まれている。

5. ブラウザーを開き、http://localhost:3000 にアクセスしてください。
モダンなチャット インターフェースが表示され、以下のような特徴があります。

  • ダークモード/ライトモードの切り替えが可能な、クリーンでレスポンシブなデザイン
  • 最初のプロンプト入力に対応したメッセージ入力エリア
  • フッターには使用中のモデル情報が表示されます
図 6: GenAI チャットボットのインターフェース。入力トークン/出力トークン、応答時間、エラーレートなどのライブ メトリクス パネルが表示されている様子。

6.「展開」ボタンをクリックすると、以下のようなメトリクスを確認できます。

  • 入力トークン数
  • 出力トークン数
  • 総リクエスト数
  • 平均応答時間
  • エラーレート
図 7: 展開されたメトリクス ビュー。入力トークンと出力トークン、詳細なチャットプロンプト、Llama 3.2 モデルによる応答が表示されている。

Grafana では、カスタマイズ可能なダッシュボードを通じてメトリクスの可視化が可能です。
「詳細ダッシュボードを表示」をクリックして、Grafana のダッシュボードを開きましょう。

図 8: チャット インターフェースに表示されたメトリクス ダッシュボード。プロンプトと応答が確認でき、Grafana で詳細なメトリクスを表示するオプションもある。

デフォルトの認証情報 (ユーザー名、パスワードともに「admin」) でログインすると、トークン処理速度、メモリ使用量、モデルのパフォーマンスなどリアルタイムの指標を表示する、あらかじめ設定された AI パフォーマンス ダッシュボードを確認できます (下図参照)。

データソースの追加手順

  1. 「Add your first data source (最初のデータソースを追加)」を選択
  2. データソースとして Prometheus を選択
  3. Prometheus Server URL に「http://prometheus:9090」を入力
  4. ページ最下部までスクロールし、「Save and test (保存してテスト)」をクリック
  5. 「Successfully queried the Prometheus API (Prometheus API へのクエリ成功)」のメッセージが表示されれば設定完了
  6. 「Dashboard (ダッシュボード)」を選択し、すべてのダッシュボードについて「Re-import (再インポート)」をクリック

これで、Prometheus 2.0 Stats ダッシュボードが起動し、リアルタイム監視ができる状態になります。

図 9: Grafana ダッシュボード。複数のグラフパネルで GenAI チャットボットのパフォーマンスを監視しており、メモリ使用量、処理速度、アプリケーションの健全性を時系列チャートで表示している。

Prometheus は時系列メトリクスデータの収集と保存を行います。
http://localhost:9091 の Prometheus クエリ画面を開き、クエリ入力欄に「genai」と入力してみてください (下図参照)。

トークン処理速度、レイテンシー計測、llama.cpp に特化したパフォーマンス データなど、数十種類の自動収集されたメトリクスを確認できます。

図 10:Prometheus のウェブインターフェース。利用可能な GenAI メトリクスのドロップダウンメニューが表示されており、例えば「genai_app_active_requests」や「genai_app_token_latency」などが含まれている。

Jaeger はリクエストのフローやパフォーマンスのボトルネックを視覚的に解析できるツールで、http://localhost:16686 からアクセス可能です。

実装の詳細

フロントエンドの実装

React を用いたフロントエンドは、TypeScript と最新の React パターンでビルドされたシンプルかつレスポンシブなチャット インターフェースを提供します。

中核となる App.tsx コンポーネントでは、ユーザー体験を向上させるためのダークモードの設定と、バックエンドのヘルスエンドポイントから取得したモデルのメタデータという 2 つの重要な状態を管理しています。

コンポーネントがマウントされると、useEffect フックが自動的に現在稼働中の AI モデルの情報を取得し、モデル名などの詳細をフッターに表示して、利用者にどの言語モデル (LLM) がチャットを支えているかを明示しています。

// Essential App.tsx structure
function App() {
  const [darkMode, setDarkMode] = useState(false);
  const [modelInfo, setModelInfo] = useState<ModelMetadata | null>(null);
 
  // Fetch model info from backend
  useEffect(() => {
    fetch('http://localhost:8080/health')
      .then(res => res.json())
      .then(data => setModelInfo(data.model_info));
  }, []);
 
  return (
    <div className="min-h-screen bg-white dark:bg-gray-900">
      <Header toggleDarkMode={() => setDarkMode(!darkMode)} />
      <ChatBox />
      <footer>
        Powered by Docker Model Runner running {modelInfo?.model}
      </footer>
    </div>
  );
}

メインの App コンポーネントは全体のレイアウトを管理しつつ、ナビゲーション操作を担当する Header や会話インターフェースを担う ChatBox といった専門的なコンポーネントに機能を委譲しています。このような関心の分離により、コードの保守性が高まっています。また、モデル情報の自動取得機能は、フロントエンドが Go 製バックエンドの API を通じて Docker Model Runner とシームレスに連携していることを示しており、ローカル AI モデルの実行という複雑さをユーザーから隠しつつ統一感のある操作体験を実現しています。

バックエンド実装 ~ Model Runner との連携

本アプリケーションの中核は、 Docker Model Runner と通信する Go 製のバックエンドです。以下に main.go の重要な部分を示します。

client := openai.NewClient(
option.WithBaseURL(baseURL),
option.WithAPIKey(apiKey),
)

ここでは、 Docker Model Runner の OpenAI 互換 API を活用している様子がわかります。 Model Runner は OpenAI の API 構造に準拠したエンドポイントを公開しているため、標準のクライアントをそのまま利用できます。接続方法に応じて baseURL は次のいずれかに設定されます。

  • Docker ソケット経由の場合
    http://model-runner.docker.internal/engines/llama.cpp/v1/
  • TCP 経由の場合
    http://host.docker.internal:12434/engines/llama.cpp/v1/

ホストからコンテナーへのメトリクスの流れ

ここで理解しておくべき重要なアーキテクチャのポイントは、 llama.cpp はホスト上でネイティブに動作し (Docker Model Runner 経由)、一方で Prometheus や Grafana はコンテナー内で動いていることです。両者は次のように連携しています。

バックエンド (メトリクスの橋渡し役)

  • Model Runner API (http://localhost:12434) を通じて llama.cpp と接続
  • 各 API 呼び出しのパフォーマンスデータ (応答時間やトークン数) を収集
  • トークン毎秒やメモリ使用量などのメトリクスを計算
  • これらのメトリクスを Prometheus フォーマットで http://backend:9090/metrics に公開
  • コンテナー内の Prometheus がホストに直接アクセスせずにメトリクスを取得可能にする

このハイブリッド構成により、ネイティブ実行による高いパフォーマンスと、コンテナー化された監視環境の利便性の両方を享受できます。

llama.cpp のメトリクス統合

本プロジェクトでは、 llama.cpp モデル向けにリアルタイムで詳細なメトリクスを提供しています。

メトリクス名説明コード上での定義名
(metrics.go 内)
トークン毎秒数 (Tokens per Second)モデルが 1 秒あたりに生成するトークン数。生成速度の指標です。LlamaCppTokensPerSecond
コンテキスト ウィンドウ サイズモデルが扱える最大の文脈長 (トークン数)。長いほど会話の記憶が保たれるLlamaCppContextSize
プロンプト評価時間ユーザーの入力をモデルが理解するまでにかかる処理時間LlamaCppPromptEvalTime
トークンあたりのメモリ使用量1トークン生成に対して消費されるメモリ量。効率性の指標です。LlamaCppMemoryPerToken
スレッド使用数モデルの処理に使用された CPU スレッド数。リソース活用の目安になりますLlamaCppThreadsUsed
バッチサイズ同時に処理されるトークンの数。応答速度と処理効率に関係します。LlamaCppBatchSize

llama.cpp モデル向けに詳細なメトリクス収集を行うことが、本プロジェクトの最も強力な特徴のひとつです。これらのメトリクスはモデルのパフォーマンス最適化や、推論パイプラインにおけるボトルネックの特定に役立ちます。

// LlamaCpp metrics
llamacppContextSize = promautoFactory.NewGaugeVec(
prometheus.GaugeOpts{
Name: "genai_app_llamacpp_context_size",
Help: "Context window size in tokens for llama.cpp models",
},
[]string{"model"},
)

llamacppTokensPerSecond = promautoFactory.NewGaugeVec(
prometheus.GaugeOpts{
Name: "genai_app_llamacpp_tokens_per_second",
Help: "Tokens generated per second",
},
[]string{"model"},
)

// その他のメトリクス定義...

これらのメトリクスは収集、処理され、 Prometheus によるスクレイピング用だけでなく、フロントエンドのリアルタイム表示にも活用されています。これにより、 llama.cpp 推論エンジンの動作状況をこれまでにない形で可視化できます。

ストリーミングによるチャット実装

チャットのエンドポイントでは、リアルタイムのトークン生成のためにストリーミングを実装しています。

// 適切な SSE フォーマットでストリーミングをセットアップ
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")

// チャンクが届くたびにストリーム送信
if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" {
outputTokens++
_, err := fmt.Fprintf(w, "%s", chunk.Choices[0].Delta.Content)
if err != nil {
log.Printf("Error writing to stream: %v", err)
return
}
w.(http.Flusher).Flush()
}

このストリーミング実装により、ユーザーインターフェース上でトークンがリアルタイムに表示され、滑らかで応答性の高いチャット体験を実現します。また、最初のトークン到達時間やトークン毎秒数などの重要なパフォーマンス指標を計測できます。

パフォーマンス計測

モデルのさまざまなパフォーマンス指標を計測可能です。

// 最初のトークン到達時間を記録
if firstTokenTime.IsZero() && len(chunk.Choices) > 0 &&
chunk.Choices[0].Delta.Content != "" {
firstTokenTime = time.Now()

// llama.cpp の場合、プロンプト評価時間を記録
if strings.Contains(strings.ToLower(model), "llama") ||
strings.Contains(apiBaseURL, "llama.cpp") {
promptEvalTime := firstTokenTime.Sub(promptEvalStartTime)
llamacppPromptEvalTime.WithLabelValues(model).Observe(promptEvalTime.Seconds())
}
}

// llama.cpp のトークン毎秒数を計算
if strings.Contains(strings.ToLower(model), "llama") ||
strings.Contains(apiBaseURL, "llama.cpp") {
totalTime := time.Since(firstTokenTime).Seconds()
if totalTime > 0 && outputTokens > 0 {
tokensPerSecond := float64(outputTokens) / totalTime
llamacppTokensPerSecond.WithLabelValues(model).Set(tokensPerSecond)
}
}

これらの計測により、モデルのパフォーマンス特性を把握し、ユーザー体験の最適化に役立てています。

メトリクス収集

metrics.go ファイルは Docker Model Runner ベースのチャットボット監視基盤の中核コンポーネントで、アプリケーション パフォーマンスや llama.cpp モデルの挙動を監視するための包括的な Prometheus メトリクス群を定義しています。

メトリクスの基本構成

このファイルでは次の種類の Prometheus メトリクスを定義しています。

  • カウンター (Counters)。累積値の追跡 (例: リクエスト数、トークン数)
  • ゲージ (Gauges)。増減する値の追跡 (例: アクティブリクエスト数)
  • ヒストグラム (Histograms)。値の分布計測 (例: 遅延時間)

すべてのメトリクスは promauto ファクトリーを使って生成され、 Prometheus への自動登録が行われます。

メトリクスのカテゴリ

メトリクスは大きく3つのカテゴリに分けられます。

1. HTTP およびアプリケーションメトリクス

// RequestCounter は総HTTPリクエスト数をカウント
RequestCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "genai_app_http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "endpoint", "status"},
)

// RequestDuration はHTTPリクエストの処理時間を計測
RequestDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "genai_app_http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "endpoint"},
)

これらのメトリクスは HTTP サーバーのパフォーマンスを監視し、リクエスト数、処理時間、エラー率を追跡します。ラベルとしてメソッド、エンドポイント、ステータスを付与し、詳細な分析を可能にしています。

2. モデル パフォーマンス メトリクス

// ChatTokensCounter はチャットの入出力トークン数をカウント
ChatTokensCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "genai_app_chat_tokens_total",
Help: "Total number of tokens processed in chat",
},
[]string{"direction", "model"},
)

// ModelLatency はモデルの応答時間を計測
ModelLatency = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "genai_app_model_latency_seconds",
Help: "Model response time in seconds",
Buckets: []float64{0.1, 0.5, 1, 2, 5, 10, 20, 30, 60},
},
[]string{"model", "operation"},
)

これらは LLM の利用状況やパフォーマンスを追跡するメトリクスで、入力、出力トークン数や全体の遅延時間を含みます。特に FirstTokenLatency はモデルから最初のトークンを得るまでの時間を測定し、ユーザー エクスペリエンスの重要な指標となっています。

3. llama.cpp 特有のメトリクス

// LlamaCppContextSize はコンテキストウィンドウのサイズを計測
LlamaCppContextSize = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "genai_app_llamacpp_context_size",
Help: "Context window size in tokens for llama.cpp models",
},
[]string{"model"},
)

// LlamaCppTokensPerSecond は生成速度を計測
LlamaCppTokensPerSecond = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "genai_app_llamacpp_tokens_per_second",
Help: "Tokens generated per second",
},
[]string{"model"},
)

これらは Docker Model Runner が使用する llama.cpp 推論エンジンに特化した詳細なパフォーマンス指標を表しています。主な内容は以下の通りです。

  1. コンテキスト サイズ
    モデルが扱うトークンのウィンドウ サイズで、通常 2048~8192 トークン。メモリ使用量と会話品質のバランスを調整します。メモリ使用が多い場合は 2048 トークンに減らすと高速化します。
  2. プロンプト評価時間
    トークン生成前の入力処理にかかる時間で、ファーストトークンまでの遅延を表します。目標は 2 秒以内。3 秒超ならコンテキスト サイズ削減やプロンプト圧縮を検討します。
  3. トークン毎秒 (TPS)
    トークン生成速度で、8 TPS 以上が良好なユーザー体験の目安です。TPS が 5 未満に落ちた場合は、より強い量子化 (Q8 から Q4 など) や小型モデルに切り替えます。
  4. メモリ使用量 (1 トークンあたり)
    トークン生成ごとの RAM 消費量を追跡。100MB/トークン超で会話の剪定を行い、長時間の会話でメモリが増加する場合は一定回数で自動リセットを入れます。
  5. スレッド使用数
    モデル処理に使われる CPU コア数を監視。利用率が 50% 未満ならスレッド数を増やして性能向上を図ります。
  6. バッチサイズ
    同時に処理するトークン数。リアルタイム チャットでは遅延軽減のため 32~64 トークンの小バッチを推奨します。

要するに、これらのメトリクスは llama.cpp の性能特性を把握・最適化するために不可欠であり、チャットボットのユーザー体験に直結しています。

Docker Compose ~ LLM をファーストクラス サービスとして扱う

Docker Model Runner との連携により、Compose で AI モデルのデプロイが他のサービスと同じように簡単になります。1つの docker-compose.yml ファイルで以下を定義可能です。

  • AI モデル (Docker Model Runner 経由)
  • アプリケーションのバックエンド、フロントエンド
  • 監視スタック (Prometheus、Grafana、Jaeger)
  • ネットワークや依存関係

特に革新的なのは llm サービスで、Docker のモデルプロバイダーを使い、複雑な設定不要でモデルを直接統合できます。

llm:
provider:
type: model
options:
model: ${LLM_MODEL_NAME:-ai/llama3.2:1B-Q8_0}

この設定により、AI モデルをデータベースやウェブ サーバーのような通常のサービスとして扱います。provider 構文は Docker がネイティブに AI モデルを扱う新方式です。コンテナー ビルドやイメージ取得の手間なく、Docker がモデル提供のインフラを自動管理します。

model: ${LLM_MODEL_NAME:-ai/llama3.2:1B-Q8_0} は環境変数でモデル指定が可能で、未指定時は Llama 3.2 1B がデフォルトとして使われます。

Docker Compose ~ ワンコマンドでスタック全体を起動

なぜこれが画期的なのか?これまで LLM をデプロイするには、複雑な設定が数十行に及びました。カスタム Dockerfile の作成、GPU デバイスのマッピング、モデルファイル用のボリュームマウント、ヘルスチェック、細かい起動コマンドの記述など、多くの手間がかかっていました。

しかし今では、わずか数行の設定でそれらすべてを置き換えられます。Docker がモデルのダウンロード、推論エンジンの設定、GPU へのアクセス構成、API エンドポイントの公開まで自動で行います。他のサービスはシンプルなサービス名で LLM に接続できるため、AI モデルの利用が他のインフラ構成要素と同じくらい簡単になります。

これにより、AI のデプロイは専門的な課題から標準的なインフラ コードの一部へと変わりました。

以下が、アプリケーション全体をオーケストレーションする compose.yml ファイル全文です。

services:
backend:
env_file: 'backend.env'
build:
context: .
target: backend
ports:
- '8080:8080'
- '9090:9090' # メトリクスポート用ポート
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Dockerソケットへのアクセスを追加
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://localhost:8080/health']
interval: 3s
timeout: 3s
retries: 3
networks:
- app-network
depends_on:
- llm

frontend:
build:
context: ./frontend
ports:
- '3000:3000'
depends_on:
backend:
condition: service_healthy
networks:
- app-network

prometheus:
image: prom/prometheus:v2.45.0
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--web.enable-lifecycle'
ports:
- '9091:9090'
networks:
- app-network

grafana:
image: grafana/grafana:10.1.0
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_DOMAIN=localhost
ports:
- '3001:3000'
depends_on:
- prometheus
networks:
- app-network

jaeger:
image: jaegertracing/all-in-one:1.46
environment:
- COLLECTOR_ZIPKIN_HOST_PORT=:9411
ports:
- '16686:16686' # UI
- '4317:4317' # OTLP gRPC
- '4318:4318' # OTLP HTTP
networks:
- app-network

# Docker Compose の model provider を使った新しい LLM サービス
llm:
provider:
type: model
options:
model: ${LLM_MODEL_NAME:-ai/llama3.2:1B-Q8_0}

volumes:
grafana-data:

networks:
app-network:
driver: bridge

構成のポイント

この compose.yml は、マイクロサービス構成のアプリケーション全体を定義し、統合された可観測性ツールと Model Runner をサポートしています。

  • backend
    • Go製の API サーバーで、Docker ソケットにアクセス可能
    • ヘルスチェックを実装し、API (8080) ポートとメトリクス (9090) ポートを公開
  • frontend
    • React ベースのユーザーインターフェースで、チャット エクスペリエンスを提供
    • backend のヘルスチェック完了後に起動し、安定稼働を確保
  • prometheus
    • 時系列データベースとしてパフォーマンス データを収集・保存
    • アプリケーションの動作を監視するためのカスタム設定済み
  • grafana
    • メトリクスの可視化プラットフォーム
    • 永続的なダッシュボード保存機能付き、管理者アクセス設定済み
  • jaeger
    • 分散トレーシング システムで、サービス間のリクエスト フローを可視化
    • gRPC/HTTP に対応し、ポート16686で UI を提供
  • llm
    • Docker Compose の model provider を使った新しい AI モデルサービス
    • 環境変数 ${LLM_MODEL_NAME} でモデルを指定可能。指定がない場合はデフォルトで Llama 3.2 1B モデルを使用

Docker Model Runner との連携

  • 接続設定
    • 内部 DNS: http://model-runner.docker.internal/engines/llama.cpp/v1/
    • ホスト経由 TCP: localhost:12434
  • ホストネットワーキング
    • extra_hostshost.docker.internal をホストのゲートウェイ IP にマッピング
  • 環境変数
    • BASE_URLばっModel Runner の URL
    • MODEL: モデル識別子 (例: ai/llama3.2:1B-Q8_0)
  • API通信
    • backend がメッセージをフォーマットして Model Runner に送信し、リアルタイムでトークンを frontend にストリーミング

この構成のメリット

  • プライバシーとセキュリティ。全データがローカル環境内に留まる
  • コスト管理。トークンやリクエスト単位の API 料金なし
  • パフォーマンスの可視化。モデル挙動や効率を詳細に把握可能
  • 開発体験向上。Docker ベースのワークフローに強力な監視ツールが統合
  • 柔軟性。モデルや設定を簡単に切り替えられる

まとめ

この genai-model-runner-metrics プロジェクトは、Docker Model Runner を活用してローカルで AI アプリケーションをビルドしつつ、性能特性を可視化する強力な手法を示しています。

カスタマー サポート チャットボット、コンテンツ生成ツール、専門 AI アシスタントなど、どんな用途にも対応可能な基盤となり、メトリクス駆動型で継続的に最適化できます。

リポジトリをクローンして Docker Desktop を起動するだけで、未来の AI 開発環境がすぐに手に入ります。ローカルでメトリクス管理された GenAI アプリケーションが docker compose up で立ち上がります!

Docker Mondel Runner に関するご質問がございましたら、エクセルソフト株式会社までお問い合わせください。


エクセルソフトは Docker の Preferred Reseller として、Docker Desktop を販売しています。Docker 製品のライセンスや機能に関するご質問、製品デモのご要望を承っています。お問い合わせはこちらから。


*本記事は、Docker 社が提供している以下の記事から抜粋・転載したものです。

Docker Model Runnerを使用してAIチャットボットをゼロから作成する方法

Docker の最新情報をお届けするエクセルソフトのメールニュース登録はこちら

タイトルとURLをコピーしました