当AI成为编程语言的第一公民:Vercel Zero语言的设计哲学与未来

当AI成为编程语言的第一公民:Vercel Zero语言的设计哲学与未来

人类提出需求,Agent查询图、提交已检查的编辑、证明结果。这不是一句口号,而是一门语言的全部设计起点。

2026年,编程语言的版图上多了一个略显异类的名字:Zero。它由 Vercel Labs 以 Apache 2.0 协议开源,源文件用 .0 作为扩展名,编译为原生可执行文件,与 C、Rust 处于同一设计空间。但真正让它引发讨论的,不是语法,而是一句近乎挑衅的定位——这是一门为 AI Agent 而非人类设计的系统编程语言。发布仅两天,GitHub 便收获 1100+ Star。

这篇文章不打算复述新闻稿,而是从编程语言的演进逻辑出发,剖析 Zero 的图原生(graph-native)范式、Agent 优先的工具链契约,并探讨一个更深层的问题:当 AI 成为语言设计的第一公民,软件工程的底层逻辑正在发生怎样的位移。

从打孔卡到语义图:编程语言的演进逻辑

理解 Zero,需要先把它放回编程语言长达七十多年的演进脉络中。每一次语言范式的跃迁,本质上都是"谁在理解程序"这一问题的回答发生了变化。

机器码与汇编:机器理解人类

最早的程序是用打孔卡和二进制机器码写就的。那个时代,是机器在迁就人类笨拙的表达——人类必须把自己的意图翻译成机器能逐位执行的电平信号。汇编语言用助记符替代了二进制,但本质仍是"人向机器低头"。

高级语言:人类理解人类

Fortran、C、Pascal 的出现,让程序开始用接近人类思维的方式表达。编译器承担了"翻译官"的角色,把人类可读的代码转成机器指令。这个阶段的核心矛盾是抽象层次:我们不断发明更高层的抽象(面向对象、函数式、泛型),让人类能管理日益膨胀的复杂度。

AI时代:谁理解程序?

大语言模型的崛起,让"理解程序"的主体变得模糊。今天,大量代码由 AI 生成、由 AI 审查、由 AI 修复。但讽刺的是,这些 AI 仍在使用为人类设计的语言和工具链。错误信息是给人类读的散文,类型系统是人类发明的契约,依赖管理是人类维护的图。Agent 在这个体系里始终是个"二等公民"——它必须反复地把人类可读的文本解析成自己能操作的结构,而这个解析过程脆弱且昂贵。

Zero 的回答很直接:既然 Agent 已经成为代码的主要读者和写者,那就让语言从一开始就为它优化。

Zero是什么:一门为Agent而生的系统语言

