所要時間: 約40分 | 難易度: ★★★☆☆

この記事で作るもの

  • 特定のディレクトリ内のソースコードを全スキャンし、バグの発見とリファクタリング案を自動生成する「AIコードレビュアー」
  • 前提知識: Pythonの基本的な読み書き、ターミナル(コマンドプロンプト)の操作ができること
  • 必要なもの: Python 3.10以上、8GB以上のVRAM(GPU)を推奨(CPUでも動作可能だが低速)

📦 この記事に関連する商品

GeForce RTX 4060 Ti 16GB

VRAM 16GB搭載でQwen 32Bモデルを安価かつ安定して動かせる最適な1枚です

Amazonで見る 楽天で見る

※アフィリエイトリンクを含みます

なぜこの方法を選ぶのか

現在、コーディング特化型LLMの分野で、Alibaba Cloudがリリースした「Qwen2.5-Coder」は、オープンソースでありながらGPT-4oに匹敵する、あるいは凌駕するベンチマークを叩き出しています。シンガポールのチャンギ空港に巨大な広告が出るほど、Alibabaはこのモデルに巨額の投資をしており、その実力は「仕事で使える」レベルに達しました。

他にもGitHub CopilotやClaude 3.5 Sonnetを使う選択肢はありますが、社外秘のソースコードを外部サーバーに送信できない制約がある現場も多いはずです。そこで、ローカル環境で完結し、かつAPI料金を気にせず「128kの大文脈」を活かせるこの構成が、現時点でのエンジニアにとって最強の自炊環境だと私は断言します。今回は、軽量かつ高速にLLMを動かせる「Ollama」をバックエンドに採用し、Pythonから制御する方法を解説します。

Step 1: 環境を整える

まずは、モデルを動かすためのエンジンであるOllamaをインストールします。

# macOS / Linux の場合
curl -fsSL https://ollama.com/install.sh | sh

# Windows の場合
# 公式サイト (https://ollama.com/) からインストーラーをダウンロードして実行

次に、Qwen2.5-Coderの32B(320億パラメータ)モデルをダウンロードします。私の検証では、7Bモデルは速度こそ速いものの、複雑なロジックの理解力で一歩劣ります。仕事で使うなら、量子化された32BモデルをRTX 3060(12GB)以上の環境で動かすのがベストバランスです。

# Qwen2.5-Coderの32Bモデルを起動
ollama run qwen2.5-coder:32b

⚠️ 落とし穴: VRAM(グラボのメモリ)が足りない場合、モデルの読み込みが非常に遅くなるか、エラーで終了します。12GB以下のGPUを使っている場合は、qwen2.5-coder:7b(約4.7GB)から試してください。32Bモデルは約19GBのVRAMを消費しますが、Ollamaは自動でメインメモリ(RAM)にオフロードしてくれます。ただし、RAMへのオフロードは推論速度が1/10以下に低下するため、実用性を重視するならモデルサイズを下げる判断も必要です。

Step 2: 基本の設定

PythonからOllama経由でQwenを叩くためのライブラリをインストールします。

pip install ollama

次に、Pythonスクリプトを作成します。APIキーは不要ですが、接続先のURLなどは環境変数で管理する癖をつけておきましょう。

import os
import ollama

# Ollamaはデフォルトで localhost:11434 で待機しています
# 自宅サーバーなど別PCで動かす場合は、ここをそのIPアドレスに変更します
OLLAMA_HOST = os.getenv("OLLAMA_HOST", "http://localhost:11434")

client = ollama.Client(host=OLLAMA_HOST)

def get_ai_response(prompt, model="qwen2.5-coder:32b"):
    try:
        response = client.generate(
            model=model,
            prompt=prompt,
            stream=False,
            options={
                "num_ctx": 32768, # 32kトークンのコンテキストを確保。ソースコード解析には必須。
                "temperature": 0.2 # コード生成時は決定論的な出力を好むため低めに設定。
            }
        )
        return response['response']
    except Exception as e:
        return f"エラーが発生しました: {str(e)}"

「なぜこの設定にするのか」についてですが、num_ctxをデフォルト(通常2048〜4096)のままにすると、長いソースコードを入力した瞬間に古い記憶を忘れてしまいます。Qwen2.5-Coderは最大128kまで対応していますが、ローカル環境ではメモリ消費とのトレードオフになるため、まずは32k(約2.4万文字)程度に設定するのが実用的です。

Step 3: 動かしてみる

