ChatGPT

ChatGPTとVSCodeの連携方法とその使用例:開発効率を飛躍的にアップさせる

こんにちは、石原と申します。

今回のブログが初投稿となります。最近注目を集めているChatGPTと普段使いしているエディタのVSCodeを連携させることで、コード開発の効率が大幅にアップしたので、その方法を紹介していきたいと思います。流行りのChatGPTに関してn番煎じの記事ではありますが、初めて触れる方でも導入できるよう、わかりやすく解説しますので、ぜひご覧ください!

ChatGPTとは

「ChatGPTとは、OpenAIが開発した人工知能チャットボットの名称です。このチャットボットは、自然言語処理技術を用いて、人間との対話を模倣することができます。

ChatGPTは、大量のテキストデータを学習することで、人間のような応答を生成することが可能です。そのため、一般的な質問や会話に対して、適切な回答を返すことができます。

また、ChatGPTは、様々な分野において活用されています。例えば、カスタマーサポートや教育分野において、人手不足の解消や効率化に貢献しています。

今後も、ChatGPTの技術は進化し続け、より高度な対話システムの実現に向けて、研究が進められていくことが期待されています。」

以上はChatGPTによって作成された文章になります。

ChatGPTは様々な分野への応用が期待されている注目の技術です。しかし、問題点もいくつか挙げられています。必ずしも正確な応答をするわけではないことや、多くの仕事をAIによって奪われてしまうことへの危機感、AIの学習やAIの生成物に対する著作権の問題、入力内容の情報漏洩に関するセキュリティ課題などが挙げられています。

特に、法人組織がChatGPTを利用する上では機密情報の取り扱いに注意する必要があり、従業員へChatGPTの利用を禁止している企業も増えています。実際にSamusungで情報漏洩が発生したという事例も確認されています。

なお、今回紹介する拡張機能ではChatGPTのAPIを用いています。OpenAIのAPIのデータ取り扱いポリシーによると、APIを介して送信されたデータは原則、モデルのトレーニングや改善には使われないとされていますので、心配する必要はないようです。また、Web版のChatGPTでもオプトアウト申請が可能なので法人組織の方はこちらもチェックしておいてください。

ChatGPTとVSCodeの連携

VSCodeの拡張機能マーケットプレイスにはChatGPTをサポートしたものがいくつか存在しています。元々gencay.vscode-chatgptという拡張機能があったようですが、自動ログイン機能が利用規約に抵触していたようで、こちらは現在開発中止になっています。

今回はgencay.vscode-chatgptの開発者に代替として挙げられているgenieai.chatgpt-vscodeを使います。こちらは現時点(2023/04/05)で最新のモデルであるGPT-4にも対応しています。

導入

それではgenieai.chatgpt-vscodeの導入方法について説明していきます。

ChatGPTは登録の際に3ヵ月間の$18分の無料クレジットが利用可能になります。この記事の内容を動かすくらいなら無料分でも十分です。

1.ChatGPTにアカウントを登録

必要な情報はメールアドレスと電話番号です。

メールアドレスの認証とパスワードの登録を完了させます。

氏名と電話番号を登録します。

2.APIキーを作成

APIキーは一度表示されたら再び表示されませんので注意が必要です。必ずコピーしておいてください。

[Create new secret key]ボタンより新規APIキーの作成ができます。組織設定からAPIキーの所属する組織を設定することもできます。

以下の例では個人アカウントで実行することを想定しています。

コピー忘れ等でAPIキーを削除したい場合は、新しいAPIキーを作成する必要があります。

しかし、最初に生成されたAPIキー以外を使用すると、無料枠のクレジットが反映されないという報告があります(参照)。無料分で試してみようという方は注意してください。

3.VSCodeに拡張機能genieai.chatgpt-vscodeをインストール

サイドバーのアイコンをクリックするとメッセージを入力できるようになります。

何かメッセージを入力するとAPIキーを求められるため、コピーしておいたAPIキーを入力します。

これで導入は完了です。

ChatGPTが有効になると、コードを選択してから右クリックすることでいくつかのプロンプトを実行可能になります。(ショートカットキーでも実行可能)

