Open WebUIでRAG化してみた

VS codeのCursorからRAG機能の呼び出しうまくいかなかったので、Open WebUIから呼び出しているollamaで動作するLocal LLMにRAG機能を追加してみた

Open WebUIを使えば完全にノーコードでRAG機能が追加できます、でも無論ハルシネーションもでるだろうけど、数年前の知識しかないLocal LLMから見れば大きな進歩だろうと思う

実はOpen WebUIには、ベクターDBもWebクローラー機能(実は内部ではfirecrawlとパイプラインでつながってるとのこと)も実装されてるから実現できるわけですが、チームでの使用とかには荷が重いと思いますが個人で使うならこれで当面は間に合うんじゃないかと思う

以下のイメージはチャットモードで作成済みのLocal LLM qwen2.5-coder:14B + RAGのモデル(Qwen2.5)がモデル選択メニューから見えてるとこ

 

で、このモデルの作り方は、ワークスペースを選択するとこの画面(モデル名はQwenにリネーム前)になります、今現在入力しているのは「モデル」と「ナレッジベース」だけ、プロンプトとツールは必要になった時点で追加します、モデルそのものは画面右上のNew Modelボタンを押して作成します

これはすでに作成したナレッジベースですが、

ナレッジの追加は、コレクションの追加メニューで右上の+ボタンを押すと種々の方法で追加できます、ここではwebpageから内部的にはおそらくmarkdown形式で取り込まれてます、これらはgithubから取り込んだmarkdownファイルですね

チャット画面で、投げたプロンプトに対して、回答の下部に(1 Source)というのが参考にされたナレッジになります

その部分の拡大は、以下のとおりでmarkdownからの抽出になってますね

しばらくはこの環境でパーソナルエージェント的な使い方をやってみます、違うエージェントが必要になればその時はモデル追加すれば良い、自分が持っているいろんなファイルをぶち込んでしまいたいと思う

P.S. 2026/2/10

Local LLMも分野特化してきていて、例えばqwen2.5-coder:14Bは英語は全くダメ、qwen2.5:14Bはちゃんと使えるから、用途ごとに専門家用意しとく感覚だね

 

admin

ollamaのモデルを変えてみた

昨日はとりあえずのcodeサポート用のモデルを入れてみたけど、結構重量級だったので同等性能でも負荷が軽いモデルに、同時に編集時のtab補完してくれる軽量モデルを設定してみた

% ollama list
NAME                 ID              SIZE      MODIFIED
qwen2.5-coder:14B    9ec8897f747e    9.0 GB    28 minutes ago
qwen2.5-coder:7b     dae161e27b0e    4.7 GB    44 minutes ago

Continueのconfig.jsonファイルの設定

tabAutocompleteModel:このブロックがタブ補完時のLLM指定

{
  "models":[
   {
      "title": "Main Coder (14B)",
      "provider": "ollama",
      "model": "qwen2.5-coder:14b"
     }
    ],
  "tabAutocompleteModel": {
    "title": "Tab Autocomplete",
    "provider": "ollama",
    "model": "qwen2.5-coder:7b"
  }
}

qwen2.5-coder:14b:メモリ使用量がmaxでも24GB程度で収まるようになったので、こちらにしよう

しかしLocal LLMは特にプログラム言語系の変化の早い領域ではRAG使うようにしないと実質的には使えないね、次はRAG使えるようにしよう

-> 2026/2/3:やってみたけどできなかった(@rag search “hello”が通らない)、まだ流動的なところが多そうだからしばしサスペンド

 

admin

Cursorを使ってみる

生成AIでコード補完を行えるツールはいくつかありますが、オールインワンになっているのがCursorだろうと思う

UIがVScodeそのままだからエディタそのものに慣れる必要もないから使う障壁が低い、さらにはプラグイン機能もVScode用のがそのまま使えるし

Cursorにはいくつかのライセンス方式ありますが、個人で使うならばHobbyでもそこそこ使えそうだからHobby版をインストしてみた、他にはPro/Businessがあります、ここでLLMにはGemini 2.5 Flashを選択しています、無料と引き換えの情報提供はビジネスじゃないから良いかな

無料のHobby版と有料のエントリーのPro版との差異は、

https://zenn.dev/umi_mori/books/ai-code-editor-cursor/viewer/price

を参照してください

最初の一歩はHello world!的なもので、新規ファイルを作成するとプロンプトが出てくるので「golangで簡単なwebサーバーのコード作成」、そのあとで「違うディレクトリでレスポンス変えて」といって作成されたコードは以下のコード

ただしGoのプロジェクトを作成したわけではないから、main.goが作成されただけ

次に既存のコード(ラズピコのpico-sdk + CMSIS dsp)を開いて、関数の解説をさせると、

コード全体のリファクタリングしてというと、

こんな感じ、