まずは最小限のコードで、Qwenが正しく動作するか確認します。

test_prompt = "Pythonでクイックソートを実装して。解説は不要でコードだけ出力して。"
result = get_ai_response(test_prompt)
print(result)

期待される出力

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

この結果が出るまで、レスポンスに何秒かかったか計測してください。私のRTX 4090環境では、この程度の出力は0.5秒もかかりません。もし10秒以上かかる場合は、GPUではなくCPUで推論されている可能性があります。その際はOllamaのログを確認し、GPUドライバが正しく認識されているかチェックしてください。

Step 4: 実用レベルにする

ここからが本番です。単一のプロンプトではなく、指定したディレクトリにある複数のファイルを読み込み、依存関係を考慮してレビューを行うスクリプトへ拡張します。

import glob

def code_reviewer(target_dir):
    # 特定の拡張子を持つファイルのみを収集
    files = glob.glob(f"{target_dir}/**/*.py", recursive=True)
    combined_code = ""

    for file_path in files:
        with open(file_path, "r", encoding="utf-8") as f:
            code = f.read()
            combined_code += f"\n--- File: {file_path} ---\n{code}\n"

    prompt = f"""
    あなたはシニアソフトウェアエンジニアです。
    以下のソースコード群をレビューし、以下の3点について日本語で回答してください。
    1. セキュリティ上の脆弱性やバグ
    2. パフォーマンス改善の余地
    3. 可読性を高めるためのリファクタリング案

    ソースコード:
    {combined_code}
    """

    print("解析中... 規模によっては時間がかかります。")
    review_result = get_ai_response(prompt)

    with open("review_report.md", "w", encoding="utf-8") as f:
        f.write(review_result)

    print("レビューが完了しました。review_report.md を確認してください。")

# 実行例
if __name__ == "__main__":
    # レビューしたいプロジェクトのパスを指定
    code_reviewer("./my_project")

このスクリプトは、指定したフォルダ内の全てのPythonファイルを一つのコンテキストとしてQwenに流し込みます。これができるのは、Qwenの長いコンテキスト性能があるからです。私が実際に20ファイル程度の小規模プロジェクトを食わせたところ、循環参照の予兆や、不要なリスト内包表記によるメモリ浪費を的確に指摘しました。

よくあるトラブルと解決法

エラー内容原因解決策
ConnectionErrorOllamaが起動していない、またはポートが閉じているollama serve を実行するか、サービスが起動しているか確認
OutOfMemoryError指定したモデルがGPUメモリに収まりきらないqwen2.5-coder:7b にモデルサイズを下げる
レスポンスが途中で切れるnum_predict の制限に達しているoptions 内で "num_predict": -1(無制限)を設定する

次のステップ

ここまでで、ローカル環境で動く「AIコードレビュアー」が完成しました。これをベースに、Gitのプリコミットフック(pre-commit)に組み込んで、コミット前に自動でAIレビューを走らせる仕組みを作るのが次のステップとしておすすめです。

また、Qwen2.5-Coderは「Tool Calling(関数呼び出し)」の精度も非常に高いです。例えば、「特定のバグを見つけたら、AI自身がos.replaceを使ってファイルを修正する」というエージェント化も可能です。まずは、本記事のコードで手持ちの古いプロジェクトをスキャンしてみてください。自分が書いたコードの「恥ずかしい部分」を、驚くほど冷静に指摘してくれるはずです。

よくある質問

Q1: API版(Alibaba Cloud API)と比べてローカル版の利点は?

一番の利点は機密保持です。ソースコードは資産そのものですから。また、ローカル版は通信遅延がないため、自分の思考スピードを落とさずにコーディングを続けられます。RTX 3090/4090クラスを持っていれば、APIと遜色ない速度が出せます。

Q2: Qwenは日本語のコメントやドキュメントを正しく理解できますか?

はい。Qwenシリーズは多言語対応に非常に力を入れており、日本語のニュアンスも驚くほど正確に汲み取ります。変数名が英語でコメントが日本語という日本の現場に多いスタイルでも、文脈を崩さずに解析可能です。

Q3: VRAMが8GBしかないゲーミングノートPCでも動きますか?

動きます。その場合は qwen2.5-coder:7b モデルを使用してください。4bit量子化版であれば4.7GB程度で収まります。推論速度も速く、1ファイル単位のレビューであれば十分実用的なパフォーマンスを発揮します。


あわせて読みたい