iT邦幫忙

0

在Arduino UNO Q開發板上實作本地端大語言模型對話程序

  • 分享至 

  • xImage
  •  

延續前一篇文章:在Arduino UNO Q開發板上,使用Needle將文字輸入轉化為動作,接著往下進行更深入的開發。由於Cactus Needle模型只是針對「語言 - 動作」進行處理,並無法應對一般性的對話(如:Where is the capital of France?)。接下來會在Arduino UNO Q開發板外接ASUS UGen300 USB AI 加速器來實作完整的本地端大語言模型之對話應用程序。先看一下成果:
1004_1
可以看到在使用者想要控制LED點亮或熄滅時Cactus Needle會呼叫tool進行控制,而一般性的對話則會交由本地端大語言模型(這邊用到的llama3.2:1b大語言模型,由hailo-ollama來提供服務)接手處理。
因此會比前一篇文章在開發與執行環境上更為複雜。Arduino UNO Q開發板(4GB/32GB版本)需要運作在SBC模式並搭配周邊設備,硬體組成可參考以下照片所示:
1004_2
在軟體方面,因為搭配ASUS UGen300 USB AI 加速器軟體所以無法使用Arduino App Lab來進行開發工作;改以命令列方式(在Terminal上操作)進行微控制器(MCU)之編譯與下載,以及Python之環境建立、相關套件安裝與執行應用程序。步驟相對複雜,因此分段進行說明。

SBC模式下的環境準備

Arduino UNO Q開發板的SBC模式就相當於操作一台Linux迷你電腦(概念等同於樹莓派Raspberry Pi),可以在上面編輯與編譯程式。為了開發便利性就先安裝編輯器:

sudo apt install geany

接著建置Python環境,這邊是安裝Miniforge:

curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"

bash Miniforge3-$(uname)-$(uname -m).sh

安裝ASUS UGen300 USB AI 加速器驅動程式與應用程序,請至官網下載「UGen Utility for UGen300 USB AI Accelerator (Linux-Debian)」後依以下程序安裝(安裝過程若有疑問請參考壓縮檔內的README.txt文件):

unzip ugen-utility_2.4.0-9_arm64_usb.zip

cd ugen-utility_2.4.0-9_arm64_usb

chmod +x ./ugen-utility-install.sh

./ugen-utility-install.sh

安裝完成後請確認一下應用程序與Python環境是否可以運作,確認沒有問題後再往下進行。

建立MCU韌體並編譯下載

使用命令來建立MCU韌體專案:

arduino-cli sketch new McuLedCtrl

修改McuLedCtrl.ino加入以下程式碼:

#include "Arduino_RouterBridge.h"

void setup() {
    
    pinMode(LED_BUILTIN, OUTPUT);                   // Initialize digital pin LED_BUILTIN as an output.

    Bridge.begin();                                 // Is mandatory calling Bridge.begin() to initialize Bridge communication.
    Bridge.provide("set_led_state", set_led_state); // Provide the "set_led_state" function to be called from Python
}

void loop() {
}

void set_led_state(bool state) {
    digitalWrite(LED_BUILTIN, state ? LOW : HIGH);  // Set the LED state based on the state input parameter
}

修改好後進行編譯與上傳:

arduino-cli compile --fqbn arduino:zephyr:unoq ./McuLedCtrl/

arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:zephyr:unoq ./McuLedCtrl/

安裝Hailo Model Zoo GenAI套件

前面在環境準備時的安裝完成後並沒有hailo-ollama命令可以使用,因此須至Hailo’s Developer Zone中找到相對應的套件(hailo_gen_ai_model_zoo_5.3.0_arm64.deb)並下載,安裝命令如下所示:

sudo dpkg -i hailo_gen_ai_model_zoo_5.3.0_arm64.deb

完成後另開「終端機」執行以下命令以啟動hailo-ollama服務:

hailo-ollama

然後透過以下命令將模型下載至本地:

curl --silent http://localhost:8000/api/pull \
     -H 'Content-Type: application/json' \
     -d '{ "model": "llama3.2:1b", "stream" : true }'

建立Python虛擬環境

建立一個虛擬環境以方便開發與應用:

conda create --name ArduinoUnoQ python=3.13

完成後進入該環境:

conda activate ArduinoUnoQ

並安裝以下必要套件:

pip install arduino-router-bridge

pip install cactus-needle==2.0.15

pip install requests

撰寫本地端大語言模型對話程序Python程式碼

UnoQ.py程式碼如下所示:

from arduino.router_bridge import Bridge
import needle
import requests
import json

bridge = None

# Define your hardware action tools using the @needle.tool decorator
@needle.tool
def set_led(state: str):
    """Turn the device LED on or off.

    Args:
        state: Must be either 'on' or 'off'.
    """
    global bridge
    if state.lower() == "on":
        bridge.call("set_led_state", True)
        print("Hardware action: LED turned ON")
        return {"status": "success", "led": "on"}
    elif state.lower() == "off":
        bridge.call("set_led_state", False)
        print("Hardware action: LED turned OFF")
        return {"status": "success", "led": "off"}
    return {"status": "error", "message": "Invalid state argument"}

def hailo_ollama_chat( question) :
    
    url = "http://localhost:8000/api/chat"
    model_name = "llama3.2:1b"
    responses = ""
    
    data = {
        "model": model_name,
        "temperature": 0.7,
        "max_length": 2048,
        "messages": [
            {"role": "user", "content": question}
        ]
    }
    
    try:
        res = requests.post(url, json=data, stream=True)
        if res.status_code == 200:
            for line in res.iter_lines():
                if not line:
                    continue
                data = json.loads(line.decode("utf-8"))
                content = data.get("message", {}).get("content", "")
                if content:
                    responses += content
                if data.get("done"):
                    break
        else:
            pass
    except Exception as e:
        print(e)
    return responses

def main():
    global bridge
    bridge = Bridge()
    bridge.connect(timeout=5)  # Waits until connected; True if connected, False on timeout
    
    print("Hardware initialize: LED turned OFF")
    bridge.call("set_led_state", False)
    
    # Initialize the Needle agent with your tools
    agent = needle.Needle(tools=[set_led])
    
    dbgmsg_enable = False
    tool_is_call  = False
    while True :
        tool_is_call = False
        
        message = input("Enter a message: ")
        if message == 'exit' :
            break
        # Run a natural language prompt to trigger the action
        # response = agent.run(message)
        response = agent.complete(message)
        if dbgmsg_enable is True :
            print('DEBUG : agent.complete() response = {}'.format(response))
        if response["type"] == "call" and response["confidence"] >= 0.7:
            if len(response["function_calls"]) > 0 and response["function_calls"][0]["name"] == "set_led" :
                out = set_led(**response["function_calls"][0]["arguments"])
                response = agent.complete(json.dumps(out))
                tool_is_call = True
        agent.reset()
        
        if tool_is_call is False :
            response = hailo_ollama_chat(message)
            print(response)
    
    bridge.disconnect()
    
if __name__ == "__main__":
    main()

執行Python程式碼並與其對話

python UnoQ.py

執行結果如下所示:
1004_3

參考資訊


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言