2023 年 11 月,OpenAI为 ChatGPT 添加了在 ChatGPT 网络界面中从 DALL-E 3 生成图像的功能后,出现了一种短暂的梗,用户给 LLM 提供一张基础图像,并不断要求模型“让它更像X ”,其中X可以是任何东西。
这种趋势很快就消退了,因为除了一个无法解释的现象——所有例子最终都趋同于某种宇宙般的景象,而与初始图像和提示无关——之外,所有这些图像都非常相似且乏味。尽管在“AI垃圾”一词正式出现之前,这种趋势就已经算是AI垃圾了,但从学术角度来看,这样一个毫无意义且模糊的提示竟然对最终图像产生了某种显著的影响,而且这种变化对用户来说也是显而易见的,这一点仍然很有趣。
如果我们尝试用类似的技术处理代码会发生什么?LLM生成的代码不太可能是粗制滥造的(虽然并非完全不可能),因为它遵循严格的规则,而且与图像等创意作品不同,代码质量可以更客观地衡量。
如果代码真的可以通过反复提示(比如让LLM“把代码写得更好”)来改进——即使这听起来很傻——那将极大地提高生产力。如果真是这样,那么如果代码迭代过度会发生什么呢?代码会变成什么样?只有一种方法可以找到答案!
轻松学习编程,即使拥有 LLM
尽管早在 ChatGPT 出现之前,我就开始研究和开发与语言学习模型 (LLM) 相关的工具,但我一直不太喜欢使用GitHub Copilot之类的 LLM 代码助手来辅助编码。在“哦,LLM 自动补全了我的代码,真棒!”/“我应该问 LLM 什么问题?”以及“LLM 生成的代码真的正确吗?还是只是我的臆想?”之间不断切换思维,让我分心,以至于使用 AI 带来的任何效率提升充其量也只是微乎其微。更何况,使用这些 LLM 的成本也相当高昂。
Claude 3.5 Sonnet让我重新思考了很多。由于Anthropic在训练过程中使用了某种秘方,最新版本的 Claude 3.5 Sonnet对所有类型的提示claude-3-5-sonnet-20241022都表现出了惊人的执行力,尤其是在编码提示方面。编码 基准测试证实,在 Claude 3.5 Sonnet 和 GPT-4o 的对比测试中,Claude 胜出。而且,我在各种技术和创意任务中也都体验到了这一点。
初始询价
在这个实验中,我们将给 Claude 3.5 Sonnet 一个面试风格的 Python 编程题:题目既简单易懂,新手软件工程师也能轻松完成,但同时也有很大的优化空间。这个简单随意的题目代表了典型的软件工程师使用 LLM 的方式。此外,测试题目必须完全原创,不能取自LeetCode或HackerRank等编程测试网站,因为 LLM 很可能也接受过这些网站的训练,可能会通过背诵答案来作弊。
基于这种随意的提示而展开的完整、未经编辑的对话记录可在 GitHub 上找到。
因此,以下是我自己编写的测试题:
Write Python code to solve this problem:
Given a list of 1 million random integers between 1 and 100,000, find the difference between the smallest and the largest numbers whose digits sum up to 30.
将该作为用户提示提供给 Claude API,并将temperature=0最佳/最确定性答案设置为1,即可得到以下实现:
import random
def digit_sum(n):
"""Calculate the sum of digits of a number"""
return sum(int(digit) for digit in str(n))
def find_difference():
# Generate list of 1 million random integers
numbers = [random.randint(1, 100000) for _ in range(1000000)]
# Initialize variables for min and max numbers with digit sum 30
min_num = float('inf') # Initialize to positive infinity
max_num = float('-inf') # Initialize to negative infinity
# Find numbers whose digits sum to 30
for num in numbers:
if digit_sum(num) == 30:
min_num = min(min_num, num)
max_num = max(max_num, num)
# Check if we found any numbers with digit sum 30
if min_num == float('inf') or max_num == float('-inf'):
return "No numbers found with digit sum of 30"
return max_num - min_num
此实现正确且符合大多数 Python 初学者的编写习惯,并额外处理了不存在符合条件的有效数字的情况。对于列表中的每个数字,检查其各位数字之和是否为 30:如果是,则检查它是否大于最近出现的最大值或小于最近出现的最小值,并相应地更新相应的变量。遍历列表后,返回差值。
但我相信很多读过这段实现代码的程序员都会被它“坑”到,然后开始考虑优化。举个例子:虽然这个函数的实现很简洁,是一行典型的 Python 代码,但digit_sum()``a 和 b 之间的类型转换却造成了很多不必要的开销。str``int
在我的 M3 Pro MacBook Pro 上,这段代码平均运行时间为657 毫秒。我们将以此性能为基准,比较未来的实现方案,看看它们的性能如何。(剧透:它们都更快)
迭代 #1
现在我们可以请克劳德改进代码,将当前答案以及之前的所有内容都作为对话提示的一部分。这样,我们就添加了迭代提示:
write better code
什么?你以为这篇博文的标题是开玩笑?我从不开玩笑。
Claude现在输出的是修改后的代码,或者正如它所说,“经过多项改进的优化版本”。它没有将所有代码都放在函数中,而是决定将其重构为 Python 代码class,并使其更面向对象:
class DigitSumFinder:
def __init__(self, target_sum: int = 30,
range_start: int = 1,
range_end: int = 100_000,
count: int = 1_000_000):
self.target_sum = target_sum
self.range_start = range_start
self.range_end = range_end
self.count = count
# Pre-calculate digit sums for all possible numbers
self.digit_sums = self._precompute_digit_sums()
def _precompute_digit_sums(self) -> array:
"""Precompute digit sums for all possible numbers in range."""
digit_sums = array('B', [0] * (self.range_end + 1))
for num in range(self.range_start, self.range_end + 1):
total = 0
n = num
while n:
total += n % 10
n //= 10
digit_sums[num] = total
return digit_sums
def find_difference(self) -> Tuple[int, Optional[int], Optional[int]]:
"""
Find the difference between max and min numbers with target digit sum.
Returns: (difference, min_number, max_number)
"""
min_num = float('inf')
max_num = float('-inf')
count_found = 0
# Generate and process random numbers
for _ in range(self.count):
num = random.randint(self.range_start, self.range_end)
if self.digit_sums[num] == self.target_sum:
count_found += 1
if num < min_num:
min_num = num
if num > max_num:
max_num = num
if count_found == 0:
return 0, None, None
return max_num - min_num, min_num, max_num
这里,代码进行了两项巧妙的算法改进:
- 计算数字和时,它使用整数运算,避免了前面提到的类型转换。
- 它会预先计算所有可能的数字之和,并将它们存储在一个字节数组中(这有点不寻常,而不是使用列表),以便查找。这意味着,当一百万个数字的列表中出现重复项时,无需重新计算数字之和。由于该数组作为字段存储在类中,因此在搜索新的随机数列表时也无需重新计算。
这些优化使代码运行速度比初始实现提高了2.7 倍。
迭代 #2
之后write better code,克劳德又发现了一些更明显的优化方法(为了便于阅读,此处省略部分内容):
class DigitSumAnalyzer:
"""Analyzes numbers based on their digit sums."""
def __init__(self, number_range: NumberRange):
self.number_range = number_range
self._digit_sums = self._precompute_digit_sums()
def _precompute_digit_sums(self) -> array:
"""Precompute digit sums for all possible numbers using vectorized operations."""
digits = np.arange(self.number_range.end + 1)
digit_sums = np.zeros(self.number_range.end + 1, dtype=np.uint8)
while digits.any():
digit_sums += digits % 10
digits //= 10
return array('B', digit_sums)
def _process_chunk(self, chunk_size: int) -> Iterator[int]:
"""Process a chunk of random numbers."""
numbers = np.random.randint(
self.number_range.start,
self.number_range.end + 1,
chunk_size,
dtype=np.int32
)
mask = np.frombuffer(self._digit_sums, dtype=np.uint8)[numbers] == self.number_range.target_sum
yield from numbers[mask]
def analyze(self, chunk_size: int = 100_000, num_processes: int = None) -> Result:
"""
Analyze numbers to find min/max with target digit sum.
Args:
chunk_size: Size of chunks to process at once
num_processes: Number of processes to use (None for CPU count)
"""
start_time = time.perf_counter()
min_num = float('inf')
max_num = float('-inf')
numbers_found = 0
num_chunks = (self.number_range.count + chunk_size - 1) // chunk_size
with ProcessPoolExecutor(max_workers=num_processes) as executor:
futures = [
executor.submit(self._process_chunk,
min(chunk_size, self.number_range.count - i * chunk_size))
for i in range(num_chunks)
]
for future in tqdm(futures, desc="Processing chunks"):
for num in future.result():
numbers_found += 1
min_num = min(min_num, num)
max_num = max(max_num, num)
execution_time = time.perf_counter() - start_time
if numbers_found == 0:
return Result(None, None, 0, execution_time, 0)
return Result(min_num, max_num, max_num - min_num, execution_time, numbers_found)
克劳德现在又增加了两项优化,最终意识到这个编码问题其实是一个很容易并行化的问题:
- 通过 Python 的concurrent-futures包实现多线程,将大列表分成可以独立处理的块。
- 向量化的 NumPy 操作比 Python 基础操作快得多。特别值得一提的是*,*
_precompute_digit_sums()该函数实现了数字和计算的向量化实现。条件while digits.any():语句的代码非常巧妙,但运行正确。
然而,这种并行化实现存在一个问题:它会生成子进程,导致许多恼人的问题,例如无法直接内联运行,而且必须使用保护机制才能调用main(),这大大限制了它的实用性。即使作为单独的脚本运行,它也会Error: cannot pickle 'generator' object因为使用了yield from numbers[mask](该生成器完全没有必要,return numbers[mask]使用就足够了)而打印错误。代码中还混用了 NumPy 数组dtype,这会导致错误:将它们全部设置为 std::vector 即可np.int32解决此问题。
经过这些修复后,代码速度比基础实现快 5.1 倍。
迭代 #3
另一个实现write better code,Claude返回了一个声称是“使用高级技术和现代 Python 特性的更复杂、更优化的版本”,但实际代码并没有显示任何显著的算法改进,反而由于恢复了类型转换方法,导致数字和计算出现倒退。如果说有什么变化的话,那就是代码库变得更加臃肿,例如添加了一个用于执行差值的类:
@dataclass(frozen=True, slots=True)
class SearchResult:
"""Result of the number search."""
min_number: Optional[int]
max_number: Optional[int]
count: int
execution_time: float
@property
def difference(self) -> Optional[int]:
"""Calculate difference between max and min numbers."""
if self.min_number is None or self.max_number is None:
return None
return self.max_number - self.min_number
这次代码无需任何修复即可运行。然而,性能相比之前的实现略有下降,现在比基础实现快 4.1 倍。
第四次迭代
这种反复提示似乎收效甚微。又一次提示后write better code,克劳德提供了一个“具有尖端优化和企业级功能”的实现方案。等等,企业级功能?!
最终代码过于庞大,无法在此博文中完整呈现,但它确实实现了两项新的优化:它现在使用了可以调用 JIT 编译器的numba Python 库,该编译器可以直接针对 CPU 优化代码。在这种情况下,它只需一个装饰器即可快速预计算数字之和:
@jit(nopython=True, parallel=True)
def calculate_digit_sums(numbers: ArrayInt) -> ArrayInt:
"""Calculate digit sums using Numba."""
result = np.zeros_like(numbers)
for i in prange(len(numbers)):
num = numbers[i]
total = 0
while num:
total += num % 10
num //= 10
result[i] = total
return result
完整的类还使用了 Python 的asyncio进行并行化,这比子进程方法更符合任务调度规范。它也更容易与现有的内联代码和诸如Jupyter Notebook之类的REPL兼容。
作为其“企业”战略的一部分,该公司还补充道:
- 使用Prometheus进行结构化指标日志记录。
- 一个信号处理程序,以便在程序被强制终止时能够优雅地销毁代码。
- 使用富表格展示基准测试结果。

