コードを完成させ、開発プロセスを支援する

完了

Azure OpenAI は、単体テストの作成、部分コードの完成、コードのコメント作成、ドキュメントの生成など、一般的なソフトウェア開発タスクにおいて開発者を支援できます。 AI アシスタンスを使用すると、開発者は複雑なプログラミングと問題解決のタスクにより多くの時間を費やすことができます。

部分コードを完成させる

Azure OpenAI モデルでは、コメント、関数名、および部分的に記述されたコードに基づいてコードを生成できます。 モデルに提供できるコンテキストが多いほど、応答の精度が高くなります。

たとえば、次のプロンプトが表示されたとします。

complete the following function  
"""  
# calculate the average of the numbers in an array, but only if they're even  
def 
complete the following function    
"""    
// calculate the average of the numbers in an array, but only if they're even    
public 

モデルでは、コメントと関数定義の開始を受け取り、どのようなコンテキストであってもそれを完成させます。

# calculate the average of the even numbers in an array  
def calculate_even_average(numbers):  
    total = 0  
    count = 0  
    for number in numbers:  
        if number % 2 == 0:  
            total += number  
            count += 1  
    if count == 0:  
        return 0  # avoid division by zero  
    else:  
        return total / count  
// calculate the average of the even numbers in an array  
public double CalculateEvenAverage(int[] numbers) {  
    int total = 0;  
    int count = 0;  
    foreach (int number in numbers) {  
        if (number % 2 == 0) {  
            total += number;  
            count++;  
        }  
    }  
    if (count == 0) {  
        return 0;  // avoid division by zero  
    } else {  
        return (double) total / count;  
    }  
}

この場合、モデルでは、関数の開始前に比較的単純かつ完全なコメントがあったため、必要な内容を識別できました。 より複雑な関数またはタスクでは、有用な応答を得るために、より多くのコンテキストが必要です。

