自然言語からコードを構築する

完了

Azure OpenAI モデルの機能の 1 つは、自然言語プロンプトからコードを生成することです。 タスクの範囲は、シンプルな 1 行のコマンドから完全なアプリケーションまでとすることができます。 AI モデルでは、指定されたコードまたは以前の応答を編集および更新して、要求されたタスクを完了することもできます。

このユニットの例では、gpt-35-turbo を使用しています。

関数を記述する

Azure OpenAI モデルでは、必要なものを記述するだけで、複数の言語で関数とアプリを作成できます。 例えば、プロンプト write a function for binary search in python が表示されたら、関数とコードの説明を含む応答が返される可能性があります。

Sure, here's an example implementation of binary search algorithm in Python:

def binary_search(array, target):  
    low = 0  
    high = len(array) - 1  
  
    while low <= high:  
        mid = (low + high) // 2  
        if array[mid] == target:  
            return mid  
        elif array[mid] < target:  
            low = mid + 1  
        else:  
            high = mid - 1  
  
    return -1  
 
This function takes in two arguments - an array of integers and a target integer that we want to search
for in the array. The function initializes two pointers - low and high - to the first and last indices
of the array, respectively.

Inside the while loop, the function calculates the middle index using integer division (//). If the 
middle element is equal to the target, the function returns the index of the middle element. If the 
middle element is less than the target, we update the low pointer to mid + 1. Otherwise, we update the 
high pointer to mid - 1. We continue these steps until we find the target or the pointers cross each 
other (i.e., low > high).

If the target is not found in the array, the function returns -1.

Note that the binary search algorithm assumes that the input array is sorted in ascending order. If 
the array is not sorted, the algorithm may not return the correct result.

要求は関数よりも優先され、一連の関数またはアプリ全体を要求することができます。 応答は、達成しようとしているタスクの適切な出発点となります。

コーディング言語を変更する

ある言語で記述されたコードがあるが、それを別の言語にする必要がある場合、Azure OpenAI を使用すれば翻訳できます。 たとえば、この print_squares 関数が Python で記述されているとします。

def print_squares(n):  
    for i in range(1, n+1):  
        print(i**2)   

そのコードをプロンプト convert this code to C#と共に指定すると、次の関数のような結果が得られる可能性があります。

public void PrintSquares(int n)  
{  
    for (int i = 1; i <= n; i++)  
    {  
        Console.WriteLine(i * i);  
    }  
}  

モデルでは、さまざまな言語での for ループと関数の定義方法 (C# のアクセス修飾子を含む) の違いを理解し、コードを適切に変更している、ことに注目してください。

不明なコードを理解する

Azure OpenAI モデルは、意味がわからないコードや、馴染みのない言語で使用されているコードを理解するのに役立ちます。 たとえば、(架空のコーディング言語による) 次の関数が与えられたが、それを理解する方法を知らなかったとします。

fn qzplv(n: i32, m: i32) -> i32 {
    if n == 0 {
        return m + 1;
    } else if m == 0 {
        return qzplv(n - 1, 1);
    } else {
        return qzplv(n - 1, qzplv(n, m - 1));
    }
}

プロンプト could you explain what this code is doing? とともにモデルに指定すると、次のような応答が返されます。

Sure, I'd be happy to explain what this code is doing!

This code is implementing the Ackermann function, which is a well-known mathematical function that 
grows very quickly in terms of computation time as its inputs increase. The function takes two integer 
arguments (n and m) and returns another integer.

Here's how the function works:
- If n is equal to 0, the function returns m + 1.
- If m is equal to 0, the function calls itself recursively with n - 1 and 1 as arguments.
- Otherwise, the function calls itself recursively with n - 1 and the result of calling itself with n 
and m - 1 as arguments.

The function is implemented in a way that is easy to understand and follow, but it has a very high 
computational complexity. In fact, it grows so quickly that it can't be computed for values of n and m 
greater than about 4 or 5.

説明と使い慣れた言語への翻訳を組み合わせると、この機能はさらに便利になります。

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

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 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);  
    }  
}

応答には、その関数の動作に関する自然言語の説明も含まれる可能性があります。 このケースでは、階乗関数の再帰的な実装で応答しました。

単体テストを作成する

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;  
    }  
}  

さらに 1 ステップ進み、ドキュメントを要求すると、OpenAI によって入力と出力を含む説明が追加されます。

バグを修正し、コードを改善する

開発者が記述するコードは、ほとんどの場合は機能しますが、バグ、構文、パフォーマンス、モジュール性を修正することで改善できる場合もあります。 Azure OpenAI モデルを使用すると、コードを改善する方法を特定でき、より優れたコードを記述する方法が提案されます。

