📌

Reachy mini を賢くする:Function Calling(Tool)の追加方法を内部構造まで踏み込んで解説

に公開

Reachy mini を賢くする:Function Calling(Tool)の追加方法を内部構造まで踏み込んで解説

CES 2026 でも話題になった Reachy mini にカスタムのToolを導入する方法をご紹介します。この記事では、公式のReachy Mini conversation appcore_tools.pyprofiles/ の仕組みを前提に、新しい Tool を追加する最短手順をまとめます。

https://www.youtube.com/watch?v=dMpLCGvE2A0

今回使用する公式のReachy Mini conversation appリポジトリ
https://github.com/pollen-robotics/reachy_mini_conversation_app


全体像:Reachy mini はどうやって「道具」を使うのか?

Function Calling の流れは、クライアントと OpenAI のキャッチボールです。

処理の流れ(概要)

  • Client:起動時に「使える Tool 一覧」を OpenAI に渡す
  • OpenAI:会話の流れから Tool 使用を決定し、Tool 実行指示(JSON)を返す
  • Client:指示を受け取り、ローカルの Python で Tool を実行する(dispatch_tool_call
  • Client:結果(JSON)を OpenAI に返す
  • OpenAI:結果を踏まえ、自然言語で返答する

シーケンス図(Mermaid)


core_tools.py は何をしているのか?

Reachy mini のアプリにおいて、core_tools.pyツール管理を担います。ツール追加が簡単に見える理由は、ここが面倒な処理を吸収しているからです。

主な役割

  • 動的ロード
    profiles/ などをスキャンし、ツールを自動で読み込む

  • スペック生成
    OpenAI に渡す JSON Schema を自動生成する(get_tool_specs

  • 依存性注入(Dependency Injection)
    カメラ、ロボット、各種クライアントなどを ToolDependencies として実行時に渡す


実践:新しい Tool を追加する

ここでは例として、サーバー時刻を返す server_time ツールを追加します。


Step 1:置き場所を決める

ツールの置き場所は、用途で決めます。

  • 共通で使う(推奨)
    reachy_mini_conversation_app/tools/server_time.py

  • 特定プロファイル専用
    reachy_mini_conversation_app/profiles/<profile_name>/server_time.py

今回は共通ツールとして tools/ に追加します。


Step 2:コードを書く

Tool を継承して実装します。重要点は次の 2 つです。

  • parameters_schema:OpenAI に渡す 引数の定義(JSON Schema)
  • async def __call__:実処理(返り値は JSON)
# reachy_mini_conversation_app/tools/server_time.py
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from zoneinfo import ZoneInfo

from reachy_mini_conversation_app.core_tools import Tool, ToolDependencies


@dataclass
class ServerTimeTool(Tool):
    # 1) ツール名と説明(AI が読む)
    name: str = "server_time"
    description: str = "サーバーの現在時刻を返します。"
    parameters_schema: dict | None = None

    def __post_init__(self) -> None:
        # 2) 引数定義(JSON Schema)
        if self.parameters_schema is None:
            self.parameters_schema = {
                "type": "object",
                "properties": {
                    "timezone": {
                        "type": "string",
                        "description": "タイムゾーン(例: Asia/Tokyo, UTC)",
                        "default": "UTC",
                    },
                },
                "required": [],
                "additionalProperties": False,
            }

    # 3) 実処理
    async def __call__(
        self,
        deps: ToolDependencies,
        timezone: str = "UTC",
        **kwargs,
    ) -> dict:
        try:
            tz = ZoneInfo(timezone)
            now = datetime.now(tz)
            return {
                "ok": True,
                "timezone": timezone,
                "iso_time": now.isoformat(),
                "display_time": now.strftime("%Y-%m-%d %H:%M:%S"),
            }
        except Exception as e:
            return {"ok": False, "error": str(e)}

Step 3:tools.txt に登録する

ファイルを作っただけでは読み込まれません。対象プロファイルの tools.txt に追記します。

  • 場所:reachy_mini_conversation_app/profiles/<profile_name>/tools.txt
  • 書き方:拡張子は不要
# tools.txt に追記
server_time

Step 4:再起動して確認する

アプリを再起動し、ログで server_time のロードを確認します。次に、音声またはテキストで質問します。

  • 「今の時間は?」
  • 「UTC の時刻を教えて」
  • 「Asia/Tokyo の時刻は?」

Tool が呼ばれれば、次のような形式の JSON が返り、OpenAI が自然な文章にして返します。

{
  "ok": true,
  "timezone": "Asia/Tokyo",
  "iso_time": "2026-01-20T21:00:00+09:00",
  "display_time": "2026-01-20 21:00:00"
}

ハマりポイントと実装のコツ

additionalProperties: false は必須

parameters_schemaadditionalProperties: False を入れると、OpenAI が存在しない引数を送る事故を減らします。

deps を使う前に必ず確認する

deps にはカメラやロボット操作の依存関係が入ります。ただし、状況により利用できないケースがあります。ツール内では 存在確認を入れます。

返り値は小さく保つ

Tool の返り値は、そのまま会話コンテキストに入ります。巨大なデータを返すと、動作が遅くなりコストも増えます。必要最低限の JSON を返します。


まとめ

  • Reachy mini の Tool 追加は **「Tool 実装」→「tools.txt 登録」**で完了します
  • core_tools.py動的ロード/スキーマ生成/依存性注入を担うため、追加コストが小さくなります
  • この仕組みで、天気取得、IoT 操作、社内検索などを段階的に増やせます

Happy Hacking 🤖✨

Discussion