Python などの一部の言語では、構文が明確であるため、モデルによって目的の言語を想定できることに注意してください。 構文的に似た言語 (C# や Java など) では、モデルで不適切な言語が使用される可能性が高くなります。 その場合は、プロンプトで言語を指定するか、コンテキストに対してさらに多くのコードを指定してみてください。

同様の機能は、コメントなしでモデルに部分的なコードを提供することで確認できます。 たとえば、次のプロンプトを受け取ります。

complete the following code  
"""  
def func1(n)
  if n==0:
complete the following code  
"""  
public int Func1(int n) {  
    if (n == 0) { 

AI モデルでは、最も可能性の高い関数の完成によって関数を完成させるよう最善を尽くします。

def func1(n):  
    if n == 0:  
        return 1  
    else:  
        return n * func1(n-1)  
public int Func1(int n) {  
    if (n == 0) {  
        return 1;  
    } else {  
        return n * Func1(n-1);  
    }  
}

応答には、その関数の動作に関する自然言語の説明も含まれる可能性があります。 このケースでは、階乗関数の再帰的な実装で応答しました。 ただし、プロンプトはフィボナッチ関数の開始であった可能性もあります。これは、モデルに何を求めるかをより適切に示すために、プロンプトでより多くのコンテキストを必要とするケースを示しています。

GitHub Copilot などのツールでは、OpenAI モデルを利用して、上記の例と同様の方法でコードと関数の完成を提案します。 GitHub Copilot は、この機能の実際の使用例として最適です。この機能では、ペアのプログラマーとしての役割を果たすために、組み込みのプロンプトと、記述中のコードのコンテキストが使用されます。

単体テストを作成する

Azure OpenAI モデルでは、コードの堅牢性を高めるために、記述する関数の単体テストを生成できます。 たとえば、バイナリ検索関数を考えてみましょう。

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1
public static int BinarySearch(int[] arr, int target)
{
    int left = 0;
    int right = arr.Length - 1;

    while (left <= right)
    {
        int mid = (left + right) / 2;

        if (arr[mid] == target)
        {
            return mid;
        }
        else if (arr[mid] < target)
        {
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    return -1;
}

プロンプト write three unit tests for this function と共にその関数を指定すると、次のような応答が返されます。

def test_binary_search():  
    # Test case 1: Target element is in the middle of the array  
    arr1 = [1, 2, 3, 4, 5, 6]  
    target1 = 4  
    assert binary_search(arr1, target1) == 3  

    # Test case 2: Target element is at the beginning of the array  
    arr2 = [1, 2, 3, 4, 5, 6]  
    target2 = 1  
    assert binary_search(arr2, target2) == 0  

    # Test case 3: Target element is not in the array  
    arr3 = [1, 2, 3, 4, 5, 6]  
    target3 = 7  
    assert binary_search(arr3, target3) == -1
[Test]  
public void TestBinarySearch1()  
{  
    int[] arr = { 1, 2, 3, 4, 5 };  
    int target = 3;  
    int expected = 2;  
    int result = BinarySearch(arr, target);  
    Assert.AreEqual(expected, result);  
}  

[Test]  
public void TestBinarySearch2()  
{  
    int[] arr = { 10, 20, 30, 40, 50 };  
    int target = 35;  
    int expected = -1;  
    int result = BinarySearch(arr, target);  
    Assert.AreEqual(expected, result);  
}  

[Test]  
public void TestBinarySearch3()  
{  
    int[] arr = { 3, 6, 9, 12, 15 };  
    int target = 6;  
    int expected = 1;  
    int result = BinarySearch(arr, target);  
    Assert.AreEqual(expected, result);  
}  

この機能は、プロンプトに含めるケースを指定する場合にさらに便利です。これにより、コードの単体テストの作成にかかる時間が短縮されます。

コメントを追加し、ドキュメントを生成する

コードをさらに改善するために、AI モデルではコメントとドキュメントを追加できます。 たとえば、次の関数を考えてみましょう。最初にコード コメントなしで読むと、少しわかりにくいかもしれません。

def permutations(lst):  
    if len(lst) == 0:  
        return []  
    elif len(lst) == 1:  
        return [lst]  
    else:  
        result = []  
        for i in range(len(lst)):  
            temp = lst[i]  
            remaining = lst[:i] + lst[i+1:]  
            for p in permutations(remaining):  
                result.append([temp] + p)  
        return result  
public static List<List<int>> Permutations(List<int> lst)  
{  
    if (lst.Count == 0)  
    {  
        return new List<List<int>>();  
    }  
    else if (lst.Count == 1)  
    {  
        return new List<List<int>> { lst };  
    }  
    else  
    {  
        List<List<int>> result = new List<List<int>>();  
        for (int i = 0; i < lst.Count; i++)  
        {  
            int temp = lst[i];  
            List<int> remaining = new List<int>(lst);  
            remaining.RemoveAt(i);  
            foreach (List<int> p in Permutations(remaining))  
            {  
                List<int> permutation = new List<int> { temp };  
                permutation.AddRange(p);  
                result.Add(permutation);  
            }  
        }  
        return result;  
    }  
}  

コードにコメントを追加するよう求めるプロンプトと共に、その関数をモデルに指定すると、次のような応答を受け取ります。

def permutations(lst):  
    # Check if the input list is empty  
    if len(lst) == 0:  
        return []  
    # Check if the input list has only one element  
    elif len(lst) == 1:  
        return [lst]  
    else:  
        # Initialize an empty list to store permutations  
        result = []  
        # Iterate through each element of the input list  
        for i in range(len(lst)):  
            # Remove the current element from the list and store it in a variable  
            temp = lst[i]  
            remaining = lst[:i] + lst[i+1:]  
            # Recursively call the function on the remaining list  
            for p in permutations(remaining):  
                # Append the current element to the beginning of each permutation and add it to the result list  
                result.append([temp] + p)  
        # Return the final list of permutations  
        return result  
public static List<List<int>> Permutations(List<int> lst)  
{  
    // Check if the input list is empty  
    if (lst.Count == 0)  
    {  
        return new List<List<int>>();  
    }  
    // Check if the input list has only one element  
    else if (lst.Count == 1)  
    {  
        return new List<List<int>> { lst };  
    }  
    else  
    {  
        // Initialize an empty list to store permutations  
        List<List<int>> result = new List<List<int>>();  
        // Iterate through each element of the input list  
        for (int i = 0; i < lst.Count; i++)  
        {  
            // Remove the current element from the list and store it in a variable  
            int temp = lst[i];  
            List<int> remaining = new List<int>(lst);  
            remaining.RemoveAt(i);  
            // Recursively call the function on the remaining list  
            foreach (List<int> p in Permutations(remaining))  
            {  
                // Append the current element to the beginning of each permutation and add it to the result list  
                List<int> permutation = new List<int> { temp };  
                permutation.AddRange(p);  
                result.Add(permutation);  
            }  
        }  
        // Return the final list of permutations  
        return result;  
    }  
}  

さらに一歩進み、さきほどコメントを追加した関数のドキュメントを要求します。

def permutations(lst):  
    """  
    Generates all possible permutations of a given list of integers using recursion.  

    Args:  
        lst (list): The list of integers to generate permutations for.  

    Returns:  
        list: A list of all possible permutations of the input list.  
    """  
    # Check if the input list is empty  
    if len(lst) == 0:  
        return []  
    # Check if the input list has only one element  
    elif len(lst) == 1:  
        return [lst]  
    else:  
        # Initialize an empty list to store permutations  
        result = []  
        # Iterate through each element of the input list  
        for i in range(len(lst)):  
            # Remove the current element from the list and store it in a variable  
            temp = lst[i]  
            remaining = lst[:i] + lst[i+1:]  
            # Recursively call the function on the remaining list  
            for p in permutations(remaining):  
                # Append the current element to the beginning of each permutation and add it to the result list  
                result.append([temp] + p)  
        # Return the final list of permutations  
        return result  
/// <summary>  
/// Generates all possible permutations of a given list of integers using recursion.  
/// </summary>  
/// <param name="lst">The list of integers to generate permutations for.</param>  
/// <returns>A list of all possible permutations of the input list.</returns>  ```
public static List<List<int>> Permutations(List<int> lst)  
{  
    // Check if the input list is empty  
    if (lst.Count == 0)  
    {  
        return new List<List<int>>();  
    }  
    // Check if the input list has only one element  
    else if (lst.Count == 1)  
    {  
        return new List<List<int>> { lst };  
    }  
    else  
    {  
        // Initialize an empty list to store permutations  
        List<List<int>> result = new List<List<int>>();  
        // Iterate through each element of the input list  
        for (int i = 0; i < lst.Count; i++)  
        {  
            // Remove the current element from the list and store it in a variable  
            int temp = lst[i];  
            List<int> remaining = new List<int>(lst);  
            remaining.RemoveAt(i);  
            // Recursively call the function on the remaining list  
            foreach (List<int> p in Permutations(remaining))  
            {  
                // Append the current element to the beginning of each permutation and add it to the result list  
                List<int> permutation = new List<int> { temp };  
                permutation.AddRange(p);  
                result.Add(permutation);  
            }  
        }  
        // Return the final list of permutations  
        return result;  
    }  
}