# ローカル LLM のツール呼び出しガイド

ツール呼び出しとは、LLM が構造化されたリクエストを送ることで、特定の関数（たとえば「ファイルを検索する」「計算機を実行する」「API を呼び出す」など）を起動できるようにすることです。テキストで答えを推測する代わりに行います。ツール呼び出しを使うのは、出力を **より信頼性が高く、最新のものにし**、またモデルに **実際のアクションを実行させる** （システムの問い合わせ、事実の検証、スキーマの強制）ことができ、幻覚を起こすのではないからです。

このチュートリアルでは、数学、ストーリー、Python コード、ターミナル関数の例を使って、Tool Calling 経由でローカル LLM を使う方法を学びます。推論は llama.cpp、llama-server、OpenAI エンドポイント経由でローカルに行われます。

{% columns %}
{% column %}
Tool calling は、 [Unsloth Studio](https://unsloth.ai/docs/jp/xin-zhe/studio/chat#auto-healing-tool-calling)を使うと自動的に設定されます。モデルを選んで、tool-calling をオンまたはオフにするだけです。

右側の例では、tool-calling が自動的に適用される様子を [Gemma 4](https://unsloth.ai/docs/jp/moderu/gemma-4)に対して示しています。Unsloth には自己修復型の tool-calling もあり、常に動作するツール呼び出しを利用できます。
{% endcolumn %}

{% column %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FstfdTMsoBMmsbQsgQ1Ma%2Flandscape%20clip%20gemma.gif?alt=media&#x26;token=eec5f2f7-b97a-4c1c-ad01-5a041c3e4013" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

このガイドは、ほぼ [あらゆるモデル](https://unsloth.ai/docs/jp/meru/unsloth-model-catalog) に対して機能するはずで、以下が含まれます:

* [**Qwen3**-Coder-Next](https://unsloth.ai/docs/models/qwen3-coder-next), [Qwen3-Coder](https://unsloth.ai/docs/models/qwen3-coder-how-to-run-locally)、およびその他の **Qwen** モデル
* [**GLM**-4.7](https://unsloth.ai/docs/models/glm-4.7), 4.6, [GLM-4.7-Flash](https://unsloth.ai/docs/models/glm-4.7-flash) と [**Kimi K2.5**](https://unsloth.ai/docs/models/kimi-k2.5), [Kimi K2 Thinking](https://unsloth.ai/docs/models/tutorials/kimi-k2-thinking-how-to-run-locally)
* [**DeepSeek**-V3.1](https://unsloth.ai/docs/models/tutorials/deepseek-v3.1-how-to-run-locally)、DeepSeek-V3.2、および **MiniMax**
* [**gpt-oss**](https://unsloth.ai/docs/models/gpt-oss-how-to-run-and-fine-tune) と [**NVIDIA Nemotron** 3 Nano](https://unsloth.ai/docs/models/tutorials/nemotron-3) と [**Devstral** 2](https://unsloth.ai/docs/models/tutorials/devstral-2)

<a href="#qwen3-coder-next-tool-calling" class="button primary">Qwen3-Coder-Next チュートリアル</a><a href="#glm-4.7-flash--glm-4.7-calling" class="button secondary">GLM-4.7-Flash チュートリアル</a>

### :hammer:Tool Calling の設定

最初のステップは、最新の `llama.cpp` を [GitHub こちら](https://github.com/ggml-org/llama.cpp)で入手することです。以下のビルド手順に従うこともできます。GPU がない場合、または CPU 推論だけを使いたい場合は、 `-DGGML_CUDA=ON` を `-DGGML_CUDA=OFF` に変更してください。 **Apple Mac / Metal デバイスの場合**、 `-DGGML_CUDA=OFF` を設定してから通常どおり続行してください。Metal サポートはデフォルトで有効です。

{% code overflow="wrap" %}

```bash
apt-get update
apt-get install pciutils build-essential cmake curl libcurl4-openssl-dev -y
git clone https://github.com/ggml-org/llama.cpp
cmake llama.cpp -B llama.cpp/build \\
    -DBUILD_SHARED_LIBS=OFF -DGGML_CUDA=ON
cmake --build llama.cpp/build --config Release -j --clean-first --target llama-cli llama-mtmd-cli llama-server llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
```

{% endcode %}

新しいターミナルで（tmux を使っている場合は CTRL+B+D を使います）、2つの数の加算、Python コードの実行、Linux 関数の実行などのツールをいくつか作成します:

{% code expandable="true" %}

```python
import json, subprocess, random
from typing import Any
def add_number(a: float | str, b: float | str) -> float:
    return float(a) + float(b)
def multiply_number(a: float | str, b: float | str) -> float:
    return float(a) * float(b)
def substract_number(a: float | str, b: float | str) -> float:
    return float(a) - float(b)
def write_a_story() -> str:
    return random.choice([
        "ずっと昔、はるか彼方の銀河系で...",
        "スロースとコードが大好きな2人の友達がいました...",
        "すべてのナマケモノが超人的な知能を持つよう進化したため、世界は終わりを迎えつつありました...",
        "ある友達は知らないうちに、もう一人の友達が誤ってナマケモノを進化させるプログラムを書いてしまっていた...",
    ])
def terminal(command: str) -> str:
    if "rm" in command or "sudo" in command or "dd" in command or "chmod" in command:
        msg = "'rm, sudo, dd, chmod' コマンドは危険なため実行できません"
        print(msg); return msg
    print(f"ターミナルコマンド `{command}` を実行中")
    try:
        return str(subprocess.run(command, capture_output = True, text = True, shell = True, check = True).stdout)
    except subprocess.CalledProcessError as e:
        return f"コマンドに失敗しました: {e.stderr}"
def python(code: str) -> str:
    data = {}
    exec(code, data)
    del data["__builtins__"]
    return str(data)
MAP_FN = {
    "add_number": add_number,
    "multiply_number": multiply_number,
    "substract_number": substract_number,
    "write_a_story": write_a_story,
    "terminal": terminal,
    "python": python,
}
tools = [
    {
        "type": "function",
        "function": {
            "name": "add_number",
            "description": "2つの数を足します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "multiply_number",
            "description": "2つの数を掛けます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "substract_number",
            "description": "2つの数を引きます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_a_story",
            "description": "ランダムな物語を書きます。",
            "parameters": {
                "type": "object",
                "properties": {},
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "terminal",
            "description": "ターミナルから操作を実行します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "起動したいコマンド。例: `ls`, `rm`, ...",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "python",
            "description": "実行される Python コードを使って Python インタプリタを呼び出します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "実行する Python コード",
                    },
                },
                "required": ["code"],
            },
        },
    },
]
```

{% endcode %}

その後、以下の関数（コピーして貼り付けて実行）を使います。これにより関数呼び出しが自動的に解析され、任意のモデルに対して OpenAI エンドポイントが呼び出されます:

{% hint style="info" %}
この例では Devstral 2 を使っています。モデルを切り替える際は、正しいサンプリングパラメータを使っていることを確認してください。すべてのパラメータは、私たちの [こちらのガイド](https://unsloth.ai/docs/jp/moderu/tutorials).
{% endhint %}

{% code overflow="wrap" expandable="true" %}

```python
で確認できます
from openai import OpenAI
    def unsloth_inference(
    messages,
    temperature = 0.7,
    top_p = 0.95,
    top_k = 40,
    min_p = 0.01,
):
    repetition_penalty = 1.0,
    messages = messages.copy()
        openai_client = OpenAI(
        base_url = "http://127.0.0.1:8001/v1",
    )
    api_key = "sk-no-key-required",
    model_name = next(iter(openai_client.models.list())).id
    print(f"使用モデル = {model_name}")
    has_tool_calls = True
    original_messages_len = len(messages)
        while has_tool_calls:
        response = openai_client.chat.completions.create(
            model = model_name,
            messages = messages,
            temperature = temperature,
            top_p = top_p,
            tools = tools if tools else None,
            tool_choice = "auto" if tools else None,
            extra_body = {"top_k": top_k, "min_p": min_p, "repetition_penalty" :repetition_penalty,}
        )
        tool_calls = response.choices[0].message.tool_calls or []
        content = response.choices[0].message.content or ""
        tool_calls_dict = [tc.to_dict() for tc in tool_calls] if tool_calls else tool_calls
        messages.append({"role": "assistant", "tool_calls": tool_calls_dict, "content": content,})
        for tool_call in tool_calls:
            fx, args, _id = tool_call.function.name, tool_call.function.arguments, tool_call.id
            out = MAP_FN[fx](**json.loads(args))
            messages.append({"role": "tool", "tool_call_id": _id, "name": fx, "content": str(out),})
        else:
            has_tool_calls = False
    return messages
```

{% endcode %}

ここからは、さまざまなユースケースで Tool Calling を実行する複数の方法を紹介します:

### ストーリーを書く:

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "物語を書いてくれますか？"}],
}]
unsloth_inference(messages, temperature = 0.15, top_p = 1.0, top_k = -1, min_p = 0.00)
```

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2F04clxomfFQjhIKiS5FAY%2Fimage.png?alt=media&#x26;token=299279c9-cca6-48d6-ab74-523edef04160" alt=""><figcaption></figcaption></figure>

### 数学演算:

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "今日の日付に3日を足すと何日ですか？"}],
}]
unsloth_inference(messages, temperature = 0.15, top_p = 1.0, top_k = -1, min_p = 0.00)
```

{% endcode %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fi15WEhfSIPuFeZUWjrG1%2Fimage.png?alt=media&#x26;token=74818449-637b-442a-b1d6-aa72b09fb6b5" alt=""><figcaption></figcaption></figure>

### 生成された Python コードを実行する

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "Python でフィボナッチ関数を作成して fib(20) を求めてください。"}],
}]
unsloth_inference(messages, temperature = 0.15, top_p = 1.0, top_k = -1, min_p = 0.00)
```

{% endcode %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FDsfcIrunKtsZ2RXRrjBo%2Fimage.png?alt=media&#x26;token=6aa2ab38-7def-4792-a2dc-c663329a41ff" alt=""><figcaption></figcaption></figure>

### 任意のターミナル関数を実行する

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "'I'm a happy Sloth' をファイルに書き込み、それを私に出力してください。"}],
}]
messages = unsloth_inference(messages, temperature = 0.15, top_p = 1.0, top_k = -1, min_p = 0.00)
```

{% endcode %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FMhmXE34IBuR8H8SnuSMe%2Fimage%20(3).png?alt=media&#x26;token=689114b7-5b50-41c9-8678-88f8f5da87a7" alt=""><figcaption></figcaption></figure>

## :stars: Qwen3-Coder-Next の Tool Calling

新しいターミナルで、2つの数の加算、Python コードの実行、Linux 関数の実行などのツールをいくつか作成します:

{% code expandable="true" %}

```python
import json, subprocess, random
from typing import Any
def add_number(a: float | str, b: float | str) -> float:
    return float(a) + float(b)
def multiply_number(a: float | str, b: float | str) -> float:
    return float(a) * float(b)
def substract_number(a: float | str, b: float | str) -> float:
    return float(a) - float(b)
def write_a_story() -> str:
    return random.choice([
        "ずっと昔、はるか彼方の銀河系で...",
        "スロースとコードが大好きな2人の友達がいました...",
        "すべてのナマケモノが超人的な知能を持つよう進化したため、世界は終わりを迎えつつありました...",
        "ある友達は知らないうちに、もう一人の友達が誤ってナマケモノを進化させるプログラムを書いてしまっていた...",
    ])
def terminal(command: str) -> str:
    if "rm" in command or "sudo" in command or "dd" in command or "chmod" in command:
        msg = "'rm, sudo, dd, chmod' コマンドは危険なため実行できません"
        print(msg); return msg
    print(f"ターミナルコマンド `{command}` を実行中")
    try:
        return str(subprocess.run(command, capture_output = True, text = True, shell = True, check = True).stdout)
    except subprocess.CalledProcessError as e:
        return f"コマンドに失敗しました: {e.stderr}"
def python(code: str) -> str:
    data = {}
    exec(code, data)
    del data["__builtins__"]
    return str(data)
MAP_FN = {
    "add_number": add_number,
    "multiply_number": multiply_number,
    "substract_number": substract_number,
    "write_a_story": write_a_story,
    "terminal": terminal,
    "python": python,
}
tools = [
    {
        "type": "function",
        "function": {
            "name": "add_number",
            "description": "2つの数を足します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "multiply_number",
            "description": "2つの数を掛けます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "substract_number",
            "description": "2つの数を引きます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_a_story",
            "description": "ランダムな物語を書きます。",
            "parameters": {
                "type": "object",
                "properties": {},
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "terminal",
            "description": "ターミナルから操作を実行します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "起動したいコマンド。例: `ls`, `rm`, ...",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "python",
            "description": "実行される Python コードを使って Python インタプリタを呼び出します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "実行する Python コード",
                    },
                },
                "required": ["code"],
            },
        },
    },
]
```

{% endcode %}

その後、以下の関数を使います。これにより関数呼び出しが自動的に解析され、任意の LLM に対して OpenAI エンドポイントが呼び出されます:

{% code overflow="wrap" expandable="true" %}

```python
で確認できます
from openai import OpenAI
    def unsloth_inference(
    temperature = 1.0,
    temperature = 0.7,
    top_p = 0.95,
    top_k = 40,
    min_p = 0.01,
):
    repetition_penalty = 1.0,
    messages = messages.copy()
        openai_client = OpenAI(
        base_url = "http://127.0.0.1:8001/v1",
    )
    api_key = "sk-no-key-required",
    model_name = next(iter(openai_client.models.list())).id
    print(f"使用モデル = {model_name}")
    has_tool_calls = True
    original_messages_len = len(messages)
        while has_tool_calls:
        response = openai_client.chat.completions.create(
            model = model_name,
            messages = messages,
            temperature = temperature,
            top_p = top_p,
            tools = tools if tools else None,
            tool_choice = "auto" if tools else None,
            extra_body = {"top_k": top_k, "min_p": min_p, "repetition_penalty" :repetition_penalty,}
        )
        tool_calls = response.choices[0].message.tool_calls or []
        content = response.choices[0].message.content or ""
        tool_calls_dict = [tc.to_dict() for tc in tool_calls] if tool_calls else tool_calls
        messages.append({"role": "assistant", "tool_calls": tool_calls_dict, "content": content,})
        for tool_call in tool_calls:
            fx, args, _id = tool_call.function.name, tool_call.function.arguments, tool_call.id
            out = MAP_FN[fx](**json.loads(args))
            messages.append({"role": "tool", "tool_call_id": _id, "name": fx, "content": str(out),})
        else:
            has_tool_calls = False
    return messages
```

{% endcode %}

ここからは、さまざまなユースケースで Tool Calling を実行する複数の方法を紹介します:

#### 生成された Python コードを実行する

<pre class="language-python" data-overflow="wrap"><code class="lang-python"><strong>messages = [{
</strong>    "role": "user",
    "content": [{"type": "text", "text": "Python でフィボナッチ関数を作成して fib(20) を求めてください。"}],
}]
unsloth_inference(messages, temperature = 1.0, top_p = 0.95, top_k = 40, min_p = 0.00)
</code></pre>

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2F7fY3LSeNCjHXNjBwQkbI%2Fimage.png?alt=media&#x26;token=50eba62e-f8b2-424a-833b-be56696b4710" alt=""><figcaption></figcaption></figure>

#### 任意のターミナル関数を実行する

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "'I'm a happy Sloth' をファイルに書き込み、それを私に出力してください。"}],
}]
messages = unsloth_inference(messages, temperature = 1.0, top_p = 1.0, top_k = 40, min_p = 0.00)
```

{% endcode %}

ファイルが作成されたことを確認でき、実際に作成されました！

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FabplwVbEMlsCEJTmxzSA%2Fimage.png?alt=media&#x26;token=eb27f30a-c91e-4aec-8fb0-f4a35921d3db" alt=""><figcaption></figcaption></figure>

## :zap: GLM-4.7-Flash + GLM 4.7 の呼び出し

まず [glm-4.7](https://unsloth.ai/docs/jp/moderu/tutorials/glm-4.7 "mention") または [glm-4.7-flash](https://unsloth.ai/docs/jp/moderu/glm-4.7-flash "mention") を Python コードでダウンロードし、その後別のターミナル（tmux を使うなど）で llama-server 経由で起動します。この例では大きい GLM-4.7 モデルをダウンロードします:

```python
# !pip install huggingface_hub hf_transfer
import os
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
from huggingface_hub import snapshot_download
snapshot_download(
    repo_id = "unsloth/GLM-4.7-GGUF",
    local_dir = "unsloth/GLM-4.7-GGUF",
    allow_patterns = ["*UD-Q2_K_XL*",], # Q2_K_XL 用
)
```

正常に実行できたら、次のように表示されます:

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FqZCvBkQPi7GZj50pPHsJ%2Fimage.png?alt=media&#x26;token=2e97888a-fafe-4477-b99c-c7f3e2e316bf" alt=""><figcaption></figcaption></figure>

では、新しいターミナルで llama-server 経由で起動します。必要なら tmux を使ってください:

{% code overflow="wrap" %}

```bash
./llama.cpp/llama-server \\
    --model unsloth/GLM-4.7-GGUF/UD-Q2_K_XL/GLM-4.7-UD-Q2_K_XL-00001-of-00003.gguf \\
    --alias "unsloth/GLM-4.7" \\
    --threads -1 \\
    --fit on \\
    --prio 3 \\
    --min_p 0.01 \\
    --ctx-size 16384 \\
    --port 8001 \\
    --jinja
