上級 13 分API

関数呼び出しと構造化されたJSON出力による Ollama

Function calling(関数呼び出し)により、LLMがコード内の関数を呼び出すことを自ら決定できます。例えば、天気検索、データベースへのクエリ、メール送信などです。引数は適切な形式で返されます。Ollama のfunction callingは2つの要素で構成されています。1つは有効なJSONを保証するためのformatパラメータ、もう1つは利用可能な関数を宣言するためのAPIのtoolsフィールドです。このガイドでは、Pythonでの両方の実装方法、実際に信頼できるローカルモデル、そしてスキーマ検証とリトライによる堅牢化の方法を示します。

著者 Mohamed Meguedmi·更新 2026-08-27·Windows・macOS・Linuxでテスト済み

#ローカルでfunction callingを使う理由

LLMが生成するのはテキストであり、アクションではありません。function callingはこの隔たりを埋めます。モデルは通常の文章で回答する代わりに、「都市をParisとしてget_meteo関数を呼び出す」という指示を示す構造化オブジェクトを返します。ユーザー側のコードがその関数を実行して実際の結果を取得し、その結果をモデルに渡すと、モデルが最終的な回答を作成します。これは、外部の世界とやり取りするエージェントやアシスタントの基本的な仕組みです。

ローカル環境では課題は二重です。まず、出力が100%パース可能なJSONであることを保証することです。「JSONはこちら:」と追加する饒舌なモデルは、パイプライン全体を壊します。次に、モデルが正しい関数と正しい引数を選択することを確認することです。これは小型モデルでは困難になります。OllamaはAPIを通じて両方を処理しますが、知っておくべきガードレールがあります。

JSON出力が保証されています
formatパラメータはデコードを制約します。モデルは構文的に正しいJSONしか出力できず、特定のスキーマに準拠させることもできます。
関数呼び出し
toolsフィールドはOpenAI形式の関数を宣言しています。モデルは引数を含むtool_callsを返します。
100 % ローカル
すべてがお使いのマシン上で、http://localhost:11434のOllamaデーモンを通じて動作します。APIキーは不要で、データの漏洩もありません。

#前提条件と対応モデル

ローカルコパイロットキット

このガイドでモデルの導入まで、キットでエディタ内でコードを書くコパイロットの導入まで進められます。

  • 永久に利用できるオンラインスペース
  • PDF + ファイル
  • 生涯アップデート

JSON モード(format パラメータ)は、どのモデルでも機能します。一方、tools を使う関数呼び出しには、ツール使用のために訓練されたモデルが必要です。そうでなければ、tool_calls フィールドは空のままになります。すべてのモデルが同等というわけではありません。仕様上は「対応」とされる3Bモデルでも引数をよく間違えますが、14B以上のモデルなら単純なスキーマには十分対応できます。

Ollama インストール済み
デーモンが起動しており、http://localhost:11434 に接続できる状態。ollama listで確認してください。
Python SDK
pip install ollama pydantic — le client officiel plus Pydantic pour la validation.
信頼できるツール使用モデル
qwen3.5:9b、mistral-small (24B)、gpt-oss:20b は、2026 年にまず試すモデルとして優れた選択肢です。Q4 で必要な VRAM は、Qwen 3.5 9B が約 6.6 GB、24B モデルが約 14 GB です。
推奨GPU
RTX 3060 12GBならQwen 3.5 9Bを快適に動かせます。ツール呼び出しの信頼性をしっかり確保するには、20~24Bモデル(RTX 4070/4080 16 GB)を目指してください。
i
JSONモード ≠ 関数呼び出し
formatパラメータは有効なJSONを保証しますが、関数を呼び出すものではありません。モデルがオブジェクトに値を入力し、それを解釈するのは利用者自身です。一方、toolsフィールドでは、モデルが実際に関数を選択します。この2つはよく組み合わせて使われます。

#formatパラメータで正しい形式のJSONを強制する

最も簡単なケースは、モデルに常にJSONで応答させ、自由形式のテキストでは一切応答させない場合です。chat呼び出しに format: 'json' を指定してください。するとOllamaは、構文的に有効なオブジェクトを生成するよう、トークンごとにデコードを制約します。重要なのは、期待するフィールドを明示した指示をプロンプトに残しておくことです。そうしないと、モデルが構造を勝手に作ってしまいます。

json_mode.py
import ollama
import json

resp = ollama.chat(
    model='qwen3.5:9b',
    messages=[{
        'role': 'user',
        'content': (
            "Extrais le nom, la ville et l'age de ce texte et reponds "
            "UNIQUEMENT en JSON avec les cles nom, ville, age. "
            "Texte : Marie, 34 ans, habite a Lyon."
        ),
    }],
    format='json',  # contraint la sortie a un JSON valide
    options={'temperature': 0},
)