4.genieaiのカスタム方法

VSCodeのsetting.jsonを変更することでカスタムプロンプトを作成できます。

setting.jsonを変更するためにコマンドパレットを起動します。

コマンドパレットは全OS共通で[F1]キー、または、Windows/Linuxでは[Ctrl]+[Shift]+[P]キー、macOSでは[Command]+[Shift]+[P]キーで起動します。

Genie: Show settingsと入力してください。すると設定画面が表示されます。

ここからお好みの設定に変更可能です。

日本語化したい場合は、デフォルトのプロンプトのメッセージGenieai › Prompt Prefixの項目を日本語で入力することで応答が日本語化されます。また、プロンプトメッセージによって応答が変わる場合もありますので、お好みで文章を入力してください。

私のsetting.jsonを載せておきますので参考にどうぞ。カスタムプロンプトはよく使うものを登録するとよいと思います。

{
    "genieai.promptPrefix.findProblems": "次のコードの問題点を見つけてください",
    //findProblemsは右クリックのメニューではFind Bugsに該当します
    "genieai.promptPrefix.addTests": "次のコードにテストを追加してください",
    "genieai.promptPrefix.optimize": "次のコードを最適化してください",
    "genieai.promptPrefix.explain": "次のコードを説明してください",
    "genieai.promptPrefix.addComments": "次のコードにコメントを追加してください",
    "genieai.promptPrefix.completeCode": "次のコードを完成させてください",
    "genieai.openai.temperature": 0.5,
    //返答を生成する際に使用する言葉の多様性がこの数値によって決定されます。
    //プログラムコードの場合は、通常0.5~0.7の間の値が最適とされています。
    //1に近いほど独創的な表現を用いるようになります。
    "genieai.promptPrefix.customPrompt1": "次のコードを○○してください",
    //よく使うプロンプトを入力してください。
    "genieai.promptPrefix.customPrompt1-enabled": true,
    "genieai.promptPrefix.customPrompt2": "次の文章を○○してください",
    //コード以外にも選択した文章に対して使えます。
    "genieai.promptPrefix.customPrompt2-enabled": true
}

機能の紹介

コードを選択した状態で右クリックすると、以下のプロンプトをデフォルトで使用できます

  • Add tests: テストの実装
  • Find bugs: 問題の発見
  • Optimize: 最適化
  • Explain: 説明
  • Add Comments: コメントの追加
  • Complete code: コードの完成
  • Ad-hoc prompt: コードに対して任意のプロンプトを入力できる
  • カスタムプロンプトを2つまで設定できます。
    • 以下はカスタムプロンプトの例です。よく使うプロンプトを登録しておくとよいでしょう。
      • 翻訳
      • 文章の推敲
      • 類似表現の提案

ChatGPTによるコード作成

genieai.chatgpt-vscode拡張機能で追加されたプロンプトを使ってみます。

まず、ソースコードを「簡単なRPGのプログラムをpythonで作成してください。勇者やモンスターはCharacterBaseクラスを継承したクラスとして定義してください。」で作成してもらいました。

ChatGPTは非決定論的AIと呼ばれており、同じプロンプトを入力しても返答に揺らぎがありますので以下は参考までにどうぞ。

以下が生成されたコードです。

import random

class CharacterBase:
    def __init__(self, name, hp, attack):
        self.name = name
        self.hp = hp
        self.attack = attack
    
    def is_alive(self):
        return self.hp > 0
    
    def take_damage(self, damage):
        self.hp -= damage
        if self.hp < 0:
            self.hp = 0
    
    def attack_target(self, target):
        damage = random.randint(1, self.attack)
        target.take_damage(damage)
        print(f"{self.name} attacks {target.name} for {damage} damage!")
    
class Hero(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)
    
    def heal(self):
        self.hp += 10
        print(f"{self.name} heals for 10 HP.")
        
class Monster(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)

def main():
    hero = Hero("Hero", 30, 5)
    monster = Monster("Goblin", 20, 3)
    
    while hero.is_alive() and monster.is_alive():
        # Hero attacks first
        hero.attack_target(monster)
        if not monster.is_alive():
            break
        
        # Monster attacks second
        monster.attack_target(hero)
        if not hero.is_alive():
            break
    
    if hero.is_alive():
        print("You win!")
    else:
        print("Game over.")
    
