1. 从“鹈鹕骑车”说起:为什么一个3D小场景能测出大模型的真实水平
第一次看到“鹈鹕骑车”这个测试题,我差点笑出声。一只鹈鹕,蹬着一辆自行车,在3D空间里摇摇晃晃地前进——这画面本身就带着一种荒诞的喜感。但笑完之后我意识到,这道题的精妙之处恰恰在于它的“不正经”。它不像那些标准的代码评测题,让你写个排序算法或者实现一个红黑树,那些题目大模型早就背得滚瓜烂熟了。鹈鹕骑车不一样,它要求模型同时理解三件事:一个具体的动物形象、一个机械装置、以及两者之间的物理交互关系,最后还要用代码把这个场景在浏览器里渲染出来。
我最初是在一个技术社区里看到有人用这个题目测试GPT-6 Astra的。当时那个帖子只放了一张截图,一只用基本几何体拼出来的鹈鹕,身体是个椭球,嘴巴是两个圆锥,翅膀是压扁的球体,骑在一辆用圆柱体和圆环组成的自行车上。画面谈不上精致,但该有的元素一个不少,而且鹈鹕的脚确实踩在踏板上,翅膀搭在车把上,整个姿态是合理的。底下有人评论说“这比很多人类画的示意图都强”,也有人不服气,说“不就是堆几个Three.js的几何体吗,有什么难的”。
我属于后者。作为一个写了七八年前端、最近两年一直在折腾大模型应用的人,我第一反应是:这题不难啊,无非就是调用Three.js的API,创建几个Mesh,设置一下位置和旋转,再写个动画循环让轮子转起来。任何一个熟悉Three.js的开发者,花个把小时都能手搓出来。但当我真正开始用不同的大模型去生成这个场景的代码时,我才发现自己低估了这件事的复杂度。问题不在于“能不能写出来”,而在于“能不能一次写对”。大模型生成的代码,往往在几何体的比例、位置关系、旋转角度这些细节上出问题。鹈鹕的嘴巴可能长在头顶上,自行车轮子可能悬空,或者鹈鹕的腿直接穿模到车架里面。这些错误在纯文本代码里看不出来,但一渲染就原形毕露。
所以这个测试的本质,其实是在考察大模型的空间推理能力和代码生成的精确性。它要求模型不仅知道Three.js有哪些API,还要能在脑子里构建出一个三维场景,理解各个物体之间的相对位置和层级关系,最后用准确的数值把这些关系表达出来。这比生成一段业务逻辑代码要难得多,因为业务逻辑有明确的输入输出和边界条件,而三维场景的“正确性”是模糊的、连续的。一个鹈鹕的嘴巴偏离了5度,在代码层面可能只是rotation.z从Math.PI/2变成了Math.PI/2.1,但渲染出来就是“看起来怪怪的”。
我决定认真做一次横向对比。我选了12款目前主流的大模型,包括GPT-6 Astra、Claude 4 Opus、Gemini 2.5 Ultra、DeepSeek-V4、Qwen 3.5-Max、Llama 4-405B,以及几个国内外的开源和闭源模型。测试方法很简单:给每个模型相同的提示词,要求它生成一个完整的HTML文件,用Three.js渲染一只骑自行车的鹈鹕,包含基本的动画效果。然后我把生成的代码保存下来,在浏览器里逐一打开,从几何体完整性、空间关系正确性、动画流畅度、代码可读性四个维度打分。结果出乎我的意料,也让我对“大模型写3D代码”这件事有了全新的认识。
2. 测试环境搭建:从零准备一个可复现的评测流程
2.1 为什么选择Three.js而不是其他3D方案
在开始测试之前,我需要先确定技术栈。市面上做Web 3D的方案不少,Three.js、Babylon.js、PlayCanvas,还有直接用WebGL或者WebGPU的。我选Three.js的原因有三个。第一,它的生态最成熟,文档和示例最丰富,大模型在训练数据里见过的Three.js代码量远超其他库,这意味着模型对它的API更熟悉,生成的代码质量上限更高。第二,Three.js的抽象层级适中,它不像直接写WebGL那样需要处理着色器和缓冲区,也不像某些高层引擎那样把细节全封装起来,刚好能考察模型对三维空间的理解。第三,它的CDN引入方式极其简单,一行<script>标签就能用,不需要构建工具,方便我快速测试。
提示:如果你也想复现这个测试,建议固定Three.js的版本。我使用的是r168,不同版本之间API有差异,比如
Geometry和BufferGeometry的用法就完全不同。固定版本能保证测试结果的可比性。
2.2 统一的提示词设计:如何让模型“听懂”需求
提示词的设计直接决定了测试的公平性。如果提示词太模糊,模型自由发挥的空间太大,出来的结果千奇百怪,没法比较。如果提示词太详细,又变成了“填空”,考察不出模型的真实能力。我最终采用的提示词是这样的:
请生成一个完整的HTML文件,使用Three.js创建一个3D场景,场景中有一只鹈鹕骑着一辆自行车。要求: 1. 鹈鹕和自行车都用Three.js的基本几何体组合而成,不要加载外部模型文件。 2. 鹈鹕要有身体、嘴巴、翅膀、腿和脚,自行车要有两个轮子、车架、车把和踏板。 3. 鹈鹕的脚要踩在踏板上,翅膀要搭在车把上。 4. 添加一个动画循环,让自行车的轮子转动,鹈鹕的身体有轻微的上下起伏。 5. 场景要有基本的灯光和相机,相机能看到整个鹈鹕和自行车。 6. 代码要完整,可以直接在浏览器中打开运行。这个提示词的关键在于第3条——“鹈鹕的脚要踩在踏板上,翅膀要搭在车把上”。这是整个测试的核心难点。模型需要理解“踩”和“搭”这两个动作在三维空间中的含义,并计算出正确的坐标和旋转角度。很多模型在这一步翻车,要么脚悬空,要么翅膀穿模,要么干脆把鹈鹕和自行车做成两个独立的物体,没有任何交互。
2.3 评测维度的量化标准
为了把主观感受变成可比较的分数,我设计了一个四维评分表,每个维度满分10分,总分40分。
| 维度 | 评分标准 | 权重 |
|---|---|---|
| 几何体完整性 | 鹈鹕和自行车的所有部件是否齐全,有没有缺失或多余的物体 | 25% |
| 空间关系正确性 | 脚是否踩在踏板上,翅膀是否搭在车把上,各部件比例是否协调 | 35% |
| 动画流畅度 | 轮子转动是否自然,鹈鹕起伏是否与踩踏动作匹配,有无卡顿或跳变 | 20% |
| 代码可读性 | 变量命名是否清晰,结构是否合理,有无冗余或重复代码 | 20% |
空间关系正确性占了最高的权重,因为这是“鹈鹕骑车”这个题目的灵魂。一个几何体再完整、动画再流畅的模型,如果鹈鹕是飘在自行车上方的,那这个测试就失败了。
2.4 测试过程中的意外发现:模型对“鹈鹕”的理解差异
在正式跑测试之前,我先用几个模型做了预实验,结果发现了一个有趣的现象:不同模型对“鹈鹕”这个生物的理解差异巨大。有的模型把鹈鹕的嘴巴做得又长又尖,像一根针;有的模型把嘴巴做成了一个扁平的盒子,像鸭嘴兽;还有的模型干脆忽略了嘴巴,只做了一个圆球当脑袋。这让我意识到,大模型对具体生物形态的理解,很大程度上取决于训练数据中相关描述的丰富程度。鹈鹕不是猫狗这种常见动物,模型见过的3D鹈鹕模型可能很少,所以它只能根据“鹈鹕有大嘴巴”这个模糊的印象来发挥。
这个发现也解释了为什么有些模型在“鹈鹕骑车”这个测试上表现不佳——它们连鹈鹕本身都画不对,更别说让鹈鹕骑车了。相比之下,那些在预实验中能准确还原鹈鹕特征的模型,在后续的空间关系处理上也普遍表现更好。这说明模型的细粒度理解能力和空间推理能力是正相关的。
3. 十二款大模型实测:谁在裸泳,谁在领跑
3.1 第一梯队:GPT-6 Astra与Claude 4 Opus的巅峰对决
GPT-6 Astra是这次测试的焦点。它的表现确实配得上“爆火”这个词。生成的代码一次通过,打开浏览器就能看到一只像模像样的鹈鹕骑在自行车上。鹈鹕的身体是一个拉长的椭球,嘴巴是两个圆锥拼接而成,上喙比下喙长,符合鹈鹕的特征。翅膀用压扁的球体表示,自然地搭在车把上。最让我惊讶的是,它给鹈鹕的脚和踏板之间加了一个Group,把脚和踏板绑定在一起,这样当踏板转动时,脚会跟着一起动,看起来就像真的在踩踏。这个细节我在提示词里没有要求,是模型自己“想到”的。
Claude 4 Opus的表现同样出色,但在风格上有明显差异。GPT-6 Astra的代码更简洁,几何体数量少但比例精准;Claude 4 Opus的代码更“啰嗦”,用了更多的几何体来细化鹈鹕的羽毛和自行车的链条,但整体协调性稍逊一筹。比如它给鹈鹕加了三个脚趾,但脚趾的旋转角度没算对,看起来像是脚扭了。在动画方面,Claude 4 Opus的轮子转动更平滑,但鹈鹕的起伏幅度过大,像是坐在弹簧上。
| 模型 | 几何体完整性 | 空间关系正确性 | 动画流畅度 | 代码可读性 | 总分 |
|---|---|---|---|---|---|
| GPT-6 Astra | 9 | 9 | 8 | 9 | 35 |
| Claude 4 Opus | 9 | 8 | 9 | 8 | 34 |
| Gemini 2.5 Ultra | 8 | 7 | 8 | 8 | 31 |
| DeepSeek-V4 | 8 | 8 | 7 | 9 | 32 |
3.2 第二梯队:Gemini 2.5 Ultra与DeepSeek-V4的稳健发挥
Gemini 2.5 Ultra的代码结构很漂亮,用了模块化的函数来分别创建鹈鹕和自行车,可读性很高。但它在空间关系上犯了一个典型错误:鹈鹕的腿太短,脚够不到踏板,模型为了解决这个问题,把整只鹈鹕往下移,结果鹈鹕的身体穿进了车架里。这个错误很能说明问题——模型知道“脚要踩在踏板上”,但它没有能力去调整腿的长度或者鹈鹕的位置来满足这个约束,只能粗暴地平移整个物体。
DeepSeek-V4的表现让我有点意外。它的几何体完整性很好,鹈鹕的嘴巴甚至做出了上下喙的区分,自行车的车架也用了正确的三角形结构。空间关系上,脚和踏板的接触点找得很准,但翅膀的位置偏了,搭在了车把的前方而不是上方。动画方面,轮子转动没问题,但鹈鹕的起伏和踩踏节奏对不上,看起来像是各动各的。不过它的代码可读性是所有模型里最好的,变量命名规范,注释清晰,拿过来改一改就能用。
3.3 第三梯队:那些“翻车”的模型到底错在哪
有几个模型的表现就比较尴尬了。Llama 4-405B生成的代码里,鹈鹕的嘴巴是一个巨大的圆锥,直接穿过了自行车的前轮,整个场景看起来像是一只鹈鹕在用嘴巴戳轮胎。Qwen 3.5-Max的鹈鹕没有腿,身体直接悬浮在自行车上方,轮子倒是转得很欢,但鹈鹕和自行车完全是两个独立的物体,没有任何交互。还有一个国内的开源模型,生成的代码里自行车只有一