面向程序员的提示
Prompt Engineering - 程序员的高效提示
Section titled “Prompt Engineering - 程序员的高效提示”在本章中,我们将探讨程序员如何通过有效的 Prompt Engineering(提示工程)来利用大型语言模型(LLMs),如 ChatGPT 的强大能力。LLM 凭借其自然语言处理和代码生成能力,可以成为程序员提升工作效率、解决编码难题、理解新概念以及生成各种代码相关成果的宝贵助手。
1. 代码生成与脚手架(Scaffolding)
Section titled “1. 代码生成与脚手架(Scaffolding)”程序员可以提示 LLM 生成各种编程语言的代码片段、函数、类,甚至完整的应用程序脚手架(scaffolds)。
示例:
User: 编写一个 Python 函数,它接受一个整数列表并返回一个只包含偶数的新列表。
LLM:```pythondef get_even_numbers(numbers): """接收一个整数列表,并返回一个只包含偶数的新列表。""" even_numbers = [] for num in numbers: if num % 2 == 0: even_numbers.append(num) return even_numbers
# 示例用法:# my_list = [1, 2, 3, 4, 5, 6]# print(get_even_numbers(my_list)) # 输出:[2, 4, 6]### 2. 代码解释与理解
LLM 可以用自然语言解释复杂的代码片段、算法或编程概念,帮助学习和理解。
示例:
```cssUser: 像给初学者一样解释这段 JavaScript 代码:`const sum = (a, b) => a + b;`
LLM: 当然!让我们来分解这段 JavaScript 代码:
* `const`: 这个关键字用来声明一个变量,它的值不会被重新赋值。你可以把它想象成一个带有固定标签的容器。* `sum`: 这是我们给变量(我们的容器)起的名字。在这个例子中,这个变量将持有一个函数。* `=`: 这是赋值运算符。它表示我们将某个东西放入 `sum` 这个容器中。* `(a, b) => a + b;`: 这是一个箭头函数,它是 JavaScript 中一种简洁的函数写法。 * `(a, b)`: 这些是函数的参数。当你使用(或“调用”)这个函数时,你会提供两个值,在函数内部它们将被命名为 `a` 和 `b`。 * `=>`: 这个箭头分隔了参数和函数所做的事情。 * `a + b`: 这是函数的主体。它简单地将 `a` 的值和 `b` 的值相加。 * 因为它是一个没有花括号 `{}` 的简洁箭头函数,所以 `a + b` 的结果会自动被函数返回。
所以,简单来说,这段代码创建了一个名为 `sum` 的函数,它接受两个数字(`a` 和 `b`)作为输入,并返回它们的总和。3. 调试(Debugging)和故障排除协助
Section titled “3. 调试(Debugging)和故障排除协助”程序员可以描述错误或粘贴有问题的代码,并向 LLM 询问潜在的原因、调试技巧或解决方案。
示例:
User: 我的 Python 代码中遇到了 `TypeError: 'NoneType' object is not iterable` 错误。这可能是什么原因造成的?这是我代码的相关部分:```pythondef get_user_data(user_id): # 模拟一个可能返回 None 的数据库调用 if user_id == 0: return None return ["data1", "data2"]
user_info = get_user_data(0)for item in user_info: print(item)LLM: TypeError: 'NoneType' object is not iterable 错误发生是因为当 user_id 为 0 时,你的 get_user_data 函数返回了 None。然后,在 for item in user_info: 这行代码中,你试图对 user_info 进行循环(迭代),而 user_info 当前的值是 None。
None 在 Python 中是一个特殊值,表示没有值,它不是一个你可以像列表或字符串那样进行循环的对象。
要解决这个问题,你需要在尝试迭代 user_info 之前检查它是否为 None:
def get_user_data(user_id): if user_id == 0: return None return ["data1", "data2"]
user_info = get_user_data(0)
if user_info is not None: for item in user_info: print(item)else: print("未找到用户数据。")这样,你只有在 user_info 确实包含数据(本例中是列表)时,才会尝试进行循环。
### 4. 代码重构(Refactoring)和优化(Optimization)
LLM 可以对现有代码提出改进建议,使其更高效、可读性更强或更符合最佳实践。
示例:
```pythonUser: 你能帮我重构这段 Python 代码,让它更符合 Python 习惯或更高效吗?```pythonmy_string = "hello world"upper_case_string = ""for char in my_string: upper_case_string += char.upper()LLM: 可以,这段代码可以写得更符合 Python 风格且更高效。以下是几种方法:
-
直接使用
str.upper()方法: 最简单的方法是直接调用整个字符串的.upper()方法:my_string = "hello world"upper_case_string = my_string.upper()# print(upper_case_string) # 输出:HELLO WORLD -
使用列表推导式(list comprehension)和
str.join()(对于这种情况比较冗长,但适用于更复杂的转换): 对于简单的转换为大写字母,这种方法可能有点过度,但它展示了一种更复杂的逐字符转换的常见模式:my_string = "hello world"upper_case_string = "".join([char.upper() for char in my_string])# print(upper_case_string) # 输出:HELLO WORLD
仅仅为了将字符串转换为大写,第一种方法(my_string.upper())是最直接且最符合 Python 习惯的方式。
### 5. 生成文档(Documentation)和注释(Comments)
提供代码,并要求 LLM 生成 docstrings(文档字符串)、注释,甚至 README 文件中的部分内容。
### 6. 代码语言翻译
LLM 可以协助将代码从一种编程语言翻译成另一种,尽管始终需要仔细审查。
### 7. 编写单元测试(Unit Tests)
提供一个函数或类,并要求 LLM 使用特定的测试框架为其生成单元测试用例。
### 程序员使用 LLM 提示的最佳实践
- 具体并提供上下文:清晰地说明编程语言、涉及的库/框架以及期望的结果。对于代码生成,描述函数的功能、输入和输出。- 提供代码片段:询问关于现有代码的问题时,包含相关的代码片段。- 迭代和细化:如果首次回复不完美,细化您的提示或提出后续问题。- 指定限制条件:如果您有特定的限制(例如,“使用 Python 3.8 的特性”、“避免使用外部库”),请提及。- 验证和测试:在将 LLM 生成的任何代码用于生产环境之前,务必进行严格审查和彻底测试。LLM 可能会犯错。- 分解复杂问题:对于大型任务,将其分解为更小、更易管理的部分,并分别对每个部分进行提示。
### 应用示例:Python 实现(使用 LLM 解决编码问题)
这个 Python 脚本演示了如何使用 OpenAI API 向 LLM 提问编程相关的问题,例如如何实现一个算法。
```pythonimport openaiimport os
# 推荐:通过环境变量设置你的 API key。# openai.api_key = os.getenv("OPENAI_API_KEY")# 对于本教程,使用一个占位符。请替换为你实际的 key。openai.api_key = 'YOUR_API_KEY'
def get_coding_assistance(question, language="Python"): prompt_content = ( f"我有一个关于 {language} 的编程问题。\n" f"问题:{question}\n" f"请提供清晰的解释,并在适用的情况下提供代码示例。" )
messages = [ {"role": "system", "content": "你是一位专业的编程助手,擅长解释概念并提供准确的代码示例。"}, {"role": "user", "content": prompt_content} ]
try: response = openai.chat.completions.create( model="gpt-3.5-turbo", # 或更新的模型,如 gpt-4o-mini messages=messages, max_tokens=800, # 为详细的解释和代码留出足够的 token temperature=0.5, # 平衡创造性和事实性 n=1, stop=None ) return response.choices[0].message.content.strip() except Exception as e: return f"发生错误:{e}"
# 示例用法:programming_question = "如何在 Python 中实现二分查找算法?请编写代码并解释其工作原理。"
assistance = get_coding_assistance(programming_question, language="Python")print("LLM 协助结果:")print(assistance)该脚本将打印 LLM 的响应,通常会包含对二分查找的解释和一个 Python 代码实现:
LLM 协助结果:当然!二分查找(Binary search)是一种从**已排序**的元素列表中查找特定元素的有效算法。它的工作原理是反复将可能包含目标元素的列表部分分成两半,直到将可能的位置缩小到只剩一个为止。
概念上它是这样工作的:1. 将目标值与已排序列表的中间元素进行比较。2. 如果目标值与中间元素匹配,则找到了其位置。3. 如果目标值小于中间元素,则它只能位于列表的下半部分。因此,对下半部分重复此过程。4. 如果目标值大于中间元素,则它只能位于列表的上半部分。因此,对上半部分重复此过程。5. 持续此过程,直到找到元素或子列表变空(表示列表中不存在该元素)。
以下是二分查找的 Python 实现:
```pythondef binary_search(sorted_list, target): """ 在已排序列表中执行二分查找以查找目标元素。 如果找到目标,返回其索引;否则返回 -1。 """ low = 0 high = len(sorted_list) - 1
while low <= high: mid = (low + high) // 2 # 找到中间索引
if sorted_list[mid] == target: return mid # 目标在索引 mid 处找到 elif sorted_list[mid] < target: low = mid + 1 # 目标在右半部分 else: high = mid - 1 # 目标在左半部分
return -1 # 列表中未找到目标
# 示例用法:my_sorted_list = [2, 5, 7, 8, 11, 12, 15, 18]target_element = 12index = binary_search(my_sorted_list, target_element)
if index != -1: print(f"元素 {target_element} 在索引 {index} 处找到")else: print(f"列表中未找到元素 {target_element}。")
# 另一个示例target_element_not_present = 10index_not_present = binary_search(my_sorted_list, target_element_not_present)if index_not_present != -1: print(f"元素 {target_element_not_present} 在索引 {index_not_present} 处找到")else: print(f"列表中未找到元素 {target_element_not_present}。")关于二分查找需要记住的关键点:
- 它必须用于已排序的列表。如果列表未排序,二分查找将无法正确工作。
- 它非常高效,时间复杂度为 O(log n),适用于大型数据集。
### 结论
在本章中,我们探讨了程序员如何通过战略性的 Prompt Engineering 有效地使用 LLM,如 ChatGPT。从生成代码和解释,到协助调试、重构和编写文档,LLM 可以显著增强程序员的能力。
通过遵循最佳实践——具体说明、提供上下文、进行迭代以及始终验证 LLM 生成的输出——程序员可以利用这些 AI 工具来改进工作流程、更快地学习并提高整体生产力。