ローカルLLMでコーディングエージェントは使えるか|OpenCode+OllamaをM4 Maxで試した

PC
※本サイトの記事にはプロモーションが含まれています

普段はClaude Codeを使っているが、「オープンソースのローカルAIコーディングエージェントはどこまで実用になるのか」を試してみたくなり、OpenCodeというツールをMac(M4 Max/64GB)にセットアップしてみた。以前書いた「15万円で手に入れる、クラウド不要のAI開発環境」の延長線上の話でもある。

先に書いておくと、一度は「このモデルはエージェントには使えない」と判断したが、それは間違いだった。ただし、犯人を特定しきれたわけでもない。4か月のあいだに3回試して、そのたびに結論が変わった。その記録を、つまずいた順にそのまま残しておく。

先に結論。
・OpenCode+Ollamaはインストール自体は10分で終わる。
・Qwen3-Coderでtool callingが壊れた。Ollamaが持つAnthropic API互換の口を直接叩いたら動いた。さらに4か月後に試したら、OpenCode経由でも普通に動いた。
・それでも速度でクラウドのClaudeに届かない。エージェント用途は結局クラウド優位という結論は変わらなかった。
・ローカルモデルの名前は、ブログも自分のメモも信じず公式ライブラリで存在確認してからpullする。

OpenCodeとは

OpenCodeは、sstというチームが開発しているターミナル上で動くAIコーディングエージェントで、UIや操作感はClaude Codeによく似ている。大きな違いは、Anthropic(Claude)だけでなくOpenAI、Google、そしてローカルLLMなど複数のAIプロバイダーを自由に切り替えて使える点だ。

インストールはHomebrewで一発

brew install sst/tap/opencode

Node/npmやHomebrewが既に入っている環境なら数分で終わる。バージョンは1.17.15だった。

ローカルLLMバックエンドにOllamaを用意

ローカルモデルを動かすには推論エンジンが必要になる。今回はOllamaを選択した。

brew install ollama
brew services start ollama

常時起動のバックグラウンドサービスとして登録しておけば、OpenCodeからいつでも呼び出せる。バージョンは0.31.1。

最初に試したのはDevstral(フランス製)

コーディングエージェント用に最適化された24BモデルということでMistral AI(フランス)の「Devstral」をまず試した。Q4量子化で約14GB、64GB環境なら余裕を持って動く。

ollama pull devstral

OpenCode側の設定ファイル(~/.config/opencode/opencode.jsonc)にOllama用のカスタムプロバイダーを追加すれば、ollama/devstralとしてOpenCodeから呼び出せるようになる。簡単な質問には問題なく答えてくれた。

ネット情報の裏取りで学んだこと

「もっと性能のいいモデルはないか」と探していたところ、いくつかのブログ記事で「Devstral 2」や「Qwen3-Coder-Next」といった名前を見かけた。しかし実際にOllama公式ライブラリ(ollama.com/library)で確認すると、どちらも公式には存在しなかった。出てきたのは個人が勝手にアップロードした非公式版や、安全策を無理やり外した改造版ばかりだった。

AI生成っぽいSEOブログには、もっともらしいが裏の取れないモデル名が紛れ込むことがある、という実地の教訓。ローカルLLMを試す際は、名前を鵜呑みにせず公式ライブラリで存在確認をしてから導入するのが安全だ。

Qwen3-Coderに乗り換え、ここでも「名前の裏取り」でつまずく

公式に存在が確認できたQwen3-Coder(30B、実働3BのMoE構成、Q4で約19GB)に切り替えることにした。MoE(Mixture of Experts)構造のため、パラメータ数の割に応答が速いのが特徴だ。

ところが最初に設定ファイルに書いていたqwen3-coder:30b-a3bというタグ名でpullしたところ、こんなエラーで即座に失敗した。

ollama pull qwen3-coder:30b-a3b
Error: pull model manifest: file does not exist

ここでもう一度、ollama.com/libraryの公式タグ一覧をあたってみると、実際に存在するのはqwen3-coder:30b(デフォルトでq4_K_M量子化、19GB)やqwen3-coder:30b-a3b-q4_K_Mのような表記で、単体の30b-a3bというタグは存在しなかった。前段で書いた「もっともらしいが存在しないモデル名」の教訓を、今度は自分の設定ミスで身をもって体験した形だ。

ollama pull qwen3-coder:30b

これで無事にダウンロードが完了し、OpenCode側の設定ファイルのモデル名もqwen3-coder:30bに修正した。ローカルLLMを使う際は、ブログ記事だけでなく自分がメモした設定値も含めて、pull直前にもう一度公式タグページで確認する癖をつけたほうがよさそうだ。