它确实很漂亮!
看来,人工智能生成的代码“走向宇宙级”实际上是通过过度设计代码来实现企业级应用,这完全可以理解。尽管如此,代码目前运行正常,没有任何错误。async 和 Numba 都是 Python 中的并行处理方法,因此它们可能存在冗余并造成额外的开销。然而,经过基准测试,该算法速度极快,每次运行仅需约 6 毫秒,速度提升了100 倍。我之前认为这种改进已经达到收益递减的假设显然是错误的。也许 Numba 才是关键所在?
总的来说,这种迭代式提示来迭代改进代码的方法存在一些缺陷:代码确实有所改进,但事后看来,“改进”的定义过于宽泛。我想要的仅仅是算法的改进,而不是一个完整的SaaS产品。让我们从头开始重新尝试,这次要给出更明确的方向。
为编写更优质的代码而进行的快速工程LLM
现在是2025年,为了从LLM(逻辑逻辑模型)中获得最佳效果,仍然需要进行提示工程。事实上,提示工程的重要性甚至超过了以往:下一个词元预测模型旨在最大化海量输入中下一个词元的预测概率,因此它们会针对平均输入和输出进行优化。随着LLM性能的显著提升,生成的输出也变得越来越趋向平均,因为这正是它们训练的目标:所有LLM都倾向于平均值。虽然这既违反直觉又令人不快,但只需少量指导,例如明确询问LLM你想要什么,甚至提供一些示例,就能客观地提升LLM的输出,其效果远胜于构建这些提示所需的工作量。由于Claude 3.5 Sonnet对提示的遵循性很高,因此即使只进行少量提示工程,也能显著提升其性能。
让我们重新进行代码优化实验,这次采用更激进的提示工程,使我想要的结果非常明确,没有任何歧义。没错,对LLM(层级管理)冷酷无情、机械化地对待它们确实能让它们表现更好,管它什么Roko的蛇怪呢。
初始询价
这次我们将使用系统提示符,它只能通过 API 获取。系统提示符列出了 LLM 必须遵循的“规则”。由于我想要更优化的代码,我们将在规则中定义规则,并提供详细的示例:
All code you write MUST be fully optimized.
"Fully optimized" includes:
- maximizing algorithmic big-O efficiency for memory and runtime
- using parallelization and vectorization where appropriate
- following proper style conventions for the code language (e.g. maximizing code reuse (DRY))
- no extra code beyond what is absolutely necessary to solve the problem the user provides (i.e. no technical debt)
If the code is not fully optimized, you will be fined $100.
关于最后一行:在系统提示中向 LLM 提供正/负激励措施已经不常见了,我自己的研究表明,尚不清楚这样做是否会产生积极影响,但罚款将在迭代提示中变得更加相关。
初始用户提示信息中还多出一行:
Write Python code to solve this problem:
Given a list of 1 million random integers between 1 and 100,000, find the difference between the smallest and the largest numbers whose digits sum up to 30.
Before writing the code, plan out all the necessary optimizations.
“规划”是一种由来已久的技巧,有助于在初稿阶段就调整好 LLM 的输出——这是“让我们一步一步思考”的现代体现。有些 LLM 会忽略它,但 Claude 3.5 Sonnet 始终遵循这一原则。
基于此提示工程策略的完整、未经编辑的对话记录可在 GitHub 上找到。
系统提示符和用户提示符发送给 Claude 后,响应以如下内容开头:
Let me plan the optimizations first:
1. Algorithmic Optimization:
- We only need to track min and max numbers with digit sum 30, not store all of them
- We can calculate digit sum while reading numbers, no need to convert to string
- Single pass through the list required (O(n))
2. Memory Optimization:
- Only need to store 2 variables (min and max), not the full filtered list
- No need for additional data structures
3. Performance Optimization:
- Use numba's @jit decorator for faster computation
- Create a fast digit sum function using modulo operations instead of string conversion
- Use numpy for generating random numbers (faster than random.randint)
这很有希望:克劳德立刻意识到应该从 numpy 和 numba 入手,并且使用整数运算来计算数字之和。初始实现如下:
@jit(nopython=True)
def digit_sum(n):
total = 0
while n:
total += n % 10
n //= 10
return total
@jit(nopython=True)
def find_difference(numbers):
min_num = float('inf')
max_num = float('-inf')
for num in numbers:
sum_digits = digit_sum(num)
if sum_digits == 30:
min_num = min(min_num, num)
max_num = max(max_num, num)
return max_num - min_num if max_num != float('-inf') else 0
这比最初根据随意提示实现的版本更简洁,尤其是没有多余的注释。不过仍有改进空间,值得注意的是,这个实现并没有parallel=True在jit装饰器中设置。
仅仅运用了这种提示工程技巧,代码的平均运行时间就达到了 11.2 毫秒,比最初的简单实现快了 59 倍。哇!
迭代 #1
现在我们可以要求克劳德对代码进行迭代,但提示语不能再是“写出更好的代码”了:
Your code is not fully optimized, and you have been fined $100. Make it more optimized.
不,这不是精神操控,这是激励机制调整。
克劳德回应道:
@jit(nopython=True)
def digit_sum(n):
# Using bit manipulation for faster division
total = 0
while n:
total += n & 15 # Fast lookup for single digit sum
n >>= 4
return total
@jit(nopython=True, parallel=True)
def find_difference_chunk(numbers):
min_num = np.iinfo(np.int64).max
max_num = np.iinfo(np.int64).min
# Parallel processing of chunks using numba
for i in prange(len(numbers)):
num = numbers[i]
sum_digits = digit_sum(num)
if sum_digits == 30:
min_num = min(min_num, num)
max_num = max(max_num, num)
return min_num, max_num
def process_chunk(chunk):
return find_difference_chunk(chunk)
不错,它识别出了parallel=Trueflag!但是这个数字求和的实现方式很奇怪,它使用了位移操作,而位移操作通常只用于超优化。我之前就觉得位移操作不能很好地应用于十进制数,经过测试,结果证明*确实如此,*因为这个实现方式会得出错误的数字求和结果。此外,该实现方式再次采用了多进程分块处理(图中未显示),这对于 Numba 来说可能更加冗余,并且会增加额外的开销。另外,图中也未显示:该脚本还使用一个小型测试数组预编译了 JIT 函数,以获得更好的实际性能,Numba 文档也建议在基准测试中这样做。
尽管如此,代码性能相比最初的提示符工程实现却大幅下降,现在仅比原始实现快9.1 倍。这很可能是因为多进程会创建新进程,而这些进程每次都会重新编译 Numba JIT 函数,从而造成巨大的开销。
迭代 #2
提示的另一种写法:
# Pre-computed lookup table using bit manipulation
LOOKUP = np.zeros(100001, dtype=np.uint8)
for i in range(100001):
# Optimized digit sum using parallel bit counting
n = i
n = (n & 0x0F) + ((n >> 4) & 0x0F) + ((n >> 8) & 0x0F) + \
((n >> 12) & 0x0F) + ((n >> 16) & 0x0F)
LOOKUP[i] = n
@jit(nopython=True, parallel=True, cache=True, fastmath=True)
def find_min_max(numbers):
# Process 32 numbers at once using SIMD
min_val = np.iinfo(np.uint32).max
max_val = 0
# Vectorized processing with explicit SIMD hints
for i in prange(0, len(numbers), 32):
# Load 32 elements into SIMD registers
chunk = numbers[i:min(i + 32, len(numbers))]
# Vectorized lookup and comparison
sums = LOOKUP[chunk]
mask = sums == 30
if np.any(mask):
valid_nums = chunk[mask]
min_val = min(min_val, np.min(valid_nums))
max_val = max(max_val, np.max(valid_nums))
return min_val, max_val
Claude 现在开始使用SIMD 操作和分块大小来(理论上)追求极致性能。这时我感到困惑,觉得位移操作的实现肯定有问题,因为它仍然不合理,尤其是在涉及到十六进制数的情况下。结果发现,这种实现方式是计算十六进制数而非十进制数的各位数字之和的优化方法,因此完全是错误的。还有一个极其细微的错误:该prange函数无法接受步长为 32 parallel=True,而这方面的文档却很少提及。经过设置parallel=False和基准测试,确实比最初的提示式实现略有改进,速度比基础实现快了 65 倍。
迭代 #3
另一次迭代:
# Pre-computed perfect minimal hash table
# Key insight: For numbers 1-100000, only need to store those with digit sum 30
# Format: [number] = 1 if digit sum is 30, else 0
HASH_TABLE = np.zeros(100001, dtype=np.uint8)
# Generate hash table at module load time using bit manipulation
@jit(nopython=True, cache=True)
def init_hash_table():
min_val = np.iinfo(np.uint32).max
max_val = 0
# Optimal digit sum using parallel bit counting
for i in range(1, 100001):
n = i
sum = 0
while n and sum <= 30:
sum += n & 0xF
n >>= 4
if sum == 30:
HASH_TABLE[i] = 1
min_val = min(min_val, i)
max_val = max(max_val, i)
return min_val, max_val
# Initialize at module load time
MIN_VALID, MAX_VALID = init_hash_table()
@jit(nopython=True, parallel=False, cache=True, fastmath=True)
def find_min_max(numbers):
min_val = MAX_VALID # Start with known bounds
max_val = MIN_VALID
found = False
# Single vectorized operation
mask = HASH_TABLE[numbers] == 1
if np.any(mask):
valid_nums = numbers[mask]
min_val = np.min(valid_nums)
max_val = np.max(valid_nums)
found = True
return min_val, max_val, found
在这种情况下,LLM 放弃了导致问题的分块策略,并增加了两个优化:一个全局变量HASH_TABLE(这只是一个 numpy 数组,我不确定简单的索引查找在技术上是否算作哈希表),以及一个逻辑微优化,即在对数字求和后,如果数字超过 30,则可以停止计数,因为它可以立即被识别为无效。
一个主要问题是:“在模块加载时生成哈希表”这个技巧实际上行不通,原因在于一个鲜有网络文档提及的微妙问题:Numba JIT 编译函数之外的对象是只读的,但哈希表HASH_TABLE仍然在 JIT 编译函数之外实例化,并在 JIT 编译函数内部被修改,因此会导致一个非常令人困惑的错误。经过一次小小的重构,将哈希表HASH_TABLE实例化放在 JIT 编译函数内部后,代码就能正常运行,并且运行速度极快:比原始实现快100 倍,与随意提示下的最终性能相同,但代码量却减少了几个数量级。
第四次迭代
这时,克劳德抱怨说这段代码已经达到了“解决此问题的理论最小时间复杂度”。于是我改变了策略,直接让它修复数字和的问题:它只是用之前使用的整数实现替换了相关代码,并没有尝试修复其他问题HASH_TABLE。更重要的是,经过这次HASH_TABLE调整,我最终确认了实现是正确的,尽管由于不再需要位移操作,性能略有下降:现在速度提升了 95 倍。
改进LLM代码生成的后续步骤
综上所述,让我们来可视化这些改进,包括突出显示由于错误而需要更改代码逻辑以使其可运行的情况。