Hobby版での制限は、たまにコード書くならなんとか使えるかなというレベルですかね、仕事で使う人は間違いなくPro以上の選択になります

この領域の進歩は日進月歩だから、このレベルの機能はそれほど遠くなく無償化されるように落ちてくるように思う

 

admin

 

qwen2.5から3.0,ついでにollamaからLMStudioに変更

qwen3.0の方がモデルサイズが小さくとも性能は2.5の大きいモデルと同等との情報あったので3.0系を使ってみようと思ったけど、ollamaでそのまま使える3.0系のモデルがなかったから、LMStudioをインストしてみた

デフォルトではOpenAIの大きめのモデルをロードするようになっているけど、それはSSD領域もったいないので削除

メニュー右上のダウンロードボタンから、画像に示すメニューが開けるから、Open Downloads Directoryをクリックして不要なモデルを削除すれば良い

今ダウンロードしたのは4Bと8Bモデル、

4Bでもそこそこの対応力があって速度も速いから、こちらを標準で使ってみようと思う、uvはC言語で書かれてると言ってくるけどもね、それでも初期のLLMモデルに比べればかなり優秀ではある

Roo codeからollmaは設定できるけど、LMStudioは見えない、起動はしているはずなのだけど起動してない状態だね

ollamaを使うと、ClineもそうだけどLLMとして想定しているのはClaudeなので回答の出方はイマイチ、今の所の利用範囲でクラウドの利用料払うつもりは無いね

P.S. 2025/8/20

Qwen3-8Bだとuvについて正しく回答する、その後4Bに切り替えても同様だから、一見結果を共有しているように見える、ただし8Bだとメモリ管理(メモリ32GBでもコンテナも立ち上げてるから多分厳しい)でyellowマークが出てしまうけども

 

 

admin

 

A.Iアシストでコーディング

最近はコード自体はほぼ生成A.Iで作成されることが多いと思うけど、ローカルでLLM動かして使えるかどうかやってみた

・参考サイト

https://zenn.dev/mkj/articles/cf8536923d9cd7#discuss

・環境:M4 MacBook Pro 32GBメモリ、ollama、VScode + Cline

・モデルの選択(Alibabaのモデルが限定されらリソースではコーディング目的には一番向いているらしいから)

% ollama pull qwen2.5-coder:7b-instruct

コンソールから動かしてみた感じではなかなかいけてる感じ、Rustは知らないと言われるけどC言語、Python、Golangは扱える

・設定:ollamaを選択、

・動かしてみたとこ、

ソースファイルが見つからないと言われるから設定が必要かもしれない

・リソース消費状況

メモリもかなりキツいし、途中でファンも回り出すから、高負荷ではあるからAirでは32GBでもきついかもしれない

ローカルLLMでどこまで使い物になるかやってみる

P.S.

結構タイムアウトするケースが多くて、いまいちollamaとの相性がよくなさそうに思える、コンソールからollama経由でモデル使う方が遥かに安定している

 

admin

geminiのAPI経由の使用可能モデル変更されてるね

https://isehara-3lv.sakura.ne.jp/blog/2025/04/28/ラズパイ5のchatbot機能を統合/

4月にラズパイ5で作ったchatbot久々に動かそうとしたら動かない、より正確にはDifyからのレスポンスが返らない(回答が空か短すぎると言われる)、さらに調べるとgeminiへのqueryがエラーになっている

5月あたりにgoogleの対応が変わっていて、古いモデル名は使えなくなっているらしい、以下のFlash 001用のようなモデルは終了で末尾がlatestのモデルを選択したら動いた

変更後、

確認はcurlで、

curl -X POST 'http://localhost/v1/chat-messages' \
--header 'Authorization: Bearer app-***** your api key' \
--header 'Content-Type: application/json' \
--data-raw '{
    "inputs": {},
    "query": "What are the specs of the iPhone 13 Pro Max?",
    "response_mode": "streaming",
    "conversation_id": "",
    "user": "abc-123",
    "files": [
      {
        "type": "image",
        "transfer_method": "remote_url",
        "url": "https://cloud.dify.ai/logo/logo-site.png"
      }
    ]
}'

但し、最近無償版は混雑しているようで、割と頻繁にbusyで帰ってくるから、使いたいなら有償にしなさいよと言ってるようだ、それならばローカルLLMの選択もありだよね

 

admin

Difyにナレッジを追加

前回、ローカルにgemma3:4bをOllamaで動かしてDifyをインストだけして、Pythonからもアクセスしてみましたが、Difyの主たる機能であるRAGの手始めにナレッジを追加して割と最近の情報も活用するようにしてみた

参考は、

テキストファイルの追加は、

https://tech-lab.sios.jp/archives/46102

crawlingについては、

https://zenn.dev/zozotech/articles/d177f4cdc02755

