NVIDIA LaunchPadでRAG実装したAI Chatbotを体験した

# NVIDIA LaunchPad
NVIDIA LaunchPadは、インターネットブラウザを通じて、エンタープライズ向けのNVIDIAハードウェアとソフトウェアに無料でアクセスできる素晴らしいプラットフォームです。

このプラットフォームを使えば、ガイド付きのハンズオンラボや開発サンドボックスを通じて、AIの力を実際に体験することができます。最新のNVIDIA技術を活用して、自分のアプリケーションやモデルをテスト、プロトタイプ、デプロイすることができるんです。


https://www.nvidia.com/en-us/launchpad/


## AI Chatbot with RAG
今回は、企業用に大事にするのRAG（リトリーバル強化型生成） を使用したAI Chatbotを体験しました。

**NVIDIA LaunchPad**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/4adb6d5d-12e3-4283-96fb-f617cf1148e1.png)


申し込みの後に、お予想1-2日ぐらいハンズオンラボのリンクが届きます。


ハンズオンラボの画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/d994fe77-b083-431f-81d8-be39def8fa61.png)


リソースタブにいくつのリソースがありますが、今回は主にCode Server IDEとDesktopを使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/de25cd29-7e7c-413a-afea-da241a303d2e.png)




## 前提条件
今回導入するAI Chatbotのモデルは、以下のバージョンが必要です。
ハンズオンラボで既に導入済です。
- Ubuntu Linux 22.04
- NVIDIA GPU with at least 80 GB framebuffer (A100 or H100)
- NVIDIA Linux GPU driver version 550
- CUDA version 12.4

## LLMの導入

NVIDIA NIM は、LLM（大規模言語モデル）推論のための簡単にデプロイできるマイクロサービスです。

このセクションでは、Llama3-8b モデルを提供する NVIDIA NIM をダウンロードしてデプロイします。


``` 
cd /home/nvidia/enterprise-rag-docker_v24.06
source compose.env
docker compose -f docker-compose-nim-ms.yaml --profile llm-embedding up -d nemollm-inference
```

ラボ既に用意したyamlファイルは以下です。

```
cat docker-compose-nim-ms.yaml
```
```
services:
  nemollm-inference:
    container_name: nemollm-inference-microservice
    image: nvcr.io/nim/meta/llama3-8b-instruct:1.0.0
    volumes:
    - ${MODEL_DIRECTORY}:/opt/nim/.cache
    user: ${DOCKER_USER}
    ports:
    - "8000:8000"
    expose:
    - "8000"
    environment:
      NGC_API_KEY: ${NGC_API_KEY}
    shm_size: 20gb
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: ${INFERENCE_GPU_COUNT:-all}
              capabilities: [gpu]
    profiles: ["llm-embedding", "nemo-retriever"]
    
networks:
  default:
    name: nvidia-rag
    
......

```










NIMのインストール状況を確認
``` 
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
```

```
＃アウトプット
CONTAINER ID   NAMES                            STATUS
b1c950073d64   nemollm-inference-microservice   Up 3 minutes
1d1f5da726a9   jupyter-notebook                 Up 5 days
```


NIMログを確認すると、

``` 
docker logs nemollm-inference-microservice | tail
```

予想される出力（「平均プロンプトスループット」メッセージが表示されるまで数分かかることがあります）:
```
2025-02-19 14:44:40,540 [INFO] PyTorch version 2.2.2 available.
2025-02-19 14:44:41,423 [WARNING] [TRT-LLM] [W] Logger level already set from environment. Discard new verbosity: error
2025-02-19 14:44:41,424 [INFO] [TRT-LLM] [I] Starting TensorRT-LLM init.
2025-02-19 14:44:46,989 [INFO] [TRT-LLM] [I] TensorRT-LLM inited.
INFO 02-26 02:56:57.782 metrics.py:334] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Swapped: 0 reqs, Pending: 0 reqs, GPU KV cache usage: 0.0%, CPU KV cache usage: 0.0%
INFO 02-26 02:57:07.783 metrics.py:334] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Swapped: 0 reqs, Pending: 0 reqs, GPU KV cache usage: 0.0%, CPU KV cache usage: 0.0%
INFO 02-26 02:57:17.783 metrics.py:334] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Swapped: 0 reqs, Pending: 0 reqs, GPU KV cache usage: 0.0%, CPU KV cache usage: 0.0%
INFO 02-26 02:57:27.784 metrics.py:334] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Swapped: 0 reqs, Pending: 0 reqs, GPU KV cache usage: 0.0%, CPU KV cache usage: 0.0%
```


