コードを書かないSE日誌

SE歴26年。コードを書かずにClaude Codeで8体のAIエージェントチームを動かしています。AIエージェント・自動化・GTDの実験日誌。

Ollamaでコミットメッセージ生成を実装してわかったコストと速度の現実

この記事の実施記録(2026年5月): Mac mini M4 24GB にOllama(v0.23.2)を導入し、git diff --staged からConventional Commits形式のコミットメッセージを自動生成するスクリプト(95行)を作成・動作確認した。モデルはqwen3:14bを採用。実測レイテンシは約59〜79秒(Claude APIは約1〜3秒)。コミットメッセージ生成1回あたりのClaudeのAPI費用は$0.002〜$0.004程度で、コスト削減の動機が成立しないことが判明した。


Mac mini M4を買って最初にやりたくなること、ありますよね。「せっかくこのマシンがあるんだから、Ollamaを入れてローカルLLMを活用したい」。

私もそう思いました。Claude Codeを使い倒していたので、「コストが気になるタスクをローカルに肩代わりさせよう」という発想も自然に浮かびました。

実際に試してみた結果——正直に言うと、当初の目論見は外れました。でも、外れ方が面白かった。

この記事では、Ollamaでコミットメッセージ自動生成を実装した顛末と、そこから得た「ローカルLLMをどこに使うか」の判断軸を書きます。


「サブエージェントとして使えないか」という最初の問い

Claude Codeには .claude/agents/ にサブエージェントを定義できる仕組みがあります。「ここのモデルをOllamaに向けられれば、特定のエージェントだけローカルLLMで動かせるのでは」と思ったのが最初の発想でした。

調べると、model フィールドが受け付けるのは sonnet / opus / haiku などのAnthropicモデルのみ。外部LLMを個別サブエージェントに割り当てる機能は、2026年5月時点では実装されていませんでした。

ANTHROPIC_BASE_URL 環境変数を差し替えてOllamaのエンドポイントに向ける方法はあります。ただしこれは全エージェントが一括でローカルLLMに切り替わる設定です。「このエージェントだけOllama」という個別指定はできない。

想定していた使い方とは違いました。方針を変える必要が出てきました。


発想の転換:「中に組み込む」より「ツールとして直接叩く」

サブエージェントへの組み込みをあきらめたとき、別の切り口が見えてきました。

エージェントの「中」に入れようとしていたOllamaを、エージェントが呼び出す「ツール」として位置づけ直す。具体的には2つのパターンが考えられます。

Pattern A(直接呼び出し): BashツールからcurlでOllamaのAPIを叩く。Ollamaはテキスト生成エンジンとして機能し、判断・ツール操作はClaude Code側が持つ。シンプルで即座に動く。

Pattern B(非同期バッチ処理): Claude Code + Ollamaバックエンドで別プロセスを走らせ、ファイル経由でタスクをやり取りする。セッション後のログまとめや大量ファイルの前処理向き。

コミットメッセージ生成のような「短いdiff → 短いテキスト生成」タスクには、明らかにPattern Aが合います。ファイルをブリッジにすると往復のオーバーヘッドが逆効果になります。

ということで、まず小さく試せるコミットメッセージ生成から実装することにしました。

なお、Ollamaの概念とパターンをもう少し体系的につかみたい方には、日経ソフトウエアの「ローカルLLM実践入門」が参考になります。GUIから始められる入門書ですが、API連携の基礎まで扱っています。


実装:local-commit-msg.sh(95行)

作ったスクリプトの動作はシンプルです。

  1. git diff --staged でステージ済みの差分を取得
  2. Conventional Commits形式・日本語でメッセージを生成するプロンプトに差分を埋め込む
  3. OllamaのAPIにPOSTして結果を受け取る
#!/bin/bash
# local-commit-msg.sh — ステージ済み差分からコミットメッセージを生成する(Ollama使用)
#
# Usage:
#   bash scripts/util/local-commit-msg.sh
#   bash scripts/util/local-commit-msg.sh --model qwen2.5-coder:7b