追加したのはMacのメモを画像を除外してtxtファイル一本にまとめたものと、Web URLからcrawlingインストしてスクレーピングしたもの、

この状態でナレッジを有効化してポッドにプロンプト送ると、

ナレッジの参照先がリンクとして表示されてます

Macのファンが何故か回りっぱなしになってます、アイドル90%ぐらいなのに

 

admin

gemma3は優れものだね

今月公開されたようですが、Googleのgemma3は4bぐらいだと普通に回答のレベルも高いから、応答時間含めて実用レベルです

1b/4b・・・とありますが、実は1bだとラズパイ5でも普通に動いた、swapは起きてますが

モデルサイズも1G以下でコンパクト、

但しMacで動かした4bと比較すると精度は違う、以下は1bのレスポンス

4bだと、

と言う感じですから、差は明らか

次にDifyでモデルを、以下を参考にGeminiからollamaに変えてみた

https://note.com/dify_lab/n/n09e680c825cf

Difyからの接続設定

使えるモデルは、以下のように二つになります

どちらを使うかは、モデルのところをクリックしてこれはollmaに変えた後、

メモリ使用量もそれほどでもない、

と言うことで、gemma3は期待に違わずよく出来てます、

 

admin

Mac(32GBメモリ)のOllamaで動かせるモデル

パラメータ数が多くなるとメモリとGPUの能力への要求レベルが高くなりますが、32GBのM4 MacBook Proでどの程度まで動くのか試してみた

モデルは以下の通り、

% ollama ls
NAME               ID              SIZE      MODIFIED          
gemma2:27b         53261bc9c192    15 GB     About an hour ago    
mixtral:latest     a3b6bef0f836    26 GB     2 hours ago          
elyza:jp8b         e81c07bbe038    4.9 GB    4 weeks ago          
llama3.2:latest    a80c4f17acd5    2.0 GB    4 weeks ago

 

mixtralだと、アクティビティモニターが黄色(ほぼ赤に近い)レベルまでメモリを食い尽くすから使えない、使って初めてスワップも発生

ハードリソース的にほぼ限界かと思えるのが、gemma2:27bでこの時のメモリモニターを見ると、メモリは最大近くまで使う感じ

ちなみにOllamaの情報見ると、仮想メモリサイズが1.48TBとか、この数値はSSDのサイズ1Tも超えているんですが、

ということで、モデルのパラメータ数で30b程度が32GBメモリのMacで動かせる限界のようです

ちなみにこのサイズのパラメータで初めて日本で一番高い山の回答が正しく返ってくるから、それ以下のパラメータでは実用性はそれほどないのかもしれない

 

admin

Difyをローカルで動かす(さわり)

ローカルで動かせて、かつカスタマイズが簡単(ノーコードで実現可能)なLLM(モデルプロバイダを設定)が使えるプラットホームです、Webページのこのメッセージが全てかもしれません、一番特徴的なのはRAGエンジンじゃないかと思いますね

============

DifyはオープンソースのLLMアプリ開発プラットフォームです。RAGエンジンを使用して、エージェントから複雑なAIワークフローまでLLMアプリを編成します。

============

<インストール>

・ターゲット:M4 MacBook Pro 14

・Docker :Engine: 28.0.1/Compose: v2.33.1-desktop.1

わざわざカスタムインストの意味はないから、Docker使って素直にインストします、以下にはRancher Desktopでインスト時のメモも残ってますが、ともかく4行のコマンド実行でDockerで動くようになります

% git clone https://github.com/langgenius/dify.git
% cd dify/docker
% cp .env.example .env	# 環境変数のコピー

# Rancher Desktopの場合には、
# Docker-compose.yamlの修正、ブラウザポートの重複回避のためにポート番号を変更(8888に)、661行目でした(@2015/3/16)

      - '${EXPOSE_NGINX_PORT:-8888}:${NGINX_PORT:-80}'

# 注)Rancher Desktopで再インストするとアクセスできない(8888開かない?)

% docker compose up -d
# デタッチモードでバックグランドで起動させる

Dify自体にLLM機能はなく外部サービスを利用する形態なので、モデルプロバイダーはGeminiを設定しています

DockerとRancher  Desktop両方を動かす時の切り替え方法と再インストール他のコマンド

% docker compose up --build
# imageの再ビルドを行う

% docker compose down
# containerを停止すると共に削除する

% docker compose down --rmi all
# これはimageを削除する

% docker compose stop(コンテナ停止)、start(コンテナ起動)


# Dockerの切り替え(Baker link. Env用にrancher desktopを優先させる)

% docker context use rancher-desktop

% docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT                                       ERROR
default             Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                           
desktop-linux       Docker Desktop                            unix:///Users/usamiryuuichi/.docker/run/docker.sock   
rancher-desktop *   Rancher Desktop moby context              unix:///Users/usamiryuuichi/.rd/docker.sock           


