
最近折腾 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 个包的失败原因,从日常低级错误到严重安全问题都有:
install_requires 列表不完整,运行时缺少传递依赖,包因此直接崩溃。python -m py_compile 就能发现问题,但当时没人执行这一步。eval()、以 shell=True 调用 subprocess,以及不安全的 pickle 反序列化。唯一成功的那个包,大概只是个简单工具:只做一件事,而且把那件事做对了。这并不是偶然。
0.6% 的成功率不能简单归结为 AI“不够聪明”。更准确地说,这是评估标准失灵了。大语言模型接受训练,目标是生成看起来像代码的文本,而不是生成行为正确的代码。它没有运行环境的完整心智模型,也不真正理解依赖图,更不知道所调用库的实际语义。它更像模式匹配器,而不是推理器。
具体看,这背后有几类典型的技术故障。
最常见的失败就是幻觉。模型会调用类似 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 生成的代码当成不可信输入。落实到日常开发,大致是下面这些。
pip-audit、safety 和 bandit 等工具,检查已知漏洞和常见安全反模式。这应该成为 CI(持续集成)流水线里的标准步骤。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/
其中任何一步失败,都不要继续使用这个包。为了这点便利承担供应链风险,不值得。
这个实验不该被解读成对 AI 在软件工程领域的否定。它更像是在呼吁我们拿出更好的工具、更好的流程。
未来不是“AI 负责写包”,而是“AI 负责写测试、审查代码、提交补丁、标记潜在漏洞”。换句话说,AI 应该当副驾驶,而不是自动驾驶。
一旦未经人工验证,就把 AI 生成的代码放进生产环境的依赖树里,你就是在拿自己的软件供应链下注。
我们还需要更靠谱的评测基准。当前对 AI 代码生成的评估标准——“能不能编译?”或者“能不能通过单元测试?”——远远不够。我们需要衡量真实场景下的正确性:代码能不能处理边界情况?能不能处理安全问题?它到底有没有解决自己声称要解决的问题?
0.6% 的成功率是一记警钟。它说明 AI 目前还无法独立编写生产级软件;但同时也说明,AI 已经能在极短时间内制造出海量代码。如果放任不管,这种规模本身就是开源生态的重大风险。
想了解 AI 与软件工程的更多内容,可以继续关注 Tamiz's Insights 和 tamiz.pro。