順應潮流,解放雙手,讓ChatGPT不廢話直接幫忙編寫可融入業務可執行的程式程式碼(Python3.10實現)

劉悅的技術部落格發表於2023-03-16

眾所周知,ChatGPT可以幫助研發人員編寫或者Debug程式程式碼,但是在執行過程中,ChatGPT會將程式程式碼的一些相關文字解釋和程式碼段混合著返回,如此,研發人員還需要自己進行編輯和貼上操作,效率上差強人意,本次我們試圖將ChatGPT直接嵌入到程式碼業務中,讓ChatGPT生成可以直接執行的程式碼。

ChatGPT的主觀回答問題

首先,我們向ChatGPT提出一個簡單的程式碼需求:

可以看到,就像上文所描述的那樣,ChatGPT會將文字描述和程式碼片段混合著返回,其實對於真正的需求者來說,文字描述本身是不必要的,因為如果提問者不知道什麼是布隆過濾器,也就不會提出布隆過濾器相關的程式碼需求。

再看ChatGPT返回的布隆過濾器程式碼:

import hashlib  
  
class BloomFilter:  
    def __init__(self, size, hash_count):  
        self.size = size  
        self.hash_count = hash_count  
        self.bit_array = [False] * size  
  
    def add(self, string):  
        for seed in range(self.hash_count):  
            result = hashlib.sha256((string + str(seed)).encode()).hexdigest()  
            index = int(result, 16) % self.size  
            self.bit_array[index] = True  
  
    def __contains__(self, string):  
        for seed in range(self.hash_count):  
            result = hashlib.sha256((string + str(seed)).encode()).hexdigest()  
            index = int(result, 16) % self.size  
            if not self.bit_array[index]:  
                return False  
        return True

大體上,沒有毛病。但是主觀性太強,什麼是主觀性?就是ChatGPT其實不是站在需求者的視角來編寫程式碼,而是站在自己的角度上,它沒有考慮業務的上下文關係,也就是類和方法命名、方法引數、以及引數型別或者返回值以及型別,這些東西是否符合需求者當前的程式碼業務。

當然,這並不是ChatGPT的錯,主要是輸入的問題描述不夠明確和詳細,但如果每次都需要將程式碼業務邏輯轉化為文字告訴ChatGPT,又有些畫蛇添足,狗尾續貂之感。

基於業務配置ChatGPT

那麼怎樣將ChatGPT融入業務程式碼?首先建立Openai接入函式:

import openai  
  
openai.api_key = "apikey"  
  
def generate_code(func, docstring):  
    init_prompt = "You are a Python expert who can implement the given function."  
    definition = f"def {func}"  
    prompt = f"Read this incomplete Python code:\n```python\n{definition}\n```"  
    prompt += "\n"  
    prompt += f"Complete the Python code that follows this instruction: '{docstring}'. Your response must start with code block '```python'."  
  
    response = openai.ChatCompletion.create(  
        model="gpt-3.5-turbo",  
        temperature=0,  
        max_tokens=1024,  
        top_p=1,  
        messages=[  
            {  
                "role": "system",  
                "content": init_prompt,  
            },  
            {  
                "role": "user",  
                "content": prompt,  
            },  
        ],  
    )  
  
    codeblock = response.choices[0].message.content  
    code = next(filter(None, codeblock.split("```python"))).rsplit("```", 1)[0]  
    code = code.strip()  
  
    return code

訣竅就是提前設定好引導詞:

init_prompt = "You are a Python expert who can implement the given function."  
    definition = f"def {func}"  
    prompt = f"Read this incomplete Python code:\n```python\n{definition}\n```"  
    prompt += "\n"  
    prompt += f"Complete the Python code that follows this instruction: '{docstring}'. Your response must start with code block '```python'."

這裡我們提前設定兩個引數func和docstring,也就是函式名和功能描述,要求ChatGPT嚴格按照引數的輸入來返回程式碼,現在執行函式:

if __name__ == '__main__':  
      
    print(generate_code("test","Sum two numbers"))

程式返回:

➜  chatgpt_write_code /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/chatgpt_write_code/chatgpt_write_code.p  
y"  
def test(a, b):  
    return a + b

如此一來,ChatGPT就不會返回廢話,而是直接交給我們可以執行的程式碼。

裝飾器呼叫ChatGPT

事實上,函式呼叫環節也可以省略,我們可以使用Python裝飾器的閉包原理,直接將所定義函式的引數和描述傳遞給ChatGPT,隨後再直接執行被裝飾的函式,提高效率:

import inspect  
from functools import wraps  
  
def chatgpt_code(func):  
    @wraps(func)  
    def wrapper(*args, **kwargs):  
        signature = f'{func.__name__}({", ".join(inspect.signature(func).parameters)}):'  
        docstring = func.__doc__.strip()  
        code = generate_code(signature, docstring)  
        print(f"generated code:\n```python\n{code}\n```")  
        exec(code)  
        return locals()[func.__name__](*args, **kwargs)  
  
    return wrapper

將方法定義好之後,使用基於ChatGPT的裝飾器:

if __name__ == '__main__':  
      
    @chatgpt_code  
    def sum_two(num1,num2):  
        """  
        Sum two numbers.  
        """  
  
    print(sum_two(1,2))

程式返回:

➜  chatgpt_write_code /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/chatgpt_write_code/chatgpt_write_code.p  
y"  
sum_two(num1, num2):  
generated code:  
  
def sum_two(num1, num2):  
    """  
    Sum two numbers.  
    """  
    return num1 + num2  
  
3

直接將業務邏輯和執行結果全部返回。

那麼現在,回到開篇的關於布隆過濾器的問題:

if __name__ == '__main__':  
      
    @chatgpt_code  
    def bloom(target:str,storage:list):  
        """  
        Use a Bloom filter to check if the target is in storage , Just use this func , no more class  
        """  
  
    print(bloom("你好",["你好","Helloworld"]))

程式返回:

➜  chatgpt_write_code /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/chatgpt_write_code/chatgpt_write_code.p  
y"  
generated code:  
  
def bloom(target, storage):  
    # Initialize the Bloom filter with all zeros  
    bloom_filter = [0] * len(storage)  
      
    # Hash the target and set the corresponding bit in the Bloom filter to 1  
    for i in range(len(storage)):  
        if target in storage[i]:  
            bloom_filter[i] = 1  
      
    # Check if all the bits corresponding to the target are set to 1 in the Bloom filter  
    for i in range(len(storage)):  
        if target in storage[i] and bloom_filter[i] == 0:  
            return False  
      
    return True  
  
True  
➜  chatgpt_write_code

絲滑流暢,和業務銜接得天衣無縫,拉鍊般重合,不需要挑挑揀揀,也不必複製貼上。

結語

毫無疑問,ChatGPT確然是神兵利器,吹毛可斷,無堅不摧。但工具雖好,也需要看在誰的手裡,所謂工具無高下,功力有高深,類比的話,如果倚天劍握在三歲孩童手中,不僅毫無增益,還可能傷其自身,但是握在峨眉掌門滅絕師太手裡,那就可以橫掃千軍如卷席了,那才能體現大宗匠的手段。最後,奉上專案程式碼,與眾鄉親同饗:github.com/zcxey2911/chatgptapi_write_code

相關文章