2026年9月4日 金曜日
AI時短ラボ
活用· 約16

ローカルLLMでコーディングエージェントは実用になるか──Ollamaで動かした結果

Ollama上のqwen2.5-coder(1.5B/3B)に、コードを書かせるテストと、ツール呼び出しをさせるテストを分けて行った。コード生成は3Bでもコーナーケースでバグが出て、ツール呼び出しはOllama側が構造化されたtool_callsを一度も返さなかった。

ローカルLLMでコーディングエージェントは実用になるか──Ollamaで動かした結果
執筆・編集:
目次

「ローカルLLM コーディングエージェント」を検索する人が知りたいのは、おそらく「コードを書いてくれるか」だけではない。ファイルを読み、コードを書き、実行して確認し、失敗したら直す──この一連のループを、クラウドAPIへの課金なしにローカルモデルだけで回せるかどうかだと思う。

この記事では2つに分けてテストした。(1)少し意地悪なコード生成タスクを1回で正しく書けるか、(2)エージェントの土台になる「ツール呼び出し」がそもそも機能するか。どちらもOllama上のqwen2.5-coderシリーズで実際に動かした結果を載せる。

3行まとめ

  • qwen2.5-coder:1.5b/3bにコーナーケース入りのCSVパース関数を書かせたところ、1.5Bは要件を満たさず、3Bは方針は正しいがバッファのクリア忘れで重複バグが実際に発生した
  • Ollamaの/api/chatにツール定義付きでリクエストしたが、2モデルとも構造化されたtool_callsは一度も返らず、JSON文字列がcontent欄に書かれるだけだった。この記事の実測後にOllama公式GitHubのissueを確認したところ、同じ症状が2025年5月・9月から報告済みで、2026年8月時点(Ollama v0.33.0)でも未解消の既知バグだと分かった
  • 8Bクラス(llama3.1:8b)は8GBメモリのMac上で2分のタイムアウトに達し、比較テストを完了できなかった

使ったモデルとバージョン

  • 機種: MacBook Air / Apple M2 / 統合メモリ8GB(前回記事と同一機体)
  • Ollama: v0.33.0
  • モデル: qwen2.5-coder:1.5b(986MB)、qwen2.5-coder:3b(1.9GB)、比較用にllama3.1:8b(4.9GB)
  • ollama show qwen2.5-coder:3bで確認した対応機能: completion tools insert(tool callingに対応した状態でモデルが配布されている)

テスト1: 「引用符付きコンマ」を含むCSVパースは書けるか

単純な一行足し算のような課題では差が出にくいので、少しだけ引っかかりのあるタスクを与えた。

Write a Python function parse_csv_line(line: str) -> list[str] that splits a single CSV line by commas, but correctly handles double-quoted fields that may contain commas inside them (example: "a,b",c should become two fields: a,b and c). Strip surrounding quotes from quoted fields. Return only the function code with no explanation.

OllamaのHTTP API(/api/generate)に直接投げ、返ってきたコードをその場でPythonに貼って実際に実行した。

qwen2.5-coder:1.5b(応答6.12秒、生成速度36.47トークン/秒)

def parse_csv_line(line: str) -> list[str]:
    return [field.strip('"') if field.startswith('"') and field.endswith('"') else field.split(',')[0] for field in line.split(',')]

'"a,b",c'を渡すと['"a', 'b"', 'c']が返ってきた。単純にline.split(',')で先にコンマ分割してから後処理しているため、引用符の中のコンマも普通に切られてしまい、そもそも要件を満たしていない。

qwen2.5-coder:3b(応答13.02秒、生成速度22.3トークン/秒)

def parse_csv_line(line: str) -> list[str]:
    result = []
    i = 0
    quoted = False
    buffer = []
    while i < len(line):
        if line[i] == '"':
            if quoted:
                if buffer:
                    result.append("".join(buffer))
                quoted = False
            else:
                quoted = True
        elif line[i] == ',' and not quoted:
            if buffer:
                result.append("".join(buffer))
            buffer = []
        else:
            buffer.append(line[i])
        i += 1
    if buffer:
        result.append("".join(buffer))
    return result

