JapaneseTinyAgentLM Action 3M

日本語の短い依頼文を、ロボットの動作呼び出し(JSON)に変える、パラメータ数 3,148,608 の小さな言語モデルです。M5Stack のスタックチャン(CoreS3、ESP32-S3)の本体だけで動かすために、一から学習しました。NPU、外付けのモジュール、ネットワークは使いません。

入力: 左を見て、真ん中に戻ってきて。
出力: [{"name":"look","arguments":{"direction":"left","amount":"normal"}},
       {"name":"look","arguments":{"direction":"center","amount":"normal"}}]

コード(学習、評価、C の runtime、firmware): GitHub(Apache-2.0)

ブラウザで試す: デモ(Hugging Face Space)。インストール不要で、実機と同じ C の runtime(WebAssembly)と INT4 の重みがブラウザの中で動きます。

English summary at the end.

できること

出力は、次の3種類の動作を最大2個まで並べた JSON の配列です(action_schema_v0.json)。動作の依頼でない文、否定された依頼、このロボットにはできない依頼には [](何もしない)を返します。

動作 引数
look(首を向ける) direction: left / right / up / down / center、amount: slight / normal / large
set_expression(表情) expression: happy / sad / surprised / neutral
nod(うなずく) count: 1〜3

評価セットでの実際の出力の例です(いずれも正解)。

入力 出力
ほら 笑顔を見せて set_expression(happy)
ほんの少し左を向いてくれる? look(left, slight)
右向いて、一回うなずきな。 look(right, normal), nod(1)
いや、下は見なくて大丈夫。上を向いてみて! look(up, normal)
右むかないで、ちょっとやめといてくれる? []
まっすぐ行って、右に曲がってください。 []

すぐに試す(Python)

必要なのは Python 3.10 以上と、PyTorch、NumPy、sentencepiece、safetensors だけです。GPU は要りません(CPU で1文あたり約 0.03 秒)。

1. インストール

pip install torch numpy sentencepiece safetensors huggingface_hub

2. ダウンロードして実行

hf download ayousanz/JapaneseTinyAgentLM-Action-3M --local-dir JapaneseTinyAgentLM-Action-3M
python JapaneseTinyAgentLM-Action-3M/inference.py 右を向いて 笑わないでね
{"input": "右を向いて", "actions": [{"name": "look", "arguments": {"direction": "right", "amount": "normal"}}], "confidence": 0.9989, "raw": "..."}
{"input": "笑わないでね", "actions": [], "confidence": 0.9999, "raw": "[]"}

引数を付けずに python JapaneseTinyAgentLM-Action-3M/inference.py と実行すると、標準入力から1行に1文ずつ読みます。

Python から使う

import sys
from huggingface_hub import snapshot_download

folder = snapshot_download("ayousanz/JapaneseTinyAgentLM-Action-3M")
sys.path.insert(0, folder)
from inference import ActionModel

model = ActionModel(folder)
print(model("少し上を向いてから、二回うなずいて"))
# [{'name': 'look', 'arguments': {'direction': 'up', 'amount': 'slight'}},
#  {'name': 'nod', 'arguments': {'count': 2}}]
print(model.predict("こんにちは"))  # {'actions': [], 'confidence': ..., 'raw': '[]'}

uv を使う場合は、インストールせずに uv run --with torch --with numpy --with sentencepiece --with safetensors JapaneseTinyAgentLM-Action-3M/inference.py 右を向いて でも動きます。

出力の項目 意味
actions 実行する動作のリスト。[] なら何もしない
confidence 生成した token の確率の最小値。0.86808 未満のときは、actions を [] にしています
raw gate をかける前のモデルの出力

inference.py は、評価に使ったコードと同じ計算をする単体のスクリプト(約 270 行、Apache-2.0)です。評価セット全 4,794 文で、評価したときの出力と完全に一致することを確かめています。

ロボットにつなぐ

actions を順に実行します。スタックチャン(K151)では、次の角度を使いました。ほかのロボットでは、可動域に合わせて変えてください。

動作 角度
look left / right 左右に slight 10°、normal 20°、large 30°
look up / down 上下に slight 5°、normal 10°、large 15°
look center 左右・上下とも 0°(正面)
nod 下へ 14° 振って戻す動きを count 回
set_expression 画面の顔を変える(首は動かさない)
  • 出力は必ず action_schema_v0.json に合いますが、ロボットを動かす前に、角度の上限で必ず制限してください。
  • 文字の入力を前提にしています。音声で使う場合は、音声認識の結果を入力してください(音声認識の誤りへの強さは評価していません)。

