Trying Out Ollama Part 4 (Conversations Between LLMs, Gemma3:4B, Python, Node-RED)
Introduction
In this post, I tried using Ollama to facilitate a conversation between two local LLMs.
In a previous article, I used a Python library to enable interactions while maintaining conversation history. By connecting the output of one local LLM to the input of another, I’ve made it possible for them to converse.
▼I am using a gaming laptop purchased for around 100,000 yen, running Windows 11.
▼Previous articles are here:
Creating the Node-RED Flow
In a previous post, I set up a TCP server using Ollama. This time, I’ll build upon that flow.
▼This is the article:
I set up TCP servers using Ollama in Python and send messages to those servers using the "tcp request" node.
▼Here is the flow:

I didn't save the JSON file from this specific stage, but it's almost the same as the one in the previous article. I used a "switch" node to filter out the initial messages sent when the server starts.
▼Messages that do not contain "Client connected" or "Listening on" are passed through.

The initial human input is sent via an "inject" node or a "text input" node. The TCP server is set to shut down when "bye" is sent, just like when conversing with Ollama via the command prompt.
Letting Them Converse
I ran the conversation using the flow I created. Both local LLM models are "Gemma3:4B."
I started with a simple "Hello" (Konnichiwa).
▼The small talk progressed even faster than a human conversation.

Even though I only sent "Hello," the AIs started proposing topics and moving the conversation forward. For some reason, they assumed they had just seen a beautiful view.
▼The content of the conversation changes every time you run it. It’s interesting how AIs "watch" YouTube videos or read novels as training data…

I occasionally encountered errors during the process, so some troubleshooting might be necessary.
▼One conversation ended in a way that made it sound like they wanted to stop talking.

I adjusted the settings to keep the answers short and added "Delay" nodes, but I plan to keep refining it as I use it.
▼Sometimes the responses were so short it felt like a conversation that wasn't going anywhere.

▼Perhaps because they are using the same model, they are generally very agreeable with each other.

▼When the conversation flowed well, they engaged in discussions involving technical knowledge.


▼Check the video here. They are discussing robot simulations.
Improving the Flow
I improved the flow using Dashboard 2.0.
▼The scale has grown significantly. Here is the overall flow: (Although not included this time, it further connects to a speech synthesis process.)

