site logo

Marico's space

AI 编写了 162 个 Python 包,却只有一个能用。这对开源意味着什么?

AI技术与应用 2026-11-03 14:49:04 11

最近折腾 AI(人工智能)生成代码这件事,踩了不少坑,也看到了一个挺刺眼的结果:让 AI 批量生成 Python 包,162 个里真正能用的只有 1 个,成功率只有 0.6%。这篇把这个实验拆开说清楚,也聊聊它对开源软件供应链到底意味着什么。

最初发布于 tamiz.pro。

这个实验给 Python 生态出了一道 harsh 的考题:AI(人工智能)生成了 162 个包,最后只有一个通过了完整检查。0.6% 不只是一个统计数字,它更像一个信号,暴露出“看起来像正确代码”和“运行起来真的正确”之间到底隔了多远,也直接影响我们该如何信任、审查和保护开源生态。

实验到底发生了什么

实验设置并不复杂:研究人员或团队向一个 LLM(大语言模型,Large Language Model)发送提示词,让它生成对开发者有用的 Python 包。AI 随后产出了 162 个包,每个包里都有 setup.py、若干源码文件和一份 README(说明文档)。

接着,团队跑了一套标准质量检查:在干净环境里安装包,执行测试套件(如果有的话),检查常见的安全反模式,再验证公开 API(应用程序接口)是否真的按照文档描述工作。

最终只有一个包通过了全部检查。剩下 161 个包的失败原因,从日常低级错误到严重安全问题都有:

  • 导入失败:包导入了 Python 标准库或声明依赖中根本不存在的模块、函数。
  • API(应用程序接口)调用错误:代码调用库函数时用了错误签名,或者假设某个方法仍然存在,实际上它已经在新版本中被移除了。
  • 依赖缺失:install_requires 列表不完整,运行时缺少传递依赖,包因此直接崩溃。
  • 语法错误:生成的代码甚至不是合法的 Python。只要跑过一次 python -m py_compile 就能发现问题,但当时没人执行这一步。
  • 安全反模式:硬编码 API 密钥、对用户输入直接使用 eval()、以 shell=True 调用 subprocess,以及不安全的 pickle 反序列化。
  • 语义漂移:包单独运行看起来没问题,但接入真实数据或真实业务场景后就会失效。

唯一成功的那个包,大概只是个简单工具:只做一件事,而且把那件事做对了。这并不是偶然。

AI 生成的包为什么会失败

0.6% 的成功率不能简单归结为 AI“不够聪明”。更准确地说,这是评估标准失灵了。大语言模型接受训练,目标是生成看起来像代码的文本,而不是生成行为正确的代码。它没有运行环境的完整心智模型,也不真正理解依赖图,更不知道所调用库的实际语义。它更像模式匹配器,而不是推理器。

具体看,这背后有几类典型的技术故障。

API 幻觉

最常见的失败就是幻觉。模型会调用类似 requests.get_json() 的函数——这个函数根本不存在,只是把 requests.get() 和 .json() 拼成了一种看起来很合理的组合。人眼快速扫一遍代码时很容易觉得没问题,但真正运行时就会直接崩溃。

版本盲区

大语言模型有训练截止时间。它知道某个时间点之前的库是什么样,却不知道 pandas 在 2.0 版本中改过 API,也不知道 numpy 已经弃用 np.float。生成包时,模型可能会在 setup.py 里固定一个根本不存在的版本,也可能使用与声明版本不兼容的 API。

没有错误处理

生成的代码很少包含健壮的错误处理逻辑。它默认一切都走 happy path(理想路径),没有 try/except,没有输入校验,也没有边界情况处理。这意味着即使包能够安装成功,放到生产环境、面对真实条件时依然会失败。

默认不安全

这是最让人不安的一类。模型没有真正的安全模型。它可能顺手生成 subprocess.run(f"rm -rf {path}", shell=True),因为训练数据里这种写法很常见;也可能把凭据直接写进源码,因为它见过太多类似代码。它不知道这些是典型反模式。

开源软件供应链问题

开源软件建立在信任之上。当你执行 pip install 安装一个包时,默认是在信任维护者写过代码、跑过测试,也没有故意埋后门。AI 生成代码会从两个方向破坏这套信任模型。

