Docker Model Runnerで実現する簡単生成AIアプリケーション ～Hello GenAI実践レポート～

## Docker Model Runnerとは

https://docs.docker.com/desktop/features/model-runner/

Docker Model Runner は、Docker Desktop に組み込まれた機能で、AIモデルを Docker Hub からプルし、ローカルで直接実行できるプラグインです。
この機能を使うことで、初回実行時に大容量のモデルがダウンロードされ、以降はローカルキャッシュから迅速にモデルが読み込まれます。また、OpenAI互換のAPIを介してモデルに対するプロンプト送信やチャット形式での対話が可能となり、開発者は自分のアプリケーションに簡単に生成AI機能を組み込むことができます。

## 必要な環境

- Docker Desktop 4.40以降
- Docker Desktop for Mac with Apple Silicon

## OpenAI APIを通じてモデルと会話する

https://docs.docker.com/desktop/features/model-runner/#how-do-i-interact-through-the-openai-api

別のコンテナから`curl`を使ってOpenAIのエンドポイント(`chat/completions`)を呼び出す例です。

まずは、モデルをDocker HubからPullします

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

次に、別のコンテナを立ち上げます

```bash
docker run -it golang:1.23
```

次に、「ローマの滅亡について500字で書いてください。」というリクエストを送ります

```bash
curl http://model-runner.docker.internal/engines/llama.cpp/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "ai/llama3.2:1B-Q8_0",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": "Please write 500 words about the fall of Rome."
            }
        ]
    }'
```

すると、以下のようなレスポンスが返ってきます

```bash
{
    "choices": [
        {
            "finish_reason": "stop",
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "The Fall of Rome, one of the most significant events in human history, was a gradual process that spanned several centuries. It began in the 2nd century AD, when the empire faced internal decay and external threats. The once-mighty Roman Empire, which had been the dominant power in the Mediterranean world for centuries, began to unravel from within.\n\nOne of the primary causes of the fall of Rome was its internal decay. The empire's bureaucracy, which had been the backbone of its success, became increasingly corrupt and ineffective. Corruption was rampant, and officials were more concerned with maintaining their own power and privilege than with serving the empire. This led to a decline in the empire's military strength, as it became increasingly reliant on mercenaries and auxiliary forces.\n\nThe Roman legions, which had once been the epitome of military power, were also in decline. They had been replaced by newer, more effective forms of warfare, such as the Roman heavy cavalry and the Greek light infantry. The legions were also plagued by internal conflicts, as different factions vied for power and influence within the empire.\n\nExternal threats also played a significant role in the fall of Rome. The empire's borders were constantly under threat from various barbarian groups, such as the Goths, Vandals, and Huns. These groups often exploited the empire's weaknesses, such as its military fatigue and its lack of effective leadership.\n\nOne of the most significant external threats to Rome was the rise of Christianity. As Christianity spread throughout the empire, it began to challenge the traditional Roman values and institutions. The early Christian Church, which emerged in the 1st century AD, was initially seen as a threat by the Roman authorities, who viewed it as a heretical and subversive force.\n\nHowever, as Christianity continued to grow and gain influence, it began to challenge the traditional Roman values and institutions. The Church's emphasis on moral reform and social justice, as well as its anti-tyranny stance, resonated with many Romans who were disillusioned with the empire's corruption and decay.\n\nThe final blow to Rome came in the 5th century AD, when the Huns, a nomadic people from Central Asia, invaded the empire. The Huns were a powerful and relentless force, and they swept through the empire, leaving destruction and chaos in their wake. The empire's military was decimated, and its borders were soon overrun.\n\nIn 476 AD, the Western Roman Empire finally fell when the Germanic king Odoacer deposed the last Roman Emperor, Romulus Augustus. This marked the end of the Western Roman Empire, which had been in decline for centuries.\n\nThe Eastern Roman Empire, also known as the Byzantine Empire, continued to exist for another thousand years, but it too eventually fell to the Ottoman Turks in 1453 AD. The fall of Rome was a gradual process, but it was marked by a series of internal decay, external threats, and external invasions that ultimately led to its downfall.\n\nIn the end, the fall of Rome was a testament to the inevitability of decline and fall. Despite its many achievements, the Roman Empire was unable to stem the tide of external threats and internal decay, and it ultimately succumbed to its own weaknesses.\n\nThe fall of Rome also had a profound impact on Western civilization. The decline of the Roman Empire led to a period of cultural and intellectual decline, as the classical values and institutions of Rome were lost. However, the legacy of Rome continues to shape Western society today, from the language and literature of the Roman Empire to the architecture and art of the Byzantine Empire.\n\nIn conclusion, the fall of Rome was a complex and multifaceted event that was driven by a combination of internal decay, external threats, and external invasions. Despite its many achievements, the Roman Empire was ultimately unable to stem the tide of decline and fall, and it ultimately succumbed to its own weaknesses."
            }
        }
    ],
    "created": 1744069734,
    "model": "ai/llama3.2:1B-Q8_0",
    "system_fingerprint": "b1-be7c303",
    "object": "chat.completion",
    "usage": {
        "completion_tokens": 794,
        "prompt_tokens": 52,
        "total_tokens": 846
    },
    "id": "chatcmpl-7xZMNzKcgcAwqZTsQ6tdFNdQs1uTB9sz",
    "timings": {
        "prompt_n": 1,
        "prompt_ms": 70.408,
        "prompt_per_token_ms": 70.408,
        "prompt_per_second": 14.202931485058516,
        "predicted_n": 794,
        "predicted_ms": 13975.926,
        "predicted_per_token_ms": 17.601921914357682,
        "predicted_per_second": 56.811977968400804
    }
}
```

## チャットアプリを試してみる

https://github.com/docker/hello-genai

はじめに、リポジトリをクローンします

```bash
git clone https://github.com/docker/hello-genai
cd hello-genai
```

次に、アプリを動かします

```bash
./run.sh
```

ブラウザを開き、以下のリンクにアクセスします

- http://localhost:8080 Goの生成AIアプリケーション
- http://localhost:8081 Pythonの生成AIアプリケーション
- http://localhost:8082 Nodeの生成AIアプリケーション

実際に動かしてみると...

![go.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3337464/ddf9ccb6-41cd-4ac2-a59e-d6e947132d7f.gif)

## コード解説

https://github.com/docker/hello-genai/blob/main/go-genai/main.go

以下のようなAPIが実装されています
| エンドポイント | メソッド | 処理内容 |
|----------------|----------|----------|
| `/`          | GET      | チャットのWebインターフェイス（HTMLページ）を提供。ユーザーがアクセスすると、チャットUI（メッセージ表示領域、入力フィールド、送信ボタンなど）が表示される。 |
| `/api/chat`  | POST     | チャットAPIのリクエストを処理。<br>リクエストボディの `message` を解析。<br>ユーザーメッセージと共に、システムメッセージ `"You are a helpful assistant."` を含むリクエストをLLM APIへ送信し、その応答（チャット結果）を返す。 |

ユーザーからメッセージを含むリクエストを受け取り、上記で示したOpenAIのAPIを叩き、メッセージだけをユーザーに返すというシンプルな構成になっています。

## まとめ

Docker Model Runnerを使うと、このように簡単にLLMを使ったアプリケーションを作れるので、便利な世の中になったなあと思います。