OLLAMA_BASE_URL="${OLLAMA_BASE_URL:-http://localhost:11434}"
MODEL="${MODEL:-qwen3:14b}"

Ollamaの起動は brew services start ollama で済みます。Mac起動時に自動で立ち上がるようになるので、「ollamaを起動してから使う」という手順が不要になります。

差分が大きくなるとトークン超過するので、8,000文字で打ち切る処理も入れています。

核心処理の流れは以下の通りです(実際のコードから抜粋):

# ステージ済み差分を取得(大きすぎる場合は8,000文字で打ち切る)
DIFF="$(git -C "$PROJECT_ROOT" diff --staged)"
if [[ ${#DIFF} -gt 8000 ]]; then
  DIFF="${DIFF:0:8000}"$'\n...(省略)'
fi

# プロンプト構築:Conventional Commits形式・日本語を指示
PROMPT="以下の git diff を見て、Conventional Commits 形式の日本語コミットメッセージを1行で生成してください。
形式: <type>(<scope>): <日本語の説明>
コミットメッセージのみを出力し、説明や補足は一切不要です。
--- git diff ---
${DIFF}
--- end ---"

# Ollama REST API に POST して結果を受け取る
PAYLOAD="$(jq -n --arg model "$MODEL" --arg prompt "$PROMPT" \
  '{model: $model, prompt: $prompt, stream: false, options: {temperature: 0.2}}')"

RESPONSE="$(curl -sf "${OLLAMA_BASE_URL}/api/generate" \
  -H "Content-Type: application/json" -d "$PAYLOAD")"

COMMIT_MSG="$(echo "$RESPONSE" | jq -r '.response' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')"

curl 1本で完結するシンプルな構成です。OllamaはOpenAI互換のAPIも持っているので、/api/generate の代わりに /api/chat エンドポイントを使うことも可能です。


モデル比較:qwen2.5-coder vs qwen3

せっかくなので2つのモデルで同じdiffを試しました。テストに使ったのは「空行を1行追加した」だけのシンプルな変更です。

モデル 出力 評価
qwen2.5-coder:14b feat: コミットメッセージの表示に区切り線を追加 typeがfeat(誤)、内容も実際の変更と違う
qwen3:14b chore(local-commit-msg.sh): 空行を追加 type・scope・内容すべて正確

qwen3は「空行を追加しただけ」という変更の性質を正しく読んで chore を選んでいます。qwen2.5-coderは内容を過剰解釈して feat(新機能追加)を選んでしまいました。

type選択の精度・scope付与・内容の正確さで、qwen3:14bの方が明確に上でした。


レイテンシの実測:59〜79秒 vs 1〜3秒

ここが本題です。

実測環境: Mac mini M4(無印、24GBメモリ)、Ollamaウォームアップ済み(モデルのロード後)

レイテンシ
Ollama qwen3:14b(M4無印・ウォームアップ済み) 約59〜79秒
Claude API(Sonnet系) 約1〜3秒

差は20〜80倍程度です(最小: 59秒/3秒 ≒ 20倍、最大: 79秒/1秒 = 79倍)。

コミットメッセージを生成するのに1分以上待つのは、実用上ほぼ無理です。コミットのたびに79秒待つなら、自分で書いた方が速い。

なぜここまで遅いのか。主な原因が2つあります。

Thinkingモード: qwen3はデフォルトで内部推論トークンを大量に生成します。/no_think を付けることで抑制できますが、完全には止まりません。その分だけ生成時間が増えます。

メモリ帯域の律速: M4無印のメモリ帯域幅は120 GB/sです。14Bパラメータのモデルは十分に動かせますが、Thinkingモードと組み合わさると帯域が律速になります。M4 Pro(273 GB/s)やM4 Max(546 GB/s)、あるいはメモリ48GB以上の構成なら改善する可能性があります。


「もったいない感」の正体:コスト計算してみると

ローカルLLMに移行したかった動機のひとつが「Claude APIのトークン費用」でした。でも実際に試算すると——

コミットメッセージ生成1回あたりに使うトークンは、差分テキスト(プロンプト)+ 生成結果(数十トークン)で大体500〜1,000トークン程度です。Claude Sonnet 4.6の価格(入力$3/百万トークン・出力$15/百万トークン)で計算すると、1回あたり$0.002〜$0.004程度です。

1日に10回コミットしたとして、月300回。それでも月$1未満。

「ローカルLLMに移行すれば費用が浮く」という感覚と、実際の費用の間に大きな乖離がありました。コストへの「もったいない感」は本物でしたが、数字で確認してみると、その感覚が指していた実態はほぼゼロでした。


では、ローカルLLMはどこで使うべきか

コミットメッセージ生成には向かなかったOllama。では何に使えばいいのか。

実験を通じて見えてきた判断軸はこれです。

ローカルLLMが活きる条件: - 遅くていい(非同期で処理できる) - 量が多い(大量のファイルを一括処理する) - プライバシー上、外部に送りたくないデータを扱う - Thinkingモードの推論時間がむしろ品質向上に繋がる

逆に向かない条件: - 即座に結果が必要(インタラクティブな対話・コミット前の一手間) - 差分が小さく、APIコストがもともと微小 - レイテンシが体験の品質に直結する場面

具体的に向いているタスクとしては、以下のようなものが挙がります。これらはPattern B(非同期バッチ処理)として走らせられます。

  • 顧客データや機密ログの要約・整理: 顧客IDや個人情報が含まれるアプリログ、社内の未公開API仕様書——これらは外部のAPIに送ることをためらうデータだ。ローカルLLMなら通信が発生しない
  • 社内設計書・コードレビューコメントの構造化: 蓄積されたドキュメントを一括でMarkdown化・タグ付けする用途。遅くていい・量が多い・外に出せない、の3条件が揃っている
  • セッション終了後のログを整理してネタ帳に仕分ける処理(個人用途)
  • 大量ファイルの重複チェック・前処理

まとめ:「サブエージェントに組み込む」より「用途を絞ったツール」として使う

Mac mini M4でOllamaを試した実験の結論を整理すると:

  1. Claude Codeのサブエージェントへの組み込みは現状不可(全体を一括切り替えになる)
  2. コミットメッセージ生成はAPI費用が$0.002〜$0.004程度/回(月300回でも月$1未満)で、コスト削減の動機が成立しない
  3. レイテンシは20〜80倍程度の差があり、インタラクティブ用途では実用的でない
  4. ローカルLLMの本領は「遅くていい・量が多い・非同期でいい」タスクにある

「ローカルLLMがあれば何でも安く速くできる」は幻想でした。でも「適切な用途に絞ればAPIより有利な場面がある」のは事実です。正しい期待値を持ったうえで使う場所を選ぶこと——それがローカルLLM活用の第一歩だと思います。


次の実験として、軽量モデル(3B / 7B クラス)に切り替えたときにレイテンシがどこまで改善するかを試してみます。Thinkingモードを無効化した場合の挙動、M4無印のメモリ帯域の実際の限界も確認したいところです。後編として続きを書く予定です。


実装に使ったOllamaのドキュメント: Ollama REST API

スクリプトのパス: scripts/util/local-commit-msg.sh(95行)


「ローカルLLMをサブエージェントに組み込めない」とわかったとき、私は逆の問いを持った——そもそもClaude Codeのサブエージェントをどう設計・運用すれば、チームとして機能するのか。コスト配分・役割分担・自動化の仕組みを体系的に整理したくなった。調べていくうち、この問いに正面から答える実践記録が必要だと感じ、Zenn Bookにまとめた。Vol.1「作るまで」はマルチエージェント構成の設計から動かすところまでを扱い、序章と第1部が無料で読める。Vol.2「回すまで」は自動化・スケジューリング・Routinesによる継続運用が主題で、序章が無料だ。

関連記事

この記事のテーマを深掘りした本

Claude Codeで作る1人エージェントチーム エンジニア向け。writer + reviewer の2体から始めるサブエージェント設計(序章無料)

シリーズ全6冊: Vol.1 作るまでVol.2 回すまでVol.3 書き続けるまでVol.4 仕組みを渡すまでVol.5 仕事を任せるまでVol.6 1人エージェントチーム