IBMが出してるGraniteというモデルがありますが、Ollamaで使えそうだったので試しつつNode-REDでLINE Botにしようと思います。
ちなみに最新は4系っぽいです。
今回は使わないですが画像処理もできる3.2-visionも楽しそうですね。
Ollamaで動かす
まずはOllamaで動かしてみます。
最近のOllamaはGUIがあるのでそのまま話しかけます。
謎に「おまえさん」って返事がありました。
軽く試すぐらいなので350mのパラメータにします。
Node-REDから呼び出す
Node-REDから呼び出すためにはNode-REDのOllamaノードがあるのでこれを使ってみます。
こちらの記事を参考に。
Ollama Chatがうまく動かず、Ollama Genarateのノードを利用します。
このようにインジェクト、Ollama Generate、デバッグとつなぎます。
Ollama Generateのノードは以下で設定します。
- Model:
Ibm/granite4:350m(参考: モデル名 https://ollama.com/ibm/granite4:350m ) - Prompt: msg.payload
[ { "id": "ba1c0ba49b586916", "type": "inject", "z": "1f2d6f34fb146e21", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "こんにちは", "payloadType": "str", "x": 140, "y": 80, "wires": [ [ "b62ea4ef7e22a628" ] ] }, { "id": "3928f4cdd88cc2c0", "type": "debug", "z": "1f2d6f34fb146e21", "name": "debug 5", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 560, "y": 260, "wires": [] }, { "id": "b62ea4ef7e22a628", "type": "ollama-generate", "z": "1f2d6f34fb146e21", "name": "Ollama Generate", "server": "", "format": "", "model": "Ibm/granite4:350m", "modelType": "str", "prompt": "payload", "promptType": "msg", "suffix": "", "suffixType": "str", "system": "", "systemType": "str", "template": "", "templateType": "str", "raw": false, "images": "", "imagesType": "json", "stream": false, "think": false, "keepAlive": "5m", "keepAliveType": "str", "options": "", "x": 350, "y": 180, "wires": [ [ "3928f4cdd88cc2c0" ] ] }, { "id": "462756c3cb4cfd74", "type": "global-config", "env": [], "modules": { "node-red-contrib-ollama": "0.5.0" } } ]
試すとデバッグパネルに回答が表示されました。
LINE Botにする
LINE Messaging APIのノードを使ってLINE Bot化します。
https://flows.nodered.org/node/node-red-contrib-line-messaging-api
Ollamaで試したところから、(LINE) Webhookノード、(LINE) Reply Messageノード、Changeノードの3つを追加しています。
それぞれ以下を設定します。
-
(LINE) Webhookノード
-
/webhookのパスを指定
-
-
Changeノード
-
msg.payload.responseをmsg.payloadに代入
-
-
(LINE) Reply Messageノード
- アクセストークンとシークレットをConfigから指定
まとめたフローを置いておきます。試す場合はアクセストークンなどは各自のものを指定してください。
[ { "id": "ba1c0ba49b586916", "type": "inject", "z": "1f2d6f34fb146e21", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "こんにちは", "payloadType": "str", "x": 140, "y": 80, "wires": [ [ "b62ea4ef7e22a628" ] ] }, { "id": "3928f4cdd88cc2c0", "type": "debug", "z": "1f2d6f34fb146e21", "name": "debug 5", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 760, "y": 140, "wires": [] }, { "id": "b62ea4ef7e22a628", "type": "ollama-generate", "z": "1f2d6f34fb146e21", "name": "Ollama Generate", "server": "", "format": "", "model": "Ibm/granite4:350m", "modelType": "str", "prompt": "payload", "promptType": "msg", "suffix": "", "suffixType": "str", "system": "", "systemType": "str", "template": "", "templateType": "str", "raw": false, "images": "", "imagesType": "json", "stream": false, "think": false, "keepAlive": "5m", "keepAliveType": "str", "options": "", "x": 410, "y": 140, "wires": [ [ "3928f4cdd88cc2c0", "44fc91a31856704a" ] ] }, { "id": "e6d55be2c3ef3fb2", "type": "Webhook", "z": "1f2d6f34fb146e21", "name": "", "url": "/webhook", "x": 140, "y": 180, "wires": [ [ "b62ea4ef7e22a628", "a2f2123b015d5976" ] ] }, { "id": "bdc2fd4599b33743", "type": "ReplyMessage_New", "z": "1f2d6f34fb146e21", "name": "", "lineConfig": "ecd98ffb90c981ef", "replyMessage": "", "x": 860, "y": 280, "wires": [ [] ] }, { "id": "a2f2123b015d5976", "type": "debug", "z": "1f2d6f34fb146e21", "name": "debug 7", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 300, "y": 280, "wires": [] }, { "id": "44fc91a31856704a", "type": "change", "z": "1f2d6f34fb146e21", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "payload.response", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 620, "y": 220, "wires": [ [ "bdc2fd4599b33743" ] ] }, { "id": "ecd98ffb90c981ef", "type": "lineConfig", "botName": "ももたろう", "botIconUrl": "" }, { "id": "82774e4b0b9348d3", "type": "global-config", "env": [], "modules": { "node-red-contrib-ollama": "0.5.0", "node-red-contrib-line-messaging-api": "0.4.2" } } ]
トンネリングと設定
LINE Botにするためにはトンネリングが必要です。今回はMacのローカルで試しているのでngrokやVS Codeのトンネルツールでトンネリングサーバーを立てます。Node-REDが1880ポートなので1880ポートを指定です。
VS Codeはこんな表示になりますね。
LINE Developersの管理画面ではhttps://トンネリングサーバーのドメイン/webhookなどを
試す
ここまでのNode-RED、トンネリングサーバー、Ollmaと全て起動していてやっとつながります。
こんな感じで会話できました。
この仕組みは過去のログは覚えていないので
応用: 自前のモデルルーティング風処理
350Mよりも大きなバージョンでmicroというものもあったのでこちらも試してみます。
Node-REDで秋葉原か岡山(試してたLINEがももたろうBOTなので)かを質問して
- 秋葉原の場合 => Granite4:350m
- 岡山の場合 => Granite4:micro
が回答するといった感じに処理を分けてみます。Ollamaノードで指定できるので手軽ですね。
Node-REDで文字列の処理はこれが良いのか分からないけど正規表現の選択肢に直接入れてみたら動いたので一旦良いことにします。
- Granite4:350mの回答 秋葉原
- Granite4:microの回答 岡山
これくらいだと検証とは呼べないですがどっちも回答怪しいですねw
パッと見でハルシネーションしてます。
LLM性能的にはもっとパラメータ数が大きいGranite4のモデルの方が確実です。
所感など
Node-REDのollamaノードやGraniteを試してみたくてまとめたサンプル作ってみました。
Ollamaノードはちゃんと作られてそうなので設定ほぼ不要で使えるのが便利でしたね。
同じやり方でGoogleのGemmaなど他モデルも試せるので遊んでみたいと思います。














