このワークショップでは、GitHub Copilot を使ってコードの解説や改善を行う方法を学びます。 GitHub Copilot Chat は Chat 体験を通じて AI との対話を行うことができます。 ぜひ、このワークショップを通じて GitHub Copilot の使い方を学んでみましょう。
Visual Studio Code の設定を開きます。
設定画面に github.copilot.chat.localeOverride
を打ち込み、ロケールを ja
に設定してください。
下記のファイルを DelivaryManager.cs
として保存してください。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DeliveryManager : MonoBehaviour
{
public event EventHandler OnRecipeSpawned;
public event EventHandler OnRecipeCompleted;
public event EventHandler OnRecipeSuccess;
public event EventHandler OnRecipeFailed;
public static DeliveryManager Instance { get; private set; }
[SerializeField] private RecipeListSO recipeListSO;
private List<RecipeSO> waitingRecipeSOList;
private float spawnRecipeTimer;
private float spawnRecipeTimerMax = 4f;
private int waitingRecipesMax = 4;
private int successfulRecipesAmount;
private void Awake()
{
Instance = this;
waitingRecipeSOList = new List<RecipeSO>();
}
private void Update()
{
spawnRecipeTimer -= Time.deltaTime;
if (spawnRecipeTimer <= 0f)
{
spawnRecipeTimer = spawnRecipeTimerMax;
if (KitchenGameManager.Instance.IsGamePlaying() && waitingRecipeSOList.Count < waitingRecipesMax)
{
RecipeSO waitingRecipeSO = recipeListSO.recipeSOList[UnityEngine.Random.Range(0, recipeListSO.recipeSOList.Count)];
waitingRecipeSOList.Add(waitingRecipeSO);
OnRecipeSpawned?.Invoke(this, EventArgs.Empty);
}
}
}
// レシピの材料と皿の材料が一致しているかどうかを確認する
public void DeliverRecipe(PlateKitchenObject plateKitchenObject)
{
for (int i = 0; i < waitingRecipeSOList.Count; i++)
{
RecipeSO waitingRecipeSO = waitingRecipeSOList[i];
if (waitingRecipeSO.kitchenObjectSOList.Count == plateKitchenObject.GetKitchenObjectSOList().Count)
{
bool plateContentsMatchesRecipe = true;
foreach (KitchenObjectSO recipeKitchenObjectSO in waitingRecipeSO.kitchenObjectSOList)
{
bool ingredientFound = false;
foreach (KitchenObjectSO plateKitchenObjectSO in plateKitchenObject.GetKitchenObjectSOList())
{
if (plateKitchenObjectSO == recipeKitchenObjectSO)
{
ingredientFound = true;
break;
}
}
if (!ingredientFound)
{
plateContentsMatchesRecipe = false;
}
}
if (plateContentsMatchesRecipe)
{
successfulRecipesAmount++;
waitingRecipeSOList.RemoveAt(i);
OnRecipeCompleted?.Invoke(this, EventArgs.Empty);
OnRecipeSuccess?.Invoke(this, EventArgs.Empty);
return;
}
}
}
OnRecipeFailed?.Invoke(this, EventArgs.Empty);
}
public List<RecipeSO> GetWaitingRecipeSOList()
{
return waitingRecipeSOList;
}
public int GetSuccessfulRecipesAmount()
{
return successfulRecipesAmount;
}
}
Copilot Chat にこのコードを解説させてみましょう。
DelivaryManager.cs
の解説を自分のプロンプトで Copilot Chat に尋ねてみましょう。 (必要に応じて説明してもらいたい箇所をカーソルで選択しましょう) /explain
を使ったとき、 Copilot Chat がどのような解説を返してくるか確認してみましょう。 DeliverRecipe()
メソッドの中身を改善するためにはどのような方法があるか聞いてみましょう #selection
のコンテキスト変数を使って、特定の部分について聞くことができます。DeliverRecipe()
においてループ処理で効率化できる可能性がわかりました。
改善してみましょう。
以下のコードを logic-errors.js
として保存してください。
// ソース: https://tutorial.eyehunts.com/js/javascript-logic-errors/
function calculateAverage(nums) {
let sum = 0;
for (let i = 0; i <= nums.length; i++) {
sum += nums[i];
}
let avg = sum / nums.length;
return avg;
}
let numbers = [1, 2, 3, 4, 5];
let avg = calculateAverage(numbers);
console.log(`The average is ${avg}.`);
このコードを解説させてみましょう。
node logic-errors.js
を実行してみましょう。 The average is NaN.
と表示されるはずです。
/fix
で修正してもらいましょう。#terminalLastCommand
を使って文脈を指定し、直前のコマンドの実行結果の解説をしてもらいましょう。もし、node の環境準備ができない場合でも、node logic-errors.js
というコマンドを実行してみましょう。
bash: node: command not found
のようにでた場合は、#terminalLastCommand
を使って、エラーの内容を解説してもらいましょう。 なぜ実行できなかったかは自明ですが、Copilot Chat もターミナルをちゃんと見てくれるか確認してみましょう。
#terminalSelection
を使って、選択した部分について質問してみましょう。任意のコマンドを選択して、そのコマンドや、そのコマンドの実行結果について質問することができます。
@account ➜ /workspaces/workshops
のようなターミナルの表示についても聞いてみることができますnpm -h
, pip -h
, git -h
などを実行後、出力の一部を選択して、それについて質問してみましょう。#terminalSelection
を使って質問してみましょう。#editor
と #file
というコンテキスト変数を使って、コンテキストを指定することができます。 また、@workspace
を使うことによってエディタ全体をコンテキストに含めることができます。
#editor
は、エディタの内容について解説をしてもらうことができます。 #file
は、ファイルの内容について解説をしてもらうことができます。
logic-errors.js
ファイルを開き、DelivaryManager.cs
ファイルを閉じます。#editor
を使って、logic-errors.js
の内容について解説をしてもらいましょう。無事解説されましたか?#editor
を使って、DelivaryManager.cs
の内容について解説をしてもらいましょう。解説されましたか? - 申し訳ありませんが、現在のエディターコンテキストでは DelivaryManager.cs ファイルの内容を確認することはできません。
と出るはずです。#file:DelivaryManager.cs
を使って、ファイルを指定して同ファイルを解説をしてもらいましょう。解説されましたか?@workspace
を使って、エディタ全体をコンテキストに含めてみましょう。DeliveryManager.cs
と logic-errors.js
を両方閉じてから、@workspace
を使って、それぞれのファイルを解説してもらいましょう。解説されましたか?単体テストを実行する
ここで、スラッシュコマンドの /tests
を使って、単体テストを作成してみましょう。
janken.py
というファイルをつくり、/tests
について単体テストを作成してみましょう。#selection
を使って judge
関数についてのみテストを書いてみましょう# じゃんけんゲームを書いてください
import random
import unittest
# 勝敗の判定ロジックをハンドルするjudge関数を定義
def judge(player_hand, computer_hand):
# プレイヤーの手とコンピューターの手を比較して結果を表示
if player_hand == computer_hand:
return "あいこです。"
elif player_hand == "グー":
if computer_hand == "チョキ":
return "あなたの勝ちです。"
else:
return "あなたの負けです。"
elif player_hand == "チョキ":
if computer_hand == "パー":
return "あなたの勝ちです。"
else:
return "あなたの負けです。"
elif player_hand == "パー":
if computer_hand == "グー":
return "あなたの勝ちです。"
else:
return "あなたの負けです。"
else:
return "グー、チョキ、パーのいずれかを入力してください。"
# ロジックを全てハンドルするmain関数を定義
def main():
# プレイヤーの手を入力
player_hand = input("じゃんけんをしましょう!(グー、チョキ、パー):")
# プレイヤーの手を表示
print("あなたの手は" + player_hand + "です。")
# コンピューターの手をランダムに選択
computer_hand = random.choice(["グー", "チョキ", "パー"])
# コンピューターの手を表示
print("コンピューターの手は" + computer_hand + "です。")
# judge関数を呼び出して結果を表示
print(judge(player_hand, computer_hand))
次に異なるテストを書いてみましょう GitHub Copilot Chat で /tests
を使った場合と、GitHub Copilot の自動補完機能を使ってテストを書いた場合の違いを見てみましょう。
# テストのためのモジュールをインポート
import unittest
# 文字列が渡された場合は、エラーを起こす
# それ以外の場合は、掛け算を行う
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class
自動補完機能で、class
と入力すると、以下のように補ってもらえます。
# テストのためのモジュールをインポート
import unittest
# 文字列が渡された場合は、エラーを起こす
# それ以外の場合は、掛け算を行う
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class TestMultiply(unittest.TestCase):
def test_multiply(self):
self.assertEqual(multiply(2, 3), 6)
エクササイズ:
duration 00:04:00
次に、テストのバリエーションを増やします。
エクササイズ:
# テストのためのモジュールをインポート
import unittest
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class TestMultiply(unittest.TestCase):
# 10 通りのテストパターン
def test_multiply(self):
duration 00:04:00
次にコードを読んでみましょう。 GitHub Copilot Chat に以下のコードをマークダウンにしてもらうように聞いてみましょう。
CREATE TABLE documents (
document_id VARCHAR(63) PRIMARY KEY, -- Primary key, unique ID
store_facility VARCHAR(63) NOT NULL, -- Storage facility (name of the SST where actual data exists)
sst_document_id VARCHAR(63) NOT NULL, -- Communication document ID
title VARCHAR(255) NOT NULL, -- Title
from_adr TEXT NOT NULL, -- Sender's address
to_adr TEXT NOT NULL, -- Recipient's address
data_type VARCHAR(63) NOT NULL, -- Content data type
extra_data TEXT, -- Additional data type
pt_guid VARCHAR(255), -- Patient guide in case of a patient
password_text VARCHAR(63), -- Security password
create_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- Creation date
last_status VARCHAR(63), -- Last status
last_caption VARCHAR(255), -- Last description
last_update TIMESTAMP WITHOUT TIME ZONE, -- Last update date
limit_date TIMESTAMP WITHOUT TIME ZONE, -- Expiry date
fix_flg VARCHAR(1), -- Fixed flag (0: normal, 1: fixed)
del_flg VARCHAR(1) -- Delete flag (1: deleted, 0: valid)
);
エクササイズ:
選択した範囲をマークダウンテーブルに変換して
のように聞いてみましょう。 希望通りの結果が返ってこない場合は、聞き方を工夫してみましょう。選択した範囲をマークダウンテーブルに変換してください。以下の列を持つテーブルを書いてください No., カラム名, 型, 長さ(length), Decimal, 必須(Yes/No), 主キー, 詳細(日本語)
以下に Python の FastAPI で書かれたコードがあります main.py
のファイルを咲くえいしてして、/explain
機能を使って解説を出力する際に、より詳細な仕様が返ってくるようにフォーマットを整えてみましょう。 どのように詳細仕様書に変換することができますか?
@router.get('/', response_model=schema.Showarticle)
def all_articles(db: Session = Depends(get_db)):
return article.get_all(db)
@router.get('/{article_id}', status_code=status.HTTP_200_OK, response_model=schema.Showarticle)
def all_articles(article_id: int, db: Session = Depends(get_db)):
return article.show_all_articles(article_id, db)
@router.post('/', status_code=status.HTTP_201_CREATED)
def create(articles: schema.articleBase, db: Session = Depends(get_db)):
return article.create(articles, db)
@router.put('/{article_id}', status_code=status.HTTP_202_ACCEPTED)
def update_article(article_id: int, articles: schema.articleBase, db: Session = Depends(get_db)):
return article.update(article_id, articles, db)
@router.delete('/{article_id}', status_code=status.HTTP_204_NO_CONTENT)
def delete_articles(article_id: int, db: Session = Depends(get_db)):
return article.delete(article_id, db)
次に以下のようなフォーマットを与えて書いてもらいましょう。
以下のリストを網羅できるように、API について仕様を書き出してくだくさい
- 処理概要
- アクセスURL
- プロトコル
- メソッド
- GET
- POST
- PUT
- DELETE
- リクエスト
- フォーマット
- JSON
- その他
- パラメータ
- 数
- 名前(例:`recipe_id`)
- タイプ(数値、文字列など)
- 長さ
- 必須(必須/任意)
- 説明
- 備考
- レスポンス
- フォーマット
- JSON
- その他
- パラメータ
- 数
- 名前(例:`chef`)
- タイプ(数値、文字列など)
- 長さ
- 繰り返し(はい/いいえ/回数)
- 説明
- 備考
- サンプル
GitHub Copilot を使うと、Markdown で使える Mermaid表記を使って以下のように図を描いてくれます。
変換をしてみましょう。
https://gist.github.com/yuhattor/cab9ae84bd41608e5d61cb96b76458b6
classDiagram
class users{
+id: string
first_name: string
last_name: string
email: string
...
}
class inquiries{
+id: string
user_id: string
listing_id: string
message: text
...
}
class reservations{
+id: string
user_id: string
listing_id: string
appointment: datetime
...
}
class filters{
+id: string
user_id: string
name: string
description: string
...
}
class favorites{
+id: string
user_id: string
share: string
title: string
...
}
class invitations{
+id: string
user_id: string
email: string
invited_at: datetime
...
}
users "1" -- "*" inquiries : has
users "1" -- "*" reservations : has
users "1" -- "*" filters : has
users "1" -- "*" favorites : has
users "1" -- "*" invitations : has
Zero-shotプロンプティング モデルに事前の例示(example)やトレーニングを与えずに、直接質問やタスクを提示する方法です。
練習: GitHub Copilot Chat で未知の技術問題(例えば、「このコードのセキュリティを強化するにはどうすればよいか?」)をAIに問いかけ、どのような解答やアプローチを示すか分析する。
Few-shotプロンプティングは、少数の例を用いてモデルに特定のタスクの解法を理解させる方法です。
練習: ソフトウェアの仕様書の出力例を数件提示し、それに基づいて新しいコードの仕様書をAIに作らせる。
Chain-of-Thoughtプロンプティングは問題解決の過程をステップバイステップで説明させることで、より複雑な問題への対処を可能にする方法です。
練習: システム設計問題(例えば、コードやインフラ設計の最適化)を提示し、その解決策を段階的に説明させる。
矛盾しない一貫した回答を得るために、同じ質問を異なる形で複数回尋ねることができます。
練習: ソフトウェアの要件定義を異なる表現で複数回尋ね、AIの回答の一貫性を検証する。
知識生成プロンプティングはモデルに新しい情報やアイデアを生成させることに重点を置いたプロンプティングです。
練習: ITに関する創造的な問題(例:「このドキュメントを改善するにはどのようにすればよいですか」)をAIに問いかけ、革新的なアイデアを探求する。
Tree of Thoughts はある問題に対する複数の解答ルートや思考プロセスを探索させるアプローチです。
練習: 特定のIT課題(例えば、「リモートワークを効果的にサポートするITシステムの設計」)に対し、異なる観点からの解決策をAIに考えさせる。