GPU 上で実行中の Python プロセスの表示
```
nvidia-smi --query-compute-apps=gpu_bus_id,pid,name,used_memory --format=csv
```

```
gpu_bus_id, pid, process_name, used_gpu_memory [MiB]
00000000:CA:00.0, 3185884, python3, 72034 MiB
```
### NIM ポートの確認

docker port と netstat を使用して、推論ポートが開いていてアクセス可能であることを確認します。

```
docker port nemollm-inference-microservice
```

```
8000/tcp -> 0.0.0.0:8000
8000/tcp -> [::]:8000
```

netstatを確認
```
netstat -na | grep 8000
```

```
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp6 0 0 :::8000 :::* LISTEN
```

以上でNVIDIA NIMマイクロサービスが確認済です。


### LLM 導入確認およびテスト
まず、モデルエンドポイントをクエリして利用可能な LLM をリストします。
```
curl -s ‘http://0.0.0.0:8000/v1/models’ | jq .data[].id
```

```
“meta/llama3-8b-instruct”
```

LLM レスポンスの生成
```
curl -s -X 'POST' 'http://0.0.0.0:8000/v1/chat/completions' -H 'accept: application/json'   -H 'Content-Type: application/json'   -d '{
  "messages": [
    {
      "content": "You are a polite and respectful chatbot helping people plan a vacation.",
      "role": "system"
    },
    {
      "content": "What should I do for a 4 day vacation in Spain?",
      "role": "user"
    }
  ],
  "model": "meta/llama3-8b-instruct",
  "max_tokens": 128,
  "top_p": 1,
  "n": 1,
  "stream": false,
  "stop": "\n",
  "frequency_penalty": 0.0
}' | jq .choices[].message

```

```
{
“role”: “assistant”,
“content”: “Spain is a fantastic destination! With only 4 days, I recommend focusing on one or two cities to make the most of your time. Here’s a suggested itinerary for you:”
}
```

以上でNvidia NIMによりLlama3-8bのLLMの導入が確認しました。


## Embedding機能の実装


NeMo Retriever Embedding NIM は、テキストをベクトルに変換するマイクロサービスです。これらのベクトルは、検索システムによって効率的に検索できます。

まずは、HuggingFace から Snowflake の Arctic-Embed-Large embeddingモデルをデプロイするための変数の設定
```
cd /home/nvidia/enterprise-rag-docker_v24.06
source compose.env
grep EMBEDDING compose.env
```
結果：
```
export EMBEDDING_MS_GPU_ID=0
export APP_EMBEDDINGS_MODELNAME=“NV-Embed-QA”
export EMBEDDING_MODEL_CKPT_NAME=“snowflake-arctic-embed-l”
export EMBEDDING_MODEL_PATH=“https://huggingface.co/Snowflake/snowflake-arctic-embed-l”
```

Docker Compose を使用して、Embeddingマイクロサービスコンテナをデプロイします。
```
docker compose -f docker-compose-nim-ms.yaml --profile llm-embedding up -d nemollm-embedding
```
出力（完了までに最大 2 分かかることがあります）:
```
[+] Running 3/3
✔ Container nemollm-embedding-download-ngc Exited 1.0s
✔ Container nemo-retriever-embedding-microservice Started 1.3s
✔ Container nemollm-embedding-download-hf Exited
```

docker ps コマンドを使用して、実行中のコンテナを表示します。
```
docker ps --format “table {{.ID}}\t{{.Names}}\t{{.Status}}”
```
出力（完了までに最大 2 分かかることがあります）:
```
CONTAINER ID NAMES STATUS
ce5cb5d87128 nemo-retriever-embedding-microservice Up 2 minutes (healthy)
b1c950073d64 nemollm-inference-microservice Up 19 minutes
1d1f5da726a9 jupyter-notebook Up 5 days
```
### GRPC サービスが開始されたことの検証
docker logs コマンドを使用して、GRPC サービスが開始されたことを確認します。
```
docker logs nemo-retriever-embedding-microservice | grep Started
```

