AI コード支援機能をサービス、ローカルで構築して比較してみる

## はじめに
サービスは「Amazon CodeWhisperer」、ローカル LLM は「Code Llama」を対象に AI コード支援機能を環境から構築し、両者のメリデメを比較してみます。

### 想定読者
以下の要望がある開発者向けです。ローカル LLM は Mac ユーザー向けに 
- 無料で手軽に AI によるコード支援を試してみたい
- ネットワークがない環境でもコード支援を動かしたい
- NVIDIA GPU がない Mac でも AI を動かしたい

### 選定理由
無料で手軽が大前提、かつコード支援を行う以上は VSCode 上で動作すること。
- **Amazon CodeWhisperer**
https://aws.amazon.com/jp/codewhisperer/
    - 大規模事業者サービスであること
        - サービス基盤の堅牢性、ネットワーク応答性、サービスの長期継続性を見込めるため
	- 商用利用可能
	- データ収集のオプトアウト
- **Code Llama**
https://about.fb.com/news/2023/08/code-llama-ai-for-coding/
	- ChatGPT 3.5 同等性能の LLM であること
    	- それ以下の場合、基本的に ChatGPT を使用した方が良いため
	- 商用利用可能

### 検証環境
- Mac mini 2023: Apple M2 Pro, 16GB RAM

## Amazon CodeWhisperer について
### 特徴
- AWS サービスへの最適化
    - 基本的に Amazon のコードで学習しているため
    - AWS のベストプラクティスに基づく提案
- セキュリティスキャン
    - 対象は Java、JavaScript、Python のコード
    - CodeWhisperer の提案かどうかに関わりなくチェックしてくれる
    - 無料版は月 50 回まで
- リファレンストラッカー
    - 一部オープンソースを元に CodeWhisperer が学習している場合に、提案コードのライセンスなどの付属情報を確認することができる
    - 筆者はまだ提案されたコードで見たことがないが、商用コードで使用する場合に便利そう

他機能の概要は公式を参照

https://aws.amazon.com/jp/codewhisperer/features/
## Code Llama について
### 特徴
- Meta 社の Llama-2 コード生成特化 LLM
    - ChatGPT 3.5 同等の性能
        - 34B パラメータ利用時。今回は環境制約もあり 13B の 4bit 量子化モデルを使用。そのためパフォーマンスは良くても 90% 程度
- 最大 100,000 トークンの入力に対応
    - プログラムコンテキストの詳細な把握が可能

https://ai.meta.com/blog/code-llama-large-language-model-coding/

## サービス利用環境のセットアップ 〜 デモ
**構成図**
<img width="540" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/39b61f40-d4e8-e36f-260a-c02b9e2a9c7c.png">

**前提**
- VSCode は最新版がインストール済み
- AWS Builder ID 登録時に使用可能なメールアドレス
### 手順
#### 1. AWS Toolkit のインストールと設定
- 拡張機能からインストールする
![awstoolkit1rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/44be0e76-e9ed-da98-4e08-6494dd781235.png)

- AWS Toolkit ウィンドウの Developer Tools > CodeWhisperer > Start をクリックし、AWS Builder ID の「Sign up or Sign in」から Builder ID の登録処理を行う
![awstoolkit2rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/0f24261d-6e3e-b5c6-00a4-08ec16973077.png)

- メアドとパスワードを登録後に認証コードがメールに届くため、入力してアクティベーションする。登録後に VSCode との接続が切れた場合は、次は Sign in するだけでよい
#### 2. データ収集のオプトアウト
- VSCode の設定から以下の AWS の設定を無効化する
![awstoolkit3rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/2ae97681-28a8-6ac6-7f72-a09fabdb4bc9.png)
![awstoolkit4rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/2b9ae1d8-6ed3-ef22-f7bc-b4a37fbf229d.png)

#### 3. 自動コード支援の停止
- 好みの問題だが、カーソル移動毎にコード支援されるのは逆に集中力を削がれるため、自動支援を停止する
![awstoolkit5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/6f3b97df-9f79-f177-ad16-3c30d358192f.png)
    - 「Pause Auto-Suggestions」をクリックする
    - 手動でコード支援を呼び出す場合は `Alt + c` or `Option + c`

### デモ
#### コード支援機能
- 100 より小さい素数を求める関数
    - 英語でコメントを入力する（日本語も可能だが回答精度が落ちるため）
![codewhis1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/a1fbc4b5-4ea9-7c31-9dc8-722e32790a41.png)
    - 次の行でコード支援を呼び出すと関数定義のコードが 1 行提案される
    - 左右のキーで異なる提案も選択可能（メニューが表示されるのは少し遅いが入力は可能）
![codewhis2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/6cfc3127-2f53-4c8a-650b-e37a052472c3.png)
    - 3 行目以降は関数ブロックの終了まで提案される
![codewhis3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/41e6caf7-3eba-e251-267e-f22308d3183b.png)
    - 最終的にはこのようなコードが提案される
![codewhis4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/667cb006-c3cd-fa17-81b5-019956e30e51.png)
    - `console.log`で上記の関数を出力すると妥当なコードであることが分かる
![codewhis5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/9c1845f2-b379-b256-9499-4ea70dee0cbc.png)

- S3 バケットからメタデータ一覧を取得する AWS Lambda 関数
    - 手順を明確にすればある程度複雑なコードも提案してくれる（動作検証済み）
![codewhis6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/299188c0-6dc6-ee56-b3d8-d2d831751bc9.png)
        - 「特定のバケット」をイベントから取得すると解釈している
        - `prefix`はフォルダまで指定する場合に必要