先给 Zero 一个准确的定位。根据其官方仓库的描述,Zero 是一门实验性的图原生(graph-native)编程语言,旨在实现可靠的自主软件生成。它被优化为以下几个目标:

  • Token 效率(对大模型上下文窗口友好)

  • 低内存占用

  • 快速启动

  • 快速构建

  • 低运行时延迟

  • 零依赖
  • 它在设计空间上与 C、Rust 并列:编译为原生可执行文件,提供显式的内存控制,面向底层环境。但关键的差异在于——编译器输出和工具链从第一天起就是为 AI Agent 设计的,而不是只为人类工程师

    这一点体现在一个朴素却深刻的设计取舍上。传统的编译器反馈循环是这样的:Agent 写代码,编译器吐出一段非结构化的错误文本,Agent 再去解析这段文本来判断哪里出了问题、如何修复。这个循环极其脆弱——错误信息的措辞会随版本变化,信息是写给人类阅读的,而且根本不存在"修复动作"这个一等概念。

    Zero 的做法是让编译器默认输出结构化的 JSON 诊断,每条诊断都携带稳定的错误码、人类可读的消息、行号,以及一个带类型的"修复标识符"。人类读消息,Agent 读码和修复标识符。二者共用同一条 CLI 命令,无需切换模式,也无需额外的分析服务。

    图原生:让程序成为可查询的数据库

    如果说"Agent 优先"是 Zero 的立场,那么"图原生"就是它的方法论。这是 Zero 最具想象力,也最容易被低估的一点。

    语义图即程序本身

    在 Zero 的世界观里,语义图就是程序数据库。这不是一个比喻,而是一个工程事实。传统编译器内部当然也构建 AST(抽象语法树)和各种中间表示,但这些结构对开发者是不可见的内部实现细节。Zero 则把这张图提升为一等公民:程序的模块、导入、公开符号、能力、副作用、所有权事实,都作为图的节点和边被显式建模并对外暴露。

    运行 zero graph --json,你能拿到一份结构化的程序地图:

    bash
    zero graph --json examples/systems-package

    输出包含模块、导入边、公开符号、能力声明、效应信息、所有权事实,以及接口指纹。对 Agent 而言,这意味着它不必"猜测"一个程序的依赖关系,而是可以直接查询。

    从"读源码"到"查数据库"

    这里有一个范式级的转变值得深思。过去的 Agent 改代码,依赖的是把整个源文件塞进上下文,靠模型的语义理解去推断符号从哪来、改一处会不会影响别处。这是一种基于概率的"模糊推理",天然存在幻觉风险。

    而图原生意味着,Agent 可以像一个查询数据库那样去查询程序的结构关系:

  • 这个符号被谁引用?

  • 这个函数有哪些效应?

  • 修改这个公开接口会影响哪些下游模块?

  • 这段代码分配了哪些资源,所有权归谁?
  • 当这些关系是确定性的、可查询的图数据,而非模型脑补的猜测,Agent 生成代码的可靠性和可验证性就有了结构性的提升。人类提出需求,Agent 查询图、提交"已检查的编辑"(checked edits)、最后证明结果——这条工作流之所以成立,正是因为图本身是可信的程序事实来源。

    Agent优先的四块基石

    把 Zero 的设计拆开看,支撑"Agent 优先"的是四块互相咬合的基石。

    结构化诊断:错误不再是散文

    这是最直观的一块。运行 zero check --json,你得到的不是一段散文式的报错,而是一份契约化输出:

    json
    {
      "code": "NAM003",
      "message": "unknown identifier 'message'",
      "expected": "visible local, parameter, function, or builtin",
      "actual": "no matching visible symbol",
      "repair": {
        "id": "declare-missing-symbol"
      }
    }

    注意这里每个字段的职责分工:codeNAM003)是跨版本稳定的标识符,Agent 可以可靠地匹配它;message 是给人看的;expectedactual 把"期望与现实的差距"显式化,让 Agent 不必从措辞里猜;repair.id 则直接给出一个带类型的修复动作标识。

    这种设计击中了 Agent 与传统编译器协作的最大痛点。传统编译器的错误信息是自然语言,措辞一变,Agent 的解析逻辑就失效。而稳定的错误码加结构化的"期望/实际"对照,等于把错误从一个模糊的语义问题,降维成一个确定性的模式匹配问题。

    编译器即工具链:检查、解释、修复一体化

    Zero 的第二块基石,是把所有 Agent 需要的能力收编进同一个编译器二进制。这不是简单的功能堆叠,而是一套精心设计的"工具链契约":

    | 命令 | 契约内容 |
    |------|----------|
    | zero skills get language | 与编译器版本匹配的语言规则,随二进制分发 |
    | zero check --json | 诊断码、span、期望/实际字段、修复安全性、编译期沙箱事实、目标就绪度 |
    | zero parse --json | 稳定的解析摘要:声明、函数签名、body 节点类型 |
    | zero graph --json | 模块、导入、公开符号、能力、效应、所有权、辅助函数使用 |
    | zero fix --plan --json | 类型化修复计划,描述拟议改动而不直接改文件 |
    | zero size --json | 保留的辅助函数、体积原因、后端事实、产物预算 |

    其中两个命令尤其值得展开。zero explain --json TYP009 让 Agent 直接查询某个诊断码的详细解释,而不必去抓取可能已经过时的外部文档。zero fix --plan --json 则生成一份机器可读的修复计划——它告诉 Agent "应该怎么改",但不直接动文件,把最终决策权留给了 Agent 或人类。这是一种克制而聪明的边界划分:编译器负责"提议",Agent 负责"执行与证明"。

    这套契约的价值在于确定性。Agent 不需要推理"该用哪个工具做哪件事",因为检查、解释、修复、查询都是同一组稳定子命令。在自主循环里,减少决策点就是减少出错点。

    能力化I/O:显式效应与编译期保证

    Zero 的第三块基石是显式效应系统。在 Zero 中,如果一个函数会写标准输出、访问文件系统或发起网络调用,它必须通过一个能力对象(capability object)声明这一点。

    看这个标准的入口函数:

    zero
    pub fn main Void world World !
     if == answer() 42
     check world.out.write "math works
    "

    这里的关键约定是:worldWorld 类型的能力对象,它授予函数访问外部世界的权限。一个没有接收到 World(或从中派生能力)的函数,根本无法执行 I/O——这是编译期强制执行的,而非运行期检查。系统里不存在隐藏的全局进程对象,没有隐式的异步运行时,也没有魔法全局变量。

    check 关键字负责处理可能失败的操作:如果 world.out.write 可能失败,check 会把失败沿调用栈上抛。而函数签名末尾的 ! 标记则表明该函数会传播错误——错误路径因此被写进签名,而非埋在运行时异常里。

    对 Agent 而言,这是一个巨大的可靠性红利。当效应是签名的一部分,Agent 在调用一个函数之前就能从类型签名知道它会产生哪些副作用,而不必通读函数体去"嗅探"隐藏的 I/O。这让静态推理成为可能,也让"证明结果"这件事有了可验证的依据。

    随版本匹配的"技能":Agent的自我说明书

    最后一块基石解决的是一个看似琐碎却极其要命的问题:文档与编译器的同步

    传统生态里,Agent 要么靠训练时记住的(可能已过时的)文档,要么靠实时抓取外部文档,但外部文档和实际运行的编译器版本经常对不上。Zero 的解法是 zero skills——把与当前编译器版本匹配的 Agent 指南直接随二进制分发:

    bash
    zero skills list
    zero skills get language
    zero skills get diagnostics
    zero skills get stdlib

    这意味着 Agent 拿到的语言规则、诊断解释、标准库说明,与它正在使用的编译器是同源的、版本对齐的。zero skills get zero --full 会返回覆盖语法、诊断、构建、包、标准库、测试和 Agent 编辑循环的聚焦工作流。文档不再是外挂,而是工具链的内生部分。

    Zero语法速览:前缀表达式与极简主义

    了解了理念,我们来看 Zero 的语法面貌。它有意保持极简,追求"规整的模式优先于语法的便利"。下面是 README 中给出的官方示例:

    zero
    fn answer i32
     ret + 40 2
    
    pub fn main Void world World !
     if == answer() 42
     check world.out.write "math works
    "

    几个值得注意的语法特征:

  • 前缀表达式:运算符写在操作数前面,+ 40 2 表示 40 + 2== answer() 42 表示判断 answer() 是否等于 42。前缀表达式对 Token 友好、无歧义、无需优先级规则,这对 Agent 尤其有利。

  • 缩进界定块:用缩进而非花括号表示层级,减少噪音 Token。

  • 函数签名即契约fn answer i32 声明返回类型为 i32pub fn main Void world World !Void 是返回类型,world World 是能力参数,! 标记可传播错误。

  • ret 显式返回:没有隐式的"最后一个表达式即返回值",一切显式。
  • 基于这种风格,我们可以合理推测一个带参数和结构体的程序大致长这样(以下为依据官方语法的风格化示例,非官方片段):

    zero
    fn add a i32 b i32 i32
     ret + a b
    
    type Point
     x f64
     y f64
    
    fn length p Point f64
     ret sqrt + sq p.x sq p.y

    注意 lengthsqrtsq 同样是前缀调用,整段代码的信息密度高、结构规整、歧义极少。这正是 Zero 在 Token 效率上的考量:让每一个 Token 都承载确定性的语义,而非语法糖的噪音。

    系统语言横向对比:Zero、C、Rust、Go

    把 Zero 放回系统语言的坐标系里,能更清楚地看到它的定位与取舍。

    | 维度 | C | Rust | Go | Zero |
    |------|----|------|----|------|
    | 主要读者 | 人类 | 人类 | 人类 | AI Agent |
    | 内存控制 | 手动(malloc/free) | 所有权+借用检查 | GC | 显式,无强制GC |
    | 副作用建模 | 隐式(函数指针/全局) | 显式(部分,如unsafe) | 隐式 | 显式能力对象,编译期强制 |
    | 错误信息 | 非结构化文本 | 人类可读文本(部分结构化) | 人类可读文本 | 结构化JSON+稳定错误码+修复ID |
    | 修复闭环 | 无内置概念 | 外部工具(clippy等) | 无内置概念 | zero fix --plan原生支持 |
    | 程序结构可见性 | 内部AST | 编译器内部 | 内部 | 图原生,zero graph对外暴露 |
    | 二进制体积 | 小 | 中等 | 较大 | 小(亚10KiB级别) |
    | 工具链形态 | 分散(gcc/make/cmake) | cargo一体化 | go一体化 | 单一zero二进制 |
    | 版本同步文档 | 无 | 外部docs.rs | 外部pkg.go.dev | zero skills随二进制 |
    | 稳定性 | 稳定 | 稳定(edition演进) | 稳定 | 故意不稳定(pre-1.0) |

    这张表揭示了一个核心事实:C、Rust、Go 都把"人类理解程序"作为默认假设,结构化信息和修复能力是事后补丁或外部工具的职责;而 Zero 把这些从第一天起就内建进编译器。它不是在已有语言上加一层 Agent 友好的壳,而是从地基开始重新浇筑。

    代价同样明显:最后一行"故意不稳定"。Zero 明确声明,在 1.0 之前会为了 Agent 目标而接受破坏性变更,不保留遗留行为。这意味着它的生态成熟度远不及另外三者,今天写的代码明天可能就编译不过。

    "AI第一公民"到底意味着什么

    "AI 第一公民"这个词容易被滥用成营销话术,但在 Zero 的语境里,它有三层可以被工程化验证的含义。

    第一层:信息契约的第一受众。 当编译器输出一份诊断,它的首要消费者是 Agent。稳定错误码、结构化字段、带类型的修复标识符——这些都是为了让 Agent 能可靠地匹配和行动,而不是为了让人类读得舒服。人类依然能读 message 字段,但语言不再围绕"人类读得爽"来做取舍。

    第二层:学习方式的第一假设。 传统语言假设人类会去读一本厚厚的语言规范、踩几个月坑、形成肌肉记忆。Zero 假设它的"用户"是 Agent,而 Agent 的学习方式是即时查询——zero skills get 随取随用,随版本对齐。这暗含一种哲学转变:语言的复杂度不再由"人类记忆容量"来约束,而是由"可被即时查询和理解"来约束。规整的模式优先于语法便利,正是因为模式化意味着可预测、可查询、可生成。

    第三层:信任模型的重建。 传统的 Agent 编程依赖概率——模型"觉得"这段代码是对的,但缺乏可证明的依据。Zero 试图用结构化的图、显式的效应、编译期的能力检查,把"猜测"变成"查询",把"可能对"变成"可证明"。zero check 的修复安全性字段、编译期沙箱事实、目标就绪度,都是在为"证明结果"提供机器可验证的证据。人类提出需求,Agent 提交已检查的编辑并证明结果——这是一条从概率到确定性的信任升级路径。

    风险、挑战与冷思考

    对一项实验性技术保持热情的同时,必须清醒地看到它的风险。

    成熟度风险是首要的。 Zero 目前处于 v0.3.x,官方明确警告应预期破坏性变更和安全漏洞,"不应在生产系统、敏感数据或可信基础设施上运行"。它的编译器部分用 C 编写(位于 native/zero-c/,作为 bootstrap),部分用 Zero 自身编写(自托管编译器,位于 compiler/ 目录)——自托管是一个语言走向成熟的标志,但距离稳定还有相当的路程。

    生态真空是第二重挑战。 Zero 没有包注册中心,交叉编译仅限文档化的目标子集,标准库覆盖仍在早期。一门语言的成败不只取决于语法设计,更取决于它能否吸引足够的库和开发者。而 Zero 的目标用户——Agent——本身不会"忠诚"于某门语言,它们只是完成任务。如果 Zero 不能让 Agent 更高效地完成任务,生态就无从谈起。

    "Agent优先"是否会排斥人类,是更深层的隐忧。 如果一门语言过度为 Agent 优化,人类工程师阅读和调试它的成本会不会上升?前缀表达式、极简语法虽然对 Token 友好,但对习惯了中缀表达式的人类而言,可读性可能反而下降。Zero 需要回答:人类与 Agent 共同编写同一段代码时,谁该迁就谁?一个健康的未来,应该是人机都能高效协作,而非把人类挤出循环。

    还有信任边界的悖论。 Zero 强调"已检查的编辑"和"证明结果",但这建立在编译器本身可信的前提上。如果编译器有 bug,或者图本身被污染,那么 Agent 据此做出的"证明"就是不可靠的。把信任从"模型的概率"转移到"编译器的确定性",只是转移了单点,并没有消除信任问题。如何审计这张图、如何防止图被恶意篡改,是图原生范式必须面对的安全课题。

    写在最后:对每一位开发者的启示

    Zero 可能成功,也可能像无数实验性语言一样沉入历史。但无论它的终局如何,它提出的问题都值得每一位开发者认真对待。

    编程语言的受众正在扩容。 过去七十年,语言是为人类设计的,编译器是人类与机器之间的翻译官。未来,Agent 将成为代码的高频生产者和消费者,语言设计必须同时回应"人类能否读懂"和"Agent 能否可靠操作"两个约束。这不是要不要的问题,而是迟早的问题。

    结构化优于自然语言,正在成为工具链的新共识。 Zero 的 JSON 诊断、稳定错误码、修复计划,本质上是把"人机自然语言沟通"升级为"机机结构化契约"。这个思路不局限于 Zero——任何想让 Agent 更可靠地使用的工具,都应该思考:你的输出,是不是给 Agent 准备的稳定契约?

    确定性是 AI 可靠性的基石。 当 Agent 从"猜测"走向"查询"、从"可能对"走向"可证明",我们才能真正把关键软件的生成交给自主循环。Zero 的图原生和显式效应,指出了一个方向:把程序中那些模糊的、隐式的关系,变成可查询、可验证的结构化事实。

    对开发者而言,Zero 最直接的启示或许是:不要只学一门语言,要理解语言设计背后的取舍。 当 AI 成为代码生态的参与者,语言层面的每一次设计选择——错误如何表达、副作用如何建模、结构如何暴露——都会被放大成 Agent 行为的可靠性差异。能看透这些取舍的人,才能在 AI 时代真正驾驭工具,而不是被工具驾驭。

    Zero 还很远,但它指向的方向,已经清晰可见。

    仓库地址:github.com/vercel-labs/zerolang/

    安全提示:实验性项目,请在隔离环境中使用,勿用于生产。

    💬 评论区 (0)

    暂无评论,快来抢沙发吧!