RAG付きローカルLLM(ollama)をR shinyで (更新：GitHub オープンソース)


**GitHubで公開しました！(20250306)**
(APPの名前ゴロゴロ変わって申し訳ございませんが、最終は**rLocal-LLM-Pomelo**に落ち着きました。）

https://github.com/yin4dev/rLocal-LLM-Pomelo.git

# 前書き
この前の三連休で、ローカルLLMを **Dify**で遊んでみました。  
RAGナレッジも使えまして、ローカルLLMには夢がありますね。

---

## 背景

最近のマテリアルインフォマティクス（MI）には、AIなしの機械学習だけではもう時代遅れです。  
機械学習で出た結果を、MIに詳しくない人も分かるようにしないと、あまり（社内で）普及しない気がします。

そこで、自作の機械学習の **Shiny app** にAI機能を入れたいな～と思いました。  
しかし！自分はほぼRしかできません！（Rでも、できるとは言えませんが）
（もともと、自分は情報出身ではなく、化学や材料系出身のPhDです。）

ローカルLLMのGUIの自作の記事、大体Pythonですよね。  
（たまに、最初に機械学習を勉強する時、RではなくPythonを選んだらいいな～と思います（逃げるな！））  
諦めてはいけません！  
色々調べまして、`rollama`、`shiny.ollama`、`shiny_ollama` などがありました！

---

## 取り組みと課題

### 1. 初期の期待  
「いけるじゃん！」 

たしかに、ollamaのAPIを使えば、言語はそんなに関係ありません（かも）。  
しかし、こういったRのLLMの例は、大体基本的な**chat**、**query**しかできません。  
RAG、ファイルのやり取りができませんので、結局そのまま使えません。  
（ちなみに、`rollama`はembedding機能があります！！！！！！助かりました！！！）

### 2. 開発の詳細  
「自作しかない！」 

自作の詳細は省略（苦痛でしたので笑）。  
- rollamaなどが新しすぎて、前例もなさすぎて、ChatGPT様使っても大変でした。  
- 自分のPCが弱すぎて、RX6600XTを無理やりollamaに対応させましたが、ほぼVRAMしか機能しませんでした。  
- 一番大変なのは、やっぱりRAGでした。  
- 自分の事前知識がなさすぎて、英語、中国語のサイトも色々調べました。  
- 覚悟しましたが、Rの情報は本当に少ないんですよね。だからこそ、ちょっとだけでもRに貢献したいんです！！！！！

結果としては、**できました！**　わいーわいー

### 3. 開発後の問題点
「え？Rstudioは行けたのに？！」

しかし！ここで問題が出ました。  
RStudioで開発していますが、社内配布予定なので、**R-portable** でも機能しないといけないという自分に課した謎の制約があります。  
（Pythonも使わず、Rで完結する縛りがあります。大変でしたが、結果としてはものすごく勉強になりました。）

- **R-portableのcurl packageが古すぎて、RAG機能がしませんでした！**  
- Rtoolsを使うと、R-portable含めたフォルダー（将来のZIPファイル）が一気に1GB未満から4GBに膨らみました。  
  → 怖いですよね。

仕方なく、RAG機能なしの**Lite版**も作りました。
（後、Lite版が機械学習Appなどのアプリの追加AI機能のtemplateになったので、作ってよかったと思いました。）

---

## アプリの機能紹介

1. **GUIはザ・Shiny**  
   - マルチChat、設定類は `sidebarPanel`　（SQLiteによる履歴の保存）
   - Chat類は `mainPanel`

2. **主な機能**

   - **ローカルLLMの選択**  
     - ollamaで事前ダウンロード

   - **LLMのパラメータの設定**  
     - Temperature  
     - Context Window Size  
     - Top K Sampling  
     - Top P Sampling  
     - System Prompt

   - **Assistantの役割選択**  
     - 用意した役割：  
       - Normal  
       - Professional Data Analyst  
       - Scientific Report Writer  
       - Strict Database Retrieval Agent  
       - モモンガ（笑）  
     - 役割に対応するLLMのパラメータを設定

   - **RAGの使用選択**  
     - 事前にembeddingしたSQLiteか、PDFなどの生ファイルもOK  
     - Reranker使用OK  
     - Citationあり

   - **Embedding機能**  
     - Embeddingモデルの選択  
     - 事前ファイルをembeddingしてSQLiteとして保存  
     - SQLiteの合併

   - **Chat画面**

   - **複数ファイルのアップロード対応**
   　- 画像についてはOCRによる文字抽出

   - **アップロードしたファイルの再利用**  
     - Difyのconversation varと似た仕組み

   - **One-time Query**  
     - 前のChat履歴を送信せず、今回のChatだけを送信

   - **送信した完全なPromptの表示**  
     - 実際にLLMに送信したものが確認でき、RAGがちゃんと働いたかを検証するのに便利

---

## 感想


Rって、実はローカルLLMやollamaとめっちゃ相性いいんじゃんとおもいました。  
機械学習に特化した言語ですし、AIとの相性は言うまでもないと思います。  
一番大事なのは、**R-portable**の存在です。

ローカルでLLMを使うには、一般的には以下の手順が必要：
- ollamaをダウンロードする
- LLMをダウンロードする
- 環境設定
- Docker、Dify、LLM Studioなどを使用する

しかし、これらの設定は一般の方にとってはわけわかんなく、面倒な上に、企業にとっては商用利用可能かどうかの問題もあります。

**しかし、このShiny Appの　~~rLLm(仮）~~　rLocal-LLM-Pomeloなら**、  
- ollamaをダウンロードする
- PowerShellで `ollama run model` を実行する
- ~~rLLm(仮）~~　rLocal-LLM-PomeloとR-portableが入っているZIPファイルを解凍する
- BATファイルをクリックする
これだけで、すぐにローカルLLMが使えますよ！

`ollama run model` を実行する以外は、ほぼノーコード、設定なしです！

## 使用画面
基本UI（20250305更新）
![スクリーンショット_5-3-2025_23519_127.0.0.1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4024369/21767b19-0913-4847-bd61-5f7588367dbc.jpeg)



ファイルアップロード、前のchatでアップロードしたファイルを使用（History Files機能)（20250305更新）
![スクリーンショット_5-3-2025_23565_127.0.0.1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4024369/e2ad8154-9df9-4bca-b22f-289cf04f9aee.jpeg)



UI全開！　RAG使用(Rerankerあり)でレポートを生成（citation付き）（20250305更新）
![スクリーンショット_5-3-2025_235837_127.0.0.1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4024369/f577c4c6-6d4e-4818-a550-9b5583b60f2f.jpeg)





## まとめ

今回の ~~rLLM（仮）~~ rLocal-LLM-Pomeloの開発で、RでのローカルLLMとRAGナレッジの実装に挑戦し、RとLLMについて、大変勉強になりました。

制約の多い環境ではありましたが（ほぼ自己制限）、最終的には実用的なものを構築できたことに満足しました。

Qiitaでの初めての投稿ではありますが、今後も、RとQiitaのコミュニティにも少しでも貢献できるよう、情報共有や改善を続けていきたいと思います！！！！

~~（コードは公開するつもりですが、GitHubはいまいちよくわかんないので、そこクリアしたら公開します）~~

**GitHubで公開しました！**