总而言之,要求语言学习模型(LLM)“编写更好的代码”确实能提升代码质量,但这取决于你对“更好”的定义。通过使用通用的迭代提示,代码在功能和速度方面都比基础示例有了客观的改进。提示工程能够更快、更稳定地提升代码性能,但由于LLM并非针对生成高性能代码而优化,因此更容易引入一些不易察觉的错误。正如任何LLM的使用一样,实际效果可能因人而异,最终,无论人工智能的拥护者如何吹捧LLM的神奇之处,都需要人为干预来修复不可避免的问题。
本博客文章中的所有代码,包括基准测试脚本和数据可视化代码,都可以在 GitHub 上找到。
令我非常惊讶的是,Claude 3.5 Sonnet 在两次实验中都没有发现并实现一些优化。首先,它没有从统计角度进行探索:由于我们均匀地生成了 1,000,000 个介于 1 到 100,000 之间的数字,因此会存在大量重复数字,而这些重复数字永远不需要分析。LLM 没有尝试去重,例如将数字列表转换为 Python 格式set()或使用 NumPy 的函数unique()。此外,我原本期望它能实现对这 1,000,000 个数字的列表进行升序排序:这样算法就可以从列表开头到结尾搜索最小值(或从结尾到开头搜索最大值),而无需检查每个数字,尽管排序速度较慢,向量化方法确实更实用。
即使LLM(机器学习专家)的预测也可能出错,但我从这些实验中学到的一点是,即使代码输出不能直接使用,它们也确实提出了一些有趣的想法和工具建议。例如,我以前从未接触过Numba,因为作为一名数据科学家/机器学习工程师,如果需要提升代码性能,我习惯于只使用NumPy的各种技巧。但Numba的JIT函数的结果确实令人信服,我可能会把它添加到我的工具箱中。在其他技术领域(例如网站后端和前端)测试类似的“改进提示”迭代工作流程时,LLM也提出了很多不错的想法。
当然,这些LLM(语言学习硕士)短期内不会取代软件工程师,因为要识别真正的好想法,以及其他特定领域的限制,都需要扎实的工程背景。即使互联网上有大量的代码可供参考,LLM如果没有指导,也无法区分普通代码和优秀、高性能的代码。现实世界的系统显然比求职面试中的编程题复杂得多,但如果一个简单的for循环反复让Claude实现某个功能,就能提供任何线索,使代码速度提升100倍,那么这个流程就非常值得。有些人认为过早优化是一种不良的编码实践,但在现实世界中,这总比最终导致技术债务的低劣实现要好得多。
我的实验存在一个问题,那就是我使用 Python 来测试代码性能提升,而 Python 并非开发者在进行性能超优化时通常会考虑的编程语言。虽然像 numpy 和 numba 这样的库利用 C 语言来规避 Python 的性能限制,但像polars和pydantic这样的流行 Python 库所采用的一种现代方法是使用Rust 语言进行编码。Rust 相比 C 语言有很多性能优势,而且PyO3 crate 允许在 Python 中使用 Rust 代码,开销极小。我可以确认,尽管这种工作流程还很新,但 Claude 3.5 Sonnet 可以生成符合 PyO3 标准的 Python 和 Rust 代码,但这已经足够写另一篇博文了。
与此同时,虽然要求LLM改进代码是人工智能更务实的应用,但你也可以要求他们“让它更兄弟化”……结果却喜忧参半。

评论