```
I0619 23:45:12.863107 89 grpc_server.cc:2513] Started GRPCInferenceService at 0.0.0.0:8001
I0619 23:45:12.863321 89 http_server.cc:4497] Started HTTPService at 0.0.0.0:8000
I0619 23:45:12.905035 89 http_server.cc:270] Started Metrics Service at 0.0.0.0:8002
```

docker port コマンドと netstat コマンドを使用して、ポートが開いていてアクセス可能であることを確認します。
```
docker port nemo-retriever-embedding-microservice
```

```
9080/tcp -> 0.0.0.0:9080
9080/tcp -> [::]:9080
```
netstatで確認します。
```
netstat -na | grep 9080
```

```
tcp 0 0 0.0.0.0:9080 0.0.0.0:* LISTEN
tcp6 0 0 :::9080 :::* LISTEN
```
### Triton 推論サーバーが GPU で実行されていることの確認
nvidia-smi コマンドを使用して、Triton 推論サーバーが GPU で実行されていることを確認します。
```
nvidia-smi --query-compute-apps=gpu_bus_id,pid,name,used_memory --format=csv
```

```
gpu_bus_id, pid, process_name, used_gpu_memory [MiB]
00000000:CA:00.0, 3185884, python3, 72056 MiB
00000000:CA:00.0, 3203778, tritonserver, 478 MiB
00000000:CA:00.0, 3204038, /opt/tritonserver/backends/python/triton_python_backend_stub, 2160 MiB
00000000:CA:00.0, 3204039, /opt/tritonserver/backends/python/triton_python_backend_stub, 2160 MiB
```

## Embeddingモデルのテスト


まず、モデル名を表示するためにモデルエンドポイントをクエリします。
```
curl -s "http://0.0.0.0:9080/v1/models" | jq .data[].id
```
結果：

```
"NV-Embed-QA"
```

次に、例として「Hello world」という‘input’をエンドポイントにPOSTします。これにより、浮動小数点ベクトルが生成されるはずです。
```
curl -s -X "POST" "http://0.0.0.0:9080/v1/embeddings" -H 'accept: application/json' -H 'Content-Type: application/json' -d '{
    "input": ["Hello world"],
    "model": "'NV-Embed-QA'",
    "input_type": "query"
}' | jq . | tail -n 20
```
結果：

```
        -0.034027099609375,
        0.0231170654296875,
        -0.007396697998046875,
        0.03729248046875,
        -0.01416778564453125,
        0.0168304443359375,
        -0.00650787353515625,
        -0.035430908203125,
        -0.00525665283203125,
        -0.0168914794921875
      ],
      "object": "embedding"
    }
  ],
  "model": "NV-Embed-QA",
  "usage": {
    "prompt_tokens": 0,
    "total_tokens": 0
  }
}
```


以上、Embeddingサービスが確認しました。




## ベクトルデータベースのデプロイ


ベクトルデータベースは、RAG（Retrieval-Augmented Generation）を活用したAIチャットボットにおいて重要な役割を果たします。

ベクトルembeddingはインデックス化と呼ばれるプロセスを通じてデータベースに保存され、検索時には高度なパターンマッチングアルゴリズムでベクトルが検索されます。

Milvusは高性能でスケーラブルなベクトルデータベースであり、インデックスと検索操作の両方でGPUアクセラレーションをサポートしています。


### Docker Composeを使用してMilvusデータベースをデプロイする
```
docker compose -f docker-compose-vectordb.yaml --profile llm-embedding up -d milvus
```

```
[+] Running 3/0
 ✔ Container milvus-minio       Running                                                                     0.0s 
 ✔ Container milvus-etcd        Running                                                                     0.0s 
 ✔ Container milvus-standalone  Running
```
### ベクトルデータベースのインストールを確認する
実行中のコンテナを表示します。
```
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}" --filter Name=milvus*
```

```
CONTAINER ID   NAMES               STATUS
ae0178812ede   milvus-standalone   Up 3 minutes
f6d9d8064853   milvus-minio        Up 3 minutes (healthy)
c46b4832fc89   milvus-etcd         Up 3 minutes (healthy)
```
各コンテナのポートを表示します。
```
for i in standalone minio etcd; do echo "milvus-$i" && docker port milvus-$i; done
```