if __name__ == "__main__":
    main()

この時点で、かなりまともなコードを出力できていますね。

せっかく、作ったhealメソッドは呼び出されていないようですが、これはAIの遊び心といったところでしょうか。


では、genieの拡張機能で実装されているプロンプトを試していきます。

以下では、コメントを追加してもらいました。(Add Comments)

import random

class CharacterBase:
    def __init__(self, name, hp, attack):
        self.name = name
        self.hp = hp
        self.attack = attack
    
    def is_alive(self):
        return self.hp > 0
    
    def take_damage(self, damage):
        self.hp -= damage
        if self.hp < 0:
            self.hp = 0
    
    def attack_target(self, target):
        damage = random.randint(1, self.attack) # 攻撃力を元にランダムなダメージを与える
        target.take_damage(damage)
        print(f"{self.name} attacks {target.name} for {damage} damage!")
    
class Hero(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)
    
    def heal(self):
        self.hp += 10 # HPを10回復する
        print(f"{self.name} heals for 10 HP.")
        
class Monster(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)

def main():
    hero = Hero("Hero", 30, 5)
    monster = Monster("Goblin", 20, 3)
    
    while hero.is_alive() and monster.is_alive():
        # Hero attacks first
        hero.attack_target(monster) # 勇者がモンスターを攻撃
        if not monster.is_alive():
            break
        
        # Monster attacks second
        monster.attack_target(hero) # モンスターが勇者を攻撃
        if not hero.is_alive():
            break
    
    if hero.is_alive():
        print("You win!") # 勇者が生き残った場合は勝利
    else:
        print("Game over.") # 勇者が死亡した場合はゲームオーバー
    
if __name__ == "__main__":
    main()

日本語のプロンプトで入力したせいか、コメントも日本語で追加されています。
追加された場所を見てみると、なかなか適切な場所にコメントがついている感じがします。

それではこのコードへのテストコードを作成してもらいました。(Add tests)

import unittest
from unittest.mock import patch
from character import Hero

class TestHero(unittest.TestCase):

    def setUp(self):
        self.hero = Hero("Test Hero", 30, 5)

    def test_is_alive(self):
        self.assertTrue(self.hero.is_alive())
        self.hero.hp = 0
        self.assertFalse(self.hero.is_alive())

    def test_take_damage(self):
        self.hero.take_damage(10)
        self.assertEqual(self.hero.hp, 20)
        self.hero.take_damage(100)
        self.assertEqual(self.hero.hp, 0)

    @patch('builtins.print')
    def test_heal(self, mock_print):
        self.hero.heal()
        self.assertEqual(self.hero.hp, 40)
        mock_print.assert_called_with("Test Hero heals for 10 HP.")

if __name__ == '__main__':
    unittest.main()

見たところHeroクラスのテストコードのようです。

実行コマンドも教えてくれました。

python -m unittest test_character.py

test_character.pyで新規ファイルとして保存し実行してみます。

