📑

ローカルLLMを用いたコーディング支援環境の構築・検証

に公開

対象読者

この記事は以下の読者を想定しています:

  • LLMの基礎を理解しており、ローカル環境での活用に興味があるエンジニア
  • ローカルLLM環境の構築と性能検証に興味がある開発者
  • ローカルLLMの実用性について知りたい技術者
  • Google Colab無料枠でローカルLLMを試してみたい方

概要

Cursorのトークン制限問題を解決するため、Google Colab + Qwen3-Coder-30BでローカルLLM環境を構築した。Web検索と長期記憶機能を統合したコーディング支援システムを実装し、技術的な検証を行った。

結果: 技術的には動作するが、実用面では課題も発見した。検証結果を詳しく報告する。

動機:Cursorの制限を何とかしたかった

Cursorを使っていると時々発生する問題:

  • トークン制限による作業中断
  • 月額コストの継続的な負担

これらの問題を解決するため、ローカル環境で動作するLLMベースのコーディング支援システムの構築を試みた。

構築したかった環境:

  • トークン制限なし
  • 完全にローカルで動作
  • 継続的なコスト不要
  • LLMの仕組みを学習できる

実際のGPU環境を用意するのはハードルがあったため、技術検証としてGoogle Colab無料枠を使ってこのシステムの実現可能性を調査した。

Google Colab無料枠の制約による問題:

  • メモリ制限: 12GBのRAM制限により、GPUレイヤーを0に設定せざるを得ない
    • 影響: 大規模なデータセットや複雑なモデルの処理が困難
    • 結果として今回はCPU環境での検証になってしまった
  • セッション制限: 長時間のアイドル状態でセッションが切れるリスクがある
    • 影響: 長時間の処理中に作業が中断される可能性がある
  • CPU性能: 無料枠のCPU性能が限定的で、推論速度が大幅に低下する
    • 影響: 商用サービスと比較して数十倍の処理時間が必要である
  • 接続の不安定性: 長時間の処理中にセッションが切れるリスクがある
    • 影響: 複雑なタスクの完了前に中断される可能性がある

環境構築:期待と現実のギャップ

環境情報

  • 実行環境: Google Colab (無料枠)
  • Python: 3.12
  • 主要ライブラリ:
    • llama-cpp-python (0.3.16) - LLM実行
    • huggingface-hub - モデル管理
    • chromadb - ベクトルデータベース
    • sentence-transformers - 埋め込み生成(intfloat/multilingual-e5-large)

Hugging Faceトークンの準備

Hugging Face Token Creation
1. profileからAccess tokensを選択

Create New Token
2. Create new tokenを選択

Create Read Token
3. Read権限でトークンを作成。モデルダウンロードに必要

Google ColabでのSecrets設定方法:

  1. Colabの左サイドバーから「🔑」アイコン(Secrets)をクリック
  2. 「新しいシークレットを追加」ボタンをクリック
  3. 名前: HUGGINGFACE_HUB_TOKEN、値: 作成したトークンを入力

モデル選択の理由

Qwen3-Coder-30Bを選択した理由:

  • コード特化: プログラミングタスクに特化して訓練されたモデル
  • 多言語対応: Python、JavaScript、Go、Rustなど幅広い言語に対応
  • 量子化版の利用可能性: Q4_K_M量子化版(約2.2GB)でメモリ効率が良い
  • ライセンス: Apache 2.0ライセンスで商用利用可能

他のモデルとの比較:

  • Llama 2: 汎用性は高いが、コード生成特化ではない
  • CodeLlama: コード特化だが、より大きなモデルサイズ
  • StarCoder: コード生成に優れるが、日本語対応が限定的

環境構築の実装

Google Colab無料枠での制約を考慮しつつ、以下のコードで環境を構築した:

# ==============================================================================
# Part 1: 環境構築とAIのセットアップ (GPU利用最適化版)
# ==============================================================================

# --------------------------------------------------------------------------
# Step 1.0: Hugging Faceへのログイン
# --------------------------------------------------------------------------
from huggingface_hub import login
from google.colab import userdata