data = json.loads(resp['message']['content'])
print(data)  # {'nom': 'Marie', 'ville': 'Lyon', 'age': 34}
→
temperature は常に 0 に設定する
構造化抽出では、temperatureを0に設定してください。求められるのは決定性と要件への準拠であり、創造性ではありません。これにより、フィールドに関するハルシネーションが大幅に減ります。

#JSONスキーマに基づく構造化出力(structured outputs)

2024年末以降、Ollamaではformatに文字列'json'だけでなく、完全なJSONスキーマも指定できます。この場合、デコードにはスキーマを守る制約がかかり、型、必須フィールド、列挙値が遵守されます。モデルが構造上、スキーマに適合しないオブジェクトを生成できなくなるため、'json'だけを指定するよりもはるかに堅牢です。Pydanticを使えば、スキーマを自動生成できます。

structured_output.py
import ollama
from pydantic import BaseModel

class Personne(BaseModel):
    nom: str
    ville: str
    age: int

resp = ollama.chat(
    model='mistral-small',
    messages=[{'role': 'user',
               'content': 'Marie, 34 ans, habite a Lyon.'}],
    format=Personne.model_json_schema(),  # schema JSON complet
    options={'temperature': 0},
)

# validation stricte : leve une erreur si non conforme
personne = Personne.model_validate_json(resp['message']['content'])
print(personne)  # nom='Marie' ville='Lyon' age=34

ここではデコード時の出力形式がPersonneの構造に固定され、model_validate_jsonがPython側で再度検証を行います。二重のチェックにより、出力が解析可能で、かつ宣言された型に適合することが保証されます。これは、ローカルの本番環境で行うあらゆるデータ抽出に推奨されるパターンです。

#Python での tools API の手順解説

本格的なfunction callingに移りましょう。関数はOpenAI形式(name、description、JSON Schemaのparameters)でtoolsフィールドに宣言します。モデルはこれらの定義を読み、関数呼び出しが有用だと判断した場合、テキストメッセージの代わりに1つ以上のtool_callsを返します。関数を実行して結果を返すのはあなたです。

  1. 01
    関数を説明する
    各関数には、明確なname、正確なdescription(モデルはこれを使って関数を選びます)、そして引数とそのうちどれがrequiredなのかを列挙したJSON Schema形式のparametersを指定してください。
  2. 02
    toolsを指定して呼び出しを送信する
    ollama.chat に tools のリストを渡してください。モデルは独自に判断して、関数を呼び出すか直接回答するかを決定します。
  3. 03
    tool_callsの内容を確認する
    resp['message'].get('tool_calls') を確認してください。tool_callsが存在する場合、モデルは渡された引数で関数を呼び出そうとしています。
  4. 04
    実行して結果を返す
    実際のPython関数を呼び出し、その結果をroleが'tool'のメッセージとしてモデルに返し、最終的な回答を作成させてください。
tools_definition.py
def get_meteo(ville: str) -> str:
    # ici un vrai appel API ; on simule
    return f"Il fait 22 C et ensoleille a {ville}."

tools = [{
    'type': 'function',
    'function': {
        'name': 'get_meteo',
        'description': "Renvoie la meteo actuelle d'une ville donnee.",
        'parameters': {
            'type': 'object',
            'properties': {
                'ville': {
                    'type': 'string',
                    'description': 'Nom de la ville, ex: Paris',
                },
            },
            'required': ['ville'],
        },
    },
}]

#呼び出し → 実行 → 応答のループ

Function callingは往復のやり取りです。最初の呼び出し: モデルはtool_callを返します。関数を実行します。2回目の呼び出し: 結果を返送し、モデルが自然言語で回答を作成します。以下は、複数の関数に再利用可能な完全なループです。

boucle_tools.py
import ollama

dispatch = {'get_meteo': get_meteo}

messages = [{'role': 'user',
             'content': 'Quel temps fait-il a Marseille ?'}]

resp = ollama.chat(model='mistral-small',
                   messages=messages, tools=tools)
msg = resp['message']
messages.append(msg)

for call in msg.get('tool_calls') or []:
    fn = call['function']['name']
    args = call['function']['arguments']
    resultat = dispatch[fn](**args)  # execution reelle
    messages.append({
        'role': 'tool',
        'name': fn,
        'content': resultat,
    })

# second appel : le modele redige la reponse finale
final = ollama.chat(model='mistral-small', messages=messages)
print(final['message']['content'])
!
引数を確認せずに実行することは絶対に避けてください
モデルが関数名とその引数を決めます。evalや動的なgetattrではなく、ディスパッチ辞書(ホワイトリスト)を使用し、実行前に各引数を検証してください。侵害されたモデルやハルシネーションを起こしたモデルが、任意の関数を呼び出せる状態にしてはいけません。

