跳到主要内容

构建智能体,有 MoonBit 就够了

· 阅读需 8 分钟

摘要​

智能体是否可信,取决于它所依赖的运行基础是否可信。要让智能体自主行动,平台需要提供三样东西:判断成功与失败的客观标准、足够迅速以便融入其推理过程的反馈循环,以及由操作者掌控的边界,让智能体的代码能够执行任务,又不会逃出沙箱。MoonBit 正是为这样的场景而设计的。它是一套面向云计算和边缘计算的端到端编程语言工具链,支持 wasm、wasm-gc、js 和 native 后端,并将测试、证明、结构化并发、脚本模式和沙箱置于核心。本文认为,这些并非附带功能,而恰恰是智能体平台所需的特性;MoonBit 已将它们作为语言的一等特性提供,而非事后拼接的工具。

1. 什么是 MoonBit?​

MoonBit 是一门在设计时就考虑了 AI 需求的编程语言,也是一套端到端工具链。它可以编译到 wasm、js 和 native 等后端。因此,同一个项目可以同时包含基于 wasm 的命令行工具、基于原生后端的应用和 Web 前端,并共享同一个领域模型包。这种适用范围对智能体很重要:智能体编写的同一份代码,既可以在受限环境中运行,也可以在完整环境中运行,使用相同的工具链,并获得相同的保障。

关键在于,MoonBit 将验证和执行边界视为语言层面需要解决的问题,而不是让用户用外部脚本自行拼装的功能。测试、形式化验证、结构化并发和沙箱化后端都是平台的一部分,并通过 moon 命令统一提供。

2. 智能体自动化需要什么?​

一个平台能否承载自主执行的任务,取决于三个特性。

  1. 可靠:成功与失败应当有清晰、可由机器检查的判定标准,也就是能够区分正确与错误,而不依赖人来阅读文字说明。一个无法判断自己是否成功的智能体,既无法改进,也无法让人放心地交由它无人值守地执行任务。

  2. 足够快: 平台不能拖慢智能体的开发进程。如果每轮“编辑—运行—检查”都要花上数秒编译,智能体就会把预算花在等待上,而不是推理上;如果这个循环足够快,智能体就能像人类开发者一样持续迭代。

  3. 原生支持沙箱,并且能够跨平台运行: 智能体的代码必须能够受到约束,其行为也必须在不同操作系统、不同用户之间保持一致。依赖特定操作系统 Shell 脚本的平台,既不安全,也不具备可移植性。

3. MoonBit 如何满足这些要求​

3.1 可靠性:让智能体根据反馈修正代码​

MoonBit 提供了由弱到强、逐级递进的可靠性保障,让智能体和审查者可以根据任务选择合适的层级。

  • 断言测试。 test "name" { ... } 代码块的类型为 () -> Unit raise Error,通过 moon test 运行。普通断言(assert_eq、assert_true)会在失败时明确报错。

  • 快照测试。 当手动编写预期值过于繁琐时,inspect 可以记录任意实现了 Show 的值,json_inspect 可以记录可读的 JSON 表示,而 @test.T::write / writeln 配合 snapshot 可以将输出保存到文件中。这些内容都可以通过 moon test --update 自动插入和更新,让“这里应该输出什么?”变成一条命令就能回答的问题。

  • Cram 测试。 内置的命令行交互记录式测试(moon cram test)会精确固定实际命令行二进制程序的标准输出、标准错误和退出状态,使端到端的 CLI 行为成为可长期复用的测试基准,而不再依赖手动检查。

  • 属性测试。 借助 quickcheck 和 derive(Arbitrary) / derive(Shrink),随机输入可以触及边界情况,并将失败案例缩减为最小反例。这类测试覆盖通常是智能体手动编写测试时难以做到的。

  • 形式化验证。 除了测试,MoonBit 还提供了 moon prove。逻辑侧的谓词放在 .mbtp 文件中;程序侧的函数包含前置条件、后置条件、循环不变量和 proof_assert 步骤。包会被转换为 Why3 工具链可处理的形式,再由 SMT 求解器完成证明义务,智能体无需编写复杂的证明过程。这里的正确性由数学保证,而不是由测试覆盖率保证。