スタックチャンで動かす

ビルド済みの firmware で、M5Stack のスタックチャン(K151。CoreS3 と SCS0009 の servo ×2)の本体だけで動きます。Wi-Fi は使いません。

書き込むと、今入っている firmware(公式のスタックチャンの firmware など)は消えます。 元に戻したい場合は、先に手順 1 でバックアップを取ってください。

0. インストール(上の「すぐに試す」でダウンロード済みのフォルダを使います)

pip install esptool pyserial

USB-C でパソコンにつなぎ、port の名前を確かめます(Windows は COM3 など、Linux は /dev/ttyACM0、macOS は /dev/cu.usbmodem…)。以下の COM3 は自分の port に置き換えてください。

1. バックアップ(任意。16MB、数分かかります)

esptool --chip esp32s3 -p COM3 -b 921600 read-flash 0 0x1000000 backup_k151.bin
# 元に戻すとき: esptool --chip esp32s3 -p COM3 -b 921600 write-flash 0x0 backup_k151.bin

2. 書き込み(firmware とモデルが1つのファイルになっています。4,068,608 bytes)

esptool --chip esp32s3 -p COM3 -b 921600 write-flash 0x0 JapaneseTinyAgentLM-Action-3M/firmware/stackchan_k151_jtalm_action.bin

つながらないときは、本体の横のリセットボタンを緑の LED が点くまで約3秒押し続けて、書き込みモードにしてからやり直してください。書き込んだ後は、リセットボタンを1回押します。

3. 話しかける

python JapaneseTinyAgentLM-Action-3M/firmware/stackchan_chat.py COM3
準備ができました。依頼を入力してください(終了は Ctrl+C)。
右を向いて
→ [{"name":"look","arguments":{"direction":"right","amount":"normal"}}]  963 ms
にっこりして
→ [{"name":"set_expression","arguments":{"expression":"happy"}}]  908 ms
笑わないでね
→ []  384 ms

画面に顔が出て、表情の依頼で顔が変わります。起動したときは servo が off で、首は動きません(動きの計画だけを作ります)。

4. 首を動かす

python JapaneseTinyAgentLM-Action-3M/firmware/stackchan_chat.py COM3 --servo

servo の電源が入り、首がゆっくり正面に戻ってから、依頼に合わせて首が動きます。首のまわりに指やケーブルを近づけないでください。画面に触れる、Ctrl+C を押す、!stop を送る、のどれかで、すぐに止まり servo の電源が切れます。 角度は firmware が制限します(左右 ±30°、上下 −10〜+15°)。

! で始まる command 動き
!servo on / !servo off servo の電源を入れる(首が動く)/ 切る
!stop 動きを止めて servo の電源を切る
!center 正面を向く
!gate 0.9 確信度の gate の閾値を変える(既定 0.868。0 で off)
!info モデルと firmware の情報
  • 1文の応答時間の中央値は約 1.3 秒でした(CoreS3、2コア)。300文で、PC の PyTorch と出力が完全に一致しました。
  • firmware は ESP-IDF v5.5.5 で build しました(app の sha256 7ada159fff9494eb6dd71022207c1863d207f698d7ae80c73e39f44461a1d749)。flash の配置は、bootloader 0x0、partition table 0x8000、app 0x10000、モデル(jtalm_action_3m_q4_g64.jtlm)0x200000 です。モデルだけを替えるときは、0x200000 に .jtlm を書き込みます。
  • firmware は Apache-2.0 です。同梱した第三者のコード(ESP-IDF、newlib、FreeRTOS、M5Unified、M5GFX など)のライセンスは firmware/licenses/ にあります。firmware の source と build の手順は GitHub にあります。

ファイル

