哈希娱乐 行业新闻 党建先锋

如果不断要求 LLM 写出更好的代码它真的能写出更好的代码吗?哈希娱乐

发布时间:2025-12-06 18:07:08  浏览:

  哈希游戏作为一种新兴的区块链应用,它巧妙地结合了加密技术与娱乐,为玩家提供了全新的体验。万达哈希平台凭借其独特的彩票玩法和创新的哈希算法,公平公正-方便快捷!万达哈希,哈希游戏平台,哈希娱乐,哈希游戏:用户会给 LLM(大语言模型)一张基础图片,然后不断要求它让图片更 X,这里的 X 可以是任何特征或风格。

  A regular guy becomes more bro every time. via /u/Jojop0tato on Reddit.

  Asked ChatGPT to make Santa Claus more and more serious. via /u/hessihan on Reddit.

  这个趋势很快就消失了,因为生成的图像都过于相似,缺乏新意。有趣的是,无论初始图像和提示词如何不同,最终的结果都会趋向于某种宇宙化的效果。这种现象在AI 垃圾(AI slop)这一术语被正式定义之前,就已经是典型的AI 垃圾[3]了。不过从学术角度来看,即使是这些看似无意义和模糊的提示词,也能对最终图像产生明显的、可预测的影响,这一点仍然值得玩味。

  如果我们对代码用类似的方法会怎样呢?由于代码需要遵循严格的规则,而且与图像等创意输出不同,代码质量可以更客观地衡量,所以 LLM 生成的代码不太可能是垃圾(尽管也不是完全不可能[4])。

  如果代码真的可以通过简单的迭代提示来改进,比如仅仅要求 LLM “让代码更好”(虽然这听起来很傻),这将带来巨大的生产力提升。那么,如果不断这样迭代下去会发生什么?代码会出现什么样的宇宙化效果?让我们来一探究竟!

  尽管在 ChatGPT 出现之前我就一直在研究和开发 LLM 相关工具,但我并不喜欢使用 LLM 代码协助工具(如 GitHub Copilot)来辅助编码。在哦,LLM 自动完成了我的代码,很好/我应该问 LLM 什么问题和LLM 生成的代码真的正确吗,它是否在产生幻觉[5]并生成看似正确的代码之间不断切换思维,这种持续的心智负担抵消了使用 AI 带来的任何生产力提升。这还没有考虑使用这些 LLM 的昂贵成本。

  在这个实验中,我们将给 Claude 3.5 Sonnet 一个面试风格的 Python 编码提示词:一个简单适合被新手软件工程师实现,但同时又可以进行大量优化的问题。这个简单随意的提示词代表了典型软件工程师使用 LLM 的方式。此外,测试提示词必须完全原创,而不是取自 LeetCode 或 HackerRank 等编码测试平台,因为 LLM 很可能在这些平台上进行过训练,可能会通过背诵记忆的答案作弊。

  完整的、未经编辑的基于这种随意提示的对话内容可在 GitHub 上获取[9]。

  编写 Python 代码来解决这个问题: 给定一个包含 100 万个 1 到 100,000 之间的随机整数的列表,找出数字之和等于 30 的最大数和最小数之间的差值。

  将其作为用户提示词给 Claude API,并设置 temperature=0 以获得最佳/最确定的答案,最终实现如下:

  这个实现是正确的,并且与大多数 Python 新手程序员的写法一致,还额外处理了没有符合条件的数字的情况。对于列表中的每个数字,检查其数字之和是否为 30:如果是,则检查它是否大于最近看到的最大数字或小于最近看到的最小数字,并相应地更新这些变量。搜索完列表后,返回差值。

  但我敢肯定,许多阅读这个实现的程序员都会思考如何优化。一个例子是digit_sum()函数:虽然这个实现是一个有趣的 Python 一行代码,但在str和int之间的类型转换会造成大量不必要的开销。

  在我的 M3 Pro MacBook Pro 上,这段代码平均需要 657 毫秒运行。我们将使用这个性能作为基准,来比较后续实现的测试结果(剧透:它们都更快)。

  现在我们可以让 Claude 改进代码,将其当前答案和之前的所有内容作为对话提示的一部分。因此,我们添加迭代提示:

  Claude 输出了修改后的代码,用它的话说是代码的优化版本,有几处改进。它没有将代码保持为函数形式,而是重构为 Python 类,使其更加面向对象:

  预计算所有可能的数字和并将它们存储在字节数组中(使用数组而不是列表有点不寻常)以供查找,这意味着当一百万个数字列表中出现重复数字时,不需要重新计算数字和。由于这个数组作为类的字段存储,在搜索新的随机数列表时不需要重新计算。

  再次提示写更好的代码,Claude 发现了更多明显的优化(为了可读性进行了截断):

  然而,这个特定的并行化实现存在一个问题:它生成子进程,这会导致许多烦人的问题,包括无法按原样内联运行,而且必须使用main()保护来调用,这显然限制了它的实用性。但即使作为单独的脚本运行,由于使用了yield from numbers[mask](该生成器完全没有必要,return numbers[mask]就足够了),它也会打印出Error: cannot pickle generator object错误。代码还混合了 numpy 数组的dtype,这会导致错误:将它们全部设置为np.int32可以修复这个问题。

  再次写更好的代码,Claude 返回了新的实现,它声称是使用高级技术和现代 Python 特性的更加复杂和优化的版本。但实际代码并没有显示出重要的算法改进,实际上在数字和计算方面还出现了倒退,回到了类型转换的方法。如果说有什么的话,代码库变得更加臃肿,比如添加了一个用于执行差值计算的类:

  这次,代码无需任何修复就能运行。然而,性能略微下降,相比基础实现现在只快了 4.1 倍。

  这种迭代提示似乎遇到了收益递减。在再一次写更好的代码之后,Claude 提供了新的实现,声称具有尖端优化和企业级功能。等等,企业级功能?!

  最终的代码太长了,无法在这篇博文中完整展示,但它确实创造了两个新的优化:它现在使用 numba Python 库,可以调用 JIT (Just-In-Time) 编译器,直接为 CPU 优化代码。在这种情况下,它可以通过一个装饰器实现数字和的超快速预计算:

  完整的类还使用 Python 的 asyncio 进行并行化,这比子进程方法更规范,更适合用于任务调度。它也能更好地与现有的内联代码和 REPL(如 Jupyter Notebooks)配合使用。

  看起来 AI 生成代码的宇宙化就是通过过度工程使其变得企业级,这完全说得通。尽管如此,代码可以不出任何错误地运行。async 和 numba 都是 Python 中的并行方法,所以它们可能造成冗余并产生额外开销。然而,在基准测试后,算法运行速度非常快,每次运行大约 6 毫秒,也就是提速了 100 倍。这完全推翻了我之前认为这种提示词会遇到收益递减的假设。也许 numba 一直都是秘密武器?

  总的来说,这种形式的迭代提示词来改进代码有其注意事项:代码确实变得更好了,但事后看来,更好的定义太过宽泛。我只想要算法上的改进,而不是一个完整的 SaaS。让我们从头再来一次,这次要有更明确的方向。

  现在是 2025 年,要从 LLM 那里获得最佳结果,提示词工程 (prompt engineering) 仍然是必需的。事实上,提示词工程对 LLM 变得更加重要:下一个 token 预测模型是通过在大批量输入上最大化下一个 token 的预测概率来训练的,因此它们针对平均输入和输出进行优化。随着 LLM 的显著改进,生成的输出变得更加平均化,因为这就是它们的训练目标:所有 LLM 都偏向于平均值。虽然这既违反直觉又不有趣,但少量的指导,明确告诉 LLM 你想要什么,以及给出一些你想要的例子,将客观上改善 LLM 的输出,远超过构建这些提示词所需的努力。Claude 3.5 Sonnet 由于其强大的提示词遵循能力,即使只是一点点提示词工程也能显著受益。

  让我们重做代码优化实验,这次使用积极的提示词工程,确保我们要的结果非常明确,不留任何模糊空间。没错,对 LLM 采用冷酷和机器人化的方式反而能让它们表现得更好,管它什么洛夫克拉夫特式的恐惧呢。

  这次我们将使用系统提示词,这只能通过 API 使用。系统提示词列出了 LLM 必须遵循的规则。既然我想要更优化的代码,我们就在规则中定义这一点,并提供详细的例子:

  你写的所有代码都必须完全优化。 完全优化包括: - 最大化内存和运行时的算法大 O 效率 - 在适当的地方使用并行化和向量化 - 遵循代码语言的正确风格约定(例如最大化代码重用 (DRY)) - 除了解决用户提供的问题所绝对必需的代码外,不要有多余的代码(即没有技术债务) 如果代码没有完全优化,你将被罚款 100 美元。

  关于最后一行:在系统提示词中向 LLM 提供正面/负面激励已不再常见,而且我自己的研究表明,这种方法是否有积极影响还不确定。不过,这个罚款设定在后续的迭代提示中会变得更加重要。

  编写 Python 代码来解决这个问题: 给定一个包含 100 万个 1 到 100,000 之间的随机整数的列表,找出数字之和等于 30 的最大数和最小数之间的差值。 在编写代码之前,请规划所有必要的优化。

  规划是一个长期使用的技巧,可以帮助对齐大语言模型的第一次输出 — 这是让我们一步一步思考[13]的现代实现。有些大语言模型会忽略它,但 Claude 3.5 Sonnet 总是会遵循。

  基于这个提示词工程策略的完整、未经编辑的对话线程可在 GitHub 上获取[14]。

  让我先规划优化: 1. 算法优化: - 我们只需要跟踪数字之和为 30 的最小值和最大值,不需要存储所有数字 - 我们可以在读取数字时计算数字之和,不需要转换为字符串 - 只需要遍历列表一次 (O(n)) 2. 内存优化: - 只需要存储 2 个变量(最小值和最大值),不需要完整的过滤列表 - 不需要额外的数据结构 3. 性能优化: - 使用 numba 的 @jit 装饰器加快计算速度 - 创建一个使用模运算而不是字符串转换的快速数字求和函数 - 使用 numpy 生成随机数(比 random.randint 更快)

  这很有希望:Claude 立即意识到它应该从 numpy 和 numba 开始,并且使用整数运算来计算数字之和。初始实现:

  这比随意提示词的初始实现更简洁,特别是没有不必要的注释。但仍然有改进的空间,例如这个实现没有在jit装饰器中设置parallel=True。

  这种小型的提示词工程导致的代码平均运行时间为 11.2 毫秒,比初始实现快了 59 倍。令人惊叹!

  很好,它识别出了parallel=True标志!但是那个数字求和实现很奇怪,使用了位移操作[15],这通常只用于超优化。我不认为你可以在十进制数上很好地使用位移操作,经过测试,事实证明确实不行,因为这个实现计算出的数字之和是错误的。该实现还包括了多进程分块方法(未显示),这可能与 numba 重复并造成额外开销。同样未显示的是:脚本还使用小型测试数组预编译了 JIT 函数以获得更好的实际性能,这是numba 文档推荐[16]的基准测试方法。

  尽管如此,代码性能相比初始提示词工程实现大幅下降,现在只比朴素实现快 9.1 倍。可能的原因是由于多进程生成新进程,这些进程每次都会重新编译 numba JIT 函数[17],因此存在巨大的开销。

  Claude 开始使用SIMD 操作[18]和块大小来实现(理论上的)极致性能。我对那个位移实现感到困惑,因为它仍然是错误的,特别是现在涉及到十六进制数。事实证明,这是一个计算十六进制数字的数字之和的优化方法,而不是十进制数字,因此这完全是一个幻觉。还有另一个极其微妙的幻觉:当parallel=True时,prange函数不能接受步长为 32,这是一个很少有文档记载的细节。设置parallel=False并进行基准测试,确实比初始提示词工程实现略有改进,比基础实现快 65 倍。

  在这种情况下,大模型放弃了一直造成问题的分块策略,并添加了两个优化:一个全局HASH_TABLE(这只是一个 numpy 数组,我不确定简单的索引查找是否真的算作哈希表),它还引入了一个逻辑微优化,即在对数字求和时,如果数字超过 30,计数就可以停止,因为它可以立即被识别为无效。

  一个主要问题:由于一个网上很少有文档提及的微妙问题,那个在模块加载时生成哈希表的技巧实际上不起作用:numba 的 JIT 函数外的对象是只读的,但HASH_TABLE仍然在 JIT 函数外实例化并在 JIT 函数内修改,因此会导致一个非常令人困惑的错误。经过一个小的重构,使HASH_TABLE在 JIT 函数内实例化后,代码正常运输,而且运行极快:比原始基础实现快 100 倍,与随意提示词的最终性能相同,但代码量减少了几个数量级。

  此时,Claude 提示说代码已经达到了这个问题理论上可能的最小时间复杂度。所以我改变了方向,只是让它修复数字求和问题:它实现了[19],而且仅用之前使用的整数实现替换了相关代码,并没有试图修复HASH_TABLE。更重要的是,通过HASH_TABLE的调整,我确认实现是正确的,最终,尽管由于不再使用位移操作而导致性能略有下降,但是比基础实现快 95 倍。

  综合所有内容,让我们来可视化这些改进,包括突出显示那些由于 bug 而需要我修改代码逻辑才能运行的情况。

  总的来说,要求 LLM 写更好的代码确实能让代码变得更好,这取决于你如何定义更好。通过使用通用的迭代提示词,代码在功能性和执行速度方面都得到了显著提升。提示词工程能更快速且更稳定地改进代码性能,但也更容易引入细微的 bug,这是因为 LLM 本身并非为生成高性能代码而训练的。与使用 LLM 的其他场景一样,效果因人而异。无论 AI 炒作者们如何吹捧 LLM 为神器,最终都需要人工干预来修复那些不可避免的问题。

  本博文中的所有代码,包括基准测试脚本和数据可视化代码,都可在 GitHub 上获取[20]。

  出乎我意料的是,Claude 3.5 Sonnet 在两个实验中都没有发现和实现某些优化。具体来说,它没有从统计学角度来思考:由于我们是从 1 到 100,000 的范围内均匀生成 1,000,000 个数字,必然会出现大量无需重复分析的数字。LLM 没有通过将数字列表转换为 Pythonset()或使用 numpy 的unique()来去重。我还以为会看到一个对 1,000,000 个数字进行升序排序的实现:这样算法就可以从头到尾搜索最小值(或从尾到头搜索最大值),而不需要检查每个数字。不过排序操作较慢,向量化方法确实更实用。

  即使大语言模型可能会出错,我从这些实验中得到的一个重要启示是,即使代码输出不能直接使用,它们仍提供了有趣的想法和工具建议。例如,我从未接触过 numba,因为作为一个数据科学家/机器学习工程师,如果我需要更好的代码性能,我习惯于使用 numpy 的技巧。然而,numba JIT 函数的效果令人难以忽视,我可能会把它加入我的工具箱。当我在其他技术领域(如网站后端和前端)测试类似的“优化代码”提示词迭代工作流时,LLM 也提出了不少有价值的建议。

  当然,这些大语言模型不会很快取代软件工程师,因为需要强大的工程师背景以及其他特定领域的知识,才能识别出什么才是真正好的实现。即使互联网上有大量的代码,若没有指导,大语言模型也无法区分普通代码和优秀的高性能代码。现实世界的系统显然比面试式的编程问题复杂得多,但如果通过快速反复要求 Claude 实现一个功能,能使代码速度提高 100 倍,那这个流程就非常值得。有些人认为过早优化[21]是不好的编码实践,但在实际项目中,这比那些随着时间的推移会变成技术债务的次优实现要好得多。

  我的实验存在一个局限性,那就是我使用 Python 来对代码改进进行基准测试,而这并不是开发者在追求极致性能优化时的首选编程语言。虽然像 numpy 和 numba 这样的库通过利用 C 语言来解决了 Python 的性能瓶颈,但更现代的解决方案是采用 polars 和 pydantic 等流行 Python 库,它们使用 Rust 开发。Rust 在性能方面比 C 语言更具优势,而 PyO3 几乎没有性能损耗就能让 Python 调用 Rust 代码。我可以确认 Claude 3.5 Sonnet 能够生成兼容 Python 和 Rust 代码,不过这种工作流程太新颖了,足够成为另一篇博文的主题。

  以此同时,虽然要求 LLM 让代码变得更好是 AI 更实用的用途,但你也可以要求它们让代码更兄弟...效果好坏参半。

  如果你正在寻找优质的Python文章和项目,我必须向你推荐Python潮流周刊!

  它精选全网的优秀文章、教程、开源项目、软件工具、播客、视频、热门话题等丰富内容,让你紧跟技术最前沿,获取最新的第一手学习资料!

  欢迎点击下方图片,了解这份全世界知识密度最高、知识广度最大的 Python 技术周刊。

  特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

  悬赏10万!陕西58岁男子酒后失踪240多天,最后一通电话称“没路了”,多方搜救

  中国宅男日本报恩记,流浪日本街头被日本大叔收留,几年后他做了这么一个举动

  陈梦晒和黄晓明六宫格合照,一身西装妆容精致,黄晓明回应:谁这么幸运,有又酷又棒又美又飒的妹妹

  OpenAI“紧急提前”发布GPT 5.2,应对Gemini 3的火爆

  索尼Bravia 9 II旗舰Mini LED电视曝光:4000尼特亮度

  Wuque Studio发布内置机械腕表机芯的高端定制机械键盘Nama