#M5StackLLM 通信の内容を調べる

 LLMモジュールとM5Stick C Plus2との通信は、/dev/ttyS1で行われている。CPlus2には、スケッチが書き込まれている。ここまでは前にやったところ。

  LLM Moduleを普通に使う|kinneko|pixivFANBOX

  https://kinneko.fanbox.cc/posts/9376067

 socatでシリアルポートを仮想化して、中継し、ミラーした結果を取ろうかと思ったけど、なかなかうまくいかない。

 基本的な考え方は、/dev/ttyS1を/dev/ttyS1_realにリネームし、socatコマンドを使って/dev/ttyS1という名前の仮想シリアルポートを作成し、それを/dev/ttyS1_realに接続するというもの。realのほうにデータがコピーされて流れてくるので、それを見るという感じ。

 でも、うまくいかないので放棄する。

 llm_sysの設定で、使用するシリアルポートが指定できれば、もう少し楽なのだけど、残念ながら設定ファイルには、そのための情報がない。telnetのポート設定があるので、シリアルもあるかもしれないのだけど、ハードコードの可能性もないでもない。

 さて、あとは出力の解釈が面倒だけど、straceを使って、やりとりをモニタする方法がある。

 llm_sysのプロセスを調べる。

root@m5stack-LLM:~# ps ax |grep llm
   2643 ?        Ssl    0:00 /opt/m5stack/bin/llm_sys
   2644 ?        Ssl    0:00 /opt/m5stack/bin/llm_asr
   2645 ?        Ssl    0:07 /opt/m5stack/bin/llm_audio
   2646 ?        Ssl    0:00 /opt/m5stack/bin/llm_camera
   2647 ?        Ssl    0:48 /opt/m5stack/bin/llm_kws
   2648 ?        Ssl    0:02 /opt/m5stack/bin/llm_llm
   2649 ?        Ssl    0:12 /opt/m5stack/bin/llm_melotts
   2650 ?        Ss     0:00 /opt/m5stack/bin/llm_skel
   2655 ?        Ssl    0:00 /opt/m5stack/bin/llm_tts
   2656 ?        Ssl    0:00 /opt/m5stack/bin/llm_vlm
   2661 ?        Ssl    0:00 /opt/m5stack/bin/llm_yolo

 ポートを指定して、straceする。

root@m5stack-LLM:~# strace -p 2643 -e trace=read,write,ioctl -s 1024 -o serial_trace.log -f
strace: Process 2643 attached with 19 threads
strace: Process 3964 attached
strace: Process 3965 attached
strace: Process 3966 attached
strace: Process 3967 attached
strace: Process 3971 attached
strace: Process 3972 attached
strace: Process 3973 attached
strace: Process 3974 attached
strace: Process 3975 attached
strace: Process 3976 attached
strace: Process 3977 attached
strace: Process 3978 attached
strace: Process 3979 attached
strace: Process 3980 attached
strace: Process 3981 attached

 あれ? 切れた。

 straceのログは人間が読めるしろものではないけど、AIであれば文句を言わずに人間にわかるやりとりにしてくれる。それによると、ここまでのログでは以下のようなやりとりがある。

Pingの送信:

{"request_id":"sys_ping","work_id":"sys","action":"ping","object":"None","data":"None"}

Pingの応答:

{"created":1739962203,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"sys_ping","work_id":"sys"}

Version確認の送信:

{"request_id":"sys_version","work_id":"sys","action":"version","object":"None","data":"None"}

Version確認の応答:

{"created":1739962203,"data":"v1.3","error":{"code":0,"message":""},"object":"sys.utf-8","request_id":"sys_version","work_id":"sys"}

Resetコマンドの送信:

{"request_id":"sys_reset","work_id":"sys","action":"reset","object":"None","data":"None"}

Resetコマンドの応答:

{"created":1739962204,"data":"None","error":{"code":0,"message":"llm server restarting ..."},"object":"None","request_id":"sys_reset","work_id":"sys"}

 ログが短いのは、リセットでプロセスが再起動されてしまって、当初のプロセスが終わっているからか...

 リセットが起きているのは、Arduinoのスケッチでは、このあたりの処理の後になる。

    while (1) {
        if (module_llm.checkConnection()) {
            break;
        }
    }

 checkConnection()は、M5ModuleLLM.cppにあるけど、リセットはしてない感じ。

