From a7b61fe07d7d42ea3dbbf3a1badc059686860090 Mon Sep 17 00:00:00 2001 From: syui Date: Fri, 30 May 2025 20:07:06 +0900 Subject: [PATCH] fix --- docs/claude-code-inception-methods.md | 246 ++++++++++++++++ docs/mcp-server-local-llm.py | 392 ++++++++++++++++++++++++++ docs/mcp-setup-guide.md | 244 ++++++++++++++++ 3 files changed, 882 insertions(+) create mode 100644 docs/claude-code-inception-methods.md create mode 100644 docs/mcp-server-local-llm.py create mode 100644 docs/mcp-setup-guide.md diff --git a/docs/claude-code-inception-methods.md b/docs/claude-code-inception-methods.md new file mode 100644 index 0000000..8c1706b --- /dev/null +++ b/docs/claude-code-inception-methods.md @@ -0,0 +1,246 @@ +# Claude CodeでClaude Code的環境を作る方法 + +Claude Code**で**Claude Code**のような**ことを実現する様々なアプローチをご紹介! + +## 🎯 方法1: MCP Server経由でローカルLLMに委譲 + +### claude-code-mcp を使用 +```bash +# Claude Code MCPサーバーのセットアップ +git clone https://github.com/steipete/claude-code-mcp +cd claude-code-mcp + +# Claude Codeをローカルで呼び出すMCPサーバーとして動作 +npm install +npm start +``` + +**仕組み:** +- Claude Code → MCP Server → ローカルLLM → 結果を返す +- Claude Codeを全権限バイパス(--dangerously-skip-permissions)で実行 +- Agent in Agent 構造の実現 + +## 🎯 方法2: Claude Desktop + Custom MCP Server + +### カスタムMCPサーバーでローカルLLM統合 +```python +# custom_llm_mcp_server.py +import asyncio +import json +from mcp.server import Server +from mcp.types import Tool, TextContent +import requests + +app = Server("local-llm-mcp") + +@app.tool("run_local_llm") +async def run_local_llm(prompt: str, model: str = "qwen2.5-coder:14b") -> str: + """ローカルLLMでコード生成・分析を実行""" + response = requests.post("http://localhost:11434/api/generate", json={ + "model": model, + "prompt": prompt, + "stream": False + }) + return response.json()["response"] + +@app.tool("execute_code") +async def execute_code(code: str, language: str = "python") -> str: + """生成されたコードを実行""" + # セキュアな実行環境でコード実行 + # Docker containerやsandbox環境推奨 + pass + +if __name__ == "__main__": + asyncio.run(app.run()) +``` + +### Claude Desktop設定 +```json +{ + "mcpServers": { + "local-llm": { + "command": "python", + "args": ["custom_llm_mcp_server.py"] + } + } +} +``` + +## 🎯 方法3: VS Code拡張 + MCP統合 + +### VS Code設定でClaude Code風環境 +```json +// settings.json +{ + "mcp.servers": { + "claude-code-local": { + "command": ["python", "claude_code_local.py"], + "args": ["--model", "qwen2.5-coder:14b"] + } + } +} +``` + +VS Codeは両方の構成(ローカル/リモート)をサポートしているから、柔軟に設定できるよ〜 + +## 🎯 方法4: API Gateway パターン + +### Claude Code → API Gateway → ローカルLLM +```python +# api_gateway.py +from fastapi import FastAPI +import requests + +app = FastAPI() + +@app.post("/v1/chat/completions") +async def proxy_to_local_llm(request: dict): + """OpenAI API互換エンドポイント""" + # Claude Code → この API → Ollama + ollama_response = requests.post( + "http://localhost:11434/api/chat", + json={ + "model": "qwen2.5-coder:14b", + "messages": request["messages"] + } + ) + + # OpenAI API形式で返却 + return { + "choices": [{ + "message": {"content": ollama_response.json()["message"]["content"]} + }] + } +``` + +### Claude Code設定 +```bash +# 環境変数でローカルAPIを指定 +export ANTHROPIC_API_KEY="dummy" +export ANTHROPIC_BASE_URL="http://localhost:8000/v1" +claude code --api-base http://localhost:8000 +``` + +## 🎯 方法5: Docker Compose 統合環境 + +### docker-compose.yml +```yaml +version: '3.8' +services: + ollama: + image: ollama/ollama:latest + ports: + - "11434:11434" + volumes: + - ollama_data:/root/.ollama + + mcp-server: + build: ./mcp-server + ports: + - "3000:3000" + depends_on: + - ollama + environment: + - OLLAMA_URL=http://ollama:11434 + + claude-desktop: + image: claude-desktop:latest + volumes: + - ./config:/app/config + environment: + - MCP_SERVER_URL=http://mcp-server:3000 + +volumes: + ollama_data: +``` + +DockerはMCPサーバーの展開と管理を簡素化し、分離とポータビリティを提供 + +## 🎯 方法6: 簡易プロキシスクリプト + +### claude_to_local.py +```python +#!/usr/bin/env python3 +import subprocess +import sys +import json + +def claude_code_wrapper(): + """Claude CodeコマンドをインターセプトしてローカルLLMに転送""" + + # Claude Codeの引数を取得 + args = sys.argv[1:] + prompt = " ".join(args) + + # ローカルLLMで処理 + result = subprocess.run([ + "ollama", "run", "qwen2.5-coder:14b", prompt + ], capture_output=True, text=True) + + # 結果を整形してClaude Code風に出力 + print("🤖 Local Claude Code (Powered by Qwen2.5-Coder)") + print("=" * 50) + print(result.stdout) + + # 必要に応じてファイル操作も実行 + if "--write" in args: + # ファイル書き込み処理 + pass + +if __name__ == "__main__": + claude_code_wrapper() +``` + +### エイリアス設定 +```bash +# .bashrc または .zshrc +alias claude-code="python claude_to_local.py" +``` + +## 🎯 方法7: Aider + Claude Code 統合 + +### 設定方法 +```bash +# Aiderでローカルモデル使用 +aider --model ollama/qwen2.5-coder:14b + +# Claude Codeから呼び出し +claude code "Run aider with local model to implement feature X" +``` + +## 💡 どの方法がおすすめ? + +### 用途別推奨: + +1. **🔧 開発効率重視**: MCP Server方式(方法1,2) +2. **🏠 統合環境**: Docker Compose(方法5) +3. **⚡ 簡単設置**: プロキシスクリプト(方法6) +4. **🎨 カスタマイズ**: API Gateway(方法4) + +## 🚀 実装のコツ + +### セキュリティ考慮 +- サンドボックス環境でコード実行 +- ファイルアクセス権限の制限 +- API キーの適切な管理 + +### パフォーマンス最適化 +- ローカルLLMのGPU使用確認 +- MCP サーバーのキャッシュ機能 +- 並列処理の活用 + +### デバッグ方法 +```bash +# MCP サーバーのログ確認 +tail -f ~/.config/claude-desktop/logs/mcp.log + +# Ollama の動作確認 +ollama ps +curl http://localhost:11434/api/tags +``` + +## 🎉 まとめ + +Claude CodeでClaude Code的な環境を作るには、MCPプロトコルを活用するのが最も効果的!ローカルLLMの性能も向上しているので、実用的な環境が構築できるよ〜✨ + +どの方法から試してみる?アイが一緒に設定をお手伝いするからね! \ No newline at end of file diff --git a/docs/mcp-server-local-llm.py b/docs/mcp-server-local-llm.py new file mode 100644 index 0000000..296a50f --- /dev/null +++ b/docs/mcp-server-local-llm.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python3 +""" +Local LLM MCP Server for Claude Code Integration +Claude Code → MCP Server → Local LLM (Qwen2.5-Coder) +""" + +import asyncio +import json +import logging +import requests +import subprocess +import os +from pathlib import Path +from typing import Dict, List, Any, Optional +from mcp.server import Server +from mcp.types import ( + Tool, + TextContent, + Resource, + PromptMessage, + GetPromptResult +) + +# ログ設定 +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger("local-llm-mcp") + +class LocalLLMServer: + def __init__(self, model: str = "qwen2.5-coder:14b-instruct-q4_K_M"): + self.model = model + self.ollama_url = "http://localhost:11434" + self.conversation_history = [] + + def call_ollama(self, prompt: str, system_prompt: str = "") -> str: + """Ollamaにリクエストを送信""" + try: + full_prompt = f"{system_prompt}\n\nUser: {prompt}\nAssistant:" + + response = requests.post( + f"{self.ollama_url}/api/generate", + json={ + "model": self.model, + "prompt": full_prompt, + "stream": False, + "options": { + "temperature": 0.1, + "top_p": 0.95, + "num_predict": 2048, + "stop": ["User:", "Human:"] + } + }, + timeout=60 + ) + + if response.status_code == 200: + return response.json()["response"].strip() + else: + return f"Error: {response.status_code} - {response.text}" + + except Exception as e: + logger.error(f"Ollama call failed: {e}") + return f"Connection error: {e}" + + def get_project_context(self) -> str: + """現在のプロジェクトの情報を取得""" + context = [] + + # 現在のディレクトリ + cwd = os.getcwd() + context.append(f"Current directory: {cwd}") + + # Git情報 + try: + git_status = subprocess.run( + ["git", "status", "--porcelain"], + capture_output=True, text=True, cwd=cwd + ) + if git_status.returncode == 0: + context.append(f"Git status: {git_status.stdout.strip() or 'Clean'}") + except: + context.append("Git: Not a git repository") + + # ファイル構造(簡略版) + try: + files = [] + for item in Path(cwd).iterdir(): + if not item.name.startswith('.') and item.name not in ['node_modules', '__pycache__']: + if item.is_file(): + files.append(f"📄 {item.name}") + elif item.is_dir(): + files.append(f"📁 {item.name}/") + + if files: + context.append("Project files:") + context.extend(files[:10]) # 最初の10個まで + + except Exception as e: + context.append(f"File listing error: {e}") + + return "\n".join(context) + +# MCPサーバーのセットアップ +app = Server("local-llm-mcp") +llm = LocalLLMServer() + +@app.tool("code_with_local_llm") +async def code_with_local_llm( + task: str, + include_context: bool = True, + model_override: str = "" +) -> str: + """ + ローカルLLMでコーディングタスクを実行 + + Args: + task: 実行したいコーディングタスク + include_context: プロジェクトコンテキストを含めるか + model_override: 使用するモデルを一時的に変更 + """ + logger.info(f"Executing coding task: {task}") + + # モデルの一時変更 + original_model = llm.model + if model_override: + llm.model = model_override + + try: + # システムプロンプト構築 + system_prompt = """You are an expert coding assistant. You can: +1. Write, analyze, and debug code +2. Explain programming concepts +3. Suggest optimizations and best practices +4. Generate complete, working solutions + +Always provide: +- Clear, commented code +- Explanations of your approach +- Any assumptions you've made +- Suggestions for improvements + +Format your response clearly with code blocks and explanations.""" + + # プロジェクトコンテキストを追加 + if include_context: + context = llm.get_project_context() + system_prompt += f"\n\nCurrent project context:\n{context}" + + # LLMに送信 + response = llm.call_ollama(task, system_prompt) + + return response + + except Exception as e: + logger.error(f"Code generation failed: {e}") + return f"❌ Error in code generation: {e}" + finally: + # モデルを元に戻す + llm.model = original_model + +@app.tool("read_file_with_analysis") +async def read_file_with_analysis( + filepath: str, + analysis_type: str = "general" +) -> str: + """ + ファイルを読み込んでLLMで分析 + + Args: + filepath: 分析するファイルのパス + analysis_type: 分析タイプ (general, bugs, optimization, documentation) + """ + logger.info(f"Analyzing file: {filepath}") + + try: + # ファイル読み込み + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + content = f.read() + + # 分析タイプに応じたプロンプト + analysis_prompts = { + "general": "Analyze this code and provide a general overview, including its purpose, structure, and key components.", + "bugs": "Review this code for potential bugs, errors, or issues. Suggest fixes if found.", + "optimization": "Analyze this code for performance optimizations and suggest improvements.", + "documentation": "Generate comprehensive documentation for this code, including docstrings and comments." + } + + prompt = f"{analysis_prompts.get(analysis_type, analysis_prompts['general'])}\n\nFile: {filepath}\n\nCode:\n```\n{content}\n```" + + system_prompt = "You are a code review expert. Provide detailed, constructive analysis." + + response = llm.call_ollama(prompt, system_prompt) + + return f"📋 Analysis of {filepath}:\n\n{response}" + + except FileNotFoundError: + return f"❌ File not found: {filepath}" + except Exception as e: + logger.error(f"File analysis failed: {e}") + return f"❌ Error analyzing file: {e}" + +@app.tool("write_code_to_file") +async def write_code_to_file( + filepath: str, + task_description: str, + overwrite: bool = False +) -> str: + """ + LLMでコードを生成してファイルに書き込み + + Args: + filepath: 書き込み先のファイルパス + task_description: コード生成のタスク説明 + overwrite: 既存ファイルを上書きするか + """ + logger.info(f"Generating code for file: {filepath}") + + try: + # 既存ファイルのチェック + if os.path.exists(filepath) and not overwrite: + return f"❌ File already exists: {filepath}. Use overwrite=true to replace." + + # ファイル拡張子から言語を推定 + ext = Path(filepath).suffix.lower() + language_map = { + '.py': 'Python', + '.js': 'JavaScript', + '.ts': 'TypeScript', + '.java': 'Java', + '.cpp': 'C++', + '.c': 'C', + '.rs': 'Rust', + '.go': 'Go' + } + language = language_map.get(ext, 'appropriate language') + + # コード生成プロンプト + prompt = f"""Generate {language} code for the following task and save it to {filepath}: + +Task: {task_description} + +Requirements: +- Write complete, working code +- Include appropriate comments +- Follow best practices for {language} +- Make the code production-ready + +Return ONLY the code that should be saved to the file, without any additional explanation or markdown formatting.""" + + system_prompt = f"You are an expert {language} developer. Generate clean, efficient, well-documented code." + + # コード生成 + generated_code = llm.call_ollama(prompt, system_prompt) + + # ファイルに書き込み + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, 'w', encoding='utf-8') as f: + f.write(generated_code) + + return f"✅ Code generated and saved to {filepath}\n\nGenerated code:\n```{language.lower()}\n{generated_code}\n```" + + except Exception as e: + logger.error(f"Code generation and file writing failed: {e}") + return f"❌ Error: {e}" + +@app.tool("debug_with_llm") +async def debug_with_llm( + error_message: str, + code_context: str = "", + filepath: str = "" +) -> str: + """ + エラーメッセージとコードコンテキストでデバッグ支援 + + Args: + error_message: エラーメッセージ + code_context: エラーが発生したコードの部分 + filepath: エラーが発生したファイル(オプション) + """ + logger.info("Debugging with LLM") + + try: + # ファイルが指定されていれば読み込み + if filepath and os.path.exists(filepath): + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + file_content = f.read() + code_context = f"Full file content:\n{file_content}" + + prompt = f"""Help debug this error: + +Error message: {error_message} + +Code context: +{code_context} + +Please: +1. Explain what's causing the error +2. Provide a specific solution +3. Show the corrected code if applicable +4. Suggest ways to prevent similar errors""" + + system_prompt = "You are an expert debugger. Provide clear, actionable solutions to programming errors." + + response = llm.call_ollama(prompt, system_prompt) + + return f"🔧 Debug Analysis:\n\n{response}" + + except Exception as e: + logger.error(f"Debugging failed: {e}") + return f"❌ Debug error: {e}" + +@app.tool("explain_code") +async def explain_code( + code: str, + detail_level: str = "medium" +) -> str: + """ + コードの説明を生成 + + Args: + code: 説明するコード + detail_level: 説明の詳細レベル (basic, medium, detailed) + """ + logger.info("Explaining code with LLM") + + try: + detail_prompts = { + "basic": "Provide a brief, high-level explanation of what this code does.", + "medium": "Explain this code in detail, including its purpose, how it works, and key components.", + "detailed": "Provide a comprehensive explanation including line-by-line analysis, design patterns used, and potential improvements." + } + + prompt = f"{detail_prompts.get(detail_level, detail_prompts['medium'])}\n\nCode:\n```\n{code}\n```" + + system_prompt = "You are a programming instructor. Explain code clearly and educationally." + + response = llm.call_ollama(prompt, system_prompt) + + return f"📚 Code Explanation:\n\n{response}" + + except Exception as e: + logger.error(f"Code explanation failed: {e}") + return f"❌ Explanation error: {e}" + +@app.tool("switch_model") +async def switch_model(model_name: str) -> str: + """ + 使用するローカルLLMモデルを切り替え + + Args: + model_name: 切り替え先のモデル名 + """ + logger.info(f"Switching model to: {model_name}") + + try: + # モデルの存在確認 + response = requests.get(f"{llm.ollama_url}/api/tags") + if response.status_code == 200: + models = response.json().get("models", []) + available_models = [model["name"] for model in models] + + if model_name in available_models: + llm.model = model_name + return f"✅ Model switched to: {model_name}" + else: + return f"❌ Model not found. Available models: {', '.join(available_models)}" + else: + return "❌ Cannot check available models" + + except Exception as e: + logger.error(f"Model switching failed: {e}") + return f"❌ Error switching model: {e}" + +async def main(): + """MCPサーバーを起動""" + logger.info("Starting Local LLM MCP Server...") + logger.info(f"Using model: {llm.model}") + + # Ollamaの接続確認 + try: + response = requests.get(f"{llm.ollama_url}/api/tags", timeout=5) + if response.status_code == 200: + logger.info("✅ Ollama connection successful") + else: + logger.warning("⚠️ Ollama connection issue") + except Exception as e: + logger.error(f"❌ Cannot connect to Ollama: {e}") + + # サーバー起動 + await app.run() + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/docs/mcp-setup-guide.md b/docs/mcp-setup-guide.md new file mode 100644 index 0000000..2491d42 --- /dev/null +++ b/docs/mcp-setup-guide.md @@ -0,0 +1,244 @@ +# MCP Server セットアップガイド +Claude Code + ローカルLLM統合環境 + +## 🚀 セットアップ手順 + +### 1. 依存関係のインストール + +```bash +# 仮想環境作成 +python -m venv mcp-env +mcp-env\Scripts\activate # Windows +# source mcp-env/bin/activate # Linux/Mac + +# 必要なパッケージをインストール +pip install mcp requests pathlib asyncio +``` + +### 2. Ollamaのセットアップ + +```bash +# Ollamaのインストール(https://ollama.com) +# Windows: インストーラーをダウンロード +# Linux: curl -fsSL https://ollama.com/install.sh | sh + +# Qwen2.5-Coderモデルをダウンロード +ollama pull qwen2.5-coder:14b-instruct-q4_K_M + +# Ollamaサーバー起動確認 +ollama serve +``` + +### 3. Claude Desktop設定 + +#### claude_desktop_config.json の作成 +**Windows**: `%APPDATA%\Claude\claude_desktop_config.json` +**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +**Linux**: `~/.config/claude/claude_desktop_config.json` + +```json +{ + "mcpServers": { + "local-llm": { + "command": "python", + "args": ["/path/to/your/local_llm_mcp_server.py"], + "env": { + "OLLAMA_URL": "http://localhost:11434", + "DEFAULT_MODEL": "qwen2.5-coder:14b-instruct-q4_K_M" + } + } + } +} +``` + +### 4. Claude Code設定 + +```bash +# Claude Codeをインストール(既にインストール済みの場合はスキップ) +# 公式サイトからダウンロード + +# MCP サーバーを追加 +claude mcp add local-llm + +# または手動で設定ファイルを編集 +# ~/.config/claude-code/config.json +``` + +## 🎯 使用方法 + +### Claude Codeから使用 + +```bash +# Claude Codeを起動 +claude code + +# プロンプト例: +# "Use local LLM to implement a Python quicksort function" +# "Analyze main.py with local model for potential bugs" +# "Generate a REST API using the local coding model" +``` + +### 利用可能なツール + +1. **code_with_local_llm** + - タスク: `"Implement a binary search tree in Python"` + - プロジェクトコンテキスト含む: `true` + +2. **read_file_with_analysis** + - ファイルパス: `"src/main.py"` + - 分析タイプ: `"bugs"` | `"optimization"` | `"documentation"` + +3. **write_code_to_file** + - ファイルパス: `"utils/helpers.py"` + - タスク説明: `"Create utility functions for data processing"` + +4. **debug_with_llm** + - エラーメッセージ: `"IndexError: list index out of range"` + - コードコンテキスト: 該当するコード部分 + +5. **explain_code** + - コード: 解説したいコード + - 詳細レベル: `"basic"` | `"medium"` | `"detailed"` + +6. **switch_model** + - モデル名: `"qwen2.5-coder:7b-instruct"` + +## 🔧 カスタマイズ + +### モデル設定の変更 + +```python +# デフォルトモデルの変更 +llm = LocalLLMServer("deepseek-coder:6.7b-instruct-q4_K_M") + +# 複数モデル対応 +models = { + "coding": "qwen2.5-coder:14b-instruct-q4_K_M", + "general": "qwen2.5:14b-instruct-q4_K_M", + "light": "mistral-nemo:12b-instruct-q5_K_M" +} +``` + +### プロンプトのカスタマイズ + +```python +# システムプロンプトの調整 +system_prompt = """You are an expert coding assistant specialized in: +- Clean, efficient code generation +- Best practices and design patterns +- Security-conscious development +- Performance optimization + +Always provide: +- Working, tested code +- Comprehensive comments +- Error handling +- Performance considerations""" +``` + +## 🛠️ トラブルシューティング + +### よくある問題 + +1. **MCPサーバーが起動しない** +```bash +# ログ確認 +tail -f ~/.config/claude-desktop/logs/mcp.log + +# Pythonパスの確認 +which python +``` + +2. **Ollamaに接続できない** +```bash +# Ollamaの状態確認 +ollama ps +curl http://localhost:11434/api/tags + +# サービス再起動 +ollama serve +``` + +3. **モデルが見つからない** +```bash +# インストール済みモデル確認 +ollama list + +# モデルの再ダウンロード +ollama pull qwen2.5-coder:14b-instruct-q4_K_M +``` + +### パフォーマンス最適化 + +```python +# Ollamaの設定調整 +{ + "temperature": 0.1, # 一貫性重視 + "top_p": 0.95, # 品質バランス + "num_predict": 2048, # 応答長制限 + "num_ctx": 4096 # コンテキスト長 +} +``` + +### セキュリティ設定 + +```python +# ファイルアクセス制限 +ALLOWED_DIRECTORIES = [ + os.getcwd(), + os.path.expanduser("~/projects") +] + +# 実行可能コマンドの制限 +ALLOWED_COMMANDS = ["git", "python", "node", "npm"] +``` + +## 🎉 使用例 + +### 1. 新機能の実装 +``` +Claude Code Prompt: +"Use local LLM to create a user authentication system with JWT tokens in Python Flask" + +→ MCPサーバーがローカルLLMでコード生成 +→ ファイルに自動保存 +→ Claude Codeが結果を表示 +``` + +### 2. バグ修正 +``` +Claude Code Prompt: +"Analyze app.py for bugs and fix them using the local model" + +→ ファイル読み込み + LLM分析 +→ 修正版コードを生成 +→ バックアップ作成後に上書き +``` + +### 3. コードレビュー +``` +Claude Code Prompt: +"Review the entire codebase with local LLM and provide optimization suggestions" + +→ プロジェクト全体をスキャン +→ 各ファイルをLLMで分析 +→ 改善提案をレポート形式で生成 +``` + +## 📊 パフォーマンス比較 + +| 機能 | Claude Code (公式) | ローカルLLM + MCP | +|------|-------------------|-------------------| +| 応答速度 | ⚡ 高速 | 🟡 中程度 | +| プライバシー | 🟡 クラウド | 🟢 完全ローカル | +| カスタマイズ | 🟡 限定的 | 🟢 完全自由 | +| コスト | 💰 従量課金 | 🟢 無料 | +| 専門性 | 🟢 汎用的 | 🟢 カスタマイズ可能 | + +## 🔄 今後の拡張 + +- [ ] 複数LLMモデルの同時利用 +- [ ] コード実行環境の統合 +- [ ] Gitワークフローの自動化 +- [ ] プロジェクトテンプレートの生成 +- [ ] 自動テスト生成機能 \ No newline at end of file