ファイル 内容
inference.py 単体の推論スクリプト(上の「すぐに試す」)
firmware/stackchan_k151_jtalm_action.bin スタックチャン用の firmware とモデルを1つにした書き込み用のイメージ(0x0 に書く)
firmware/stackchan_chat.py スタックチャンと USB serial で話すスクリプト
firmware/licenses/ firmware に含まれる第三者のコードのライセンス
model.safetensors 評価した重み。INT4(group 64)で量子化した値を fp32 で保存したもので、ESP32 が計算する値と同じです
model_fp32.safetensors 量子化する前の fp32 の重み(追加学習用)
jtalm_action_3m_q4_g64.jtlm スタックチャンの firmware が読む形式(1,971,456 bytes、sha256 b90d0066075d92a2a803b40eb62112cd227480b1fdd24a4f6797a388a6ee7b5d)
tokenizer.model SentencePiece(unigram、2,048語)。JSON の部品を1語として持ちます
config.json 構造、tokenizer の hash、確信度の閾値(gate)
action_schema_v0.json 出力の JSON Schema
eval/ 評価の表と、誤差の範囲
SHA256SUMS 各ファイルの sha256(sha256sum -c SHA256SUMS で確認できます)

推論の仕組み

ほかの言語や環境に移すときは、inference.py と同じ次の手順にしてください。本モデルの評価の数値は、この手順で出したものです。

  1. 入力: <s> <act> 文の token 列 <out>。文は tokenizer.model で分割します(<act> と <out> は tokenizer にある記号です)。
  2. 文法による制約: <out> の後を </s> まで greedy に生成します(最大 24 token)。各 step で、schema に合う token だけから最も確率の高いものを選ぶので、出力は必ず schema に合う JSON になります。
  3. 確信度の gate: 生成した token(</s> を含む)の、制約をかける前の確率の最小値が 0.86808 未満なら、出力を [] にします。閾値は validation だけで決めました。

評価

INT4、文法による制約、gate 0.86808 での結果です(%)。exact は出力の完全一致、requests exact は動作を求める文の完全一致、false actions は何もしないのが正解の文で動いてしまった割合です。

gate threshold 0.86808

