VSCode Copilot と ChatGPT を併用して開発した「Ollama Proxy」で多彩な LLM バックエンドを一元化する

### 概要

GWにAIコーディングを楽しんでみました！
現場では OpenAI、Google Gemini、Ollama など複数の大型言語モデル（LLM）を用途に応じて使い分けたいケースが増えています。しかし、各サービスで API 仕様が異なるため、運用コストが増大しがちです。

本記事では、VSCode Copilot（Claude 3.7 Sonnet モード）と ChatGPT を併用しつつ開発した「Ollama Proxy」という統合プロキシサーバーの設計・実装手順を紹介します。これにより、OpenAI 互換 API と Ollama プロトコルを両対応させ、開発者は単一のエンドポイントで複数バックエンドを透過的に利用可能になります。

読者が得られる知見：
- Copilot（Claude Sonnet）と ChatGPT での分担開発ワークフロー
- LLM バックエンドの自動検出・モデルマッピング手法
- API ルーティングとストリーミング対応の実装ポイント

将来的な構想：ローカルLLMをOllamaで動作させ、生成された回答の信頼度が一定以下の場合にOpenAIなどの外部LLMへ自動エスカレーションする機能を実装予定

### 前提知識・環境

- プログラミング言語: TypeScript（Node.js 14+）
- 動作環境: VSCode + Copilot
- 使用 AI: Copilot（Claude 3.7 Sonnet モード）、ChatGPT（gpt-4-turbo）
- 必要な API キー: OpenAI、Google Cloud Access Token
- ローカル実行: Ollama（v0.x）

---

### セクション構成

1. **開発環境セットアップ**
2. **プロキシ設計とルーティング層**
3. **バックエンドプラグイン実装**
4. **Copilot と ChatGPT の分担開発フロー**
5. **ストリーミング・モデルマッピングの実装ポイント**
6. **動作検証とデモ**
7. **まとめと今後の展望**

---

## 1. 開発環境セットアップ

```bash
# リポジトリをクローン
git clone https://github.com/yourusername/ollama-proxy.git
cd ollama-proxy

# パッケージインストール
npm install
```

`.env` ファイルを作成し、下記を設定：

```dotenv
OPENAI_API_KEY=sk-...
GCP_ACCESS_TOKEN=ya29....
OLLAMA_BASE_URL=http://localhost:11434
PORT=11434
```

VSCode で Copilot の設定を確認し、Claude Sonnet モードを有効化しておきます。

---

## 2. プロキシ設計とルーティング層

メインとなる `src/index.ts` では Express を使用し、以下の２種類の API パスを定義：

- `/v1/*` → OpenAI 互換ハンドラーへルーティング
- `/api/*` → Ollama 互換ハンドラーへルーティング

```ts
app.use('/v1', openaiRouter);
app.use('/api', ollamaRouter);
```  

Copilot でルーティングテンプレートを生成し、Sonnet が詰まった部分は ChatGPT に問い合わせて修正。例えば、パスパラメータの扱いについては ChatGPT から以下の助言を得ました。

> Express の `mergeParams` オプションを有効にすると、ネストされたルーター間でパラメータを共有できます。

---

## 3. バックエンドプラグイン実装

`src/backends/` フォルダに各バックエンドクラスを配置。共通の抽象クラス `LLMBackend` を定義し、以下を実装します。

```ts
abstract class LLMBackend {
  abstract listModels(): Promise<string[]>;
  abstract chat(params: ChatParams): AsyncIterable<string>;
}
```

- `openai.ts`: OpenAI の `/chat/completions` ラッパー
- `gemini.ts`: Google Gemini の認証とエンドポイント呼び出し
- `ollama.ts`: ローカル Ollama サーバーへの HTTP リクエスト

Copilot に初期スケルトンを生成させ、認証ヘッダーやエラー処理は ChatGPT の助言を元に補完しました。

---

## 4. Copilot と ChatGPT の分担開発フロー

1. **骨組み生成**: Copilot （Claude Sonnet）に関数・クラスの雛形を提案させる
2. **具体的な実装**: Sonnet が詰まった箇所（例：ストリーミングレスポンスの AsyncIterator化）を ChatGPT へ質問し、サンプルコードを取得
3. **検証と修正**: 単体テストを実行して失敗箇所を洗い出し、Copilot と ChatGPT を行き来しながら修正

このハイブリッド手法で、開発効率と精度を両立させることができました。

---

## 5. ストリーミング・モデルマッピングの実装ポイント

- **モデル検出**: 起動時に全バックエンドの `listModels()` を呼び出し、利用可能モデルを取得
- **エイリアス生成**: 長いモデル名を `gpt4`、`gemini-pro`、`llama2` など簡易名にマッピング
- **ストリーミング**: HTTP レスポンスを Node.js の `ReadableStream` に変換し、クライアントへ順次送信

```ts
// 非同期イテレータを利用したストリーミング例
target.chat(params).on('data', chunk => res.write(chunk));
```

---

## 6. 動作検証とデモ

```bash
npm run dev
```

- `curl` による OpenAI 互換チャット実行例：
  ```bash
  curl -X POST http://localhost:11434/v1/chat/completions \
    -H 'Content-Type: application/json' \
    -d '{ "model": "gpt4", "messages": [{"role":"user","content":"Hello, world!"}] }'
  ```
- ローカル Ollama への同様のリクエスト：
  ```bash
  curl -X POST http://localhost:11434/api/chat \
    -d '{ "model": "llama2", "prompt": "こんにちは" }'
  ```

---

## 7. まとめと今後の展望

本記事では、VSCode Copilot（Claude Sonnet）と ChatGPT を併用しながら「Ollama Proxy」を開発した手順を解説しました。

- Copilot を骨組み生成、ChatGPT を問題解決に使い分けるハイブリッド開発
- 複数 LLM バックエンドの自動検出、モデルマッピング手法
- ストリーミング対応を含む API ルーティング実装ポイント

将来的な構想として、ローカルLLMをOllamaで動作させ、生成された回答の信頼度が一定以下の場合にOpenAIなどの外部LLMへ自動エスカレーションする機能を実装予定です。

## 8. githubリポジトリ

https://github.com/notfolder/ollama-proxy

## 9. この記事の作成過程

https://chatgpt.com/share/68104f82-ae1c-8009-ab7c-71586fb237a5