bool M5ModuleLLM::checkConnection()
{
    const bool result = (sys.ping() == MODULE_LLM_OK);
    llm_version       = (sys.version() == MODULE_LLM_OK);
    return result;
}

 応答は正常に返っているので、エラーでリセットが発動しているわけではなさそう。リセットどこでしよるとね?

 リセット後にstraceを再度プロセスIDを入れて動かすけれど、やっぱり欠ける部分がある。

 たぶん、まずこんな感じでAudioの初期化しているのだろうけど、それがない。

{
    "request_id": "1",
    "work_id": "audio",
    "action": "setup",
    "object": "audio.setup",
    "data": {
        "capcard": 0,
        "capdevice": 0,
        "capVolume": 0.5,
        "playcard": 0,
        "playdevice": 1,
        "playVolume": 0.5
    }
}

 Audioの初期化の応答もない。

 次にKWSユニットの初期化があるのだろうけど、それもない。たぶん、こんな感じで流れているのだろう。

{
    "request_id": "2",
    "work_id": "kws",
    "action": "setup",
    "object": "kws.setup",
    "data": {
        "model": "sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01",
        "response_format": "kws.bool",
        "input": "sys.pcm",
        "enoutput": true,
        "kws": "ECHO"
    }
}

 KWSユニットの初期化の応答からは取れた。

{"created":1739964629,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"kws_setup","work_id":"kws.1001"}

 ASR(音声認識)のセットアップ。応答はないな。

{
  "request_id": "asr_setup",
  "work_id": "asr",
  "action": "setup",
  "object": "asr.setup",
  "data": {
    "model": "sherpa-ncnn-streaming-zipformer-20M-2023-02-17",
    "response_format": "asr.utf-8.stream",
    "enoutput": true,
    "enkws": true,
    "rule1": 2.4,
    "rule2": 1.2,
    "rule3": 30,
    "input": ["sys.pcm","kws.1001"]
  }
}

 LLM(大規模言語モデル)のセットアップ。こちらも応答がない。

{
  "request_id": "llm_setup",
  "work_id": "llm",
  "action": "setup",
  "object": "llm.setup",
  "data": {
    "model": "qwen2.5-0.5B-prefill-20e",
    "response_format": "llm.utf-8.stream",
    "enoutput": true,
    "enkws": true,
    "max_token_len": 127,
    "prompt": "",
    "input": ["asr.1002","kws.1001"]
  }
}

 TTS(音声合成)のセットアップ。これも応答がない。

{
  "request_id": "tts_setup",
  "work_id": "melotts",
  "action": "setup",
  "object": "melotts.setup",
  "data": {
    "model": "melotts_zh-cn",
    "response_format": "sys.pcm",
    "input": ["llm.1003","kws.1001"],
    "enoutput": false,
    "enaudio": true
  }
}

 telnetから再現できるかどうか調べる。

root@m5stack-LLM:~# telnet localhost 10001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"request_id":"sys_ping","work_id":"sys","action":"ping","object":"None","data":"None"}
{"created":1739966632,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"sys_ping","work_id":"sys"}
{"request_id":"sys_version","work_id":"sys","action":"version","object":"None","data":"None"}
{"created":1739966664,"data":"v1.3","error":{"code":0,"message":""},"object":"sys.utf-8","request_id":"sys_version","work_id":"sys"}
{"request_id":"sys_reset","work_id":"sys","action":"reset","object":"None","data":"None"}
{"created":1739966698,"data":"None","error":{"code":0,"message":"llm server restarting ..."},"object":"None","request_id":"sys_reset","work_id":"sys"}
Connection closed by foreign host.

 リセットすると切れるというのは確認できた。

 再接続して続き。一応、送った初期化コマンドには、すべてのサービスが正常応答を返している。