第一,它带来了规模问题。一个攻击者可以利用大语言模型,在几分钟内生成数千个看起来像模像样的包。这些包不一定都能正常工作,但它们也不需要全部正常。只要表面上足够像真的,让开发者愿意安装就够了。

这正是仿冒包名的温床:AI 可以批量生成 requests2、requestss、requests-utils,配上像模像样的 README 和 setup 文件。最终真正被安装、被执行的少数几个,才是需要重点关注的对象。

第二,它带来了验证问题。162 个里只有 1 个成功,这个数字其实不是最该盯着的指标。真正的问题是:161 个失败包,看起来和那 1 个成功包一样正规。

人工审查一个包的源码时,很难快速分辨它到底是“运行起来会崩的 AI 包”,还是“藏着后门的 AI 包”。两者表面的质量完全一样:有看起来合理的代码、有 README、有许可证,还有 setup.py。

因此,包仓库需要更强的来源信息。我们得知道代码是谁写的,或者由什么工具生成;需要包签名、可复现构建,以及清晰的审计轨迹。否则,AI 生成代码会成为供应链攻击的入口,而且攻击规模会是过去难以想象的。

维护者和开发者应该怎么做

最实际的结论很简单:把 AI 生成的代码当成不可信输入。落实到日常开发,大致是下面这些。

  1. 安装包之前先看源码。不要只看 README,要检查实际代码。如果代码看起来像 AI 生成的——通常过于统一、过于整洁,只在表面细节上显得“正确”——就该提高警惕。
  2. 执行安全扫描。使用 pip-audit、safety 和 bandit 等工具,检查已知漏洞和常见安全反模式。这应该成为 CI(持续集成)流水线里的标准步骤。
  3. 在沙箱里测试。把依赖加入项目之前,先在干净的虚拟环境里安装,再运行测试套件。只要出现崩溃,就说明你及时拦住了问题。
  4. 固定精确版本并使用锁文件。不要让传递依赖自动更新到某个由 AI 生成的版本。锁文件是你的一道防线。
  5. 校验哈希值。使用 pip install --require-hashes,确保安装的正是你审查过的那个包。

下面是一段快速审计示例,可以在正式引入依赖前跑一遍:

# Create a clean venv and install the package
python -m venv /tmp/test-env
source /tmp/test-env/bin/activate
pip install --require-hashes -r requirements.txt # Audit for known vulnerabilities
pip-audit # Scan for security anti-patterns
bandit -r src/
Enter fullscreen mode Exit fullscreen mode

其中任何一步失败,都不要继续使用这个包。为了这点便利承担供应链风险,不值得。

AI 辅助开源的未来

这个实验不该被解读成对 AI 在软件工程领域的否定。它更像是在呼吁我们拿出更好的工具、更好的流程。

未来不是“AI 负责写包”,而是“AI 负责写测试、审查代码、提交补丁、标记潜在漏洞”。换句话说,AI 应该当副驾驶,而不是自动驾驶。

一旦未经人工验证,就把 AI 生成的代码放进生产环境的依赖树里,你就是在拿自己的软件供应链下注。

我们还需要更靠谱的评测基准。当前对 AI 代码生成的评估标准——“能不能编译?”或者“能不能通过单元测试?”——远远不够。我们需要衡量真实场景下的正确性:代码能不能处理边界情况?能不能处理安全问题?它到底有没有解决自己声称要解决的问题?

0.6% 的成功率是一记警钟。它说明 AI 目前还无法独立编写生产级软件;但同时也说明,AI 已经能在极短时间内制造出海量代码。如果放任不管,这种规模本身就是开源生态的重大风险。

关键结论

  • 在一套接近真实的质量检查中,AI 生成代码的成功率约为 0.6%,失败率高达 99.4%。
  • 失败主要来自技术问题:API 幻觉、版本不匹配、缺少错误处理,以及各种安全反模式。
  • 真正的风险在供应链:AI 可以批量生成大量看起来正规的包,让仿冒包名和恶意软件以规模化方式进入开源生态。
  • 解决办法是流程约束:不要在没有人工审查、安全扫描和严格版本固定的情况下,直接信任 AI 生成的代码。
  • 未来应该是副驾驶,而不是自动驾驶:在开源领域,AI 应该辅助人类,而不是取代人类判断。

想了解 AI 与软件工程的更多内容,可以继续关注 Tamiz's Insights 和 tamiz.pro。