コンテキスト長13万の罠。メモリ25GBを無駄に食っていた

動かし始めてすぐ、妙に重いことに気づいた。調べると、Ollamaはデフォルトでコンテキスト長131072(13万トークン超)としてモデルをロードする。Devstralでメモリ消費が25GBに達していて、体感速度にもはっきり影響していた。

実際のコーディング作業で13万トークンを使い切ることはまずない。Modelfileで32768に絞ったカスタムタグを作り直した。

FROM qwen3-coder:30b
PARAMETER num_ctx 32768
ollama create qwen3-coder:fast -f Modelfile

opencode.jsonc側もqwen3-coder:fastを見るように変更。これでメモリ消費も体感速度もかなり楽になった。長い会話やファイルを大量に読ませる作業で足りなくなったら、数値を上げて作り直せばいい。

本題:tool callingが動かない

ここからが本題だ。Qwen3-CoderをOpenCodeから使うと、ファイル検索(glob)のようなtool callが正しく実行されない。実行されるかわりに、生のJSONがそのまま画面に出てくる。

{"id":"call_...","function":{...

あるいは実行が止まったまま進まなくなる。何度か試しても同じで、コンテキスト長を32768に絞っても解消しなかった。Devstralでは同じ現象は起きない。

この時点での結論は「Qwen3-Coderはこの環境ではエージェント用途に使えない。単純なチャットのQ&Aなら問題なく動く」だった。tool callingが要るならGemini Flashのような安価なクラウドAPIのほうが現実的、というところまで書いて、いったん手を止めた。

3週間後の再検証。犯人はモデルではなかった

しばらく経ってから、別の経路で試す機会があった。Ollamaはv0.14以降、Anthropic Messages API互換のエンドポイント(/v1/messages)を公式に持っている。OpenCodeのopenai-compatible変換を通さず、Claude Code本体からこの口を直接叩いてみた。

結果は拍子抜けするほどあっさりしていた。Read → Edit → Bash(wc -l)の3ステップ連鎖まで含めて、報告内容と実際のファイルの状態が完全に一致した。あのtool calling不具合は一度も起きなかった。

少なくともQwen3-Coder自体の欠陥ではなかった。「このモデルはエージェントに使えない」という結論は取り下げるしかない。この時点では、間に挟まっていたOpenCodeのopenai-compatible変換層が怪しいと考えていた。ローカルLLMがうまく動かないとき、疑うべき場所はモデル・推論エンジン・クライアント・その間の変換層と4つあるが、変換層がいちばん見落としやすいからだ。

プロキシの類は要らない。環境変数を2つ渡すだけだ。

ANTHROPIC_BASE_URL=http://localhost:11434
ANTHROPIC_AUTH_TOKEN=ollama

`clo`:素のClaude Codeと安全に使い分ける

毎回環境変数を打つのは面倒だが、exportしてしまうと素のclaude(本家API・claude.aiログイン)まで巻き込んでしまう。そこでenvでその1回の起動にだけ渡す関数を~/.zshrcに置いた。ollamaという名前は本物のコマンドを上書きするので避けて、cloにしてある。

clo() {
  local model="${CLAUDE_LOCAL_MODEL:-qwen3-coder:30b}"

  if ! curl -s -o /dev/null -m 2 http://localhost:11434/api/version; then
    echo "[claude-local] Ollamaサーバーに接続できません。" >&2
    return 1
  fi

  if ! ollama list 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$model"; then
    echo "[claude-local] モデル '$model' が見つかりません。" >&2
    return 1
  fi

  env ANTHROPIC_AUTH_TOKEN=ollama \
      ANTHROPIC_BASE_URL=http://localhost:11434 \
      ANTHROPIC_MODEL="$model" \
      claude "$@"
}

Ollamaが起動しているか、モデルが手元にあるかを先に確認してから渡すようにしてある。モデルを変えたいときはCLAUDE_LOCAL_MODEL=devstral:fast cloのように指定する。

ひとつ注意。clo使用中はコネクターが使えない

この方式には副作用がある。cloで起動している間は、Google Driveなどのコネクターが読み込まれない。

理由は、コネクターがclaude.aiのOAuthログインセッションに紐づいているためだ。ANTHROPIC_AUTH_TOKENが設定されていると、Claude Code側が「APIキー認証モード」と判断して、OAuth由来のコネクター読み込みを丸ごとスキップする。ローカルモデルかどうかは関係ない。

設定でコネクターだけ残す方法は見つからなかったので、コネクターが要る作業は素のclaude、ローカル完結の作業はclo、という住み分けに落ち着いている。

さらに4か月後。今度はOpenCode経由でも動いた

この記事を書くにあたって、2026年11月にもう一度試した。opencode 1.17.15、Ollama 0.31.1、設定ファイルもモデルのタグも当時のまま。つまり7月に壊れていたのとまったく同じ構成だ。

まず、ファイル検索を使わせてみる。

✱ Glob "**/*.md"  2 matches
- note2.md
- note1.md

次に、ファイルを読んで、書き換えて、コマンドで確かめる、という連鎖。

→ Read app.py
$ wc -l app.py      1 app.py
← Edit app.py       -print("hi")  +print("hello")
$ wc -l app.py      1 app.py

実際のファイルもちゃんと書き換わっていて、報告と一致していた。生のJSONは一度も出ず、ハングもしなかった。

というわけで、「OpenCodeの変換層が原因だった」とも言い切れなくなった。7月に壊れていたのは確かだし、Anthropic互換の口に替えたら直ったのも確かだが、今はどちらの経路でも動く。間のどこかが静かに直ったのだと思う。

Claude Codeとの違い、率直な感想

OpenCodeという「器」自体はClaude Codeとほぼ同じ感覚で使えるが、動かす「頭脳」(モデル)の差はやはり大きい。SWE-bench等のベンチマークで見ると、ローカルで自己ホストできるモデルはおおむね60〜72%程度で頭打ちなのに対し、Claude Opus/Sonnetクラスは80〜95%台。単純な質問応答は問題なくても、複数ファイルにまたがる大きな実装や、曖昧な指示から自分で計画を立てて進めるようなタスクでは、まだ差を感じる場面が多い。

そして、tool callingが正常に動くようになった後も残った差が速度だった。手元のM4 Max・64GBでQwen3-Coder 30Bは毎秒100トークン前後出る(M4 Max 64GBでローカルLLMを実測した記事に数字をまとめた)。ローカルとしては速いほうだが、エージェントは1つの指示に対して何度も往復するので、1回ごとの待ち時間が積み上がる。クラウドのClaudeを使った後に戻ると、はっきり遅い。

また「OpenCodeを使うとトークンを節約できる」という話も見かけたが、調べた限りでは根拠は薄く、むしろOpenCodeのデフォルト設定はプロンプトが重いという指摘もあった。節約できるとすれば、プロンプトを自分でカスタマイズして無駄を削れる自由度の高さや、簡単な作業は安いローカルモデルに任せて重要な部分だけClaudeを呼ぶ、といった使い分け次第、というのが実態に近い。

まとめ:サブ相棒としては十分、本番はまだクラウド

単純作業やお試し用途の「サブ相棒」としてはローカルLLM+エージェントは十分実用的だが、本格的な開発をまるごと任せるにはまだClaude Codeに一日の長がある、というのが現時点の実感だ。

4か月で3回試して、結論は「モデルが悪い」→「変換層が悪い」→「今はどちらでも動く」と二転三転した。残ったのは犯人の名前ではなく、切り分けの順番のほうだ。うまく動かないときにモデルを取り替えて回るのは、いちばん時間のかかる解き方だった。間に挟まっている層を1枚ずつ外して試すほうが早い。

なお、エージェント用途でこれ以上粘るのは、ここでいったんやめた。tool callingが要らない単純な質問応答なら、ローカルモデルでも問題なく動くことは分かっている。手元のMacを使うならそちら寄りの用途のほうが向いていそうだ、というのが今のところの見立てだ。

これから買うなら、GPUが40コアのMax構成にしておきたい。32コアの下位版はメモリが36GBしか選べず、大きいモデルがそもそも載らない。

どのMacを選べばローカルLLMが快適に動くのか、メモリは何GB必要かは、M4 Max 64GBで実測した記事のほうにまとめてある。Windows側で同じことをやる場合はRyzen AI 7 350のPCで組んだ記事が参考になるはずだ。

この記事を書いた人

2010年からブログを書いていて、BDレコーダーやPCまわりの実体験記事だけで280本以上。パナソニックDIGA・東芝レグザのHDD換装、ノートPCやChromebookのメモリ・SSD・Wi-Fiモジュール換装など、実機を分解して確認したことだけを書いています。

最近はUniFi UCG Maxでの自宅ネットワーク構築や、Claude Codeを使った作業自動化など、AI・ネットワーク周りにも本格的に力を入れています。ネットの情報をまとめ直すのではなく、自分の手と目で確かめたことを、良いことも悪いことも正直に書くのがモットーです。

ヨシオをフォローする
PC

コメント