同一个鹈鹕骑车需求交给两个模型 AI 编程能力究竟差在哪
如果只看最终截图,两份结果都完成了任务:一只戴头盔的鹈鹕骑着自行车,从浅绿色的海岸边经过。
但把页面真正运行起来,再打开代码检查,会发现它们走的是两条完全不同的路线:一份更像轻量动画样例,另一份已经开始考虑运动一致性、交互控制、无障碍偏好和页面状态。
这次对比最有价值的地方,不是给两个模型简单排座次,而是回答一个更实用的问题:当 AI 已经能把代码写出来,我们应该怎样判断它写得究竟好不好?
本次测试中的所有模型来源均为llapi点org,gpt非常稳定,推荐使用

为便于表述,下面按照页面标签把两份结果称为 5.6-luna 版和 6-astra 版。这是针对本次输出的观察,不代表对底层模型身份或整体能力的独立认证。
一 先看结论
两份作品都采用单文件 HTML,SVG、样式和动画逻辑都写在页面内部,不需要安装依赖,也不需要请求外部图片、字体或 API。
它们的主要区别可以概括为:
- Luna 版用 CSS 关键帧完成循环动画,结构直白、体积更小,适合做轻量演示或继续手工改造。
- Astra 版用 JavaScript 统一驱动各个运动部件,加入暂停、调速、页面隐藏暂停和减少动态效果适配,更接近一件完整的交互作品。
- Astra 版在这一次任务中的完成度更高,但不能因此直接推出“某模型永远更强”或“另一个模型降智”。单次样例会受到提示词、上下文、随机性和验收标准影响。