ERROR: test_character (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: test_character
Traceback (most recent call last):
  File "**\********\*****\python\lib\unittest\loader.py", line 154, in loadTestsFromName
    module = __import__(module_name)
  File "**\****\****\*****\test_character.py", line 3, in <module>
    from character import Hero
ModuleNotFoundError: No module named 'character'


----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

実行してみたところ、テストに失敗してしまいました。

テストコードのバグ発見をお願いしてみます。(Find bugs)

このコードには問題点は見つかりませんでした。
ただし、このコードが正しく動作するためには、characterモジュール内にHeroクラスが定義されている必要があります。
また、このテストコードを実行する前に、characterモジュールをインポート可能な場所に配置する必要があります。

とのことなので、characterモジュールを作成してもらいます。(Ad-hoc prompt「次のコードをcharacterモジュールとして別ファイルに分割してください」)

import random

class CharacterBase:
    def __init__(self, name, hp, attack):
        self.name = name
        self.hp = hp
        self.attack = attack
    
    def is_alive(self):
        return self.hp > 0
    
    def take_damage(self, damage):
        self.hp -= damage
        if self.hp < 0:
            self.hp = 0
    
    def attack_target(self, target):
        damage = random.randint(1, self.attack) # 攻撃力を元にランダムなダメージを与える
        target.take_damage(damage)
        print(f"{self.name} attacks {target.name} for {damage} damage!")

class Hero(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)
    
    def heal(self):
        self.hp += 10 # HPを10回復する
        print(f"{self.name} heals for 10 HP.")
        
class Monster(CharacterBase):
    def __init__(self, name, hp, attack):
        super().__init__(name, hp, attack)

characterbaseクラスのモジュール化をお願いしたところ、
実行するmain.pyも同時に出力してもらえました。気が利いていますね。

from character import CharacterBase, Hero, Monster
import random

def main():
    hero = Hero("Hero", 30, 5)
    monster = Monster("Goblin", 20, 3)
    
    while hero.is_alive() and monster.is_alive():
        # Hero attacks first
        hero.attack_target(monster) # 勇者がモンスターを攻撃
        if not monster.is_alive():
            break
        
        # Monster attacks second
        monster.attack_target(hero) # モンスターが勇者を攻撃
        if not hero.is_alive():
            break
    
    if hero.is_alive():
        print("You win!") # 勇者が生き残った場合は勝利
    else:
        print("Game over.") # 勇者が死亡した場合はゲームオーバー
    
if __name__ == "__main__":
    main()

では、Heroクラスのテストを実行してみます。

python -m unittest test_character.py

結果は次のようになりました。

python -m unittest test_character.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

というわけでHeroクラスのテストが完了しました。

さらにmain.pyを最適化してもらいます。(Optimize)

from character import CharacterBase, Hero, Monster
import random

class Game:
    def __init__(self):
        self.hero = Hero("Hero", 30, 5)
        self.monster = Monster("Goblin", 20, 3)
    
    def play(self):
        while self.hero.is_alive() and self.monster.is_alive():
            # Hero attacks first
            self.hero.attack_target(self.monster) 
            if not self.monster.is_alive():
                break
            
            # Monster attacks second
            self.monster.attack_target(self.hero) 
            if not self.hero.is_alive():
                break
        
        if self.hero.is_alive():
            print("You win!")
        else:
            print("Game over.")
            
    def get_damage(self, attack_power):
        critical_hit_chance = 0.2
        is_critical_hit = random.random() < critical_hit_chance
        base_damage = attack_power * (2 if is_critical_hit else 1)
        return base_damage

if __name__ == "__main__":
    game = Game()
    game.play()

最適化してもらったことでコード全体の抽象度があがり、再利用性が向上したように感じられますね。

途中でヒールを使ってもらいたいのでコメントだけ書いて完成させてもらいます。(Complete code)

下記コードを入力しました。

def play(self):
        while self.hero.is_alive() and self.monster.is_alive():
            # Hero attacks first
            random_value =  random.randint(1, 10)
            # TODO
            # random_valueによってhealとattack_targetをランダムに選択する
            self.hero.attack_target(self.monster) 
            if not self.monster.is_alive():
                break
            
            # Monster attacks second
            self.monster.attack_target(self.hero) 
            if not self.hero.is_alive():
                break
        
        if self.hero.is_alive():
            print("You win!")
        else:
            print("Game over.")

結果は次のようになりました。

def play(self):
    while self.hero.is_alive() and self.monster.is_alive():
        # Hero attacks first
        random_value =  random.randint(1, 10)
        if random_value <= 7:
            self.hero.attack_target(self.monster) 
        else:
            self.hero.heal()
        
        if not self.monster.is_alive():
            break
            
        # Monster attacks second
        self.monster.attack_target(self.hero) 
        if not self.hero.is_alive():
            break
        
    if self.hero.is_alive():
        print("You win!")
    else:
        print("Game over.")

きちんとお願いした通りに実装されているようです。
パラメータが7以下の場合というのも極端過ぎない良いバランスのように思います。

では完成したmain.pyの説明を書いてもらいました。(Explain)

このコードは、`character.py`ファイルで定義された`CharacterBase`、`Hero`、および`Monster`クラスをインポートしています。また、ランダムなダメージ計算を行うための`get_damage`メソッドが含まれる`Game`クラスを定義しています。

`Game`クラスのコンストラクタでは、`Hero`と`Monster`オブジェクトを作成し、それらを`self.hero`と`self.monster`属性に割り当てます。

`play`メソッドは、`Hero`と`Monster`が生きている限り、攻撃を交互に行い続けます。`random_value`変数によって、`Hero`が攻撃するか回復するかが決定されます。`is_alive`メソッドは、`CharacterBase`クラスに定義されており、キャラクターが生きているかどうかを判断します。`attack_target`メソッドは、攻撃対象に対して攻撃を行います。攻撃対象が死んでいる場合は、ループから抜けます。

`get_damage`メソッドは、与えられた攻撃力に基づいてダメージを計算します。このメソッドは、攻撃がクリティカルヒットになる確率を計算し、クリティカルヒットになった場合はダメージを2倍にします。

最後に、`if __name__ == "__main__":`ブロックで、`Game`オブジェクトを作成し、`play`メソッドを呼び出してゲームを開始します。

以上です。

このように、簡単なプログラム開発ならばChatGPTを利用することで爆速で出来ます。

普段の作業でVSCodeを愛用していて、ChatGPTに興味がある方は動かしてみるとその性能に驚くと思います。ぜひお試しください。

エクスチュアはマーケティングテクノロジーを実践的に利用することで企業のマーケティング活動を支援しています。
ツールの活用にお困りの方はお気軽にお問い合わせください。

参考文献

OpenAI 制限事項

ゴールドマンサックスによるレポート

アメリカ合衆国著作権局の発表

ChatGPTのセキュリティに関する記事

法人組織がChatGPT利用時に気を付けるべきこと

サムスン電子のChatGPTによる情報漏洩のニュース

OpenAIのAPIのデータ取り扱いポリシー

「ChatGPTに入力した内容、学習されたくない」オプトアウト申請可能

ピックアップ記事

  1. 最速で理解したい人のためのIT用語集

関連記事

  1. Google Analytics

    Google Analytics: ユニバーサルアナリティクスの拡張Eコマース用dataLayerを…

    こんにちは、エクスチュアの權泳東(権泳東/コン・ヨンドン)です。…

  2. Tableau

    Tableauで複数のチャートを1シート内で表示する『パネルチャート』の作り方

    今回は、複数の項目を一瞥するのに便利な『パネルチャート 』を取り上げ…

  3. Python

    Python クローリング&スクレイピング

    最初に顧客マスタのデータに別の角度から考察を加えたいとき、外部から何…

  4. ChatGPT

    ChatGPT ProからClaude3 Proへ移行した話

    こんにちは、エクスチュアの黒岩です。突然ですが、皆様はどんな…

  5. Google Analytics

    Cloud FunctionsとOpenWeather APIを使ってGoogle Analytic…

    こんにちは、エクスチュアの権泳東(權泳東/コン・ヨンドン)です。…

  6. Adobe Analytics

    Adobe AEP SDKをTypeScriptで開発したReactNativeアプリに実装する

    こんにちは、エクスチュアの権泳東(權泳東/コン・ヨンドン)です。…

最近の記事

  1. LangChainって何?: 次世代AIアプリケーション構築…
  2. 回帰分析はかく語りき Part1 単回帰分析
  3. GitHub ActionsでGCEへのデプロイを楽にしてみ…
  4. Snowflake の Copilot が優秀すぎる件につい…
  5. Snowflake の新しいData Clean Roomの…
  1. GitHub Actions

    GitHub ActionsでGCEへのデプロイを楽にしてみた
  2. Python

    市区町村一覧・自治体の一覧を取得する
  3. ObservePoint

    ObservePoint:強力でアツい機能を持つサイト監査ツールの紹介
  4. IT用語集

    アクセス管理(Access Management)って何?
  5. Google Apps Script(GAS)

    GASを利用してWebスクレイピングをやってみよう②
PAGE TOP