# ColabのSecretsからトークンを取得(推奨)
token = userdata.get('HUGGINGFACE_HUB_TOKEN')
login(token=token)
print("✅ Secretsからトークンを取得してログインしました。")

# --------------------------------------------------------------------------
# Step 1.1: 必要なライブラリのインストール
# --------------------------------------------------------------------------
print("\n⏳ Step 1.1: 必要なライブラリをインストール中...")
!pip install --upgrade --quiet pip
!pip install \
  --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu121 \
  llama-cpp-python
!pip install huggingface-hub chromadb sentence-transformers requests beautifulsoup4 googlesearch-python --quiet
print("✅ Step 1.1: ライブラリのインストール完了!")

# --------------------------------------------------------------------------
# Step 1.2: unsloth版 Qwen3-Coder 30B GGUFモデルのダウンロード
# --------------------------------------------------------------------------
print("\n⏳ Step 1.2: AIモデル(unsloth/Qwen3-Coder 30B)をダウンロード中...")
from huggingface_hub import hf_hub_download
import os

os.makedirs("models", exist_ok=True)
hf_hub_download(
    repo_id="unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF",
    filename="Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf",
    local_dir="./models",
    local_dir_use_symlinks=False
)
print("✅ Step 1.2: モデルのダウンロード完了!")

# --------------------------------------------------------------------------
# Step 1.3: AIモデルのロードと起動確認
# --------------------------------------------------------------------------
print("\n⏳ Step 1.3: AIモデルをメモリにロード中...")
try:
    from llama_cpp import Llama
    print("✅ llama_cppライブラリのインポート成功!")

    llm = Llama(
        model_path="./models/Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf",
        n_gpu_layers=0,      # GPUを使用しない
        n_ctx=2048,           # AIが一度に処理できる文章の長さ(コンテキストウィンドウ)です。
        n_threads=2,          # GPU利用時も、データ処理などでCPUが補助的に使われるためスレッド数を指定します。
        verbose=False
    )
    print("✅ AIモデルのロード完了!いつでも使用可能です。")
except Exception as e:
    print(f"❌ 処理中にエラーが発生しました: {e}")

Environment Setup
ライブラリのインストールからモデルダウンロードまでの一連の流れ

実際の動作結果:技術検証の成果

生成AIの利用について

利用目的:
このシステムでは、Qwen3-Coder-30Bをコード生成に利用している。生成されたコードは技術検証の目的で使用し、実際のプロダクション環境での利用を前提としていない。

検証方法:

  • 生成されたコードの実行時間を測定
  • コードの動作確認(Hello World、FizzBuzz等の基本タスク)
  • 生成されるコードの品質を確認

基本的なタスクでの検証

プロンプト: "HelloWorldを出力するPythonコードを教えて"

Hello World Generation
シンプルなタスクでの動作確認。ストリーミング出力で生成過程が見える

検証結果:

  • 生成コード:正確で実用的
  • 実行時間:235.52秒
  • 品質:完璧な実装と適切な説明付き

アルゴリズム系タスクでの検証

プロンプト: "1から100までの数字を出力するPythonコードを書いて。ただし、3の倍数の時は'Fizz'、5の倍数の時は'Buzz'、15の倍数の時は'FizzBuzz'を出力してください。"

FizzBuzz Generation
より複雑なロジックを要するFizzBuzz問題での精度チェック

検証結果:

  • 実行時間:334.80秒
  • 実装品質:効率的なアルゴリズム
  • 特徴:15で割り切れる場合の最適化も含む高品質なコード

システムの工夫:小さなモデルを強化する試み

30Bモデル単体では限界があるため、以下の機能を追加実装した。

基本的なコード生成機能

ストリーミング出力に対応したコード生成機能を実装した。タイムスタンプ付きのログ機能と組み合わせることで、生成過程を可視化できる。

def generate_code_simple(prompt: str, llm_instance):
    """AIに直接質問し、コードを生成するシンプルな関数"""
    start_time = time.time()
    
    stream = llm_instance.create_chat_completion(
        messages=[{"role": "user", "content": prompt}],
        temperature=0.2,
        stream=True
    )
    
    full_response = ""
    for chunk in stream:
        token = chunk['choices'][0].get('delta', {}).get('content')
        if token:
            print(token, end="", flush=True)
            full_response += token
    
    elapsed_time = time.time() - start_time
    print(f"\n✅ 生成完了! (所要時間: {elapsed_time:.2f}秒)")
    return full_response