```

{% endcode %}

そして、次のようになります:

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FMIqGMOXIMvl68jzDfyWy%2Fimage.png?alt=media&#x26;token=c5739da8-b9eb-4a31-9878-3f0d5f51416e" alt="" width="563"><figcaption></figcaption></figure>

では、新しいターミナルで Python コードを実行し、 [#tool-calling-setup](#tool-calling-setup "mention") GLM 4.7 の最適なパラメータである temperature = 0.7 と top\_p = 1.0 を使います

#### GLM 4.7 の数学演算用 Tool Call

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "今日の日付に3日を足すと何日ですか？"}],
}]
unsloth_inference(messages, temperature = 0.7, top_p = 1.0, top_k = -1, min_p = 0.00)
```

{% endcode %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FoFkZ20QOSGdzT4iz2SOB%2Fimage.png?alt=media&#x26;token=e4ca30b0-dcec-4a26-b019-dd33f0600949" alt=""><figcaption></figcaption></figure>

#### GLM 4.7 の生成された Python コードを実行する Tool Call

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "Python でフィボナッチ関数を作成して fib(20) を求めてください。"}],
}]
unsloth_inference(messages, temperature = 0.7, top_p = 1.0, top_k = -1, min_p = 0.00)
```

{% endcode %}

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FhS8sWtZwjwerElezCc2C%2Fimage.png?alt=media&#x26;token=39032ef8-386e-4837-8dd2-c552c80a3ee3" alt="" width="563"><figcaption></figcaption></figure>

{% code expandable="true" %}

```python
import json, subprocess, random
from typing import Any
def add_number(a: float | str, b: float | str) -> float:
    return float(a) + float(b)