```
milvus-standalone
9091/tcp -> 0.0.0.0:9091
9091/tcp -> [::]:9091
19530/tcp -> 0.0.0.0:19530
19530/tcp -> [::]:19530
milvus-minio
9010/tcp -> 0.0.0.0:9010
9010/tcp -> [::]:9010
9011/tcp -> 0.0.0.0:9011
9011/tcp -> [::]:9011
milvus-etcd
```
ポートが公開されていることを確認します。
```
netstat -tulpn | grep 19530
```

```
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:19530           0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::19530                :::*                    LISTEN      - 
```
### ベクトルデータベースに割り当てられたGPUフレームバッファを表示する
GPUメモリ使用量を表示するためにnvidia-smiを使用します。デフォルトでは、MilvusはGPUの空きメモリの半分を予約します。
```
nvidia-smi --query-compute-apps=gpu_bus_id,pid,name,used_memory --format=csv
```

```
gpu_bus_id, pid, process_name, used_gpu_memory [MiB]
00000000:CA:00.0, 3185884, python3, 72316 MiB
00000000:CA:00.0, 3203778, tritonserver, 478 MiB
00000000:CA:00.0, 3204038, /opt/tritonserver/backends/python/triton_python_backend_stub, 2160 MiB
00000000:CA:00.0, 3204039, /opt/tritonserver/backends/python/triton_python_backend_stub, 2160 MiB
00000000:CA:00.0, 3228474, milvus, 1438 MiB
```
ここでは、milvus-standaloneコンテナ内のmilvus.yamlを検証して、Milvusに利用可能なGPUメモリの初期サイズと最大サイズを指定します。
```
docker exec -it milvus-standalone grep -A 2 gpu /milvus/configs/milvus.yaml 
```

```
gpu:
  initMemSize:  # Gpu Memory Pool init size
  maxMemSize:  # Gpu Memory Pool Max size
```



## RAGパイプラインのデプロイとテスト
完全なRAGパイプラインには、以下のマイクロサービスが含まれます：

- RAGアプリケーションテキストチャットボット
- RAGプレイグラウンド
- NeMo推論マイクロサービス
- NeMoリトリーバーembeddingマイクロサービス
- Milvusベクトルデータベース

テキストQAチャットボットのアーキテクチャは以下の図に示されています：


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/ae7713c4-ade2-4f07-9e48-f60cb3e4fb5d.png)


### アプリケーションコンテナのデプロイ
NeMo推論マイクロサービス、NeMoリトリーバーembeddingマイクロサービスとMilvusベクトルデータベースの準備が整いたので、最後にRAGのチェットボットとプレイグラウンドをデプロイします。
```
cd /home/nvidia/enterprise-rag-docker_v24.06
source compose.env
docker compose -f rag-app-text-chatbot.yaml up -d
```
```
cat rag-app-text-chatbot.yaml
```
```
services:
  chain-server:
    container_name: rag-application-text-chatbot
    image: nvcr.io/ohlfw0olaadg/ea-participants/rag-application-text-chatbot:24.06
    command: --port 8081 --host 0.0.0.0
    environment:
      APP_VECTORSTORE_URL: "http://milvus:19530"
      APP_VECTORSTORE_NAME: "milvus"
      APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"}
      APP_LLM_MODELENGINE: nvidia-ai-endpoints
      APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-"nemollm-inference:8000"}
      APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-"nemollm-embedding:9080"}
      APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:?please update the env file and source it before running}
      APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints
      NVIDIA_API_KEY: ""
      COLLECTION_NAME: canonical_rag
      APP_RETRIEVER_TOPK: 4
      APP_RETRIEVER_SCORETHRESHOLD: 0.25
      APP_TEXTSPLITTER_CHUNKSIZE: 506
      APP_TEXTSPLITTER_CHUNKOVERLAP: 200
      OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
      OTEL_EXPORTER_OTLP_PROTOCOL: grpc
      ENABLE_TRACING: false
      LOGLEVEL: ${LOGLEVEL:-INFO}
    ports:
    - "8081:8081"
    expose:
    - "8081"
    shm_size: 5gb

  rag-playground:
    container_name: rag-playground
    image: nvcr.io/ohlfw0olaadg/ea-participants/rag-playground:24.06
    environment:
      CHAIN_SERVER: "http://chain-server"
      CHAIN_SERVER_PORT: "8081"
      OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
      OTEL_EXPORTER_OTLP_PROTOCOL: grpc
      ENABLE_TRACING: false
    ports:
    - "3001:3001"
    expose:
    - "3001"
    depends_on:
    - chain-server

networks:
  default:
    name: nvidia-rag
```

