fix
This commit is contained in:
parent
a7b61fe07d
commit
7c3b05501f
@ -1,246 +0,0 @@
|
|||||||
# 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の性能も向上しているので、実用的な環境が構築できるよ〜✨
|
|
||||||
|
|
||||||
どの方法から試してみる?アイが一緒に設定をお手伝いするからね!
|
|
@ -1,338 +0,0 @@
|
|||||||
# ローカルClaude Code環境構築ガイド
|
|
||||||
RTX 4060 Ti + Qwen2.5-Coder + MCP Server
|
|
||||||
|
|
||||||
## 1. 必要なツールのインストール
|
|
||||||
|
|
||||||
### Ollamaのセットアップ
|
|
||||||
```bash
|
|
||||||
# Ollamaのインストール(Windows)
|
|
||||||
# https://ollama.com からダウンロード
|
|
||||||
|
|
||||||
# Qwen2.5-Coderモデルをダウンロード
|
|
||||||
ollama pull qwen2.5-coder:14b-instruct-q4_K_M
|
|
||||||
# または7Bバージョン(軽量)
|
|
||||||
ollama pull qwen2.5-coder:7b-instruct-q4_K_M
|
|
||||||
```
|
|
||||||
|
|
||||||
### Python環境の準備
|
|
||||||
```bash
|
|
||||||
# 仮想環境作成
|
|
||||||
python -m venv claude-code-env
|
|
||||||
claude-code-env\Scripts\activate # Windows
|
|
||||||
# source claude-code-env/bin/activate # Linux/Mac
|
|
||||||
|
|
||||||
# 必要なパッケージをインストール
|
|
||||||
pip install requests ollama-python rich click pathspec gitpython
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. メインスクリプトの作成
|
|
||||||
|
|
||||||
### claude_code.py
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import click
|
|
||||||
import requests
|
|
||||||
from pathlib import Path
|
|
||||||
from rich.console import Console
|
|
||||||
from rich.markdown import Markdown
|
|
||||||
from rich.syntax import Syntax
|
|
||||||
|
|
||||||
console = Console()
|
|
||||||
|
|
||||||
class LocalClaudeCode:
|
|
||||||
def __init__(self, model="qwen2.5-coder:14b-instruct-q4_K_M"):
|
|
||||||
self.model = model
|
|
||||||
self.ollama_url = "http://localhost:11434"
|
|
||||||
self.conversation_history = []
|
|
||||||
self.project_context = ""
|
|
||||||
|
|
||||||
def get_project_context(self):
|
|
||||||
"""プロジェクトのファイル構造とGitステータスを取得"""
|
|
||||||
context = []
|
|
||||||
|
|
||||||
# ファイル構造
|
|
||||||
try:
|
|
||||||
for root, dirs, files in os.walk("."):
|
|
||||||
# .git, node_modules, __pycache__ などを除外
|
|
||||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__pycache__']]
|
|
||||||
level = root.replace(".", "").count(os.sep)
|
|
||||||
indent = " " * 2 * level
|
|
||||||
context.append(f"{indent}{os.path.basename(root)}/")
|
|
||||||
subindent = " " * 2 * (level + 1)
|
|
||||||
for file in files:
|
|
||||||
if not file.startswith('.'):
|
|
||||||
context.append(f"{subindent}{file}")
|
|
||||||
except Exception as e:
|
|
||||||
context.append(f"Error reading directory: {e}")
|
|
||||||
|
|
||||||
return "\n".join(context[:50]) # 最初の50行まで
|
|
||||||
|
|
||||||
def read_file(self, filepath):
|
|
||||||
"""ファイルを読み込む"""
|
|
||||||
try:
|
|
||||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
|
||||||
return f.read()
|
|
||||||
except Exception as e:
|
|
||||||
return f"Error reading file: {e}"
|
|
||||||
|
|
||||||
def write_file(self, filepath, content):
|
|
||||||
"""ファイルに書き込む"""
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
||||||
with open(filepath, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(content)
|
|
||||||
return f"✅ File written: {filepath}"
|
|
||||||
except Exception as e:
|
|
||||||
return f"❌ Error writing file: {e}"
|
|
||||||
|
|
||||||
def call_ollama(self, prompt):
|
|
||||||
"""Ollamaにリクエストを送信"""
|
|
||||||
try:
|
|
||||||
response = requests.post(
|
|
||||||
f"{self.ollama_url}/api/generate",
|
|
||||||
json={
|
|
||||||
"model": self.model,
|
|
||||||
"prompt": prompt,
|
|
||||||
"stream": False,
|
|
||||||
"options": {
|
|
||||||
"temperature": 0.1,
|
|
||||||
"top_p": 0.95,
|
|
||||||
"num_predict": 2048
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()["response"]
|
|
||||||
else:
|
|
||||||
return f"Error: {response.status_code} - {response.text}"
|
|
||||||
except Exception as e:
|
|
||||||
return f"Connection error: {e}"
|
|
||||||
|
|
||||||
def process_command(self, user_input):
|
|
||||||
"""ユーザーの指示を処理"""
|
|
||||||
# プロジェクトコンテキストを更新
|
|
||||||
self.project_context = self.get_project_context()
|
|
||||||
|
|
||||||
# システムプロンプト
|
|
||||||
system_prompt = f"""You are an expert coding assistant. You can:
|
|
||||||
1. Read and analyze code files
|
|
||||||
2. Write and modify files
|
|
||||||
3. Explain code and provide suggestions
|
|
||||||
4. Debug and fix issues
|
|
||||||
|
|
||||||
Current project structure:
|
|
||||||
{self.project_context}
|
|
||||||
|
|
||||||
When you need to read a file, respond with: READ_FILE: <filepath>
|
|
||||||
When you need to write a file, respond with: WRITE_FILE: <filepath>
|
|
||||||
```
|
|
||||||
<file content>
|
|
||||||
```
|
|
||||||
|
|
||||||
User request: {user_input}
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.call_ollama(system_prompt)
|
|
||||||
return self.process_response(response)
|
|
||||||
|
|
||||||
def process_response(self, response):
|
|
||||||
"""レスポンスを処理してファイル操作を実行"""
|
|
||||||
lines = response.split('\n')
|
|
||||||
processed_response = []
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(lines):
|
|
||||||
line = lines[i].strip()
|
|
||||||
|
|
||||||
if line.startswith("READ_FILE:"):
|
|
||||||
filepath = line.replace("READ_FILE:", "").strip()
|
|
||||||
content = self.read_file(filepath)
|
|
||||||
processed_response.append(f"📁 Reading {filepath}:")
|
|
||||||
processed_response.append(f"```\n{content}\n```")
|
|
||||||
|
|
||||||
elif line.startswith("WRITE_FILE:"):
|
|
||||||
filepath = line.replace("WRITE_FILE:", "").strip()
|
|
||||||
i += 1
|
|
||||||
# 次の```まで読み込む
|
|
||||||
if i < len(lines) and lines[i].strip() == "```":
|
|
||||||
i += 1
|
|
||||||
file_content = []
|
|
||||||
while i < len(lines) and lines[i].strip() != "```":
|
|
||||||
file_content.append(lines[i])
|
|
||||||
i += 1
|
|
||||||
content = '\n'.join(file_content)
|
|
||||||
result = self.write_file(filepath, content)
|
|
||||||
processed_response.append(result)
|
|
||||||
else:
|
|
||||||
processed_response.append("❌ Invalid WRITE_FILE format")
|
|
||||||
else:
|
|
||||||
processed_response.append(line)
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return '\n'.join(processed_response)
|
|
||||||
|
|
||||||
@click.command()
|
|
||||||
@click.option('--model', default="qwen2.5-coder:14b-instruct-q4_K_M", help='Ollama model to use')
|
|
||||||
@click.option('--interactive', '-i', is_flag=True, help='Interactive mode')
|
|
||||||
@click.argument('prompt', required=False)
|
|
||||||
def main(model, interactive, prompt):
|
|
||||||
"""Local Claude Code - AI Coding Assistant"""
|
|
||||||
|
|
||||||
claude = LocalClaudeCode(model)
|
|
||||||
|
|
||||||
if interactive or not prompt:
|
|
||||||
console.print("[bold green]🤖 Local Claude Code Assistant[/bold green]")
|
|
||||||
console.print(f"Model: {model}")
|
|
||||||
console.print("Type 'quit' to exit\n")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
user_input = input("👤 You: ").strip()
|
|
||||||
if user_input.lower() in ['quit', 'exit', 'q']:
|
|
||||||
break
|
|
||||||
|
|
||||||
if user_input:
|
|
||||||
console.print("\n🤖 Assistant:")
|
|
||||||
response = claude.process_command(user_input)
|
|
||||||
console.print(Markdown(response))
|
|
||||||
console.print()
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
console.print("\n👋 Goodbye!")
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
response = claude.process_command(prompt)
|
|
||||||
console.print(response)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. MCP Server統合
|
|
||||||
|
|
||||||
### mcp_integration.py
|
|
||||||
```python
|
|
||||||
import json
|
|
||||||
import subprocess
|
|
||||||
from typing import Dict, List, Any
|
|
||||||
|
|
||||||
class MCPIntegration:
|
|
||||||
def __init__(self):
|
|
||||||
self.servers = {}
|
|
||||||
|
|
||||||
def add_server(self, name: str, command: List[str], args: Dict[str, Any] = None):
|
|
||||||
"""MCPサーバーを追加"""
|
|
||||||
self.servers[name] = {
|
|
||||||
"command": command,
|
|
||||||
"args": args or {}
|
|
||||||
}
|
|
||||||
|
|
||||||
def call_mcp_tool(self, server_name: str, tool_name: str, arguments: Dict[str, Any]):
|
|
||||||
"""MCPツールを呼び出す"""
|
|
||||||
if server_name not in self.servers:
|
|
||||||
return {"error": f"Server {server_name} not found"}
|
|
||||||
|
|
||||||
try:
|
|
||||||
# MCPサーバーとの通信(JSONRPCベース)
|
|
||||||
request = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": 1,
|
|
||||||
"method": f"tools/{tool_name}",
|
|
||||||
"params": {"arguments": arguments}
|
|
||||||
}
|
|
||||||
|
|
||||||
process = subprocess.Popen(
|
|
||||||
self.servers[server_name]["command"],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
text=True
|
|
||||||
)
|
|
||||||
|
|
||||||
stdout, stderr = process.communicate(json.dumps(request))
|
|
||||||
|
|
||||||
if stderr:
|
|
||||||
return {"error": stderr}
|
|
||||||
|
|
||||||
return json.loads(stdout)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return {"error": str(e)}
|
|
||||||
|
|
||||||
# 使用例
|
|
||||||
mcp = MCPIntegration()
|
|
||||||
mcp.add_server("filesystem", ["python", "-m", "mcp_server_filesystem"])
|
|
||||||
mcp.add_server("git", ["python", "-m", "mcp_server_git"])
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. 設定ファイル
|
|
||||||
|
|
||||||
### config.json
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"model": "qwen2.5-coder:14b-instruct-q4_K_M",
|
|
||||||
"ollama_url": "http://localhost:11434",
|
|
||||||
"mcp_servers": {
|
|
||||||
"filesystem": {
|
|
||||||
"command": ["python", "-m", "mcp_server_filesystem"],
|
|
||||||
"args": {"allowed_directories": ["."]}
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"command": ["python", "-m", "mcp_server_git"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"excluded_files": [".git", "node_modules", "__pycache__", "*.pyc"],
|
|
||||||
"max_file_size": 1048576
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 5. 使用方法
|
|
||||||
|
|
||||||
### 基本的な使い方
|
|
||||||
```bash
|
|
||||||
# インタラクティブモード
|
|
||||||
python claude_code.py -i
|
|
||||||
|
|
||||||
# 単発コマンド
|
|
||||||
python claude_code.py "Pythonでクイックソートを実装して"
|
|
||||||
|
|
||||||
# 特定のモデルを使用
|
|
||||||
python claude_code.py --model qwen2.5-coder:7b-instruct-q4_K_M -i
|
|
||||||
```
|
|
||||||
|
|
||||||
### MCP Serverのセットアップ
|
|
||||||
```bash
|
|
||||||
# 必要なMCPサーバーをインストール
|
|
||||||
pip install mcp-server-git mcp-server-filesystem
|
|
||||||
|
|
||||||
# 設定ファイルを編集してMCPサーバーを有効化
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. 機能一覧
|
|
||||||
|
|
||||||
- ✅ ローカルLLMとの対話
|
|
||||||
- ✅ ファイル読み書き
|
|
||||||
- ✅ プロジェクト構造の自動認識
|
|
||||||
- ✅ Gitステータス表示
|
|
||||||
- ✅ シンタックスハイライト
|
|
||||||
- ✅ MCP Server統合(オプション)
|
|
||||||
- ✅ 設定ファイル対応
|
|
||||||
|
|
||||||
## 7. トラブルシューティング
|
|
||||||
|
|
||||||
### よくある問題
|
|
||||||
1. **Ollamaが起動しない**: `ollama serve` でサーバーを起動
|
|
||||||
2. **モデルが見つからない**: `ollama list` でインストール済みモデルを確認
|
|
||||||
3. **メモリ不足**: より軽量な7Bモデルを使用
|
|
||||||
4. **ファイル権限エラー**: 実行権限を確認
|
|
||||||
|
|
||||||
### パフォーマンス最適化
|
|
||||||
- GPU使用を確認: `nvidia-smi` でVRAM使用量をチェック
|
|
||||||
- モデルサイズの調整: Q4_K_M → Q4_K_S で軽量化
|
|
||||||
- コンテキスト長を調整して応答速度を向上
|
|
||||||
|
|
||||||
重い場合は7Bバージョン(qwen2.5-coder:7b-instruct-q4_K_M)に変更。
|
|
@ -1,133 +0,0 @@
|
|||||||
# おすすめローカルLLM(RTX 4060 Ti 16GB対応)
|
|
||||||
|
|
||||||
RTX 4060 Ti 16GBにぴったりのローカルLLMをご紹介します!
|
|
||||||
|
|
||||||
## 🏆 アイのおすすめトップモデル(2025年版)
|
|
||||||
|
|
||||||
### コーディング特化
|
|
||||||
|
|
||||||
#### 1. **Qwen2.5-Coder-14B-Instruct** 🥇
|
|
||||||
- **特徴**: コーディングで最強クラス!
|
|
||||||
- **推奨量子化**: Q4_K_M(約8GB VRAM使用)
|
|
||||||
- **用途**: プログラミング、コード生成・デバッグ
|
|
||||||
- **お兄ちゃんのGPUに最適**
|
|
||||||
|
|
||||||
#### 2. **DeepSeek-Coder-V2-Lite-16B**
|
|
||||||
- **特徴**: コーディングと数学に特に強い
|
|
||||||
- **推奨量子化**: Q4_K_M(約9GB VRAM使用)
|
|
||||||
- **用途**: 複雑なアルゴリズム、数学的計算
|
|
||||||
|
|
||||||
### 汎用・バランス型
|
|
||||||
|
|
||||||
#### 3. **Qwen2.5-14B-Instruct** 🥈
|
|
||||||
- **特徴**: 日本語も得意な万能モデル
|
|
||||||
- **推奨量子化**: Q4_K_M(約8GB VRAM使用)
|
|
||||||
- **用途**: 汎用タスク、日本語対話
|
|
||||||
|
|
||||||
#### 4. **Llama 3.3-70B-Instruct(量子化)**
|
|
||||||
- **特徴**: 405Bモデルに匹敵する性能
|
|
||||||
- **推奨量子化**: Q3_K_S(約14GB VRAM使用)
|
|
||||||
- **用途**: 高度な推論タスク
|
|
||||||
- **注意**: ギリギリ動作、他のアプリケーション注意
|
|
||||||
|
|
||||||
#### 5. **Mistral-Nemo-12B-Instruct**
|
|
||||||
- **特徴**: バランスが良くて軽量
|
|
||||||
- **推奨量子化**: Q5_K_M(約7GB VRAM使用)
|
|
||||||
- **用途**: 日常的なタスク、軽快な動作
|
|
||||||
|
|
||||||
### 最新・注目株
|
|
||||||
|
|
||||||
#### 6. **Phi-4-14B**
|
|
||||||
- **特徴**: Microsoftの最新モデル
|
|
||||||
- **推奨量子化**: Q4_K_M(約8GB VRAM使用)
|
|
||||||
- **用途**: 最新技術の体験
|
|
||||||
|
|
||||||
#### 7. **DeepSeek-R1-Distill-Qwen-14B**
|
|
||||||
- **特徴**: 推論特化の新しいモデル、OpenAI-o1に匹敵
|
|
||||||
- **推奨量子化**: Q4_K_M(約8GB VRAM使用)
|
|
||||||
- **用途**: 複雑な推論タスク
|
|
||||||
|
|
||||||
## RTX 4060 Ti 16GB 推奨設定
|
|
||||||
|
|
||||||
| モデルサイズ | 推奨量子化 | VRAM使用量 | 実行速度 | 品質 |
|
|
||||||
|-------------|-----------|-----------|---------|------|
|
|
||||||
| 7B | Q5_K_M | ~5GB | 🟢 速い | 良い |
|
|
||||||
| 14B | Q4_K_M | ~8GB | 🟡 普通 | 高い |
|
|
||||||
| 22B | Q4_K_S | ~12GB | 🟠 やや遅い | 高い |
|
|
||||||
| 34B | Q3_K_S | ~15GB | 🔴 遅い | 最高 |
|
|
||||||
|
|
||||||
## アイの一番のおすすめ
|
|
||||||
|
|
||||||
### 用途別推奨モデル
|
|
||||||
|
|
||||||
- **🔧 コーディング重視**: Qwen2.5-Coder-14B Q4_K_M
|
|
||||||
- **💬 汎用対話**: Qwen2.5-14B-Instruct Q4_K_M
|
|
||||||
- **⚡ 軽さ重視**: Mistral-Nemo-12B Q5_K_M
|
|
||||||
- **🧠 推論重視**: DeepSeek-R1-Distill-Qwen-14B Q4_K_M
|
|
||||||
|
|
||||||
## インストール方法
|
|
||||||
|
|
||||||
### Ollamaを使用した場合
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# コーディング特化
|
|
||||||
ollama pull qwen2.5-coder:14b-instruct-q4_K_M
|
|
||||||
|
|
||||||
# 汎用モデル
|
|
||||||
ollama pull qwen2.5:14b-instruct-q4_K_M
|
|
||||||
|
|
||||||
# 軽量モデル
|
|
||||||
ollama pull mistral-nemo:12b-instruct-q5_K_M
|
|
||||||
|
|
||||||
# 最新推論モデル
|
|
||||||
ollama pull deepseek-r1-distill-qwen:14b-q4_K_M
|
|
||||||
```
|
|
||||||
|
|
||||||
### 使用例
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# インタラクティブ使用
|
|
||||||
ollama run qwen2.5-coder:14b-instruct-q4_K_M
|
|
||||||
|
|
||||||
# APIとして使用
|
|
||||||
curl http://localhost:11434/api/generate -d '{
|
|
||||||
"model": "qwen2.5-coder:14b-instruct-q4_K_M",
|
|
||||||
"prompt": "Pythonでクイックソートを実装して"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## パフォーマンスのコツ
|
|
||||||
|
|
||||||
### VRAM最適化
|
|
||||||
- **16GB VRAM**: 14Bモデル Q4_K_M が最適
|
|
||||||
- **余裕がある場合**: Q5_K_M で品質向上
|
|
||||||
- **複数モデル併用**: 7Bモデルと組み合わせ
|
|
||||||
|
|
||||||
### 速度向上
|
|
||||||
- **GPU使用確認**: `nvidia-smi` でVRAM使用量チェック
|
|
||||||
- **量子化レベル調整**: Q4_K_M → Q4_K_S で軽量化
|
|
||||||
- **コンテキスト長調整**: 応答速度とバランス
|
|
||||||
|
|
||||||
## トラブルシューティング
|
|
||||||
|
|
||||||
### よくある問題
|
|
||||||
|
|
||||||
1. **VRAM不足**
|
|
||||||
- より軽い量子化(Q4_K_S, Q3_K_M)を試す
|
|
||||||
- モデルサイズを下げる(14B → 7B)
|
|
||||||
|
|
||||||
2. **動作が遅い**
|
|
||||||
- GPU使用を確認
|
|
||||||
- バックグラウンドアプリケーションを終了
|
|
||||||
|
|
||||||
3. **品質が低い**
|
|
||||||
- より大きなモデルサイズを試す
|
|
||||||
- 高品質量子化(Q5_K_M, Q8_0)を使用
|
|
||||||
|
|
||||||
## 結論
|
|
||||||
|
|
||||||
RTX 4060 Ti 16GBなら、高品質量子化(Q5_K_M, Q8_0)でも快適に動作します。用途に応じてモデルを選択し、最適な設定で楽しいローカルLLM体験をお楽しみください!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*このガイドは2025年5月時点の情報に基づいています。新しいモデルが随時リリースされるため、最新情報もチェックしてくださいね〜♪*
|
|
@ -1,392 +0,0 @@
|
|||||||
#!/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())
|
|
@ -1,244 +0,0 @@
|
|||||||
# 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ワークフローの自動化
|
|
||||||
- [ ] プロジェクトテンプレートの生成
|
|
||||||
- [ ] 自動テスト生成機能
|
|
Loading…
x
Reference in New Issue
Block a user