[{"id":"7543d889d219314b","type":"venv","z":"22eb2b8f4786695c","venvconfig":"015784e9e3e0310a","name":"Node-1","code":"import socket\nimport ollama\nimport threading\nimport sys\n\nsys.stdout.reconfigure(encoding=\"utf-8\")\n\nHOST = '127.0.0.1'\nPORT = 5001\nMAX_HISTORY = 20\nchat_history = []\nserver_socket = None\nrunning = True\n\ndef chat_with_ollama(user_input):\n global chat_history\n \n # 履歴の長さを制限\n if len(chat_history) >= MAX_HISTORY:\n chat_history.pop(0)\n\n chat_history.append({'role': 'user', 'content': user_input})\n \n response = ollama.chat(model='gemma3:4b', messages=chat_history)\n chat_reply = response['message']['content']\n chat_history.append({'role': 'assistant', 'content': chat_reply})\n return chat_reply\n\ndef handle_client(client_socket):\n \"\"\" クライアントごとの処理 \"\"\"\n global running\n with client_socket:\n print(f\"Client connected: {client_socket.getpeername()}\")\n while True:\n try:\n data = client_socket.recv(1024).decode().strip()\n if not data:\n break\n if data.lower() == \"bye\":\n print(\"Received 'bye', shutting down server...\")\n client_socket.sendall(\"Ollama Shutdown\".encode(\"utf-8\"))\n running = False # サーバーの実行を停止\n break\n\n response = chat_with_ollama(data)\n client_socket.sendall(response.encode(\"utf-8\"))\n except (ConnectionResetError, BrokenPipeError, UnicodeDecodeError) as e:\n print(f\"Error: {e}\")\n break\n print(\"Client disconnected.\")\n\ndef server_thread():\n \"\"\" サーバーをスレッドで実行 \"\"\"\n global server_socket, running\n\n server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n \n try:\n server_socket.bind((HOST, PORT))\n print(f\"Server bound to port {PORT} successfully.\")\n except Exception as e:\n print(f\"Error binding server to port {PORT}: {e}\")\n return\n\n try:\n server_socket.listen()\n print(f\"Server is now listening on {HOST}:{PORT}...\")\n except Exception as e:\n print(f\"Error in server listening: {e}\")\n return\n\n server_socket.settimeout(1.0) # 1秒ごとに `Ctrl+C` チェック\n\n try:\n while running:\n try:\n client_socket, addr = server_socket.accept()\n print(f\"Accepted connection from {addr}\")\n client_thread = threading.Thread(target=handle_client, args=(client_socket,))\n client_thread.start()\n except socket.timeout:\n continue # タイムアウトしてもループを継続\n except Exception as e:\n print(f\"Server error: {e}\")\n finally:\n if server_socket:\n server_socket.close()\n print(\"Server shut down.\")\n\ndef main():\n global running\n try:\n server = threading.Thread(target=server_thread)\n server.start()\n\n while running:\n pass # メインスレッドを維持して `Ctrl+C` を待つ\n except KeyboardInterrupt:\n print(\"\\nShutting down server...\")\n running = False # サーバーの実行を停止\n server.join() # スレッドを待機\n sys.exit(0)\n\nif __name__ == \"__main__\":\n main()\n","continuous":true,"x":580,"y":4360,"wires":[["f2c4cc31c97b0dcd"]]},{"id":"9d13eadce7ba2dea","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":930,"y":4460,"wires":[["7c879421615c256c"]]},{"id":"f2c4cc31c97b0dcd","type":"debug","z":"22eb2b8f4786695c","name":"debug 463","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":4360,"wires":[]},{"id":"57fcea4b5aa2328a","type":"comment","z":"22eb2b8f4786695c","name":"Ollama Server","info":"","x":430,"y":4320,"wires":[]},{"id":"9c47865553875349","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"bye","payloadType":"str","x":770,"y":4620,"wires":[["d81bba47fda884db"]]},{"id":"930a483a4ca15f5e","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"こんにちは","payloadType":"str","x":260,"y":4720,"wires":[["8ceef8ca5d75e5f5"]]},{"id":"d81bba47fda884db","type":"tcp request","z":"22eb2b8f4786695c","name":"TCP:5001","server":"127.0.0.1","port":"5001","out":"time","ret":"string","splitc":"100","newline":"","trim":false,"tls":"","x":920,"y":4660,"wires":[["254fd2239e5cf0ce","cb8d6ee0ec00e9fc"]]},{"id":"254fd2239e5cf0ce","type":"debug","z":"22eb2b8f4786695c","name":"debug 464","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1090,"y":4660,"wires":[]},{"id":"4695b2de51635342","type":"venv","z":"22eb2b8f4786695c","venvconfig":"015784e9e3e0310a","name":"Node-2","code":"import socket\nimport ollama\nimport threading\nimport sys\n\nsys.stdout.reconfigure(encoding=\"utf-8\")\n\nHOST = '127.0.0.1'\nPORT = 5002\nMAX_HISTORY = 20\nchat_history = []\nserver_socket = None\nrunning = True\n\ndef chat_with_ollama(user_input):\n global chat_history\n \n # 履歴の長さを制限\n if len(chat_history) >= MAX_HISTORY:\n chat_history.pop(0)\n\n chat_history.append({'role': 'user', 'content': user_input})\n \n response = ollama.chat(model='gemma3:4b', messages=chat_history)\n chat_reply = response['message']['content']\n chat_history.append({'role': 'assistant', 'content': chat_reply})\n return chat_reply\n\ndef handle_client(client_socket):\n \"\"\" クライアントごとの処理 \"\"\"\n global running\n with client_socket:\n print(f\"Client connected: {client_socket.getpeername()}\")\n while True:\n try:\n data = client_socket.recv(1024).decode().strip()\n if not data:\n break\n if data.lower() == \"bye\":\n print(\"Received 'bye', shutting down server...\")\n client_socket.sendall(\"Ollama Shutdown\".encode(\"utf-8\"))\n running = False # サーバーの実行を停止\n break\n\n response = chat_with_ollama(data)\n client_socket.sendall(response.encode(\"utf-8\"))\n except (ConnectionResetError, BrokenPipeError, UnicodeDecodeError) as e:\n print(f\"Error: {e}\")\n break\n print(\"Client disconnected.\")\n\ndef server_thread():\n \"\"\" サーバーをスレッドで実行 \"\"\"\n global server_socket, running\n\n server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n \n try:\n server_socket.bind((HOST, PORT))\n print(f\"Server bound to port {PORT} successfully.\")\n except Exception as e:\n print(f\"Error binding server to port {PORT}: {e}\")\n return\n\n try:\n server_socket.listen()\n print(f\"Server is now listening on {HOST}:{PORT}...\")\n except Exception as e:\n print(f\"Error in server listening: {e}\")\n return\n\n server_socket.settimeout(1.0) # 1秒ごとに `Ctrl+C` チェック\n\n try:\n while running:\n try:\n client_socket, addr = server_socket.accept()\n print(f\"Accepted connection from {addr}\")\n client_thread = threading.Thread(target=handle_client, args=(client_socket,))\n client_thread.start()\n except socket.timeout:\n continue # タイムアウトしてもループを継続\n except Exception as e:\n print(f\"Server error: {e}\")\n finally:\n if server_socket:\n server_socket.close()\n print(\"Server shut down.\")\n\ndef main():\n global running\n try:\n server = threading.Thread(target=server_thread)\n server.start()\n\n while running:\n pass # メインスレッドを維持して `Ctrl+C` を待つ\n except KeyboardInterrupt:\n print(\"\\nShutting down server...\")\n running = False # サーバーの実行を停止\n server.join() # スレッドを待機\n sys.exit(0)\n\nif __name__ == \"__main__\":\n main()\n","continuous":true,"x":580,"y":4440,"wires":[["cd3f2a91dc5324a2"]]},{"id":"8c5e08c29ef38f4e","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":430,"y":4440,"wires":[["4695b2de51635342"]]},{"id":"f19311be04711f62","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":930,"y":4520,"wires":[["f99b02e76ff22398"]]},{"id":"cd3f2a91dc5324a2","type":"debug","z":"22eb2b8f4786695c","name":"debug 466","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":4440,"wires":[]},{"id":"534885a899478efa","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"bye","payloadType":"str","x":770,"y":4820,"wires":[["39b1d7c666707e4f"]]},{"id":"39b1d7c666707e4f","type":"tcp request","z":"22eb2b8f4786695c","name":"TCP:5002","server":"127.0.0.1","port":"5002","out":"time","ret":"string","splitc":" 100","newline":"","trim":false,"tls":"","x":920,"y":4860,"wires":[["8de97e9714f5509a","1e54c4a6e7d25700"]]},{"id":"8de97e9714f5509a","type":"debug","z":"22eb2b8f4786695c","name":"debug 467","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1090,"y":4860,"wires":[]},{"id":"1e54c4a6e7d25700","type":"switch","z":"22eb2b8f4786695c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Client connected","vt":"str"},{"t":"cont","v":"Listening on","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":1070,"y":4900,"wires":[[],[],["a6365f703cdefc49","c1153858ace9e786","2af30fdcb359b087","e74efabd3871c5f9"]]},{"id":"cb8d6ee0ec00e9fc","type":"switch","z":"22eb2b8f4786695c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Client connected","vt":"str"},{"t":"cont","v":"Listening on","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":1070,"y":4700,"wires":[[],[],["af6a3cbae08d5c05","f2201ff3b9c9a3f3","d4fd4dde6372035a","7a1d68da210cdb9b"]]},{"id":"b931621545cb30bb","type":"catch","z":"22eb2b8f4786695c","name":"","scope":["d81bba47fda884db"],"uncaught":false,"x":1070,"y":4940,"wires":[["c1153858ace9e786"]]},{"id":"3ba40b2bff69ada1","type":"catch","z":"22eb2b8f4786695c","name":"","scope":["39b1d7c666707e4f"],"uncaught":false,"x":1070,"y":4740,"wires":[["f2201ff3b9c9a3f3"]]},{"id":"c7a14f4465e71cbc","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"user-input","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":4660,"wires":[["35f2faa12208f01d"]]},{"id":"610b72b12f56b765","type":"tcp request","z":"22eb2b8f4786695c","name":"","server":"127.0.0.1","port":"5001","out":"time","ret":"string","splitc":"100","newline":"","trim":false,"tls":"","x":1510,"y":4460,"wires":[["af6a3cbae08d5c05","81bbb0b4a775f1ca"]]},{"id":"ea0788b313cf5a0c","type":"tcp request","z":"22eb2b8f4786695c","name":"","server":"127.0.0.1","port":"5002","out":"time","ret":"string","splitc":" 100","newline":"","trim":false,"tls":"","x":1510,"y":4520,"wires":[["a6365f703cdefc49","df0c96fa2fd89288"]]},{"id":"8ceef8ca5d75e5f5","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"ユーザーの入力:{{payload}}","output":"str","x":420,"y":4720,"wires":[["c7a14f4465e71cbc"]]},{"id":"af6a3cbae08d5c05","type":"ui-template","z":"22eb2b8f4786695c","group":"f0bbe692c3fc1950","page":"","ui":"","name":"","order":4,"width":"0","height":"0","head":"","format":"<template>\n <h2>Response</h2>\n <div id=\"node-1\"></div>\n</template>\n\n<script>\n this.$socket.on('msg-input:' + this.id, function(msg) {\n const markdownText = msg.payload;\n const htmlContent = marked(markdownText);\n document.getElementById('node-1').innerHTML = htmlContent;\n });\n</script>\n\n<style>\n #node-1 {\n padding: 10px;\n font-family: Arial, sans-serif;\n }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":1240,"y":4780,"wires":[[]]},{"id":"a6365f703cdefc49","type":"ui-template","z":"22eb2b8f4786695c","group":"59d519b3e322c6b9","page":"","ui":"","name":"","order":4,"width":"0","height":"0","head":"","format":"<template>\n <h2>Response</h2>\n <div id=\"node-2\"></div>\n</template>\n\n<script>\n this.$socket.on('msg-input:' + this.id, function(msg) {\n const markdownText = msg.payload;\n const htmlContent = marked(markdownText);\n document.getElementById('node-2').innerHTML = htmlContent;\n });\n</script>\n\n<style>\n #node-2 {\n padding: 10px;\n font-family: Arial, sans-serif;\n }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":1240,"y":4980,"wires":[[]]},{"id":"1178625072386c96","type":"ui-text-input","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"User Input","order":5,"width":"6","height":"2","topic":"topic","topicType":"msg","mode":"textarea","tooltip":"","delay":300,"passthru":true,"sendOnDelay":false,"sendOnBlur":true,"sendOnEnter":true,"className":"","clearable":false,"sendOnClear":false,"icon":"","iconPosition":"left","iconInnerPosition":"inside","x":250,"y":4620,"wires":[["469e324919f14b61"]]},{"id":"2390935be5742f29","type":"ui-button","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"Send","order":6,"width":0,"height":0,"emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":270,"y":4660,"wires":[["c7a14f4465e71cbc"]]},{"id":"469e324919f14b61","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"user-input","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":4620,"wires":[[]]},{"id":"96ee55fd5dc236e9","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":430,"y":4360,"wires":[["7543d889d219314b"]]},{"id":"2c046567c5b240db","type":"comment","z":"22eb2b8f4786695c","name":"Initial Settings","info":"","x":930,"y":4380,"wires":[]},{"id":"4c1faedac11c9e5b","type":"link out","z":"22eb2b8f4786695c","name":"gTTS","mode":"link","links":["fe521de6f72d8f1f"],"x":1845,"y":4520,"wires":[]},{"id":"4b22afbf2a44012b","type":"link out","z":"22eb2b8f4786695c","name":"TCP:5002","mode":"link","links":["75c39b9166c382eb"],"x":1635,"y":4720,"wires":[]},{"id":"75c39b9166c382eb","type":"link in","z":"22eb2b8f4786695c","name":"TCP:5002","links":["4b22afbf2a44012b"],"x":805,"y":4860,"wires":[["39b1d7c666707e4f","e5418034e0b5aca8"]]},{"id":"919980cc7ae31924","type":"link out","z":"22eb2b8f4786695c","name":"TCP:5001","mode":"link","links":["0ded08d45b7f994f"],"x":1635,"y":4920,"wires":[]},{"id":"27ead22d6d2630d6","type":"switch","z":"22eb2b8f4786695c","name":"","property":"user-input","propertyType":"flow","rules":[{"t":"neq","v":"","vt":"prev"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1450,"y":4680,"wires":[["30db202a149c3c40"],["45ab7364b58a431d"]]},{"id":"30db202a149c3c40","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload}}\nユーザーからの入力:{{flow.user-input}}","output":"str","x":1600,"y":4660,"wires":[["45ab7364b58a431d"]]},{"id":"b531d62bdb740a8a","type":"switch","z":"22eb2b8f4786695c","name":"","property":"user-input","propertyType":"flow","rules":[{"t":"neq","v":"","vt":"prev"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1450,"y":4880,"wires":[["47aeddebdfb078d4"],["ce02f2ed9038e99a"]]},{"id":"47aeddebdfb078d4","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload}}\nユーザーからの入力:{{flow.user-input}}","output":"str","x":1600,"y":4860,"wires":[["ce02f2ed9038e99a"]]},{"id":"f2201ff3b9c9a3f3","type":"switch","z":"22eb2b8f4786695c","name":"","property":"continue-node-1","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":1230,"y":4740,"wires":[["d5e19c1212f721af"]]},{"id":"c1153858ace9e786","type":"switch","z":"22eb2b8f4786695c","name":"","property":"continue-node-2","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":1230,"y":4940,"wires":[["543dec888bf5f431"]]},{"id":"589e31dd8ec5d417","type":"ui-text-input","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"Initial Setting (Node-1)","order":1,"width":"6","height":"2","topic":"topic","topicType":"msg","mode":"textarea","tooltip":"","delay":300,"passthru":true,"sendOnDelay":false,"sendOnBlur":true,"sendOnEnter":true,"className":"","clearable":false,"sendOnClear":false,"icon":"","iconPosition":"left","iconInnerPosition":"inside","x":1280,"y":4460,"wires":[["610b72b12f56b765"]]},{"id":"b7f918efd016f500","type":"ui-text-input","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"Initial Setting (Node-2)","order":3,"width":"6","height":"2","topic":"topic","topicType":"msg","mode":"textarea","tooltip":"","delay":300,"passthru":true,"sendOnDelay":false,"sendOnBlur":true,"sendOnEnter":true,"className":"","clearable":false,"sendOnClear":false,"icon":"","iconPosition":"left","iconInnerPosition":"inside","x":1280,"y":4520,"wires":[["ea0788b313cf5a0c"]]},{"id":"7c879421615c256c","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"あなたはAI同士の対話システムの一部です。\nあなたのユーザー名はNode-1です。\nユーザー名を含めてあなたの意見を短く回答してください。","output":"str","x":1080,"y":4460,"wires":[["589e31dd8ec5d417"]]},{"id":"f99b02e76ff22398","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"あなたはAI同士の対話システムの一部です。\nあなたのユーザー名はNode-2です。\nユーザー名を含めてあなたの意見を短く回答してください。","output":"str","x":1080,"y":4520,"wires":[["b7f918efd016f500"]]},{"id":"ebed58f313ff3b17","type":"ui-switch","z":"22eb2b8f4786695c","name":"","label":"Continue","group":"f0bbe692c3fc1950","order":3,"width":"2","height":"1","passthru":true,"decouple":false,"topic":"topic","topicType":"msg","style":"","className":"","layout":"row-spread","clickableArea":"switch","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":260,"y":4780,"wires":[["cdefba7dbbd18f31"]]},{"id":"cdefba7dbbd18f31","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"continue-node-1","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":4780,"wires":[[]]},{"id":"2f2e104de7d1d83d","type":"ui-switch","z":"22eb2b8f4786695c","name":"","label":"Continue","group":"59d519b3e322c6b9","order":3,"width":"2","height":"1","passthru":true,"decouple":false,"topic":"topic","topicType":"msg","style":"","className":"","layout":"row-spread","clickableArea":"switch","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":260,"y":4840,"wires":[["d2676ffab4375515"]]},{"id":"d2676ffab4375515","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"continue-node-2","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":4840,"wires":[[]]},{"id":"da494bbf861827b9","type":"ui-button","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"Send Node-1","order":2,"width":0,"height":0,"emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":950,"y":4420,"wires":[["7c879421615c256c"]]},{"id":"1c5b9934c0c846c2","type":"ui-button","z":"22eb2b8f4786695c","group":"133cd157318ae5b6","name":"","label":"Send Node-2","order":4,"width":0,"height":0,"emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":950,"y":4560,"wires":[["f99b02e76ff22398"]]},{"id":"1637bd2a5c4d2f1a","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"terminate","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":4480,"wires":[["4695b2de51635342"]]},{"id":"ad1e10bf3e127848","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"terminate","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":4400,"wires":[["7543d889d219314b"]]},{"id":"d5e19c1212f721af","type":"delay","z":"22eb2b8f4786695c","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1380,"y":4740,"wires":[["27ead22d6d2630d6"]]},{"id":"543dec888bf5f431","type":"delay","z":"22eb2b8f4786695c","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1380,"y":4940,"wires":[["b531d62bdb740a8a"]]},{"id":"83776ba6a7ac02c5","type":"ui-button","z":"22eb2b8f4786695c","group":"f0bbe692c3fc1950","name":"","label":"Start","order":1,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"true","payloadType":"bool","topic":"topic","topicType":"msg","buttonColor":"green","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":190,"y":4360,"wires":[["7543d889d219314b","ebed58f313ff3b17","c50d5dedab76010c"]]},{"id":"d8b424b38989a7f9","type":"ui-button","z":"22eb2b8f4786695c","group":"59d519b3e322c6b9","name":"","label":"Start","order":1,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"true","payloadType":"bool","topic":"topic","topicType":"msg","buttonColor":"green","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":190,"y":4440,"wires":[["4695b2de51635342","2f2e104de7d1d83d","c50d5dedab76010c"]]},{"id":"7dd877a42e38125c","type":"ui-button","z":"22eb2b8f4786695c","group":"f0bbe692c3fc1950","name":"","label":"Shutdown","order":2,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"false","payloadType":"bool","topic":"topic","topicType":"msg","buttonColor":"red","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":200,"y":4400,"wires":[["ad1e10bf3e127848","ebed58f313ff3b17","afbaf17313ed3656"]]},{"id":"e0d0682c92447c9e","type":"ui-button","z":"22eb2b8f4786695c","group":"59d519b3e322c6b9","name":"","label":"Shutdown","order":2,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"false","payloadType":"bool","topic":"topic","topicType":"msg","buttonColor":"red","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":200,"y":4480,"wires":[["1637bd2a5c4d2f1a","2f2e104de7d1d83d","afbaf17313ed3656"]]},{"id":"35f2faa12208f01d","type":"switch","z":"22eb2b8f4786695c","name":"","property":"send-once","propertyType":"flow","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":610,"y":4660,"wires":[["570cc79486946e82","d81bba47fda884db"]]},{"id":"570cc79486946e82","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"send-once","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":790,"y":4720,"wires":[[]]},{"id":"0ded08d45b7f994f","type":"link in","z":"22eb2b8f4786695c","name":"TCP:5002","links":["919980cc7ae31924"],"x":805,"y":4680,"wires":[["d81bba47fda884db","27802d1da7d5cfe8"]]},{"id":"afbaf17313ed3656","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"send-once","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":4560,"wires":[[]]},{"id":"c50d5dedab76010c","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"send-once","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":4520,"wires":[[]]},{"id":"3b5d0fcc82970fbe","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":290,"y":4560,"wires":[["afbaf17313ed3656"]]},{"id":"d4fd4dde6372035a","type":"file","z":"22eb2b8f4786695c","name":"","filename":"node-1.txt","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":1460,"y":4800,"wires":[[]]},{"id":"2af30fdcb359b087","type":"file","z":"22eb2b8f4786695c","name":"","filename":"node-2.txt","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":1460,"y":5000,"wires":[[]]},{"id":"6dd95bf3bbfb8997","type":"link out","z":"22eb2b8f4786695c","name":"gTTS","mode":"link","links":["fe521de6f72d8f1f"],"x":1325,"y":4860,"wires":[]},{"id":"37ea1b8efa506958","type":"link out","z":"22eb2b8f4786695c","name":"gTTS","mode":"link","links":["fe521de6f72d8f1f"],"x":1325,"y":4660,"wires":[]},{"id":"3539cfeaaa9bc031","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1300,"y":4600,"wires":[[]]},{"id":"81bbb0b4a775f1ca","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"voiceID","pt":"msg","to":"23","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1720,"y":4460,"wires":[["4c1faedac11c9e5b"]]},{"id":"df0c96fa2fd89288","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"voiceID","pt":"msg","to":"29","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1720,"y":4520,"wires":[["4c1faedac11c9e5b"]]},{"id":"7a1d68da210cdb9b","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"voiceID","pt":"msg","to":"23","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":4700,"wires":[["37ea1b8efa506958"]]},{"id":"e74efabd3871c5f9","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"voiceID","pt":"msg","to":"29","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":4900,"wires":[["6dd95bf3bbfb8997"]]},{"id":"e8da1162f4b37224","type":"inject","z":"22eb2b8f4786695c","name":"Reset","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":960,"y":4800,"wires":[["af6a3cbae08d5c05","a6365f703cdefc49"]]},{"id":"27802d1da7d5cfe8","type":"debug","z":"22eb2b8f4786695c","name":"debug 515","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":920,"y":4600,"wires":[]},{"id":"e5418034e0b5aca8","type":"debug","z":"22eb2b8f4786695c","name":"debug 516","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":840,"y":4920,"wires":[]},{"id":"45ab7364b58a431d","type":"junction","z":"22eb2b8f4786695c","x":1580,"y":4720,"wires":[["4b22afbf2a44012b"]]},{"id":"ce02f2ed9038e99a","type":"junction","z":"22eb2b8f4786695c","x":1580,"y":4920,"wires":[["919980cc7ae31924"]]},{"id":"015784e9e3e0310a","type":"venv-config","venvname":"AI","version":"3.10"},{"id":"f0bbe692c3fc1950","type":"ui-group","name":"Node-1 (Gemma3:4B)","page":"b7ce0bd27a143e8e","width":"6","height":"1","order":2,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"59d519b3e322c6b9","type":"ui-group","name":"Node-2 (Gemma3:4B)","page":"b7ce0bd27a143e8e","width":"6","height":"1","order":3,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"133cd157318ae5b6","type":"ui-group","name":"User","page":"b7ce0bd27a143e8e","width":"5","height":"1","order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"b7ce0bd27a143e8e","type":"ui-page","name":"AI","ui":"ba89d595c555beb9","path":"/ai","icon":"brain","layout":"grid","theme":"e2c9a4f37a42314e","breakpoints":[{"name":"Default","px":"0","cols":"20"}],"order":2,"className":"","visible":"true","disabled":"false"},{"id":"ba89d595c555beb9","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":"1","showDisconnectNotification":true},{"id":"e2c9a4f37a42314e","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094CE","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"density":"default","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]On the dashboard screen, I can send initial configurations for each AI, start/shutdown the TCP servers, and manage user input.
▼The screen looks like this:

By the way, I struggled a bit with displaying the AI's responses in Markdown format. I plan to summarize that in a separate article.
The gauges on the right side of the dashboard were inspired by a teammate's work during last year's Osaka 24-hour AI Hackathon, so I included them.
▼This was the screen during the hackathon:

▼It's also used in this post. Various AI tools are being tested.
I didn't want to put unnecessary load on the process, so I set it to update at 10-second intervals.
▼It uses Windows commands to perform the calculations.

[{"id":"24608505abbec992","type":"exec","z":"22eb2b8f4786695c","command":"nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"GPU Usage","x":890,"y":5980,"wires":[["36a350315036bb0a","808df70d9f1baa6c"],["ee9d23ec3a5ad0fc"],[]]},{"id":"36a350315036bb0a","type":"debug","z":"22eb2b8f4786695c","name":"debug 486","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1070,"y":5960,"wires":[]},{"id":"ee9d23ec3a5ad0fc","type":"debug","z":"22eb2b8f4786695c","name":"debug 487","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1070,"y":6000,"wires":[]},{"id":"0419118f42586e94","type":"ui-gauge","z":"22eb2b8f4786695c","name":"","group":"cddf1256830eb7c5","order":3,"width":3,"height":"1","gtype":"gauge-34","gstyle":"needle","title":"GPU","units":"%","icon":"","prefix":"","suffix":"","segments":[{"from":"0","color":"#5cd65c"},{"from":"50","color":"#ffc800"},{"from":"80","color":"#ea5353"}],"min":0,"max":"100","sizeThickness":16,"sizeGap":4,"sizeKeyThickness":8,"styleRounded":true,"styleGlow":false,"className":"","x":1390,"y":6040,"wires":[]},{"id":"808df70d9f1baa6c","type":"csv","z":"22eb2b8f4786695c","name":"","spec":"rfc","sep":",","hdrin":"","hdrout":"none","multi":"one","ret":"\\r\\n","temp":"","skip":"0","strings":true,"include_empty_strings":"","include_null_values":"","x":1050,"y":6040,"wires":[["60f8cb9196c2e001"]]},{"id":"60f8cb9196c2e001","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.col1","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1220,"y":6040,"wires":[["0419118f42586e94"]]},{"id":"1e3aea53de34dacc","type":"exec","z":"22eb2b8f4786695c","command":"powershell -command \"& { $cpu_usage = (Get-Counter '\\Processor(_Total)\\% Processor Time').CounterSamples.CookedValue; [math]::Round($cpu_usage, 2) }\"","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"CPU Usage","x":890,"y":5840,"wires":[["5337286141bcbdea","e39ccfb856f25d7d"],["cf2779ab819608be"],[]]},{"id":"4ef7736fea215c1b","type":"inject","z":"22eb2b8f4786695c","name":"","props":[],"repeat":"10","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":730,"y":5840,"wires":[["1e3aea53de34dacc","24608505abbec992","5a616651108085dd"]]},{"id":"5337286141bcbdea","type":"debug","z":"22eb2b8f4786695c","name":"debug 489","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1070,"y":5820,"wires":[]},{"id":"cf2779ab819608be","type":"debug","z":"22eb2b8f4786695c","name":"debug 490","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1070,"y":5860,"wires":[]},{"id":"e39ccfb856f25d7d","type":"ui-gauge","z":"22eb2b8f4786695c","name":"","group":"cddf1256830eb7c5","order":1,"width":3,"height":"1","gtype":"gauge-34","gstyle":"needle","title":"CPU","units":"%","icon":"","prefix":"","suffix":"","segments":[{"from":"0","color":"#5cd65c"},{"from":"50","color":"#ffc800"},{"from":"80","color":"#ea5353"}],"min":0,"max":"100","sizeThickness":"16","sizeGap":4,"sizeKeyThickness":"8","styleRounded":true,"styleGlow":false,"className":"","x":1050,"y":5900,"wires":[]},{"id":"5a616651108085dd","type":"exec","z":"22eb2b8f4786695c","command":"powershell -command \"& { $TotalMemory = (Get-WmiObject Win32_OperatingSystem).TotalVisibleMemorySize / 1024; $FreeMemory = (Get-WmiObject Win32_OperatingSystem).FreePhysicalMemory / 1024; $UsedMemory = $TotalMemory - $FreeMemory; $UsagePercent = ($UsedMemory / $TotalMemory) * 100; Write-Output \\\"Total: $([math]::Round($TotalMemory,2)) GB, Used: $([math]::Round($UsedMemory,2)) GB, Usage: $([math]::Round($UsagePercent,2)) %\\\" }\"","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"Memory Usage","x":900,"y":6120,"wires":[["1f8af5c4c8059cdf","c01ce2400e8076f7"],["b3c2f86be0c0d0d7"],[]]},{"id":"1f8af5c4c8059cdf","type":"debug","z":"22eb2b8f4786695c","name":"debug 491","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1090,"y":6100,"wires":[]},{"id":"b3c2f86be0c0d0d7","type":"debug","z":"22eb2b8f4786695c","name":"debug 492","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1090,"y":6140,"wires":[]},{"id":"c01ce2400e8076f7","type":"csv","z":"22eb2b8f4786695c","name":"","spec":"rfc","sep":",","hdrin":"","hdrout":"none","multi":"one","ret":"\\r\\n","temp":"","skip":"0","strings":true,"include_empty_strings":"","include_null_values":"","x":1070,"y":6180,"wires":[["6f28389f0f2a32f1"]]},{"id":"6f28389f0f2a32f1","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.col3","tot":"msg"},{"t":"change","p":"payload","pt":"msg","from":"Usage: ","fromt":"str","to":"","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":" %","fromt":"str","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1240,"y":6180,"wires":[["d7751a2b5ebd6177"]]},{"id":"d7751a2b5ebd6177","type":"ui-gauge","z":"22eb2b8f4786695c","name":"","group":"cddf1256830eb7c5","order":2,"width":3,"height":"1","gtype":"gauge-34","gstyle":"needle","title":"Memory","units":"%","icon":"","prefix":"","suffix":"","segments":[{"from":"0","color":"#5cd65c"},{"from":"50","color":"#ffc800"},{"from":"80","color":"#ea5353"}],"min":0,"max":"100","sizeThickness":16,"sizeGap":4,"sizeKeyThickness":8,"styleRounded":true,"styleGlow":false,"className":"","x":1420,"y":6180,"wires":[]},{"id":"cddf1256830eb7c5","type":"ui-group","name":"Usage","page":"b7ce0bd27a143e8e","width":"3","height":"1","order":4,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"b7ce0bd27a143e8e","type":"ui-page","name":"AI","ui":"ba89d595c555beb9","path":"/ai","icon":"brain","layout":"grid","theme":"e2c9a4f37a42314e","breakpoints":[{"name":"Default","px":"0","cols":"20"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"ba89d595c555beb9","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":"1","showDisconnectNotification":true},{"id":"e2c9a4f37a42314e","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094CE","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"density":"default","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]Conversing Again
I operated the dashboard screen to let the AIs converse again.
▼I asked them what they thought of the proverb "Three people together have the wisdom of Monju" (Two heads are better than one). I also provided user input during the process.
▼When I made them take opposing stances, the conversation progressed with a somewhat hostile atmosphere.
Perhaps because the theme was abstract, I got the impression that "Node-2" spent more time critiquing the wording and attitude rather than the actual theme.
Now that I’ve confirmed it works, I plan to experiment with various scenarios.
Finally
By connecting this to speech synthesis and playback, the conversation continued like a radio show. Since the conversation content remains as text, it could be used as an "AI Radio."
The use case depends on the theme, but I think if I have them discuss AI-generated code, they might just start improving it on their own.