長期記憶システムの導入

Memory System Initialization
ChromaDBとSentence Transformersを使った記憶システムの構築

過去のコードをベクトル化して保存し、類似検索で再利用するシステムを実装した。これにより、一度生成したコードパターンを学習し、類似タスクで活用できる。

class CodeMemory:
    """過去のコードを記憶し、類似のものを検索する長期記憶システム"""
    def __init__(self, model_name='intfloat/multilingual-e5-large'):
        self.embedding_model = SentenceTransformer(model_name)
        self.client = chromadb.PersistentClient(path="./code_memory_db")
        self.collection = self.client.get_or_create_collection("code_snippets")
    
    def save(self, code, description):
        """コードと説明を長期記憶に保存"""
        doc_id = str(self.collection.count())
        embedding = self.embedding_model.encode(f"Desc: {description}\nCode: {code}").tolist()
        self.collection.add(
            ids=[doc_id],
            embeddings=[embedding],
            documents=[code],
            metadatas=[{"desc": description}]
        )
    
    def recall(self, query, n=1):
        """クエリに関連する過去のコードを検索"""
        query_embedding = self.embedding_model.encode(query).tolist()
        results = self.collection.query(query_embeddings=[query_embedding], n_results=n)
        return results['documents'][0] if results['documents'] else []

Web検索機能との連携

最新の技術情報をリアルタイムで取得し、コード生成に活用する機能を実装した。Google検索APIとBeautifulSoupを組み合わせて、関連するチュートリアルやサンプルコードを自動収集する。