set n exact requests exact false actions critical
v0 eval (LLM) 1189 93.8 87.8 0.5 0.3
human v1 1159 99.6 91.9 0.0 0.0
v2/amount_words 278 94.6 94.6 — 0.0
v2/center_phrasing 223 93.7 93.7 — 0.0
v2/correction 44 84.1 84.1 — 0.0
v2/english 70 45.7 5.3 6.2 2.9
v2/fragments 182 100.0 — 0.0 0.0
v2/long_preface 247 90.3 90.3 — 0.0
v2/negation_forms 168 100.0 — 0.0 0.0
v2/numbers 167 93.4 85.7 1.9 1.2
v2/order_words 296 95.3 95.3 — 0.0
v2/orthography 282 82.6 80.8 0.0 0.0
v2/question_forms 203 90.1 90.1 — 0.0
v2/unexecutable 286 99.7 — 0.3 0.3
評価セット 書いたもの
v0 eval (LLM) llm-jp-3.1-13b-instruct4(学習データを書いたモデルとは別)。Qwen3 が正解を確かめた
human v1 人が書いた公開コーパスの文(JESC、Tatoeba、YJ AmbigDialogue、J-CRe3、対話システムライブコンペ 3、MASSIVE)。依頼はルールで確実に判定できる文だけを選び、Qwen3 と答えが一致したものを残した(依頼 62件、依頼でない文 1,097件)。学習には使っていない
v2/* 苦手になりやすい12の型(言い回し、量、数、否定、言い直し、順序、断片、できない依頼、表記、疑問形、前置き、英語)。llm-jp-3.1-13b-instruct4 が書き、Qwen3 が確かめた

誤差の範囲

数値のぶれには2つの原因があります。

  • 評価セットの大きさ: 下の1つ目の表は、公開したモデルについて、評価の文を復元抽出し直して求めた 95% の区間です(2,000回)。人が書いた依頼文は 62件しかないので、区間が広くなります。
  • 学習の seed: 同じデータと設定で seed だけを変えて5回学習し、それぞれを同じ方法(INT4、文法、validation で決めた gate)で評価しました。下の2つ目の表は、5回の平均 ± 標準偏差です。

公開したのは seed 0 です。 seed 0 は、ほかの seed を学習する前に実機への搭載と実機での検証(300文で PC と完全一致)を済ませていたモデルです。人が書いた依頼文では、5つの seed の中で最も高い値でした(seed ごとに 91.9 / 75.8 / 83.9 / 90.3 / 83.9%)。そのため、この評価セットでの実力は、5回の平均(約 85%)で見るのが妥当です。LLM が書いた評価セット(v0 eval)の依頼文は 88.1 ± 1.2% で、seed による差は小さいです。

Released model (seed 0): rate and 95% bootstrap interval (%, 2,000 resamples)

set exact requests exact false actions
human_v1 99.6 [99.1, 99.9] 91.9 [85.5, 98.4] 0.0 [0.0, 0.0]
v0_eval_LLM 93.8 [92.3, 95.2] 87.8 [85.1, 90.4] 0.5 [0.0, 1.2]
v2_amount_words 94.6 [91.7, 97.1] 94.6 [92.1, 97.1] —
v2_center_phrasing 93.7 [90.6, 96.9] 93.7 [90.6, 96.9] —
v2_correction 84.1 [72.7, 95.5] 84.1 [72.7, 95.5] —
v2_english 45.7 [34.3, 57.1] 5.3 [0.0, 13.2] 6.2 [0.0, 15.6]
v2_fragments 100.0 [100.0, 100.0] — 0.0 [0.0, 0.0]
v2_long_preface 90.3 [86.2, 93.9] 90.3 [86.6, 93.5] —
v2_negation_forms 100.0 [100.0, 100.0] — 0.0 [0.0, 0.0]
v2_numbers 93.4 [89.2, 97.0] 85.7 [76.2, 93.7] 1.9 [0.0, 4.8]
v2_order_words 95.3 [92.6, 97.6] 95.3 [92.9, 97.6] —
v2_orthography 82.6 [78.0, 86.9] 80.8 [75.7, 85.5] 0.0 [0.0, 0.0]
v2_question_forms 90.1 [86.2, 94.1] 90.1 [85.7, 94.1] —
v2_unexecutable 99.7 [99.0, 100.0] — 0.3 [0.0, 1.0]

5 seeds (0–4), mean ± standard deviation of the per-seed rates (%)

set exact requests exact false actions
human_v1 99.2 ± 0.4 85.2 ± 6.4 0.0 ± 0.0
v0_eval_LLM 94.0 ± 0.6 88.1 ± 1.2 0.4 ± 0.2
v2_amount_words 94.1 ± 0.6 94.1 ± 0.6 —
v2_center_phrasing 92.8 ± 1.8 92.8 ± 1.8 —
v2_correction 85.5 ± 3.4 85.5 ± 3.4 —
v2_english 46.6 ± 1.6 5.8 ± 2.9 5.0 ± 6.5
v2_fragments 99.9 ± 0.2 — 0.1 ± 0.2
v2_long_preface 91.3 ± 1.1 91.3 ± 1.1 —
v2_negation_forms 99.9 ± 0.3 — 0.1 ± 0.3
v2_numbers 93.4 ± 0.4 84.4 ± 1.3 1.2 ± 0.4
v2_order_words 95.8 ± 0.7 95.8 ± 0.7 —
v2_orthography 83.3 ± 0.7 81.5 ± 0.8 0.0 ± 0.0
v2_question_forms 91.9 ± 2.9 91.9 ± 2.9 —
v2_unexecutable 99.7 ± 0.3 — 0.3 ± 0.3

学習

  • 構造: decoder-only の Transformer(d_model 192、7層、GQA 6/2 head、SwiGLU 512、RoPE、RMSNorm、入出力の埋め込みを共有)。最大 128 token。
  • 学習: 66,809文(action v0.5.1)、12 epoch、lr 1e-3、1 GPU で約12分。validation の完全一致が最も高い epoch を採用しました。
  • 量子化: 2次元の重みを INT4(group 64、scale は fp16)。評価の数値は量子化した後のものです。

学習データ

出典 件数 ライセンス
オープンモデルが書いた合成文(正解を先に決め、Qwen3-30B-A3B-Instruct-2507 が温度 0 で確かめたものだけを残した) 約 6.1万 書いたモデルはすべて Apache-2.0 または MIT
Tatoeba の日本語文(何もしない例) 1,524 CC BY 2.0 FR
JESC(映画・ドラマの字幕、何もしない例) 3,518 CC BY-SA 4.0
Amazon MASSIVE(ja-JP、何もしない例) 1,169 CC BY 4.0
  • 合成文を書いたモデル: Qwen/Qwen3-30B-A3B-Instruct-2507、cyberagent/calm3-22b-chat、abeja/ABEJA-Qwen2.5-32b-Japanese-v1.0、cyberagent/Mistral-Nemo-Japanese-Instruct-2408、elyza/ELYZA-Shortcut-1.0-Qwen-32B、ibm-granite/granite-3.3-8b-instruct(以上 Apache-2.0)、sbintuitions/sarashina2.2-3b-instruct-v0.1(MIT)。
  • 人が書いた文のうち「何もしない」例の一部は、前の版のモデルが誤って動いた文を集め、Qwen3 が「何もしない」と確かめたものです。
  • Tatoeba と JESC は、hash で固定した約2割と評価セットの文を評価用に取り分け、学習には使っていません。評価セットの文と重なる文は学習データから除きました。
  • 合成データの最初の版は japanese-data-analyze/JapaneseTinyAgentLM-Action-Synth で公開しています。

限界と用途

  • 英語は扱えません。 英語の依頼の正解率は約5%です。
  • ひらがなだけの文や、言い直しの文は弱めです(表記 約83%、言い直し 約84%)。
  • 学習の乱数(seed)による差があります。 同じデータと設定でも、人が書いた依頼文の正解率は seed によって 75.8〜91.9% と変わりました(上の「誤差の範囲」)。
  • 決まった3種類の動作しか選べません。会話や質問への答えはしません。
  • 文字の入力を前提にしています。音声認識の誤りへの強さは評価していません。
  • 用途: 小型ロボットや玩具で、日本語の短い指示から安全な範囲の動作を選ぶこと。人の安全にかかわる機械の制御、医療、監視などには使わないでください。出力は必ず schema と角度の上限で検証してから動かしてください(firmware はそうしています)。

先行例との関係

マイコンで動く言語モデルや、マイコンで動く tool calling のモデル(英語と欧州の言語)、外付けの NPU で動くスタックチャンの function calling には先行例があります。日本語の発話からロボットの動作呼び出し(JSON)を決める言語モデルを、ESP32-S3 単体(NPU・外部モジュール・ネットワークなし)で動かした公開事例は、2026年10月1日時点の私たちの調査では見つかりませんでした。調べた範囲と先行例の一覧は docs/prior_art.md にあります。

ライセンスと帰属

  • 重み: CC BY-SA 4.0。コード: Apache-2.0(inference.py、firmware/。firmware の第三者のコードは firmware/licenses/。学習、評価、firmware の source は GitHub)。
  • 学習データに次のものを含みます: Tatoeba(CC BY 2.0 FR)、JESC(Pryzant et al., 2018、CC BY-SA 4.0)、Amazon MASSIVE(FitzGerald et al., 2022、CC BY 4.0)。
  • 実装、データの生成と検査、学習、評価、firmware は Claude Code(Anthropic)が行いました。学習データと評価データの文章と正解は、上記のオープンモデル、人が書いた公開コーパス、プログラムによるもので、Claude の出力は含みません。

English summary

A 3,148,608-parameter decoder-only Transformer, trained from scratch, that maps short Japanese requests to robot action calls (JSON: look, set_expression, nod; up to two per request) or [] for non-requests, negated requests and requests the robot cannot perform. It runs entirely on an ESP32-S3 (M5Stack Stack-chan, CoreS3) in INT4 with a median latency of about 1.3 s, bit-exact with the PyTorch reference on 300 prompts. Decoding uses a schema grammar plus a confidence gate (0.86808); the reported numbers use both. Japanese only (English requests are about 5% correct). Results vary across training seeds: on the 62 human-written requests the five seeds scored 75.8–91.9% (mean 85.2%); the released seed 0 was deployed and verified on the device before the other seeds were trained, and is the highest of the five on that set. See the error-bar tables above. Weights are CC BY-SA 4.0; training data includes Tatoeba (CC BY 2.0 FR), JESC (CC BY-SA 4.0) and MASSIVE (CC BY 4.0) plus sentences written by Apache-2.0/MIT open models. Built by Claude Code.

Quick start (CPU is enough):

pip install torch numpy sentencepiece safetensors huggingface_hub
hf download ayousanz/JapaneseTinyAgentLM-Action-3M --local-dir JapaneseTinyAgentLM-Action-3M
python JapaneseTinyAgentLM-Action-3M/inference.py 右を向いて

inference.py is a self-contained script (Apache-2.0) that reproduces the evaluated outputs exactly (4,794 of 4,794 evaluation prompts). Training, evaluation and firmware source: GitHub. Try it in the browser: demo (Hugging Face Space), no install; the same C runtime as the device (WebAssembly) with the INT4 weights runs in the page.

Downloads last month
175
Safetensors
Model size
3.15M params
Tensor type
F32
·
Video Preview
loading

Dataset used to train ayousanz/JapaneseTinyAgentLM-Action-3M

Space using ayousanz/JapaneseTinyAgentLM-Action-3M 1