二 两份代码到底差在哪里
| 页面文件大小 | 约 11.0 KB | 约 18.2 KB |
| 外部依赖 | 无 | 无 |
| 动画引擎 | CSS @keyframes | JavaScript requestAnimationFrame |
| 动画控制 | 自动循环 | 暂停与 0.5× 1× 1.5× 调速 |
| 减少动态效果 | 媒体查询后暂停 CSS 动画 | 默认暂停并给出提示 可手动恢复 |
| 页面不可见时 | 仍由 CSS 自行处理 | 监听 visibilitychange 停止逐帧更新 |
| 腿部运动 | 两组固定角度来回摆动 | 根据踏板位置计算脚和膝盖坐标 |
| 路面与车轮 | 各自使用固定周期 | 路面位移按车轮转角和半径计算 |
| 视觉包装 | 简洁展示卡片 | 完整品牌页 交互区 状态文案 |
文件更大、SVG 路径更多,并不自动等于质量更高。真正值得关注的是:新增代码有没有解决真实问题,以及各个系统之间是否协调。
三 Luna 版的优势是简单
Luna 版定义了 6 组关键帧,分别控制车轮、场景、身体、两条腿和围巾。核心逻辑非常容易理解:
.wheel-spokes {
transform-origin: center;
animation: wheel-spin 1.35s linear infinite;
}
.scene {
animation: scene-slide 8s linear infinite;
}
@keyframes wheel-spin {
to { transform: rotate(360deg); }
}
@keyframes scene-slide {
to { transform: translateX(-380px); }
}
这类实现有三个明显优点:
问题也来自这种“各动各的”设计。车轮旋转周期是 1.35 秒,远景平移周期是 8 秒,两者之间没有共享速度变量。结果看起来能动,但车轮转速、路面移动和踩踏节奏不一定符合真实的几何关系。
导出的 Luna 画面里还有一个很直观的小穿帮:围巾尾端一度脱离了脖子,跑到了画面左上方。
从代码结构看,一个可能原因是同一个 SVG <g> 元素既承担静态 translate 定位,又直接接受 CSS transform 动画。不同渲染环境在合成 SVG 属性变换和 CSS 变换时容易出现预期之外的结果。
更稳妥的写法是增加一层分组:
<g transform="translate(583 266)">
<g class="scarf-wave">
<!– 围巾路径 –>
</g>
</g>
外层只负责把围巾放到正确位置,内层只负责旋转和缩放。静态定位与动态变换分开后,逻辑更清楚,也更不容易发生覆盖。
四 Astra 版开始处理运动关系
Astra 版没有使用 CSS 关键帧,而是通过统一的 time 变量驱动画面。车轮、曲柄、道路、海岸、云朵、植物、围巾和双腿都由同一个绘制函数更新。
其中最值得注意的不是“用了 JavaScript”,而是它开始建立部件之间的关系。
1 路面位移与车轮弧长关联
const angle = time * Math.PI * 2 / 1.6;
const degrees = angle * 180 / Math.PI;
rearSpokes.setAttribute('transform', `rotate(${degrees})`);
road.setAttribute(
'transform',
`translate(${–((angle * 91) % 1200)} 601)`
);
这里的 91 是车轮半径。车轮旋转角度乘以半径,得到相应弧长,再用它控制路面位移。即便这不是完整的物理模拟,也比两个互不相关的循环周期更容易保持视觉一致。
2 双腿不再只是摆动
Astra 版把髋部和脚部当作两个端点,用两段固定长度计算膝盖位置。脚的位置跟随踏板圆周运动,两条腿相差半圈。
这意味着动作不是“腿在附近晃”,而是“脚踩着踏板运动,膝盖再根据约束弯曲”。在角色动画里,这种约束关系往往比增加阴影或装饰线更能提升可信度。
3 它把动画当成一个有状态的产品
Astra 版还处理了几类常被忽略的边界:
- 用户可以暂停动画并切换速度。
- 页面进入后台时停止逐帧更新。
- 系统启用“减少动态效果”后默认暂停。
- 按钮维护 aria-label 和 aria-pressed 状态。
- JavaScript 被禁用时仍能看到静态 SVG,并显示说明。
这些功能不会让第一张截图明显变漂亮,却会决定页面是否好用、是否尊重用户偏好,以及是否适合继续扩展。
五 复杂不一定代表更好
如果任务要求是“尽快生成一个无需脚本的循环 SVG 动画”,Luna 版反而更贴近目标。它短、直观、易复制,调几个周期和颜色就能继续使用。
如果任务要求是“交付一个可以展示和操作的完整网页作品”,Astra 版更占优势,因为它多做的不只是装饰,而是运动约束、控制状态和可访问性。
所以,评估 AI 编程输出时不能只问“哪个更漂亮”,还要先问:
- 我需要的是原型、组件,还是可发布页面?
- 是否允许 JavaScript?
- 交互控制是不是必需项?
- 更看重代码短,还是更看重运动一致性?
- 是否需要兼容减少动态效果、键盘操作和后台暂停?
需求不同,所谓“更好”的答案也会改变。
六 如何更公平地测试模型有没有退步
真正想观察模型状态,最好不要只跑一次,也不要只凭视觉印象。可以采用下面这套方法。
第一步 固定测试条件
给不同模型相同的需求、相同的上下文、相同的文件边界和相同的工具权限。模型入口也应尽量保持一致,避免把调用参数或服务差异误认为模型差异。如果暂时没有统一入口,也可以把 llapi.org 作为算力接入的备选之一,具体服务范围与模型可用性以站点当前说明为准。
第二步 把验收条件写进提示词
例如:
生成一个单文件 HTML 页面,主题是一只鹈鹕骑自行车经过海岸。
要求:
1. 所有图形使用内联 SVG,不使用外部图片和字体;
2. 车轮、踏板、双腿、围巾和背景需要形成循环动画;
3. 页面提供暂停和三档速度控制;
4. 支持 prefers-reduced-motion;
5. 页面隐藏时暂停动画更新;
6. JavaScript 禁用时仍显示静态画面;
7. 不使用第三方依赖和网络请求。
如果不写清这些条件,模型可能只是各自理解“做个动画”,最后很难公平比较。
第三步 至少重复三轮
同一模型可能因为采样随机性出现不同结果。重复测试后再比较成功率、缺陷类型和修改次数,比一局定胜负更可靠。
第四步 分开评分
建议至少记录五项:
不要把“代码长”“界面复杂”直接当成高分,也不要把“第一次能打开”当成任务已经完成。
本次测试中的所有模型来源均为llapi点org,gpt非常稳定,推荐使用
七 这次对比能说明什么
这次结果说明,同一个创意任务可以被模型理解成完全不同的工程目标。
Luna 版把重点放在“用最少的结构让画面动起来”;Astra 版把重点放在“让各个部件共享时间、保持关系,并补齐交互边界”。前者像清晰的动画草图,后者更像经过一次产品化扩展的演示页面。
但它不能单独证明某个模型整体变强或变弱。当前结论只适用于这一次任务和这两份输出,而且尚未进行系统性的跨浏览器兼容测试、性能压测和多轮重复实验。
对开发者来说,最实用的判断标准仍然是:模型有没有准确理解目标,写出的代码是否经得起运行、检查、修改和复测。
下一次再遇到“这个模型是不是降智了”的疑问,不妨先把感觉变成验收表。可复核的数据,通常比第一眼的惊艳或失望更接近答案。