def get_web_context(query: str, num_results: int = 1) -> str:
    """リアルタイムでWebを検索し、最新情報を取得する短期記憶システム"""
    context = ""
    try:
        urls = list(search(f"{query} tutorial example", num_results=num_results, sleep_interval=1, lang="ja"))
        
        for url in urls:
            response = requests.get(url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
            soup = BeautifulSoup(response.text, 'html.parser')
            page_text = "\n".join([
                tag.get_text(" ", strip=True)
                for tag in soup.find_all(['p', 'h2', 'h3', 'code'])
            ])
            context += f"--- Webからの参考情報 ({url}) ---\n{page_text[:1500]}\n\n"
    except Exception as e:
        return f"Web検索中にエラーが発生しました: {e}"
    
    return context

統合システム:複数の情報源を活用

長期記憶(過去のコード)と短期記憶(Web検索)を組み合わせて、より高品質なコード生成を実現する統合システムを構築した。

def generate_code_with_memory(prompt: str, llm_instance, memory_system=None):
    """長期記憶と短期記憶を統合し、最終的なコードを生成する"""
    # 長期記憶の検索
    similar_code = memory_system.recall(prompt) if memory_system else []
    
    # Web検索による最新情報の取得
    web_context = get_web_context(prompt)
    
    # プロンプトの構築
    context_prompt = "あなたは、与えられた情報を最大限活用する世界クラスのプログラマーです。\n\n"
    
    if similar_code:
        context_prompt += f"### 過去の類似コード:\n```python\n{similar_code[0]}\n```\n\n"
    
    if web_context:
        context_prompt += f"### 最新のWeb情報:\n{web_context}\n"
    
    final_prompt = f"""{context_prompt}上記の情報を踏まえて、以下のリクエストに最高のコードで応えてください:

'{prompt}'

# 生成コード
"""
    
    # AIによるコード生成
    stream = llm_instance.create_chat_completion(
        messages=[{"role": "user", "content": final_prompt}],
        temperature=0.2,
        stream=True
    )
    
    full_response = ""
    for chunk in stream:
        token = chunk['choices'][0].get('delta', {}).get('content')
        if token:
            print(token, end="", flush=True)
            full_response += token
    
    return full_response

性能評価:データで見る検証結果

測定条件

実行環境の詳細:

  • インスタンス: Google Colab無料枠(CPU専用)
  • CPU: 変動(通常2コア程度)※ColabのCPUはセッションごとに変動する可能性があります
  • メモリ: 12GB RAM※Colabのメモリサイズも変動する可能性があります
  • GPU: 使用せず(n_gpu_layers=0)
  • コンテキスト長: 2048トークン
  • 温度設定: 0.2(一貫性を重視)

実行時間の詳細分析

タスクの種類 実行時間 コード品質 特筆事項
基本的なコード 約4分 高品質 構文エラーなし、実行可能
アルゴリズム系 約5分半 高品質 最適化された効率的なコード
複雑なAPI処理 約37分 高品質 エラーハンドリング完備

既存サービスとの特性比較

特徴 Cursor/Claude Codeなど このシステム
応答速度 数秒 数分〜数十分(タスクの複雑さにより変動)
コード品質 高品質(商用レベル) 高品質(時間をかければ)
コスト 月額/従量課金 完全無料
プライバシー クラウド送信 完全ローカル
学習効果 ブラックボックス 仕組みが見える
カスタマイズ性 限定的 完全自由

コード品質の評価基準:

  • 構文エラー: 生成されたコードの構文エラー率
  • 実行可能性: そのまま実行できるコードの割合
  • 最適化: アルゴリズムの効率性(時間計算量・空間計算量)
  • 可読性: コメントや変数名の適切性
  • エラーハンドリング: 例外処理の実装状況

このシステムならではの価値

技術学習の観点:

  • LLMの動作原理を実際に体験
  • プロンプトエンジニアリングの効果を実感

プライバシーの観点:

  • 機密コードを外部送信する必要なし
  • 完全にコントロール可能な環境
  • 企業や研究機関での活用可能性

実際の使用体験:現実的な評価

完全なシステムデモンストレーション

実際にシステムを稼働させた最終的な実行例:

System Thinking Process
AIの思考プロセス:長期記憶検索→Web検索→プロンプト構築→コード生成の流れ

追加検証結果:

タスクの種類 実行時間 コード品質 特筆事項
バブルソート実装 約6分 高品質 完璧な実装生成
API連携コード 約37分 高品質 本格的なエラーハンドリング付き
ランダムシャッフル機能 約37分 高品質 破壊的・非破壊的両パターンの実装
CSV読み込み機能 約48分 高品質 包括的なpandasベースの実装
日付フォーマット機能 実行途中で停止 - Colab制限により中断

実行途中停止の原因と回避策:

  • 原因: Google Colab無料枠のセッション時間制限に達したためである
  • 回避策:
    • より軽量なモデル(7B-13Bクラス)の使用
    • 処理を分割して複数セッションで実行
    • Colab Proの利用(長時間セッションが可能)

長期記憶システムの学習効果:

  • 過去のコード例を参照した高度な実装
  • 段階的な知識蓄積による品質向上

技術的な検証結果

成功した部分:

  • ローカル環境でのLLM動作を確認
  • 長期記憶システムによる学習機能を実装
  • 高品質なコード生成が可能(時間はかかるが)

制約として判明した部分:

  • 実行時間の長さ(数分~数十分)
  • セットアップの手間

まとめ

技術的な成果

  • 完全ローカルでのLLMコード生成環境構築に成功
  • Web検索と長期記憶を統合したハイブリッドシステムを実装
  • 高品質なコード生成を確認(時間はかかるが)

実用性の評価

適している場面:

  • LLMの仕組みを学習したい場合
  • プライバシーを重視する開発環境
  • 予算制約があるプロジェクト

商用サービスが適している場面:

  • 日常的なコーディング業務
  • タイトなスケジュールでの開発

今後の改善方向

  • 軽量モデル(7B-13Bクラス)での検証
  • 量子化技術の最適化
  • バッチ処理による効率化
  • 実行時間の短縮とメモリ使用量の効率化

実際に試してみたい方へ:

時間に余裕があり、LLMの仕組みを学習したい場合には有効な実験である。ただし日常的なコーディング支援としての実用性は限定的である。

関連リソース:

株式会社MONO-X 開発チーム

Discussion