眾所周知,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