% docker context use desktop-linux 	# change to Docker

インストールから基本的な操作(応答を変化させるオーケストレーションとか)は以下のリンクで、

https://weel.co.jp/media/dify-local/

 

<Pythonから使う>

RAGはとりあえず置いといて、Pythonからの使い方

クラウドのDify使う時には、

https://zenn.dev/fa18kouki/articles/579ef29527a5d9

が参考になりますが、これをローカルに置き換えてます

APIキーは、以下の「APIアクセス」から取得します、また具体的なAPIの使い方ドキュメントも含まれます

import requests
import json
from typing import Dict

# Dify APIの認証キー
API_KEY = 'your API key'  # 取得したAPIキーに置き換えてください
# Dify APIのベースURL(ポート番号を含む)
BASE_URL = 'http://localhost/v1/chat-messages'

def get_dify_response(query: str, user: str) -> str:
    headers = {
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json'
    }

    data: Dict[str, any] = {
        "inputs": {},
        "query": query,
        "response_mode": "streaming",
        "conversation_id": "",
        "user": user,
        "files": [
            {
                "type": "image",
                "transfer_method": "remote_url",
                "url": "https://cloud.dify.ai/logo/logo-site.png"
            }
        ]
    }

    try:
        response = requests.post(BASE_URL, headers=headers, json=data, stream=True)
        response.raise_for_status()

        # ここでエンコーディングを明示的に指定
        response.encoding = 'utf-8'

        full_response = ""
        for line in response.iter_lines():
            if line:
                decoded_line = line.decode('utf-8')
                if decoded_line.startswith("data: "):
                    json_data = json.loads(decoded_line[6:])
                    if json_data.get('event') == 'message':
                        raw_answer = json_data.get('answer', '')

                        # Unicodeエスケープのデコードを削除(不要)
                        print(raw_answer, end='', flush=True)
                        full_response += raw_answer

        print()
        return full_response
    except requests.RequestException as e:
        print(f"リクエストエラー: {e}")
        return str(e)
    except json.JSONDecodeError as e:
        print(f"JSON解析エラー: {e}")
        return "JSONの解析に失敗しました"
    except Exception as e:
        print(f"予期せぬエラー: {e}")
        return str(e)

def main():
    query = "Difyでできることは?"
    user = "user0"

    print("Difyへのクエリ:", query)
    answer = get_dify_response(query, user)
    print("\nDifyからの完全な応答:")
    print(answer)

if __name__ == "__main__":
    main()

エンドポイント(サービスの種類)はいくつかありますが、ここではBASE_URL = 'http://localhost/v1/chat-messages'を使っています

レスポンスは、以下のような内容で返ってきます

Difyへのクエリ: Difyでできることは?
Difyって、すごい魔法のツールなんだ!  

Difyは、色々なことができるよ。たとえば、

* **お話を書く**  
  Difyに「お姫様とドラゴンのお話を作って」ってお願いすると、面白いお話を作ってくれるんだ!  
* **絵を描く**  
  Difyに「虹色の猫の絵を描いて」ってお願いすると、カラフルな猫の絵を描いてくれるよ!
* **音楽を作る**  
  Difyに「楽しい音楽を作って」ってお願いすると、リズムの良い音楽を作ってくれるんだ!  
* **ゲームを作る**  
  Difyに「宝探しゲームを作って」ってお願いすると、楽しい宝探しゲームを作ってくれるよ!

Difyは、まだ成長中だけど、たくさんのことができるようになるんだって!  
Difyをもっと知りたい?  もっと詳しいことを教えてあげるよ!  
他にどんなことができるか、聞いてみてね! 


Difyからの完全な応答:
Difyって、すごい魔法のツールなんだ!  

Difyは、色々なことができるよ。たとえば、

* **お話を書く**  
  Difyに「お姫様とドラゴンのお話を作って」ってお願いすると、面白いお話を作ってくれるんだ!  
* **絵を描く**  
  Difyに「虹色の猫の絵を描いて」ってお願いすると、カラフルな猫の絵を描いてくれるよ!
* **音楽を作る**  
  Difyに「楽しい音楽を作って」ってお願いすると、リズムの良い音楽を作ってくれるんだ!  
* **ゲームを作る**  
  Difyに「宝探しゲームを作って」ってお願いすると、楽しい宝探しゲームを作ってくれるよ!

Difyは、まだ成長中だけど、たくさんのことができるようになるんだって!  
Difyをもっと知りたい?  もっと詳しいことを教えてあげるよ!  
他にどんなことができるか、聞いてみてね! 

モデルプロバイダーからのレスポンスをオーケストレーション設定で「子供に話すような回答」と設定しているので、Dify内で加工されたレスポンスになっています

 

admin