root@m5stack-LLM:~# telnet localhost 10001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{
    "request_id": "1",
    "work_id": "audio",
    "action": "setup",
    "object": "audio.setup",
    "data": {
        "capcard": 0,
        "capdevice": 0,
        "capVolume": 0.5,
        "playcard": 0,
        "playdevice": 1,
        "playVolume": 0.5
    }
}
{"created":1739966741,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"1","work_id":"audio"}
{
    "request_id": "2",
    "work_id": "kws",
    "action": "setup",
    "object": "kws.setup",
    "data": {
        "model": "sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01",
        "response_format": "kws.bool",
        "input": "sys.pcm",
        "enoutput": true,
        "kws": "ECHO"
    }
}
{"created":1739966802,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"2","work_id":"kws.1001"}
{
  "request_id": "asr_setup",
  "work_id": "asr",
  "action": "setup",
  "object": "asr.setup",
  "data": {
    "model": "sherpa-ncnn-streaming-zipformer-20M-2023-02-17",
    "response_format": "asr.utf-8.stream",
    "enoutput": true,
    "enkws": true,
    "rule1": 2.4,
    "rule2": 1.2,
    "rule3": 30,
    "input": ["sys.pcm","kws.1001"]
  }
}
{"created":1739966845,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"asr_setup","work_id":"asr.1002"}
{
  "request_id": "llm_setup",
  "work_id": "llm",
  "action": "setup",
  "object": "llm.setup",
  "data": {
    "model": "qwen2.5-0.5B-prefill-20e",
    "response_format": "llm.utf-8.stream",
    "enoutput": true,
    "enkws": true,
    "max_token_len": 127,
    "prompt": "",
    "input": ["asr.1002","kws.1001"]
  }
}
{"created":1739966895,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"llm_setup","work_id":"llm.1003"}
{
  "request_id": "tts_setup",
  "work_id": "melotts",
  "action": "setup",
  "object": "melotts.setup",
  "data": {
    "model": "melotts_zh-cn",
    "response_format": "sys.pcm",
    "input": ["llm.1003","kws.1001"],
    "enoutput": false,
    "enaudio": true
  }
}
{"created":1739966941,"data":"None","error":{"code":0,"message":""},"object":"None","request_id":"tts_setup","work_id":"melotts.1004"}

 初期化はできたので、音声応答を試す。「エコー」と声をかけてみる。ログが出て、差し替えた応答音がした。

{"created":1739966961,"data":true,"error":{"code":0,"message":""},"object":"kws.bool","request_id":"2","work_id":"kws.1001"}

 「are you fine?」と聞いたのだけど、「are you wying」と認識されている。

{"created":1739966986,"data":true,"error":{"code":0,"message":""},"object":"kws.bool","request_id":"2","work_id":"kws.1001"}
{"created":1739966990,"data":{"delta":" are you wy","finish":false,"index":0},"error":{"code":0,"message":""},"object":"asr.utf-8.stream","request_id":"asr_setup","work_id":"asr.1002"}
{"created":1739966991,"data":{"delta":" are you wying","finish":false,"index":1},"error":{"code":0,"message":""},"object":"asr.utf-8.stream","request_id":"asr_setup","work_id":"asr.1002"}
{"created":1739966991,"data":{"delta":" are you wying.","finish":true,"index":2},"error":{"code":0,"message":""},"object":"asr.utf-8.stream","request_id":"asr_setup","work_id":"asr.1002"}
{"created":1739966991,"data":{"delta":"No, I","finish":false,"index":0},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966992,"data":{"delta":" am here to","finish":false,"index":1},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966992,"data":{"delta":" assist you with","finish":false,"index":2},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966993,"data":{"delta":" any questions or","finish":false,"index":3},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966993,"data":{"delta":" concerns you may","finish":false,"index":4},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966993,"data":{"delta":" have. How","finish":false,"index":5},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966993,"data":{"delta":" can I help","finish":false,"index":6},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966994,"data":{"delta":" you today?","finish":false,"index":7},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966994,"data":{"delta":"\n","finish":false,"index":8},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}
{"created":1739966994,"data":{"delta":"","finish":true,"index":9},"error":{"code":0,"message":""},"object":"llm.utf-8.stream","request_id":"llm_setup","work_id":"llm.1003"}

 応答の生成と発音もできている。

 あとは、起動時にこのプロセスを内部で呼べれば、LLMモジュール単独で動作できる。

 シリアルから通信手順的にやるか、telnetからやるか... 悩ましい。動作プロセスが死ぬと、リセットされちゃうしなぁ...

      100円投げ銭  https://kinneko.booth.pm/items/1963720


オリジナル投稿:
#M5StackLLM 通信の内容を調べる|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/9410149