Phantom 动态显影验证码
以时间维度取代识别难度的人机验证方案。目标图案与背景噪声同分布, 仅在运动中经视觉整合显现——人眼可辨,单帧不可解。 本站部分人机验证环节由其承担。
项目文件
基于 techccy/phantom 依 Mozilla Public License 2.0 授权。 下列为全部修改与新增的源码,点击展开。
核心机制
传统验证码将难度置于识别环节,人机成本同步上升。 Phantom 将其转移至时间维度:单帧信息量为零,唯有连续观测方可解题。
动态显影
目标粒子与背景噪声同灰度分布,静止状态下完全隐匿。唯有整簇同步位移时,人类视觉的「共同命运」(Common Fate)整合方能将其从噪声中析出。
行为验证
辨识仅为前置条件,尚需按住并跟随其运动。服务端据完整轨迹判定操作主体,此为拦截自动化脚本的核心环节。
零前端信任
路径基准从不下发。前端仅获取高熵随机种子,前后端各自以同一确定性 PRNG 派生贝塞尔控制点,链路上不存在可解读的几何信息。
评分体系
轨迹沿两个正交维度评分,加权求和后与阈值比较:
Composite = 0.6 · S_DTW + 0.4 · S_Bio S_Bio = 0.35 · energy + 0.30 · zerocross + 0.35 · tremor(amp + psd)
S_DTW · 路径拟合度
将用户轨迹与基准贝塞尔路径归一化至单位正方形,计算二维动态时间规整距离, 经指数饱和映射至 0~1。归一化使评分与画布尺寸解耦,规避 DPR 缩放引发的误判。
S_Bio · 生理特征度
轨迹经均匀重采样与 7Hz 低通滤除自主运动,仅保留残差,据此检验其中的人体生理特征:
- 残差能量:人类高频微抖处于 0.3~8px 区间;理想合成低于 0.05px,粗糙合成高于 20px。
- 加速度零交叉率:人类持续反馈纠偏,符号翻转具备典型频率;合成轨迹或过度平滑,或呈宽带白噪。
- 生理震颤:8~12Hz 频段的振幅与功率占比,对应人体肌肉固有频率。
一票否决
任一条触发即将综合分封顶至 0.20:
| 否决条件 | 针对的合成特征 |
|---|---|
| 平滑否决 | 残差能量趋近于零,典型于函数式生成的理想轨迹 |
| 周期性伪噪否决 | 正弦注入的伪震颤,自相关不衰减且频谱单峰 |
| 等差时间戳否决 | 按帧率步进的时间戳,Δt 变异系数趋近于零 |
| 轴向非对称否决 | X/Y 两轴同幅度对称加噪 |
| 子像素尾数否决 | 坐标取整导致小数位熵坍缩 |
| 最小时长否决 | 整体耗时低于人类生理响应下限 |
| 终点命中否决 ★ | 本站补充 · 未跟至终点即释放 |
| 时长下限否决 ★ | 本站补充 · 整体耗时显著低于应有时长 |
安全设计
- 一次一密:每道题经 ECDH P-256 临时协商会话密钥,参数与轨迹均以 AES-256-GCM 加密。服务端不持有长期对称密钥。
- 一题一答:验证时以 Redis
GETDEL原子弹出 challenge,同一题目二次提交必然失败。 - 一票一用:通过后签发 HMAC 一次性 token,业务侧核销同样采用
GETDEL。 - 基准不下发:仅下发 16 字节高熵
pathSeed,控制点由前后端各自派生。即便劫持解密调用,所得亦仅为种子。 - 时效约束:提交时刻与服务端时钟偏差超出阈值即行拦截,抑制离线求解。
移动端改造
上游采用画布内直接拖拽,移动端拇指会遮挡待跟随的目标。 本站改为触控板模式:
- 上方画布仅供观察,下方控制区承接操作,两者绝对等比映射,画布内以光标环指示当前位置。
- 控制区尺寸小于画布,等比放大的同时将手部微抖一并放大至生理区间,实际操作难度低于直接拖拽。
- 服务端无感知:接收的仍为画布坐标,判定逻辑未作改动。
surface.ts),由轨迹采集与光标环共用,
确保两者始终一致。
判定补强
上游判定聚焦于路径拟合度,对完成度着墨较少: 轨迹尚未走完即释放时,验证仍有机会通过。本站于此补充一道完整性判定。
可以补强的几处
- 终点位置未参与判定。目标半径仅用于前端绘制,评分维度限于路径拟合度与生理特征,不涉及最终落点。
- DTW 对截断不敏感。提前释放后,参考路径的剩余段会对齐至末点,其代价虽正比于剩余长度,但经序列归一化与指数饱和映射后所剩无几。
- 题目时长未传入评分。challenge 创建时已将 duration 写入存储,评分阶段未予引用,应有时长因而未参与判定。
- 既有最小时长下限为 250ms,对本场景约束有限。
补强前后实测(生产参数)
| 跟完路程 | 提前释放 | 补强前通过率 | 补强后 |
|---|---|---|---|
| 100% | — | 100% | 100% |
| 80% | 1.4s | 100% | 0% |
| 70% | 2.1s | 100% | 0% |
| 55% | 3.1s | 100% | 0% |
| 50% | 3.5s | 83% | 0% |
即跟随约 55% 的路程即可通过,相当于 7 秒的题目在 3.9 秒时释放。
补强方案
增设两道对称的一票否决:
- 终点命中:末采样点至路径终点的距离须不超过目标半边长的 2 倍。
- 时长下限:整体耗时须不低于应有时长的 80%。
可用性与适用边界
实测结论
在本站调整后的参数下,于保证一定难度的前提下进行了小规模实测。 测试者为 20 岁以下、身体与心理意识等状态良好者, 且此前从未接触过同类验证码。结果显示:
- 在不超过 5 次的尝试内即可完成验证;
- 具备一次成功经验后,后续完成的准确率接近 100%。
适用边界
本方案要求持续视觉追踪与同步精细操作并行, 对使用者的感知与操作能力均有要求。以下情形的适用性尚待验证与优化:
- 年长或年幼使用者;
- 视力受限、色觉异常,或在低对比度下辨识困难者;
- 精细动作控制受限,或使用辅助输入设备者;
- 对运动闪烁敏感者(画面为持续变化的噪声场)。
此外,方案本身不具备无障碍替代路径:内容不可由屏幕阅读器解析, 亦无音频等非视觉通道。低帧率设备或高延迟网络下,跟随体验亦会明显劣化。 因此其普适性不强,不宜作为唯一的验证入口。
已知风险
判定完全在服务端完成,前端无法影响结果。但渲染发生在客户端, 这带来一项固有让步:使用者可修改前端渲染参数,将目标粒子的亮度增益调高, 使目标在单帧画面中即可辨识,进而通过高亮区块推断路径。 此举会削弱视觉防线,存在极低概率的失效风险。
行为防线不受影响——即便完全获知目标位置,仍须构造出能同时通过路径拟合、 生理特征检验与全部一票否决的轨迹。但应当明确: 动态显影的视觉防护,对愿意改动前端者约等于不存在。
部署建议
不建议将本方案作为唯一的安全边界。合理的用法是纳入分级验证体系:
- 风控分级:由风控系统对访问来源评分,按风险档位匹配相应强度的验证方式,低风险放行、高风险升级。
- 多形态并行:与其他类型的验证码组合使用,按场景与风险分级调度,避免单一形态被针对性突破。
- 给予练习余量:首次接触者需要若干次尝试建立手感,应为其保留不计入风控评分的容错额度。本站基于小范围测试,采用前 10 次豁免的机制——该区间内的失败仅作提示,不参与风险累积,避免生疏被误判为异常。
- 保留兜底通道:为无法完成本验证的使用者提供替代验证或申诉入口,避免形成事实上的准入门槛。
- 尝试次数管理:豁免额度耗尽后采用递增退避而非硬性锁定,兼顾体验与防护。
- 服务端侧写:对跨请求的轨迹相似度、特征分布集中度等作统计,此类模式为前端伪造所不能及。
- 持续观测:跟踪线上通过率与失败分布,参数调整后重新评估,避免防护强度随时间漂移。
接入方式
引入 SDK,挂载至任意容器,所得 token 交由后端核销:
<!-- 1. 引入 SDK -->
<script src="/test_captcha3/phantom.js"></script>
<!-- 2. 挂载 widget -->
<div id="phantom-box"></div>
<script>
Phantom.mount("#phantom-box", {
apiBase: "/test_captcha3/api",
onSuccess: (r) => console.log("token =", r.token),
onFail: (r) => console.warn("未通过", r.detail),
});
</script>
/consume-token 核销,
前端所得 token 仅表示本环节通过,不可作为业务凭证。
声明
免责声明
按「现状」与「现有」提供(AS IS / AS AVAILABLE)。 依 MPL-2.0 §6,本软件及本页面所载内容按「现状」(AS IS)与「现有」 (AS AVAILABLE)提供,不附任何明示或默示的担保,包括但不限于对适销性、 特定用途适用性及不侵权的担保。
依 MPL-2.0 §7,在适用法律允许的最大范围内,任何贡献者、分发者均不对因 使用或无法使用本软件而产生的任何直接、间接、附带、特殊、惩罚性或 后果性损害承担责任。
安全性说明
本项目为人机验证组件,不对任何特定强度的防护效果作出保证。任何验证方案 均可能被绕过,不应作为唯一的安全边界使用;部署方应结合自身场景独立评估 风险,并自行承担部署与使用的全部后果。
本处的修改未经上游审阅,亦不代表上游立场。
可用性说明
本页面的在线演示与相关接口不作为服务承诺,可能随时变更、中断或下线, 不提供任何可用性保证。
AI 辅助声明
本项目(文档)部分内容由 AI 工具辅助整理完成。
AI 生成内容可能存在:
- 表述不准确
- 信息遗漏
- 与实际环境存在差异
使用者应结合实际情况进行人工审核和判断。
最终项目设计、代码实现以及使用行为应由使用者自行负责。
关于项目安全性、开源开发、AI 辅助编程及相关争议的声明
在本文结束之前,有必要就本项目的设计目的、安全边界、开源理念、AI 辅助开发,以及围绕项目产生的部分争议作出较为完整的说明。
特别说明:我并非本项目的原作者,本声明亦不代表原作者本人对任何争议事件作出的正式回应。
本声明无意延续任何个人之间的争论,也无意针对任何特定个人或群体发起攻击。对于正常、合理且具有事实依据的技术批评,始终应当保持开放态度。
但与此同时,接受技术批评并不意味着项目作者、贡献者及相关参与者应当接受脱离技术问题本身的人身攻击、公开羞辱或网络暴力。
因此,有必要进一步明确本项目的技术定位,以及我们对于开源、技术批评、年轻开发者保护和网络行为边界的基本立场。
一、关于验证码的功能定位与安全边界
首先需要明确的是,验证码并非密码系统,也不应被视为一个网站完整的安全防护体系。
验证码的主要作用,在于通过增加额外交互过程,对正常用户行为与自动化程序行为进行一定程度的区分,并由此提高自动化程序实施批量注册、撞库、暴力尝试、高频请求及其他自动化操作的时间成本、计算成本和实现成本。
因此,衡量验证码是否具有实际价值,不应简单归结为“是否存在破解方法”。
在公开运行的客户端环境中,要求一种验证码在面对任意攻击者、任意资源投入以及无限研究时间的情况下均无法被绕过,本身就是一个极难实现的目标。
现实中的安全也并非简单的“可破解”与“不可破解”二元关系。
更具有现实意义的安全目标,应当是:
在明确的威胁模型下,通过增加自动化攻击所需要付出的时间、计算、交互、适配和维护成本,降低批量自动化行为的效率,使攻击成本与潜在收益之间形成明显的不对称。
这也是本项目后续改进所重点关注的方向之一。
针对原有方案中已经发现或可能存在的部分安全问题,后续可进一步尝试引入服务端随机信息、动态状态以及交互过程验证等机制。
例如,使验证过程中下一阶段的位置或状态,不仅取决于客户端当前交互信息,同时与服务端持有的秘密信息及随机状态相关,使不同验证会话形成不同的运行过程。
其目的并不是通过隐藏算法制造所谓“绝对不可破解”的假象,而是在算法公开、实现可被研究的前提下,尽可能避免攻击者仅通过一次离线分析,即可长期复用完整验证结果。
真正需要受到保护的,应当是服务端密钥、运行状态及具体会话中的动态信息,而不应将“算法不可见”本身视作安全性的主要来源。
在此基础上,还可进一步研究交互过程中的时间变化、行为连续性以及用户面对状态突变时的响应特征,作为辅助判断信息。
但必须再次强调:
上述改进并不意味着本项目已经实现密码学意义上的不可破解性,也不意味着项目不存在其他潜在缺陷。
客户端本身不能被视为可信环境,人的行为也可能在一定程度上被模拟。随着针对性研究不断深入,新的绕过方法仍然可能出现。
这既是验证码本身的局限,也是安全工程必须面对的现实。
发现问题,应当分析问题。
能够修复,应当进行修复。
原有思路存在不足,应当重新设计。
如果最终通过充分的技术论证证明某一技术路线本身无法达到预期目标,也应当接受事实,并及时调整方向。
发现漏洞并不可耻。
拒绝面对已经得到证明的漏洞,才真正违背安全研究应有的态度。
与此同时,也不应将验证码本身能够承担的安全责任无限扩大。
验证码只是网站安全体系中的一个组成部分。
实际生产环境仍然需要结合请求频率限制、连续登录失败控制、IP 与设备风险识别、异常行为检测、密码安全策略、身份认证以及其他服务端风控机制共同形成纵深防御体系。
对于大型平台、金融业务、高价值账户以及长期面临针对性攻击的系统,更不应将实验性验证码项目作为核心安全边界,而应采用经过充分验证的成熟安全方案,并由具有相应经验的人员进行专业评估。
因此,本项目更适合作为一种实验性技术思路和面向特定场景的辅助验证机制,而不是替代完整的安全体系。
二、关于“能够破解”是否意味着验证码没有价值
在部分相关讨论中,“能够找到破解方法”似乎被直接等同于“验证码没有任何意义”。
这种判断并不完整。
任何安全机制都存在自身的威胁模型。
普通个人网站、小型社区所面对的攻击规模,与大型互联网平台、金融机构以及其他高价值目标并不相同。
大量现实中的自动化攻击,本身追求的就是低成本、高效率和批量化。
攻击者往往使用自动化工具扫描大量目标,并不会天然愿意为了其中一个价值有限的普通网站投入大量人工和计算资源进行长期针对性研究。
因此,一套验证码即使理论上存在绕过方案,只要能够显著降低通用自动化程序的攻击效率,迫使攻击者为特定站点额外开发、维护和适配自动化方案,并与服务端限速、风险控制等机制共同使用,就仍然能够产生实际安全价值。
这也是现实安全工程强调“纵深防御”的原因之一。
没有哪一个组件应当被寄予解决全部安全问题的期待。
验证码应当完成验证码自身的任务,风控系统完成风控系统的任务,身份认证系统则承担真正验证用户身份的责任。
既不应夸大验证码能够提供的保护,也不应因为验证码无法解决全部问题,就完全否定其存在意义。
三、关于开源以及 GitHub
本项目选择发布于 GitHub 并开放源代码,本身就意味着愿意接受公开审视。
开源意味着任何人都可以阅读代码,可以发现问题,可以创建 Issue,可以提交 Pull Request,也可以基于代码、实验以及理论依据,公开说明某一设计为何存在问题。
即使最终有人能够完整证明本项目的某项技术路线存在根本性缺陷,这种讨论本身仍然具有价值。
因为这正是开源的重要意义之一。
GitHub 不应当只是成熟项目和资深开发者展示成果的平台。
它当然可以容纳影响世界的大型开源项目,也同样应当允许学生上传自己的第一次尝试,允许初学者公开一个只有几百行代码的小工具,允许一个并不成熟的概念验证存在。
一个失败的实验可以告诉后来者为什么某条路线走不通。
一个存在漏洞的设计可以成为安全研究和后续改进的案例。
一个粗糙的项目,也完全可能在一次次 Issue、Pull Request 和 Code Review 中逐渐成熟。
如果一个人必须首先证明自己拥有足够高的技术水平,才“有资格”在 GitHub 发布自己的项目,那么开源社区所具有的学习、交流和共同完善价值,也将因此受到削弱。
能够发现一个年轻开发者代码中的问题,证明发现者具有相应知识。
而真正能够体现专业素养的,是准确指出问题、提供事实依据,并在可能的情况下说明问题形成的原因及可行的改进方向。
知识应当成为帮助后来者继续前进的阶梯,而不应成为证明后来者没有资格开始的门槛。
四、关于 AI 辅助开发与 Vibe Coding
随着生成式人工智能快速发展,AI 辅助编程乃至所谓 Vibe Coding 已经成为软件开发领域无法回避的新现象。
对于这一现象,既没有必要盲目推崇,也没有理由因为其不同于传统开发流程而进行全盘否定,更不应简单以是否使用 AI 作为衡量一个开发者能力、项目价值或者劳动投入的标准。
首先我们需要知道:
Vibe Coding 并非向 AI 输入一句自然语言描述,就能够自动得到一个符合预期、稳定、安全、完善并可以直接投入实际使用的最终产品。
至少在现阶段,这种想象与真实的软件开发过程仍然存在明显距离。
从最初需求的表达,到技术路线的确定,再到提示词的不断调整、功能生成、运行测试、错误反馈、重新修改、架构调整以及最终部署,一个通过 Vibe Coding 完成的项目同样可能经历大量反复迭代。
开发者可能需要一次又一次修改提示词,一次又一次重新生成代码,一次又一次运行、测试并发现新的问题;需要在模型提供的多个方案之间进行选择,需要判断生成结果是否符合自己的实际目标,也需要承担大量 Token、时间和精力上的消耗。
因此,将 Vibe Coding 简化为“让 AI 替自己把项目做完”,并据此否定开发者在整个项目过程中付出的劳动,并不符合实际情况。
AI 可以生成代码,但它并不会天然知道开发者最终想创造一个怎样的产品。
项目解决什么问题、采用怎样的交互方式、功能之间如何组织、哪些方案被接受、哪些方案被否定、如何根据真实使用效果持续调整,这些都离不开人的参与。
尤其对于具有明确原创设计思路的项目而言,即使具体实现过程中大量使用 AI,也不能因此将项目中的需求定义、产品构思、设计选择和持续迭代全部简单归结为“AI 的作品”。
工具可以参与实现创意,但工具的参与不应抹去创意本身的来源,也不应抹去使用工具者为实现这一创意所付出的判断、尝试和修改。
当然,对 Vibe Coding 的认可,并不意味着应当回避 AI 生成代码本身存在的问题。
AI 可能产生错误实现,可能虚构不存在的接口,也可能在开发者未能及时发现的情况下引入安全漏洞。
因此,有一个基本原则不应因为开发工具发生变化而改变:
AI 可以参与代码生成,但不能替代开发者对最终结果承担责任。
使用 AI 并不能免除开发者进行测试、验证和学习的必要。无论具体代码由人工编写、AI 辅助生成还是 Agent 直接完成,项目最终是否能够安全、稳定地投入实际使用,仍然需要开发者根据项目性质承担与其相匹配的审查和验证责任。
对 AI 辅助开发方式的认可,从来不意味着否认这些责任。
相反,越是依赖自动化程度更高的开发工具,就越需要意识到工具本身可能产生错误,并对最终结果保持必要的判断能力。
但从这里进一步推导出“使用 AI 就等于不会编程”,甚至认为“借助 AI 完成的项目天然没有价值”,同样是一种过于简单的判断。
近年来,在公开技术社区和内容平台中,已经有越来越多开发者及技术内容创作者主动展示利用 AI、Agent 或 Vibe Coding 完成的产品与实验项目,其中不少作品获得了积极讨论和广泛关注。
在正常的技术交流中,人们真正关注的往往是项目最终实现了什么、解决了什么问题、采用了怎样的思路、存在哪些不足,以及新的开发方式能够带来什么,而不是仅仅因为某个项目使用了 AI,就首先否定其存在价值。
这也说明了一件非常重要的事情:
使用 AI 并不天然构成一个项目应当受到贬低的理由。
对于 AI 辅助开发项目而言,开发者主动说明项目中 AI 的参与情况,并在适当情况下提醒使用者关注 AI 生成代码可能存在的可靠性、安全性及其他潜在风险,本身是一种负责任且值得鼓励的透明做法。
这种透明不应反过来成为攻击开发者的理由。
如果一个开发者主动写明“本项目包含 AI 辅助生成内容”,最终得到的结果却不是更加理性的风险判断,而是因此遭受额外贬低,那么这种风气长期发展下去,所形成的激励将恰恰与开源社区希望看到的透明原则相反。
开发者可能逐渐不愿意公开自己的 Vibe Coding 项目,也可能仍然选择公开项目,却刻意不再说明 AI 在其中承担了怎样的工作。
最终受到损害的,并不只是某一个开发者。
当真实的开发过程因为害怕遭受嘲讽而被有意隐藏以后,使用者反而更难判断代码的来源、开发方式以及可能存在的风险。
从安全角度看,这显然不是一种更加值得期待的结果。
所以,鼓励开发者如实说明 AI 的参与情况,比因为其主动披露使用 AI 而对其进行攻击,更有利于形成透明、负责的开发环境。
与此同时,也有必要重新审视所谓“使用 AI 就不算真正编程”这一判断本身。
软件开发工具的发展史,本来就是一个不断减少机械劳动、提高抽象程度和提升开发效率的过程。
早期开发者需要完成大量今天看来极为繁琐的工作。
后来,高级语言逐渐代替了大量直接面向机器的操作。
再后来,IDE 提供自动补全、错误提示、代码重构和调试工具。
开发者可以通过快捷方式快速生成 HTML 等基础模板,也可以利用框架、脚手架和代码生成工具完成过去需要大量手工输入的重复性工作。
生成式 AI 出现以后,工作方式再次发生变化。
最初,人们可能主要通过聊天工具生成代码,再将结果复制到 IDE 中进行修改。
随后,AI 开始直接集成进入编辑器。
如今,Agent 又可以进一步完成读取项目、修改文件、运行程序、定位错误并继续迭代等一系列工作。
从手工输入,到 IDE 自动化,再到 AI 辅助,直至 Agent 参与更加完整的开发流程,这本身就是人类不断改进工具使用方式、提高生产效率的延续。
因此,将“是否亲自在 IDE 中完成每一次代码输入”作为判断开发活动是否具有意义的标准,本身就缺乏足够合理的依据。
认为“将 AI 生成的代码手动复制到 IDE”天然比“让 Agent 直接修改代码”更加具有技术价值,同样是一种过于形式化的判断。
二者之间当然存在工作方式上的区别。
直接阅读和修改代码能够提供更加密集的代码接触机会;Agent 则可能将更多重复实现过程自动完成,使开发者将注意力更多集中在需求、结构、测试和结果判断上。
不同工具具有不同优势,也伴随着不同的学习成本和能力要求。
不能因为一种工具减少了某个环节的人工操作,就直接得出“使用这种工具的人什么也没有做、什么也不会、什么也学不到”的结论。
这种判断不仅过于武断,也忽视了技术工具本身始终处于发展变化之中的事实。
甚至可以进一步提出一个值得讨论的问题:
在 Vibe Coding 的工作模式下,如何更加准确地描述需求,如何建立合理上下文,如何持续优化提示方式,如何发现 AI 对需求的错误理解,如何组织 Agent 完成复杂任务,以及如何判断生成结果是否真正达到预期,本身是否同样会逐渐形成一种新的技术能力?
答案显然不应当被简单否定。
Prompt 并非代码本身,Prompt Engineering 也不能代替计算机基础知识。
但是,在高度依赖人机协作的新型开发流程中,如何有效向 AI 表达复杂需求、拆分任务、提供准确上下文、约束行为并验证输出,已经具有明确的实际价值。
提示词和上下文的不断优化,本身也可能反映出使用者对需求、系统行为和技术边界理解的逐渐深入。
随着工具变化,开发者需要掌握的部分能力也必然发生变化。
这并不是计算机技术第一次经历这样的变化,也很难成为最后一次。
当然,任何新的开发方式都不意味着传统学习方式因此失去意义。
相反,不同人处于不同阶段,对 AI 的使用方式本来就不应完全相同。
对于尚未拥有完整专业知识体系、仍处于探索阶段的年轻开发者,尤其是未成年开发者而言,Vibe Coding 可以显著降低实践门槛。
他们可能暂时没有能力独立完成一个完整项目,但可以通过与 AI 不断讨论、生成、运行、发现错误和继续修改,在真实问题中逐渐接触新的知识。
一个初学者可能最初无法完全理解 AI 生成的 JavaScript,但这并不意味着整个实践过程不会产生学习。
在第一次运行失败以后,他可能开始学习如何使用浏览器控制台;在第一次接口报错以后,他可能开始理解 HTTP 请求与响应;在第一次遭遇安全问题以后,他可能开始认识客户端与服务端之间的信任边界;在第一次被指出漏洞以后,他又可能因此开始接触真正的网络安全知识。
这些学习过程并不会因为最初的代码由 AI 辅助生成而失去意义。
实践不能代替系统性教育,但实践完全可以成为系统性学习的起点。
对于仍处于学习阶段的人而言,一个由 AI 帮助实现的项目,也完全可能成为其主动学习计算机技术的第一块敲门砖。
因此,不能简单得出“使用 AI 完成项目就什么也学不到”的结论。
真正需要关注的,是使用者是否只停留在“程序能够运行”这一结果,还是会继续追问其工作原理,理解出现的问题,并在实践中逐渐建立属于自己的知识体系。
对于正在系统学习计算机科学和软件工程的人而言,则又是另一种情况。
适当脱离 AI,亲自完成数据结构、算法、程序设计、调试及其他基础训练,仍然具有不可替代的意义。
基础能力不能完全依靠生成式 AI 建立。
但是,这同样不意味着 AI 应当被完全排除在学习过程之外。
AI 可以承担解释概念、指出错误、提供不同思路和回答问题的角色。
一个能够随时交流的辅助工具,在合理使用的前提下,本身就可以成为传统教材、课程和教师之外的重要学习补充。
从这一意义上说,AI 甚至可以在一定程度上承担“全天候一对一辅助教师”的角色,使学习者能够针对自己尚未理解的问题持续追问,并获得即时反馈。
因此,在学习阶段真正值得建立的并不是“拒绝 AI”的习惯,而是:
知道什么时候应该自己完成,什么时候可以借助 AI,以及如何判断 AI 给出的答案是否可信。
而对于已经进入实际工作的程序员而言,AI 和 Agent 所扮演的角色又有所不同。
在明确理解项目、能够判断输出质量并承担最终责任的情况下,Vibe Coding 更多体现为一种生产力工具。
如果能够将过去需要数小时完成的重复性工作缩短为更短时间,将开发者从大量机械操作中解放出来,使其能够将更多精力投入架构、业务、测试、安全和产品本身,那么这种效率提升并不值得羞耻。
软件工程从来不是以“谁输入的字符更多”作为生产力标准。
因此,仅仅因为一个专业开发者使用了 AI,就声称其项目“没有意义”、开发者“什么都不会”,既无法准确评价一个人的真实技术能力,也无法准确评价现代软件工程的实际工作方式。
不同阶段的人,可以用同一种工具完成完全不同的事情。
对于初学者,AI 可以是降低实践门槛的工具。
对于学习者,AI 可以是一名随时可以交流的辅助教师。
对于具有一定经验的独立开发者,AI 可以帮助快速验证创意。
对于专业程序员,AI 又可能成为提高生产效率的工程工具。
工具本身并不决定使用者是否具有技术能力。
真正决定结果的,仍然是使用者如何理解工具、如何使用工具,以及能否对工具产生的结果进行判断和负责。
年轻开发者的创造力、成熟开发者的专业经验以及 AI 等新工具所提供的效率,本来就可以相互补充,而不应被人为置于彼此对立的位置。
年轻开发者可能拥有尚未经过充分工程验证、但具有新意的设计思路;成熟开发者则能够凭借更加完整的知识体系和工程经验发现其中的问题,并帮助这些想法变得更加可靠;AI 则可以进一步降低实现和验证想法的成本。
如果三者能够形成良性协作,其最终产生的价值,显然比单纯争论“谁才算真正会编程”更加值得关注。
技术社区没有必要因为新的工具出现而重新制造一条技术鄙视链。
工具的发展不会使专业知识失去价值,专业知识的存在也不应成为否定新工具及其使用者的理由。
真正值得鼓励的,应当是不同经验水平的人能够利用各自掌握的知识和工具共同完善作品,而不是通过开发方式的不同划分所谓的“技术等级”。
事实上,如果将视野从人工智能暂时移开,就会发现人类技术发展的历史,本身就是一部不断创造工具、使用工具,并借助工具改变生产和生活方式的历史。
第一次工业革命时期,珍妮纺纱机等机械的出现,大幅改变了传统纺织生产的效率和组织方式。但我们显然不会因为机械开始承担过去需要大量人工完成的工作,就据此认为后来的人类已经“丧失了真正进行纺织生产的能力”,更不会认为只有完全依靠传统手工方式完成的产品才具有价值。
蒸汽机车的出现同样改变了人类出行和运输的方式。
人们不会因为选择乘坐火车而不是骑马赶路,就被认为是在“投机取巧”;更不会因为交通工具承担了大量原本需要人或牲畜完成的移动过程,就因此认定乘客已经“失去了行走的能力”。
工具改变的是完成目标的方式和效率,而不是自动否定使用工具者本身具有的能力。
进入电气化时代以后,同样如此。
电力、照明、通信以及后来不断出现的现代化设备,持续改变着人们学习、交流和生产的方式。
今天,人们当然可以在电灯下阅读电子书,也可以在纸质书上进行传统阅读。
我们不会因为一个人没有在蜡烛下阅读纸质书,就因此认定他进行的“不是真正的阅读”;也不会因为现代通信工具逐渐取代传统书信在日常沟通中的部分作用,就认为只有亲笔写在纸上的信件才属于“真正的交流”。
到了信息化时代,这种变化更加明显。
当家人与朋友相隔数百乃至数千公里时,人们可以使用网络电话、即时通信和视频通话保持联系。
我们不会因为双方没有面对面交谈,就据此得出“这种联系不是真正的联系”,更不会因为通信过程依赖互联网、服务器和终端设备,就认为彼此已经因此成为陌生人。
技术不断变化,工具不断变化,人类实现同一个目标的方式也不断变化。
过去需要完全依靠人工完成的过程,在新的技术条件下可能逐渐由机器、软件乃至人工智能承担其中的一部分。这并不天然意味着人的能力消失,更不意味着利用新工具完成的成果因此失去价值。
面对人工智能时代,同样如此。
如果因为 Agent 可以自动修改文件,就认为没有逐行手写代码的人“不是真正的开发者”;如果因为 AI 可以帮助定位错误,就认为借助 AI 调试的人“没有真正解决问题”;如果因为自然语言能够逐渐参与程序构建,就认为只有按照过去的工作流程完成的软件才算“真正的软件开发”,那么这种判断与历史上因为生产工具发生变化,就否定新生产方式本身的价值,并没有本质上的区别。
当然,这些历史类比并不意味着 AI 与蒸汽机、电气化或者互联网在技术性质和社会影响上完全相同,也不能据此证明 AI 的所有使用方式都是正确的。
它们真正说明的只是一个更基本的事实:
一种新的工具承担了过去需要人工完成的部分过程,并不能单独成为否定使用者能力和劳动价值的理由。
真正值得评价的,应当始终是最终结果本身,以及使用者是否理解自己正在完成什么、能否发现和修正问题、是否承担与结果相匹配的责任。
工具不能单独决定生产结果的价值,却能够深刻改变生产过程的效率。
人类创造工具,从来不是为了证明自己可以在没有工具的情况下完成同样的事情,而是为了让原本困难、重复、低效甚至无法实现的事情,以更加高效的方式成为可能。
从这个意义上看,AI 与 Agent 的出现并没有突然改变人类使用工具的基本逻辑。
变化的是工具的能力、人与工具之间的分工,以及由此产生的新责任和新问题。
近年来,围绕 AI 的发展,社会上经常出现“新一轮工业革命”“新一轮科技革命”或者类似表述。
未来的历史研究最终会如何界定我们今天所处的阶段,并不是本文需要讨论的问题。
但至少可以确认的是,人工智能正在快速改变普通人获取信息、进行学习以及完成工作的方式。
从大型语言模型开始进入公众视野,到今天功能越来越完善的 AI Agent 出现,AI 工具正在由需要一定学习成本的新兴技术,逐渐转变为更多普通人都能够直接接触的通用工具。
从最初需要用户主动提出每一个具体问题,到如今 Agent 可以理解更加复杂的任务、调用工具并完成连续工作流程,这种变化所体现的正是 AI 使用门槛不断降低、实际能力不断提高的过程。
不能因为一种工具越来越便利,就因此否定工具本身带来的价值。
也不能因为 AI 帮助一个人完成了某项任务,就简单否定这项任务的意义以及使用者在其中发挥的作用。
对于任何快速发展的技术,人们当然有理由保持警惕。
AI 存在幻觉、隐私、安全、版权、就业结构变化以及过度依赖等一系列值得认真讨论的问题。
技术进步从来不意味着应当停止批判。
相反,工具能力越强,对其风险的研究和约束就越重要。
但所谓“批判”,首先应当建立在事实、技术和基本尊重之上。
带着批判性的眼光进入一个新的技术时代,与以优越感否定所有使用新工具的人,是两件完全不同的事情。
我们可以质疑 AI 生成的代码。
可以指出 Vibe Coding 的安全风险。
可以讨论这种工作方式是否可能导致开发者基础能力下降。
也可以要求 AI 辅助开发的项目承担与其实际用途相匹配的测试、审查和安全责任。
这些都是有价值的讨论。
但不能因为一个人选择使用 AI,就预先否定其全部劳动;不能因为代码中存在 AI 参与,就否认其中属于开发者自身的产品构思和设计思路;更不能因为自己习惯于另一种开发方式,就将工具选择转化为评价他人是否“有资格”进行开发的标准。
归根结底,AI 并没有改变一个最基本的原则:
工具可以越来越先进,但最终如何使用工具,仍然取决于人。
使用 AI 不应成为逃避责任的理由。
同样,使用 AI 也不应成为受到轻视的理由。
我们当然应当警惕一种情况:开发者完全不了解项目的运行逻辑,不进行任何测试和审查,仅仅因为 AI 生成的程序能够运行,就直接将其用于不适合承担风险的生产环境。
这种做法值得批评,也应当被指出。
但这种批评针对的应当是缺乏必要测试、审查和责任意识的开发行为,而不是“使用 AI”这一行为本身。
一个项目是否可靠,应当由代码、测试、安全性和实际表现判断。
一个开发者是否负责,也应当由其如何对待自己的作品、如何面对已经发现的问题以及是否愿意继续学习来判断。
而不应当简单地通过“这是不是 Vibe Coding”“有没有使用 Agent”“代码是不是 AI 生成的”作出结论。
在新的工具不断出现、新的开发方式不断形成的时代,比固守某一种工作流程更加重要的,是保持学习能力、判断能力以及对技术结果负责的意识。
我们应当以批判性的目光审视新技术,也应当以合乎事实、合乎理性并保持基本尊重的方式作出批判。
接纳新的工具,不意味着放弃对技术的严谨;保持对新技术的批判,也不意味着可以否定使用新工具的人。
这或许才是面对 AI 时代更加值得坚持的态度。
五、关于技术批评与人身攻击的边界
对于围绕本项目出现的技术批评,其中合理且具有事实依据的部分应当被认真对待。
指出项目存在漏洞,是技术讨论。
认为某一设计思路错误,是技术观点。
通过可重复实验说明某一验证机制可以被绕过,是安全研究。
指出开发者对某个概念理解错误,同样完全可以属于正常的专业交流。
但是,当讨论从代码、实验和技术问题逐渐转向对作者本人能力、人格、年龄、教育经历以及其他与技术结论并无直接关系因素的持续贬低时,其性质已经发生变化。
项目存在缺陷,并不能自然推导出项目作者应当受到羞辱。
相反,一个仍处于学习阶段的开发者愿意将自己的作品公开,使其接受来自互联网的审视,本身就体现了一定的勇气,也体现了愿意分享和接受改进的开源精神。
技术能力不足,可以继续学习。
代码存在问题,可以修改。
设计思路错误,可以重新开始。
这些本就是技术成长过程中十分正常的事情。
真正具有专业能力的人,并不需要通过羞辱一个初学者来证明自己比对方知道得更多。
专业知识越丰富,越应该理解建立完整知识体系所需要付出的时间。
经验越丰富,也越应该记得每一名成熟开发者都曾经经历过不成熟的阶段。
专业知识应当带来更加准确的判断,也理应带来与专业身份相匹配的表达方式。
根据《中华人民共和国民法典》有关人格权的规定,自然人的人格尊严、名誉权、隐私权等合法权益依法受到保护。正常的技术评价、事实陈述和合理批评当然不应被混同为侵权,但公开讨论也并不意味着人格权益因此失去保护。
技术讨论可以尖锐。
安全研究可以严格。
但这些都不需要以人格贬损作为前提。
六、关于未成年人及年轻开发者
对于仍处于学习阶段,尤其是尚未成年的开发者,更应当建立理性、适度且负责任的讨论环境。
这并不意味着未成年人开发的项目可以免于批评。
只要项目公开发布并可能被他人使用,其中真实存在的技术和安全问题就应当被如实指出。
年龄不会使漏洞消失。
同样,年龄也不应成为攻击一个人的理由。
未成年人保护与正常技术批评之间并不存在冲突。
完全可以严格指出一个项目的漏洞,可以明确说明某个技术理解存在错误,可以要求公开项目对使用者充分说明风险,同时避免侮辱、羞辱、威胁、恶意损害形象以及针对个人的持续围攻。
这不仅是一种道德层面的倡议,在涉及未成年人时,同样存在明确的法律边界。
《中华人民共和国未成年人保护法》明确规定,任何组织或者个人不得通过网络以文字、图片、音视频等形式,对未成年人实施侮辱、诽谤、威胁或者恶意损害形象等网络欺凌行为。
这一规定本身也说明了一个非常清楚的边界:
未成年人可以接受技术批评,但不意味着应当承受网络欺凌。
公开项目意味着应当接受针对项目本身的合理审视。
它并不意味着项目作者放弃了自己作为自然人依法享有的人格权益。
对于年轻开发者而言,一次准确甚至严格的技术批评,可能成为其开始系统学习的契机;而持续性的公开羞辱和围攻,则可能使一个原本对技术具有兴趣的人从此不愿再公开自己的作品。
二者都可能从“发现了代码问题”开始。
但最终产生的结果截然不同。
技术社区真正应当鼓励的,显然应当是前者。
七、关于网络暴力及相关行为的法律边界
对于已经发生或者未来可能出现的网络暴力,应当保持同样明确的立场:
反对以网络暴力回应网络暴力。
不应公开他人无关个人信息,不应号召任何人进行骚扰、围攻、人肉搜索、恶意举报或其他形式的报复。
所有关注或支持本项目的人,也都应当保持必要克制。
反对网络暴力,不应以制造另一场网络暴力作为手段。
但是,克制并不意味着默认。
不主动扩大争端,也绝不意味着任何当事人必须无限承受恶意行为。
我国现行《网络暴力信息治理规定》已对网络暴力信息作出明确规范,其中包括通过网络针对个人集中发布的侮辱谩骂、造谣诽谤、威逼胁迫、侵犯隐私,以及影响身心健康的指责嘲讽、贬低歧视等违法和不良信息。
相关规定同时要求加强对涉及未成年人网络暴力风险的保护,并对涉及未成年人的网络暴力投诉、举报予以优先处理。
因此,在合法、必要的范围内,对相关公开信息、网页内容、发布时间、传播情况以及其他必要材料进行证据保存,是当事人在合法权益可能受到侵害时保护自身权益的正常方式。
如果有关行为始终停留在技术批评、合理评价和事实讨论范围内,则应当继续通过技术和事实进行讨论。
但是,如果相关行为发展为持续侮辱、诽谤、威胁、恶意曝光个人信息、侵犯隐私、冒充身份、组织围攻或者其他涉嫌违法的行为,则已经不再属于正常技术交流的范畴。
根据《中华人民共和国民法典》及其他相关法律法规,自然人的名誉、隐私、个人信息等合法权益依法受到保护;对于造成损害的相关行为,也可能依法承担相应民事责任。构成违反治安管理行为或者涉嫌犯罪的,还应依据相关法律承担相应法律责任。
对于此类问题,更适宜通过平台投诉、证据固定、依法维权以及其他正规渠道处理,而不是在网络上进行私人报复。
这既是对他人的尊重,也是对自身行为边界的约束。
八、关于本项目及相关讨论的最终立场
本项目可以不成熟。
一个想法也可以最终被证明存在错误。
一个开发者可以暂时缺少系统性的专业知识。
一个学生同样可能写出存在大量漏洞的代码。
这些都不意味着其没有公开作品、参与开源和继续学习的资格。
我们接受严格的技术审视。
我们尊重真正具有专业能力,并愿意通过事实、实验和代码提供建设性意见的人。
我们感谢每一位发现真实问题、帮助修复问题以及认真讨论设计思路的人。
项目后续存在修改,并不意味着必须否定原有探索本身。
恰恰相反,正因为存在问题,才有继续修改的意义。
正因为项目选择开源,后续参与者才有机会在已有工作的基础上继续尝试,并通过 Issue、Pull Request、Review 等正常协作机制推动项目完善。
这正是开源协作的价值所在。
技术上的不足没有必要掩饰。
已经确认的问题,可以修改。
暂时无法解决的问题,应当明确说明。
尚未掌握的知识,可以继续学习。
如果未来事实证明整个技术方向存在根本性问题,也可以重新开始。
但是:
承认不足并不意味着低人一等。
接受批评并不意味着接受羞辱。
选择克制也不意味着面对恶意只能保持沉默。
我们愿意接受对代码的否定,但拒绝将对代码的否定无限扩大为对人的否定。
技术问题,应当由技术解决。
漏洞,应当由实验和事实证明。
观点,应当由证据进行讨论。
而一个仍在成长的人是否拥有继续学习和创造的权利,本不应成为需要争论的问题。
开源最值得珍惜的地方,从来不只是让成熟开发者展示已经完成的成果。
它同样给予每一个仍在成长的人公开自己第一次尝试的机会。
今天一个并不成熟的项目,也许最终只是一场普通实验。
也可能因为一次 Issue、一次 Pull Request、一次失败,或者后来者偶然产生的一个新思路,最终成为另一个更加成熟项目的起点。
没有人能够提前知道答案。
因此,相比于证明一个年轻人的第一次尝试究竟有多么幼稚,更有价值的事情,是准确指出其错误所在,并给予其继续学习、继续修改和再次尝试的空间。
对错误保持严格,对知识保持敬畏,对技术保持开放,对仍在成长的人保留应有的善意。
这不是针对任何个人的宣战,也不应被理解为对正常技术批评的排斥。
它更应当被理解为一种对于开源环境、技术讨论边界以及年轻开发者成长环境的共同呼吁。
最后,郑重声明:
我们尊重并保障任何个人依法进行技术研究、合理批评、事实评价及正常讨论的权利,不会因为不同意见而采取任何形式的报复行为。
但言论自由和技术讨论同样具有法律边界。
对于任何涉嫌侮辱诽谤、网络欺凌、侵犯隐私、非法获取或传播个人信息、威胁骚扰,以及其他侵犯项目作者、贡献者或相关人员合法权益的行为,我们将依法保存相关证据,并保留向有关网络平台投诉举报、向有关主管机关反映情况,以及依法追究相关行为人法律责任的权利。
如相关行为涉嫌违反治安管理规定或者涉嫌犯罪,我们亦保留依法向有管辖权的公安机关等有关部门提供证据、反映情况的权利。
上述立场并非针对任何正常参与讨论的人员,更不构成对正常技术研究和合理批评的限制。
其边界十分明确:
技术问题,欢迎讨论;
事实争议,欢迎举证;
合理批评,应当接受;
善意建议,值得感谢;
真实漏洞,欢迎指出并共同修复。
但任何人的年龄、经验不足、技术水平或者作品缺陷,都不应成为实施网络暴力或者其他违法侵权行为的理由。
我们不主动制造争端,也希望所有争议最终回归代码、事实与技术本身。
这应当是一个开源项目面对批评应有的态度,也应当是一个成熟技术社区面对后来者应有的基本善意与专业素养。