#スキーマ検証とリトライのパターン

ローカル環境では、小規模なモデルが時折失敗することがあります。引数の欠落、型の誤り、存在しない関数の指定などです。未検証の出力を決してそのまま信頼しないでください。各 tool_call にPydanticによる検証を適用し、検証に失敗した場合はエラーメッセージをコンテキストに含めて再試行してください。多くの場合、モデルは2回目の試行で自己修正します。

retry_validation.py
from pydantic import BaseModel, ValidationError

class MeteoArgs(BaseModel):
    ville: str

def valider_appel(call):
    fn = call['function']['name']
    if fn not in dispatch:
        raise ValueError(f"Fonction inconnue: {fn}")
    args = MeteoArgs.model_validate(call['function']['arguments'])
    return fn, args

def appel_avec_retry(messages, max_essais=3):
    for essai in range(max_essais):
        resp = ollama.chat(model='mistral-small',
                           messages=messages, tools=tools)
        try:
            calls = resp['message'].get('tool_calls') or []
            return [valider_appel(c) for c in calls], resp
        except (ValidationError, ValueError) as e:
            messages.append({
                'role': 'user',
                'content': f"Erreur: {e}. Corrige et reessaie.",
            })
    raise RuntimeError('Echec apres retries')
実行前に検証する
関数ごとにPydanticモデルを用意すると、引数の不足や型の誤りを、引数がコードに渡される前に検出できます。
フィードバック付きリトライ
エラーメッセージをコンテキストに再投入することで、モデルが修正へ向かいます。2〜3回の試行でほぼ常に解決します。
関数の許可リスト
dispatchに含まれない関数名はすべて拒否してください。これはセキュリティ対策であると同時に、ハルシネーションを防ぐためのガードレールでもあります。
適切なフォールバック処理
N 回の失敗後は、ユーザーに明確なメッセージを返すようにし、特に小型モデルではクラッシュしないようにしてください。

#ツール使用における小型モデルの罠

ツールの使用には高度な判断能力が必要です。モデルは意図を理解し、適切な関数を選び、引数を対応付け、指定された形式を守らなければなりません。7B未満では結果が不安定です。以下では、ローカル環境で特によく起きる問題と、その対処法を紹介します。

tool_calls は空です
モデルが関数を呼び出さず、テキストで応答します。多くの場合、モデルがツール使用向けに学習されていないか、関数の説明が曖昧すぎることが原因です。Qwen 3.5またはMistral Smallに切り替え、関数の説明を丁寧に整えてください。
誤った引数
モデルが存在しないフィールドを作り出したり、必要なフィールドを省いたりします。スキーマでそれらを required に指定し、一度に公開する関数の数を減らして、必ず検証してください。
存在しない関数の呼び出し
モデルが存在しない関数を呼び出します。呼び出しを振り分ける側では、許可リストが必須です。
余計なテキストが混ざったJSON
形式を指定しないと、小型モデルはJSONの前後にテキストを追加します。抽出結果だけを出力させるには、常にformat='json'またはスキーマを使用してください。
機能が多すぎる
ツールが 5〜6 個を超えると、小規模モデルは混乱します。サブタスクごとに分割するか、2 ステップのルーティングを行ってください。
→
ローカルでの適切なバランス
ハイエンド GPU を使わずに信頼性の高い function calling を実現するには、RTX 4080 上では mistral-small(24B)の Q4(VRAM 約14 GB)が、品質と必要リソースのバランスで最も優れた選択肢になることが多いです。より軽量な選択肢では、qwen3.5:9b(約6.6 GB)は、少数の関数を明確に説明して使う場合には対応でき、gpt-oss:20b は非常に高速な代替モデルです。エージェントを主用途とするなら、24 GB の VRAM があれば glm-4.7-flash(MoE 30B-A3B、約19 GB)が優れた性能を発揮します。

#さらに詳しく

関数呼び出しは、エージェントや高度な連携の基盤となる機能です。本ガイドの内容をさらに掘り下げる、本サイトの関連ガイドはこちらです:

PythonでREST APIを介してOllamaを統合
ポート:11434のOpenAI互換エンドポイント、ストリーミング、JSONモードを、実際のFastAPI/Flaskアプリで使う。
LangChainとOllamaを使ってローカルAIエージェントを作成する
単体の関数呼び出しから、ツール、メモリ、推論を順次組み合わせる本格的なエージェントへ移行する。
MCPとローカルLLM:OllamaにMCPサーバーを接続する
各関数を手作業で定義する代わりに、Model Context Protocolを通じてツール(ファイル、ウェブ、データベース)へのアクセスを標準化する。
このガイドは役に立ちましたか?

ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。