def multiply_number(a: float | str, b: float | str) -> float:
    return float(a) * float(b)
def substract_number(a: float | str, b: float | str) -> float:
    return float(a) - float(b)
def write_a_story() -> str:
    return random.choice([
        "ずっと昔、はるか彼方の銀河系で...",
        "スロースとコードが大好きな2人の友達がいました...",
        "すべてのナマケモノが超人的な知能を持つよう進化したため、世界は終わりを迎えつつありました...",
        "ある友達は知らないうちに、もう一人の友達が誤ってナマケモノを進化させるプログラムを書いてしまっていた...",
    ])
def terminal(command: str) -> str:
    if "rm" in command or "sudo" in command or "dd" in command or "chmod" in command:
        msg = "'rm, sudo, dd, chmod' コマンドは危険なため実行できません"
        print(msg); return msg
    print(f"ターミナルコマンド `{command}` を実行中")
    try:
        return str(subprocess.run(command, capture_output = True, text = True, shell = True, check = True).stdout)
    except subprocess.CalledProcessError as e:
        return f"コマンドに失敗しました: {e.stderr}"
def python(code: str) -> str:
    data = {}
    exec(code, data)
    del data["__builtins__"]
    return str(data)
MAP_FN = {
    "add_number": add_number,
    "multiply_number": multiply_number,
    "substract_number": substract_number,
    "write_a_story": write_a_story,
    "terminal": terminal,
    "python": python,
}
tools = [
    {
        "type": "function",
        "function": {
            "name": "add_number",
            "description": "2つの数を足します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "multiply_number",
            "description": "2つの数を掛けます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "substract_number",
            "description": "2つの数を引きます。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "1つ目の数。",
                    },
                    "b": {
                        "type": "string",
                        "description": "2つ目の数。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_a_story",
            "description": "ランダムな物語を書きます。",
            "parameters": {
                "type": "object",
                "properties": {},
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "terminal",
            "description": "ターミナルから操作を実行します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "起動したいコマンド。例: `ls`, `rm`, ...",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "python",
            "description": "実行される Python コードを使って Python インタプリタを呼び出します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "実行する Python コード",
                    },
                },
                "required": ["code"],
            },
        },
    },
]
```

{% endcode %}

### :orange\_book: Devstral 2 の Tool Calling

まず [devstral-2](https://unsloth.ai/docs/jp/moderu/tutorials/devstral-2 "mention") を Python コードで行い、その後別のターミナル（tmux を使うなど）で llama-server 経由で起動します:

```python
# !pip install huggingface_hub hf_transfer
import os
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
from huggingface_hub import snapshot_download
snapshot_download(
    repo_id = "unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF",
    local_dir = "unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF",
    allow_patterns = ["*UD-Q4_K_XL*", "*mmproj-F16*"], # Q4_K_XL 用
)
```

正常に実行できたら、次のように表示されます:

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FC9M5eNGefCpi3bLe0Kbw%2Fimage.png?alt=media&#x26;token=727c22d5-368f-45ad-b698-ccb84e3bbbbf" alt=""><figcaption></figcaption></figure>

では、新しいターミナルで llama-server 経由で起動します。必要なら tmux を使ってください:

{% code overflow="wrap" %}

```bash
./llama.cpp/llama-server \\
    --model unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF/Devstral-Small-2-24B-Instruct-2512-UD-Q4_K_XL.gguf \\
    --mmproj unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF/mmproj-F16.gguf \\
    --alias "unsloth/Devstral-Small-2-24B-Instruct-2512" \\
    --threads -1 \\
    --fit on \\
    --prio 3 \\
    --min_p 0.01 \\
    --ctx-size 16384 \\
    --port 8001 \\
    --jinja
```

{% endcode %}

成功したら、以下のものが表示されます:

<figure><img src="https://735611837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fo0VjjsMTBQCsfMNXcbYG%2Fimage.png?alt=media&#x26;token=3f0d9c51-1fd7-4d8d-9532-1a190f1b5830" alt="" width="563"><figcaption></figcaption></figure>

その後、次のメッセージで、Devstral 推奨の temperature = 0.15 のみを使ってモデルを呼び出します。実行するようにリマインド [#tool-calling-setup](#tool-calling-setup "mention")