```
[+] Running 2/2
 ✔ Container rag-application-text-chatbot  Started                                                 1.9s 
 ✔ Container rag-playground                Started                                                 0.8s
```
実行中のコンテナを表示
```
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
```

```
CONTAINER ID   NAMES                                   STATUS
436ae7c030c7   rag-playground                          Up 11 minutes
a7f9b9b9ffd8   rag-application-text-chatbot            Up 11 minutes
ae0178812ede   milvus-standalone                       Up 16 hours
f6d9d8064853   milvus-minio                            Up 16 hours (healthy)
c46b4832fc89   milvus-etcd                             Up 16 hours (healthy)
ce5cb5d87128   nemo-retriever-embedding-microservice   Up 16 hours (healthy)
b1c950073d64   nemollm-inference-microservice          Up 16 hours
1d1f5da726a9   jupyter-notebook                        Up 5 days
```
各コンテナが使用するポートを表示し、アクセス可能であることを確認
```
for i in $(docker ps --format "table {{.Names}}" | grep ^rag); do echo $i && docker port $i; done
```

```
rag-playground
3001/tcp -> 0.0.0.0:3001
3001/tcp -> [::]:3001
rag-application-text-chatbot
8081/tcp -> 0.0.0.0:8081
8081/tcp -> [::]:8081
```
ポートがリスニング状態であることを確認
```
netstat -na | egrep '3001|8081'
```

```
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:3001            0.0.0.0:*               LISTEN     
tcp        0      0 172.16.0.126:33618      192.168.34.20:8081      TIME_WAIT  
tcp        0      0 172.16.0.126:58766      192.168.34.20:8081      TIME_WAIT  
tcp6       0      0 :::8081                 :::*                    LISTEN     
tcp6       0      0 :::3001                 :::*                    LISTEN 
```
### RAG UIにアクセス
1. サイドバーのデスクトップリンクを選択するか、ここをクリックしてデスクトップセッションを開きます。
2. デスクトップ環境内でウェブブラウザを開きます。
3. http://0.0.0.0:3001 にアクセスしてRAGプレイグラウンドのWebインターフェースを開きます。
4. テキストQAチャットボットのモデルカードをクリックします。


### RAGプレイグラウンドのWeb UIには以下が含まれます：

1. 質問をしてLLMをクエリするためのデモタブ
2. ドキュメントをアップロードするためのナレッジベースタブ
3. RAGプレイグラウンドAPIを説明するドキュメンテーションタブ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/412cbe99-8bdc-4bff-bb09-ab4e640ef00f.png)


### 質問をする
ナレッジベース使用しなく、モデルが知らない最近の歴史についての質問をします：

`What were the top 5 most requested pop songs of 2023?`

結果は以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/39e25edd-511e-4b2f-9b10-7d359bd10d22.png)

ナレッジベース使用すると：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000821/98d8dcef-afc2-439e-b83d-58ccea639538.png)


IDEに戻して、RAGアプリケーションコンテナーログを確認します。
```
docker logs -t --tail 10 rag-application-text-chatbot 
```

```
2025-02-25T09:01:15.924694860Z chatbot: The top 5 most requested pop songs of 2023 are:
2025-02-25T09:01:15.924700246Z 
2025-02-25T09:01:15.924705128Z 1. Morgan Wallen - Last Night
2025-02-25T09:01:15.924710046Z 2. Miley Cyrus - Flowers
2025-02-25T09:01:15.924715406Z 3. Taylor Swift - Cruel Summer
2025-02-25T09:01:15.924720989Z 4. Dua Lipa - Dance the Night
2025-02-25T09:01:15.924726604Z 5. Luke Combs - Fast Car
2025-02-25T09:01:15.924731470Z **************************************************
2025-02-25T09:01:15.924736615Z 
2025-02-25T09:01:15.924741150Z 

```

# 最後に

このハンズオンラボを通じて、RAGを活用したAIチャットボットの実装を初めて体験することができました。NVIDIA LaunchPadの提供する環境は非常に使いやすく、ステップバイステップのガイドに従うことで、スムーズにデプロイメントを行うことができました。これからもこのような最新技術を活用して、さらに多くのプロジェクトに挑戦していきたいと思います。

皆さんもぜひNVIDIA LaunchPadを試してみてください！新しい発見と学びが待っています。