另外两项保障让并发代码值得信赖。结构化并发:任务只能在 @async.with_task_group 创建的任务组中启动,任务组只有在所有子任务都终止后才会返回;如果某个子任务失败,其他同组子任务就会被取消,并执行各自的清理逻辑,因此不会出现孤儿任务。一等取消机制:每个异步操作默认都可取消。取消会在异步代码中自动传播,绕过普通的 catch 处理逻辑,同时仍然执行通过 defer 和 errdefer 注册的清理操作。因此,超时和其他控制流机制可以组合使用,不会因普通错误处理意外吞掉取消信号。

这些能力共同构成了智能体可以自行完成的反馈闭环:运行 moon check 或 moon test,获得明确的通过或失败结果,再修复编译器或测试指出的问题。

3.2 速度:缩短开发循环​

MoonBit 的工具链经过调优,确保编译不会拖慢开发。语言特性的引入十分谨慎,会避免加入可能拖慢编译的特性。

脚本模式则彻底省去了繁琐的准备工作。.mbtx 文件直接在文件内声明导入项,无需模块或包配置,因此单个文件就是一个可运行的程序:

---
import {
  "moonbitlang/async",
  "moonbitlang/async/shell",
}
---
///|
async fn main {
  let out = @shell.Cmd("moon", ["check", "--output-json"]).output()
  println(out.stdout())
}

使用 moonx script.mbtx 即可运行。这样一来,用 MoonBit 编写脚本的体验几乎和使用解释型语言一样快捷,同时仍然拥有真正的类型检查器,以及背后完整的平台支持。对于需要不断生成和重新生成代码的智能体而言,这种差异至关重要。

3.3 沙箱与可移植性:组合调用,约束依然生效​

MoonBit 的沙箱化后端(wasm)是智能体任务的执行目标,而语言通过一套可移植的接口与外部环境交互。文件 IO、HTTP/HTTPS、套接字和进程创建,在不同目标平台上都有一致的 API。因此,智能体只需编写一个程序,就能在 macOS、Linux 和 Windows 上以相同方式读取文件、发起请求或运行子进程,并在每个平台上受到相同的约束。

4. 两种赋能智能体的方式​

这两种方式相互补充,具体选择哪一种,取决于需求有多普遍。

对于常见、广泛存在的需求,MoonBit 提供已经构建好的软件:经过审查并发布的二进制程序,智能体可以直接调用。其行为固定、经过测试且可预测,智能体无需消耗 token 来重复实现。

对于范围较窄的特定场景和复杂任务,MoonBit 让智能体编写代码,编排现有工具和库。新问题几乎天然就不在已发布的工具目录覆盖范围内;此时,智能体组合平台基础能力的本领,决定了它能解决哪些问题。

提供可信的工具目录,同时允许开放式代码生成,可以兼顾覆盖范围与可控性:有现成工具时,智能体就使用它;没有时,就编写一个在沙箱中运行的程序。

5. MoonX:一个入口,两种执行模式​

MoonX 通过一个工具统一了上述两种方式,提供两种执行模式:

  1. 运行已发布、已构建的沙箱化应用——也就是将已交付的“软件”作为命令使用。

  2. 在沙箱中运行单文件脚本——即智能体编写的 .mbtx 代码,在相同约束下执行。

统一入口意味着,智能体只需理解一套使用模型,操作者也只需面对一套策略控制接口。由于这两种模式都运行在沙箱化后端上,并经过同一层可移植 IO,我们预期它们在不同操作系统上的行为会更加稳定,执行也会足够快;这正是当初要求使用沙箱所看重的两个特性。递归应用的策略还确保,在脚本和沙箱化应用构成的进程树中,不会发生沙箱逃逸。

6. 结语​

MoonBit 将智能体自动化所依赖的各项能力连接起来。

测试和验证提供了可据以采取行动的反馈。结构化并发和一等取消机制,让异步任务的生命周期可预测。快速编译和单文件脚本支持短周期的开发迭代。沙箱化执行和可移植接口,让生成的程序能够在不同环境中发挥作用,同时保留操作者的控制权。

MoonX 通过统一入口提供这一平台的能力:运行已有工具,或者编写任务所需的程序。

构建智能体,MoonBit 就够了。