こちらは状態遷移(引用符の中かどうかをquotedで管理する)というアプローチ自体は正しい。だが同じく'"a,b",c'を渡すと['a,b', 'a,b', 'c']が返ってきた。閉じ引用符に到達した時点でbufferresultに追加しているが、その直後にbufferをクリアし忘れているため、次のコンマでもう一度同じ内容が追加され、重複するバグが実際に発生した。

1.5Bは要件そのものを満たしておらず、3Bは方針は合っているが実行すると重複バグが出る。どちらも「1回書かせて、そのまま使う」水準には届かなかった。

モデル 応答時間 生成速度 結果
qwen2.5-coder:1.5b 6.12秒 36.47トークン/秒 要件を満たさず(コンマ分割を先に行い引用符内も分割)
qwen2.5-coder:3b 13.02秒 22.3トークン/秒 方針は正しいが、bufferクリア忘れで重複バグ
llama3.1:8b 2分でタイムアウト 未完了(前回記事の実測=0.88トークン/秒まで低下する機体)

テスト2: ツール呼び出し(エージェントの土台)は機能するか

コーディングエージェントが成立するには、モデルが「ファイル一覧を見せて」のような依頼に対して、自由文で答えるのではなく、構造化されたtool_callsという形式でツール呼び出しを返す必要がある。エージェントフレームワーク側はこの構造化フィールドを見て、実際にツールを実行し、結果をモデルに戻す。

Ollamaの/api/chatエンドポイントに、list_files(directory: string)という単純なツール定義を渡し、「カレントディレクトリ(.)にあるファイルの一覧を見せて。」と依頼した。返ってきたmessageオブジェクトのキーは、2回試したいずれの場合もrolecontentのみで、tool_callsというキー自体が存在しなかった。

{
  "role": "assistant",
  "content": "```json\n{\"name\": \"list_files\", \"arguments\": {\"directory\": \".\"}}\n```"
}

qwen2.5-coder:3bは、呼び出すべき関数名と引数の値自体は正しく言い当てている。だがこれはcontent欄に書かれたただのテキストで、tool_calls欄には何も入っていない。実際のエージェントフレームワークがmessage.tool_callsを見て動く実装だった場合、この応答は「ツール呼び出しなし」として扱われ、ループが止まる。

qwen2.5-coder:1.5bはさらに崩れていて、argumentsの中身が実際の値(".")ではなく、ツール定義のスキーマそのもの({"type": "string", "description": "..."})をそのまま書き写す形になっていた。

{
  "role": "assistant",
  "content": "```json\n{\n  \"name\": \"list_files\",\n  \"arguments\": {\n    \"directory\": {\n      \"type\": \"string\",\n      \"description\": \"Path to the directory to list.\"\n    }\n  }\n}\n```"
}

ollama showCapabilities欄にはtoolsと表示されているにもかかわらず、実際に構造化されたtool_callsが返ってきたケースは、今回のテストでは0件だった。

自分だけの現象ではなく、1年以上前から報告済みの既知バグだった

この実測結果を受けて、Ollama公式GitHubのissueを検索したところ、同じ症状の報告が複数見つかった。

  • Issue #10899「qwen2.5-coder and llama3.1 return empty content with tools」(2025年5月29日オープン、Ollama v0.8.0時点):qwen2.5-coder:7b・llama3.1:latest・devstral:latestでtool_calls欄自体は返るがcontentが常に空になる、という報告。投稿者は「qwen3:8bは正しくツール呼び出しを返して動作する」とも書いている。Ollama側の担当者(ParthSareen氏)がアサインされ、bugtoolsラベルが付いている
  • Issue #12174「tool_calls missing from qwen2.5-coder v0.11.7 (also v0.11.8)」(2025年9月3日オープン):まさに今回の実測と同じ症状で、「レスポンスにtool_callsが含まれない」と報告されている

