コーディング補完のLLMがローカル環境に欲しいなと思って構築した時のメモ
環境
Debian 13
Docker version 29.8.0
vim
vim-ollama
Docker GPU確認 DockerでGPUが有効になっている事を確認。こんな感じの表示が出たらOK(しょぼいGPU…)
1 2 3 4 5 6 7 8 9 10 11 $ docker run --rm --gpus all ubuntu nvidia-smi +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 550.163.01 Driver Version: 550.163.01 CUDA Version: 12.4 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA GeForce GTX 980 On | 00000000:01:00.0 Off | N/A | (以下省略)
蛇足ですが、このGPUでは古すぎてDebianにドライバが見つからず、今回は結局使わずに終わりました
docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 services: # Ollama本体 ollama: image: ollama/ollama:latest container_name: llm-ollama restart: "no" ports: - "${OLLAMA_PORT:-11434}:11434" environment: - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-30m} volumes: - ${OLLAMA_DATA_DIR}:/root/.ollama healthcheck: test: ["CMD", "ollama", "list"] interval: 5s timeout: 5s retries: 20 deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] # モデルダウンロード用コンテナ(使い捨て) ollama-pull: image: ollama/ollama:latest depends_on: ollama: condition: service_healthy environment: - OLLAMA_HOST=http://llm-ollama:11434 restart: "no" entrypoint: ["/bin/sh", "-c"] command: - | for m in ${OLLAMA_MODELS}; do ollama pull "$$m" done
.env 1 2 3 4 5 6 7 8 9 10 11 12 # 出力ファイルの保存先(絶対PATHで指定) OLLAMA_DATA_DIR=/home/<ユーザー名>/.ollama # 待ち受けポート OLLAMA_PORT=11434 # モデルをVRAMに残す時間(デフォルトは5分) OLLAMA_KEEP_ALIVE=30m # 起動時にダウンロードするモデル(スペース区切りで複数指定可) # OLLAMA_MODELS=llama3.1:8b OLLAMA_MODELS=llama3.2:3b starcoder2:3b
パラメータ
セット内容
OLLAMA_DATA_DIR
出力ファイルの保存先(絶対PATHで指定)
OLLAMA_PORT
待ち受けポート
OLLAMA_KEEP_ALIVE
モデルをVRAMに保持する時間
OLLAMA_MODELS
起動時にダウンロードするモデル
OLLAMA_DATA_DIR モデルをダウンロードする保存先。ダウンロードするモデルによっては、数GB必要になってくるので、ディスク容量に余裕のあるPathを絶対PATHで指定します
OLLAMA_KEEP_ALIVE 長く保持しておくほど、補完の応答が早くなります
OLLAMA_MODELS ここが、補完の精度を決める勘所となります。ダウンロードするモデルをスペース区切りで指定します。 ダウンロード出来るモデルは、公式サイト で確認出来ます。
以下、Claudeにオススメのモデルを聞いてみました ★のついているモデルは、CPU推論の環境で最初に試すことをお勧めするものだそうです (つまり軽量のモデル)
チャット・レビュー系
開発元
モデル
容量
構造
CPUでの速度の目安
備考
Google
gemma4:e2b
約7.2GB
密(実効2B)
速い
最軽量。多言語対応、ツール呼び出し対応
Google
gemma4:e4b ★
約9.6GB
密(実効4B)
やや速い
既定のタグ。チャットの第一候補
Google
gemma4:12b
要確認
密
遅い(毎秒2〜3)
2026年6月に追加。CPUには重い
Google
gemma4:26b ★
約18GB
MoE(実効4B)
中(毎秒5〜8前後)
レビュー向き。RAMに載る
Google
gemma4:31b
約20GB
密
非常に遅い(毎秒1前後)
最高品質だが、実用的でない
Google
gemma3:4b
約3GB(記憶ベース)
密
速い
旧世代。RAMを節約したいとき
Meta
llama3.2:3b
約2GB
密
速い(毎秒約12、実測)
日本語は不自然になりやすい
Meta
llama3.1:8b
約4.7GB
密
やや遅い(毎秒4〜5)
無難な基準。日本語は控えめ
Meta
llama3.3:70b、Llama 4系
40GB以上
密 / MoE
載らない
RAM(約31GiB)に入らない
コード補完系
FIM対応が必須(後述の追記)
開発元
モデル
容量
CPUでの速度の目安
備考
Google
codegemma:2b ★
約1.6GB
速い(毎秒15前後)
1行の補完の成功率が高い(Googleの公開データ)
Google
codegemma:7b-code
約5GB
遅い(毎秒4〜5)
複数行の補完に強い。7b はinstruct版の可能性があり、要確認
Meta
codellama:7b-code
約3.8GB
やや遅い(毎秒5〜6)
2023年の世代で、精度は控えめ(HumanEval 33.5%)
とりあえず今回は、このようにしてみました
1 OLLAMA_MODELS=starcoder2:3b gemma4:e4b gemma4:26b codegemma:2b llama3.2:3b codellama:7b-code
(追記) gemma系を使用する場合はFIM設定ファイルが必要
補完の際、「FIMファイル」という、モデルに「カーソルの前のコード」と「カーソルの後ろのコード」を渡して、「このモデルには、こういう目印で渡す」という対応表を書いた、小さなテキストファイル(JSON)が必要なようで、gemma系のモデルを使用すると、ずっと以下のようなエラーが出ていました
OllamaLogger - ERROR - Config file not found for codegemma
これを解決するために、以下の事をしました
1 2 3 4 5 6 7 $ cat ~/.vim/plugged/vim-ollama/python/configs/codegemma.json { "pre": "<|fim_prefix|>", "middle": "<|fim_middle|>", "suffix": "<|fim_suffix|>", "eot": "<|file_separator|>" }
構成確認&構築 設定値が反映されているか、最終確認して、
コンテナをビルド&起動します
ログを眺めてみると、このようにモデルのダウンロードが進行すると思います。 successが表示されるまで待ちましょう
1 2 3 4 5 6 7 8 9 $ docker compose logs -f ollama-pull pulling manifest ollama-pull-1 | pulling 4c27e0f5b5ad: 100% ▕█████████████████ ▏ 9.6 GB/9.6 GB 19 MB/s 0s pulling manifest ollama-pull-1 | pulling 4c27e0f5b5ad: 100% ▕█████████████████ ▏ 9.6 GB/9.6 GB 19 MB/s 0s ollama-pull-1 | verifying sha256 digest ollama-pull-1 | writing manifest ollama-pull-1 | success
ダウンロードが完了すると、以下のコマンドでモデルの一覧が確認出来ます
1 2 3 4 5 6 7 $ docker compose exec ollama ollama list NAME ID SIZE MODIFIED gemma4:e4b c6eb396dbd59 9.6 GB 26 minutes ago gemma4:26b 08ae7ec1744b 18 GB 10 minutes ago codegemma:2b 926331004170 1.6 GB 10 minutes ago codellama:7b-code 8df0a30bb1e6 3.8 GB 10 minutes ago llama3.2:3b a80c4f17acd5 2.0 GB 10 minutes ago
Ollama 主要コマンド 管理系コマンドの一覧
1 2 3 4 $ docker compose exec ollama ollama list # ダウンロード済みのモデル一覧 $ docker compose exec ollama ollama ps # 今メモリに載っているモデル $ docker compose exec ollama ollama show <モデル名> # モデルの詳細 $ docker compose exec ollama ollama rm <モデル名> # 削除
チャット 使ってみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ docker compose exec -it ollama ollama run gemma4:26b --verbose >>> おはよウサギ Thinking... ...done thinking. おはよウサギ!🐰🥕 今日も一日、楽しく元気に過ごしましょうね!✨ total duration: 1m13.376420431s load duration: 1.270989ms prompt eval count: 22 token(s) prompt eval cached: 16 token(s) prompt eval duration: 411.722ms prompt eval rate: 14.57 tokens/s eval count: 544 token(s) eval duration: 1m12.887118s eval rate: 7.46 tokens/s
貧弱なPCなので、ずいぶん時間がかかりました
終了は /byeです
Vim プラグインのインストール gergap/vim-ollamaをインストールします。ご自身で使用しているパッケージマネージャでインストールして下さい(本記事では vim-plug使用)
1 2 3 4 5 // .vimrcに追記 Plug 'gergap/vim-ollama' // インストール :PlugInstall
vim-ollamaの設定 :Ollama configを実行するか、 ~/.vim/config/ollama.vimファイルを直接開きます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 " Use Python virtual environment (and install packages via pip) let g:ollama_use_venv = 1 " Ollama base URL let g:ollama_host = 'http://localhost:11434' " コード補完 let g:ollama_model = 'starcoder2:3b' " チャット・レビュー let g:ollama_chat_model = 'gemma4:e4b' let g:ollama_edit_model = 'gemma4:e4b' " 補完に際にモデルに渡すカーソル前後のコードの行数 let g:ollama_context_lines = 5 " 候補の数 let g:ollama_completion_candidates = 1 " 入力が止まってから、補完を開始するまでの待ち時間(ミリ秒) let g:ollama_debounce_time = 500 " このファイルタイプだけ入力補完を行う let g:ollama_completion_allowlist_filetype = ['sh', 'markdown', 'terraform', 'python'] " このファイルタイプは入力補完を行わない "let g:ollama_completion_denylist_filetype = [] " チャットに渡すプロンプト let g:ollama_chat_systemprompt = 'Always respond in Japanese (日本語で回答してください). Keep code, identifiers and technical terms in English. Be concise.' " デバッグ・ログ設定 " let g:ollama_debug = 4 " general log file location " let g:ollama_logfile = '/tmp/logs/vim-ollama.log' " ollama chat conversation log "let g:ollama_review_logfile = '/tmp/logs/vim-ollama-review.log' " Setting to display suggestions manually instead of automatically " let g:ollama_debounce_time = 0 " imap <silent> <C-l> <Plug>(ollama-trigger-completion) " vim: filetype=vim.ollama
主要な設定だけピックアップします
モデル 使用するモデルを設定
1 2 3 4 5 6 " コード補完 let g:ollama_model = 'starcoder2:3b' " チャット・レビュー let g:ollama_chat_model = 'gemma4:e4b' let g:ollama_edit_model = 'gemma4:e4b'
補完 いずれも、少なくすると補完が早くなります
1 2 3 4 " 補完に際にモデルに渡すカーソル前後のコードの行数 let g:ollama_context_lines = 5 " 補完する候補の数 let g:ollama_completion_candidates = 1
ファイルタイプ 補完する,しないファイルタイプをここで設定。補完の必要ないファイルでムダな補完が行われなくなります
1 2 3 4 " このファイルタイプだけ入力補完を行う let g:ollama_completion_allowlist_filetype = ['sh', 'markdown', 'terraform', 'python'] " このファイルタイプは入力補完を行わない "let g:ollama_completion_denylist_filetype = []
プロンプト チャットの時に、日本語で返してくれなかったので設定してます
1 2 " チャットに渡すプロンプト let g:ollama_chat_systemprompt = 'Always respond in Japanese (日本語で回答してください). Keep code, identifiers and technical terms in English. Be concise.'
vim-ollamaの操作方法 入力モードで、 let g:ollama_debounce_time = 500で設定した秒数が経過すると補完が開始されます
Tabを押すと補完確定
他には、以下のようなコマンドで操作出来るみたいですが、自分の環境では Tab以外動きませんでした 他のプラグインのキーバインドと被ってたのかもしれません
操作
内容
Tab
提案をすべて採用する
Alt + →
提案の次の1行だけ採用する
Ctrl + Alt + →
提案の次の1単語だけ採用する
Ctrl + ]
提案を消す
Alt + ↓ / Alt + ↑
別の候補に切り替える( g:ollama_completion_candidates を2以上の時のみ)
他には、以下のような操作もあります
コマンド
内容
変更されるか
:’<,’>OllamaReview
選択範囲のコードレビュー
変更されない。結果はチャット画面に出る
:’<,’>OllamaExplain
選択範囲の解説
変更されない(読み取り専用)
:’<,’>OllamaTask “指示”
任意の指示(例: “日本語でコメントを付けて”)。結果はチャット画面に出て、手でコピーする必要がある
変更されない
:’<,’>OllamaSpellCheck
スペルチェック
変更されない
:’<,’>OllamaEdit “指示”
指示に従って、選択範囲を書き換える
変更される