コードのバグを修正する

Azure OpenAI モデルでは、コードが分析され、問題を修正できる可能性のある変更が提案されるため、コードのバグを修正するのに役立ちます。 これは、開発者がより迅速かつ効率的にバグを特定して解決するのに役立ちます。

たとえば、次の関数を作成したが、機能しないとしましょう。

def calculate_average(numbers):  
    total = 0  
    for i in range(len(numbers)):  
        number = numbers[i]  
        total += number  
    average = total  
    rerun averave  
public double CalculateAverage(int[] numbers)
{
    int total = 0;
    for (int i = 0; i < numbers.Length; i++)
    {
        int number = numbers[i];
        total += number;
    }
    double average = (double)total;
    rerun averave;
}

この関数をプロンプト Fix the bugs in this function と共にモデルに提供すると、修正されたコードと、修正された内容に関する説明が返されます。

def calculate_average(numbers):  
    total = 0  
    for i in range(len(numbers)):  
        number = numbers[i]  
        total += number  
    average = total / len(numbers)  
    return average  
public double CalculateAverage(int[] numbers)
{
    int total = 0;
    for (int i = 0; i < numbers.Length; i++)
    {
        int number = numbers[i];
        total += number;
    }
    double average = (double)total / numbers.Length;
    return average;
}
There were a few issues with the original code:

1. The variable "average" was assigned the value of "total" instead of the actual average.
2. There was a typo in the last line - "rerun" should be "return".
3. The average was not actually calculated - the corrected code divides the total by the length of 
the "numbers" list to get the average.

パフォーマンスの向上

コード開発者が記述したコードは機能する可能性がありますが、より効率的にタスクを実行する方法があるかもしれません。 最初の n 個の正の整数の合計を計算する関数の例を次に示します。これは、効率的ではない可能性があります。

def sum_of_n(n):
    result = 0
    for i in range(1, n+1):
        result += i
    return result
public int SumOfN(int n)  
{  
    int result = 0;  
    for (int i = 1; i <= n; i++)  
    {  
        result += i;  
    }  
    return result;  
}  

このバージョンは正しく機能しますが、時間計算量は O(n) です。 モデルに提供した場合の応答を次に示します。

We can improve this function it by using a mathematical formula instead.

Here's the more efficient version:
def sum_of_n(n):
    return n * (n + 1) // 2
public int SumOfN(int n)  
{  
    return n * (n + 1) / 2;  
}  

このバージョンでも正しい結果が返されますが、時間計算量は O(1) になり、効率性がはるかに向上します。

非効率的なコードをリファクタリングする

優れたコードほどバグが発生する可能性が低く、保守が容易になります。Azure OpenAI モデルは、コードのリファクタリング方法を開発者にガイドするのに役立ちます。

次の関数について考えてみましょう。

def calculateTotalPrice(item, quantity):
    if item == 'apple':
        return quantity * 0.5
    elif item == 'banana':
        return quantity * 0.75
    elif item == 'orange':
        return quantity * 0.6
    else:
        return 0
public double CalculateTotalPrice(string item, int quantity)
{
    if (item == "apple")
    {
        return quantity * 0.5;
    }
    else if (item == "banana")
    {
        return quantity * 0.75;
    }
    else if (item == "orange")
    {
        return quantity * 0.6;
    }
    else
    {
        return 0;
    }
}

このコードは、名前と数量に基づいて特定の項目の合計価格を計算します。 ただし、このコードはモジュール化されていないため、保守が困難な可能性があります。 これをリファクタリングの要求と共にモデルに提供した場合の応答を次に示します。

item_prices = {  
    'apple': 0.5,  
    'banana': 0.75,  
    'orange': 0.6  
}  

def calculate_total_price(item, quantity):  
    price = item_prices.get(item, 0)  
    return quantity * price  
static Dictionary<string, double> itemPrices = new Dictionary<string, double>()  
{  
    {"apple", 0.5},  
    {"banana", 0.75},  
    {"orange", 0.6}  
};  

static double CalculateTotalPrice(string item, int quantity)  
{  
    double price;  
    if (!itemPrices.TryGetValue(item, out price))  
    {  
        price = 0;  
    }  
    return quantity * price;  
}  

モデルからは、コードと共に、リファクタリングの説明が提供されます。

In this refactored code, we've created an object called itemPrices that maps item names to their 
prices. We've also simplified the calculateTotalPrice function by using the itemPrices object to look 
up the price of the item, rather than using a series of if/else statements. This makes the code more 
modular and easier to maintain, and also reduces the risk of introducing bugs in the future.