## ローカル環境のセットアップ 〜 デモ
**構成図**
<img width="540" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/8b42d2c2-f1e5-6059-0bb6-a87935e2b41c.png">

**前提**
- VSCode は最新版がインストール済み
- VSCode の LLM クライアントプラグインは「**Continue**」を利用する
    - 「Ollama」に対応しているため
    - ChatGPT 用クライアントとしてデザインされているため、コーディング中のシームレスなコード支援は行えないが、LLM クライアントとしてこなれているため
    - 設定が簡単（重要）
- LLM ランタイム環境として「**Ollama**」を利用する
    - 現状は Mac 版のみ（2023.09）
    - 早期プレビュー段階ではあるが、推論実行時のみのメモリ消費と軽快な動作のため
    - アイコンがかわいい（重要）
[<img width="60" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/c74577cb-63d7-39cf-93f7-4ffa14e03db6.png">](https://ollama.ai)
###	手順
#### 1. Ollama のインストール
https://ollama.ai
- 公式サイトからアプリをダウンロードして実行する
    - GUI はメニューバー上の終了コマンドのみ
    - バックグラウンド動作の許可が必要
    - アンインストールはアプリを削除し次のコマンドファイルを削除する
        - `/usr/local/bin/ollama`
        - コマンドのみであれば Homebrew 管理も可能
        https://formulae.brew.sh/formula/ollama#default


#### 2. Code Llama のインストール
- ターミナルを起動し、以下のコマンドを入力する
    - `ollama pull codellama:13b`（メモリ 16GB の場合）
    - `ollama pull codellama`（メモリ 8GB の場合）

他のオプションなどは公式 GitHub を参照

https://github.com/jmorganca/ollama
#### 3. Continue のインストールと設定
- 拡張機能からインストールする
![continue1rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/0bb5de5a-d671-36bb-a64a-f4b9cb2b92a7.png)

- Continue ウィンドウの「＋」をクリックする
![continue2rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/6e5567aa-21ff-0a22-e880-108e681ba411.png)

- リストから「Ollama」を選択する
![continue3rs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/b1c4b713-0c28-dfbe-36b7-d152f0659d53.png)


- 設定ファイルの編集画面が開くため、`model="codellama"`の箇所を Code Llama インストールに応じて修正する
    - `model="codellama:13b"`（メモリ 16GB の場合）
    - `model="codellama"`（メモリ 8GB の場合、そのまま）
        ```config.py
        ...
        config = ContinueConfig(
            allow_anonymous_telemetry=True,
            models=Models(
                default=Ollama(
                    context_length=2048,
                    model="codellama",
                    timeout=300,
                    prompt_templates={'edit': '
 Consider the following code:\n```\n{{code_to_edit}}\n```\nEdit the code to perfectly satisfy the following user request:\n{{user_input}}\nOutput nothing except for the code. No code block, no English explanation, no start/end tags.\n
'},
                    server_url="http://localhost:11434"
                ),
                unused=[]
            ),
            ...
        ```
    - ローカル動作ではあるが、`allow_anonymous_telemetry=True`の箇所を`False`に変更し、情報収集を許可しないようにしておく

### デモ
#### コード支援、コード説明機能
- 100 より小さい素数を求める関数
![ollama1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/f9f8fa75-02e3-d04b-b330-9cb166d25fe5.png)
    - `/edit`で始まるコード生成の指示を行うと元ファイルとの Diff でコードが提案され、Continue ウインドウ側ではコードの説明まで行ってくれる
    - `/`から始まる Continue コマンドには以下のようなものが用意されている
        - `/edit`: Edit code in the current file or the highlighted code
        - `/comment`: Write comments for the current file or highlighted code
        - `/test`: Write unit tests for the highlighted code
        - `/clear`: Clear step history
    - `Shift + ⌘ + Enter` で元のファイルに反映できる
![ollama4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/9e233827-e038-a1ae-2ee2-faa7c2f524d6.png)
        - `Shift + ⌘ + l` で Continue 対する入力を行えるのが便利 
![ollama3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/c46004fe-0c8c-26ec-ef44-7211b4269050.png)
    - `console.log`で上記の関数を出力すると妥当なコードであることが分かる
![ollama5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/fb65aa15-1a28-3a06-b9a3-e6a084c4c7fd.png)
- S3 バケットからメタデータ一覧を取得する AWS Lambda 関数
    - 手順を明確にすればある程度複雑なコードも提案してくれる（動作検証済み）
![ollama6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477594/442077e2-a937-7885-7fa4-bc12c54b1df3.png)
        - 12 行目の`listObjectsV2`関数で取得したオブジェクトのリストは`Contents`プロパティから取得する必要がある点が惜しい
            ```javascript:test2.js
            ...
            for (const obj of objects.Contents) {
            ...
            ```

## 両者のメリデメまとめ
一般的なコード生成の指示でもあり、提案コードに関しては大きな優劣は見られませんでした。ローカル環境でも AWS サービスと同等の機能を簡単に構築できるのは Meta 社やコミュニティのおかげと言えます。また、Continue を使用したローカル環境ではコードの説明まで行ってくれるため、提案コードを理解する点で便利に感じました。ローカル環境での構築の場合、使用する LLM やランタイム、拡張機能によっても機能が大きく変わってくるため、使用するプログラム言語に特化した環境にできるなど、自分用にカスタマイズできる優位性もありそうです。

|| サービス | ローカル |
|:-|:-:|:-:|
| コード支援機能 | ○ | ○ |
| 環境構築 | ○ | △ |
| スタンドアロン | × | ○ |
| カスタマイズ | × | ○ |