つまり、qwen2.5-coderのツール呼び出しが構造化フィールドとして返ってこない・返っても中身が壊れているという問題は、2025年5月の時点(Ollama v0.8.0)から2025年9月(v0.11.x)を経て、今回実測した2026年8月のv0.33.0まで、1年以上にわたって形を変えながら報告され続けている。Issue #10899の投稿者が指摘する「qwen3:8bは正しく動く」という情報が事実なら、この記事でqwen2.5-coderの代わりにqwen3系のモデルを使えば違う結果になった可能性がある。ただし、この点は他のユーザーの報告であり、当サイトで実機検証したものではない。

8Bクラスも同条件で試そうとしたが

比較のため、llama3.1:8b(こちらもtools対応と表示される)でも同じCSVパースのテストを試みたが、2分のタイムアウトに達しても応答が返らず、テストを完了できなかった。前回の検証記事で、この機体・このモデルは生成速度が0.88トークン/秒までスワップで落ち込むことをすでに実測しているので、今回の結果はその再現とみて矛盾はない。ただし今回は完了しなかった以上、8Bクラスでのコード品質・ツール呼び出しの挙動そのものは確認できていない。

エージェントとして使えるかの結論

  • 単発のコード生成として使うなら、1.5B・3Bとも数秒〜十数秒で応答は返る。ただし今回試した程度の「コーナーケースが1つある」タスクでも、両モデルとも無修正では使えないコードを返した。トリビアルな1行タスクなら通っても、少し複雑になると自分で目視チェックする前提が要る
  • 「エージェント」を名乗る使い方、つまりモデルにツールを呼ばせて自動でループを回す構成は、今回のOllama v0.33.0・qwen2.5-coderの組み合わせでは土台のtool_callsが返ってこず、そのままでは成立しなかった。Capabilitiestoolsと表示されていることと、実際に構造化されたツール呼び出しを安定して返すことは別の話だと分かった
  • クラウドのコーディングエージェント(例えばClaude Codeや、比較記事で扱っているCopilot・Cursor)を日常的に使っている身からすると、今回のローカル環境は「コードは書けるが、エージェントとして自動で回す」段階には今回の条件では届いていない、というのが実測ベースの結論になる

検証していないこと

  • Ollamaのバージョン依存の可能性。 v0.33.0でのテスト結果であり、GitHub issueで確認した限り2025年5月(v0.8.0)から同種の問題が報告され続けている。ただし各issueで報告されている症状の細部(tool_callsが空なのか、そもそも欄自体が無いのか)は微妙に異なっており、この記事の症状(tool_calls欄が存在しない)とissueの症状が完全に同一のバグかどうかまでは特定していない
  • qwen3系モデルでの再現。 Issue #10899の投稿者は「qwen3:8bは正しく動作する」と報告しているが、これは他のユーザーの報告であり、当サイトではqwen3系での再検証をしていない
  • プロンプトやテンプレートの工夫。 システムプロンプトでツール呼び出しのフォーマットを明示的に指示するなど、工夫次第で構造化されたtool_callsが返るようになる可能性は試していない
  • 実際のエージェントフレームワーク(Cline、aiderなど)をOllamaに繋いだ状態。 今回はOllamaのAPIに直接リクエストしただけで、これらのツールが独自に持つフォールバック処理(テキストからの正規表現抽出など)までは確認していない
  • 試行回数は各1〜2回。 tool_callsのテストでは出力のマークダウン記法の有無に揺れがあり、非決定性があることは分かったが、何回に1回成功するかといった確率的な検証はしていない
  • モデルのサイズは1.5B・3Bの2点比較にとどまる。 4B〜7B級のコード特化モデルでは結果が変わる可能性がある
シェア: ポスト はてブ

出典・参照資料

AIニュースの解説を動画でも

YouTubeでは注目ニュースの背景を解説し、Xでは新着記事をお知らせしています。

コメント

まだコメントはありません。最初のコメントを書いてみませんか?

AIについて聞きたいことはありますか?

質問箱で無料で受け付けています。回答は公開され、他の方の参考にもなります。

質問箱を見る →

新しい記事をメールで受け取る

AIの新しい発表を、出典付きで整理して届けます。

関連記事