区块链 区块链技术 比特币公众号手机端

为生产级工作设计Loop

为生产级工作设计循环 2025 年底,我们进行了一项实验来回答一个问题:“编程 Agent 能否完全自主地从零开始解决一个生产级问题?” 为此,我们让两个 Agent 使用(当时)最强大的公开可用编程模型,处理一个真实的问题和一个真实的截止期限。这项实验的成果是一个名为 toktoktok 的 tokenizer 训练器,现已在 GitHub 上开源。 在本文中,我们分享了关于设计有效循环(loop)的心得,这些循环能让 Agent 自主解决生产级问题:如何为多领域专家指定目标,以及如何搭建验证基础设施。

为什么测试自主性需要一个真实的目标

作为我们关于词表大小对边缘 LLM 影响的研究的一部分,我们需要一个能在单台机器上处理数万亿 Token 的字节对编码(BPE)tokenizer 训练器。然而,tokenizer 训练工具的选择非常有限:sentencepiece 是为非 BPE tokenizer 优化的,速度很慢;Hugging Face tokenizers 在我们的语料库上内存耗尽;而 tiktoken 则完全没有训练能力。 这就是为什么我们需要构建一个生产级 BPE tokenizer 训练器。根据使用现有库的经验,我们还知道内存大小才是真正的瓶颈,而且它们缺少我们需要的两个特性:从现有 tokenizer 热启动(词表扩展)和按语言分配的词表预算。这给了我们一个具体的任务、一个真实的截止期限,以及一个回答编程 Agent 是否足够可靠、能否自主解决任务的有效方式,因为它满足以下标准: 生产级。 Agent 通常被用于自主解决问题的方式无法回答这个问题。首先,它们常被用于原型开发,从未被要求达到生产标准。其次,它们往往是用另一种语言重新实现已有的东西,例如“将 SQLite 移植到 Rust”或“用 Zig 编写 C 编译器”,这实际上是对模型在预训练期间很可能见过的内容进行翻译。与这两者不同,我们的任务有明确的交付生产目标,而且 BPE tokenizer 训练足够新、公开的参考实现很少,这使它成为一个理想的“测试分布”问题样本。 多领域专业知识。 在 Liquid AI,我们的专家造诣深厚,但各自只限于单一领域。我们的 ML 研究人员可以凭记忆告诉你 OpenAI 的 cl100k 为什么为每个三位数保留 rank,但他们从未写过一行 Rust。我们的 Rust 工程师写的正是这个问题所需的内存感知、多线程系统代码,但他们从未训练过 tokenizer。 这是两个互不相交的人群,谁都无法独自解决这个问题。人类的两种变通办法都有损耗:要么其中一方先学习另一方的知识,要么我们以协作方式配备人员并承担协调开销。这正是我们让 Agent 攻克的地方:“它能否覆盖我们任何一位工程师都不具备的专业知识跨度?” 可外部验证。 产物必须能在 tiktoken 和 Hugging Face tokenizers 中加载。由于与第三方软件的这种互操作性,这项工作可以由 Agent 无法修改的代码来检验。成功不是自我报告的,而是取决于两个第三方库能否产生正确的 Token。 虽然需要构建的内容的细节本身就很有意思,但对本文而言,重要的是:一个真实的生产级任务、对我们的单领域专家来说很难、且可外部验证的任务,是回答 Agent 能否在没有任何人类监督的情况下完成工作的唯一诚实方式。

搭建实验

在这项实验中,我们选择了 Claude Opus 4.5 和搭载 GPT-5.2 的 Codex——2025 年底最强大的两个公开可用编程模型——作为编程 Agent,并让两者都在各自的规划模式下工作。在任何一个 Agent 写下第一行代码之前,我们为它搭建了两样东西:一个要瞄准的目标,以及一种验证它是否达到目标的方法。 实验搭建 目标在一个规范说明文件中描述。它是一份由操作员编写的单一 AGENTS.md / CLAUDE.md 文档,描述的是结果及其约束,而不是实现方式:首要的架构约束是内存。设计将复杂度预算花在内存上,使得远大于 RAM 的语料库仍能得到公平的表示。计算和 I/O 是次要的,得到直接的处理:一门系统级编程语言(Rust)和多线程应该就足够了。 为了验证 Agent 是否达到了指定的目标,我们给了它两样它无法影响的东西:

  • 生产数据:我们让 Agent 以沙箱方式访问我们的生产训练数据集,以及一台能够处理它的机器,具体是一台拥有 128 核、256 线程和 2 TB 内存的 AMD EPYC 9755。
  • 外部验证 harness:训练出的词表必须能被 tiktoken 和 Hugging Face tokenizers 加载,并检查两者的编码和解码往返,以及两者在 ID 层面的一致性,涵盖多种语言、数字、货币格式、制表符、CRLF 行尾和源代码。

有了这些组件,Agent 就可以朝着指定的目标工作了。

运行时发生了什么

我们用两个编程 Agent 都运行了这项实验。操作员从外部监控,只读取 harness,从不读一行代码。

两者都零样本完成了玩具训练器

两个 Agent 都在 30 分钟内产出了一个可用的训练器。它们解析配置、遍历语料库、应用硬编码的合并、运行 BPE 训练,并生成了一个有效的 .tiktoken 文件,通过了它们自己的单元测试。 两者都能成功在几 MB 数据上训练玩具 tokenizer。产物能在 tiktoken 中加载。所有测试都通过。如果我们在此刻停止评估,结论将是两次运行都成功了。

没有循环,两者都无法扩展到生产规模

然而,两个训练器都没能在完整的生产数据集上存活。在第一次运行中,每个阶段的每个单元测试都通过了,因为几 MB 的干净文本不会触发以下任何问题:

必须发现的问题 它如何暴露自己 什么捕获了它 修复工作量
文件编码。 Parquet 允许同一逻辑列使用多种编码。 在测试中读取正常的文件在语料库中被静默地错误处理 真实语料库文件 数小时
内存感知。 每个文档的 Vec 开销淹没了有效载荷 在大约 1% 的目标语料库处内存耗尽 全规模运行 两到三天:分块批处理、哨兵值、多段迭代
不当的并行化。 只并行化关键路径的一部分,其余部分仍是串行的 每个核心都忙碌,吞吐量仍然不可接受 全规模运行 一到两天
预分词速度。 \s+(?!\S) 迫使使用回溯型正则引擎 Profiler 显示预分词占主导;对抗性空白字符导致二次方复杂度 全规模运行 数小时,外加一次正确性判断
Rank 排序。 tiktoken 从 rank 顺序推导合并顺序,因此 rank 必须连续 词表加载时毫无报错,但编码结果与预期不同 外部 harness 数小时
重复合并。 训练出的合并可能复制现有 Token 并使词表坍缩 词表少了 N 个,之后每个 rank 都发生偏移 外部 harness 数小时
数字编码。 Rust 的 regex crate 将 {1,3}+ 重新解析为 ({1,3})+ tokenizerstiktoken 在除数字外的一切上都一致 外部 harness 一行代码

然后,我们让 Agent 针对真实数据进行循环:执行、碰壁、报告症状、让 Agent 诊断并修复、再次运行。 在超过五次迭代且进展甚微之后,我们停止了 Codex/GPT-5.2 路线的工作,它仍在训练吞吐量上苦苦挣扎。这是一个资源决策:只有一名操作员、一个真实的截止期限,而到那时,在相同的轮次下,Claude Opus 4.5 路线已经走得更远。我们的判断是,Claude 的第一个版本起步更好,因为它比 GPT-5.2 更可靠地领会了规范说明的细微之处以及约束背后的意图。 Claude Opus 4.5 在随后几次迭代中解决了剩余问题,产出了一个能运行完整生产配置的训练器:在单台机器上,多阶段处理数万亿 Token 的多语言和代码数据,几天内完成。输出干净地通过了外部 harness。

为什么循环是必要的

我们运行这项实验是为了回答这个问题:“编程 Agent 能否自主地从零开始解决一个生产级问题?” 人们很容易把“两个 Agent 都没能零样本完成”解读为关于模型能力的故事,但这是错误的结论。按照我们一开始设定的标准,实验成功了。然而,让它达到目标的不是任何一次聪明的轮次,而是循环。 闭合循环 这个仓库中的两千行代码不是零样本响应的产物,而是一个迭代过程的残留物。几乎每一行不明显的代码,一旦你知道它需要被写出来,写起来都很便宜;而昂贵的部分是知道它需要被写出来。 这意味着 Agent 能否在没有人类监督的情况下成功实现目标,取决于是否有一个能针对真实环境约束收敛的迭代循环。这让 Agent 能够迭代地发现并体验真实世界的混乱。

运行自主循环的经验教训

从这项实验中,我们了解到编程 Agent 能够通过循环自主解决任务,但更重要的是,我们学到了关于如何设计有效循环的两条宝贵经验,这些经验如今已成为我们工程团队的日常实践。

为多领域专家指定目标

从实验中,我们了解到编程 Agent 是多领域专家,覆盖了我们任何一位工程师都不具备的专业知识跨度。事实证明,它既知道 OpenAI 的 cl100k 正则表达式,也知道 Rust 的 rayon。我们可能为此任务配备的任何人都不会两者都懂。这改变了我们指定目标的方式,因为这感觉更像是在与另一个团队的同事交谈,而这位同事恰好也懂你团队的材料。 想想把这个交给一个没有 tokenizer 背景的优秀软件工程师,实际上需要什么。显而易见的答案是给他们写一份详细的规范说明。这就是专业知识传递的经典困境:规范说明写得太短,工程师就得用缓慢的方式自己发现一切;写得足够长、真正可执行,那你写的就是伪代码了,此时你自己就需要领域知识,几乎可以亲自完成这项工作了。 LLM 不受这种困境束缚,因为它自带背景知识。这改变了规范说明的本质。我们的规范说明很短。它陈述的是结果和约束,而不是机制。 以我们规范说明中的一个真实例子为例:“在训练开始前,为所有两位数和三位数保留词表”。对于没有背景的工程师来说,这是一个随意的要求。他们可以按字面实现它,但仍然会做错,因为这句话没有携带自身的动机。它的目的是给模型一个一致的数字表示,使算术不依赖于哪些数字对恰好在语料库中频繁出现,例如,想想 GPT-2 的 tokenizer,由于训练数据中的频率,它有一个独特的 2019 Token,却没有 2029 的。不知道这一点,他们就无法判断指令的哪些部分是关键的、它在流水线中属于哪个位置,或者它对设计中的其他部分意味着什么。 为多领域专家编写的规范说明

针对现实世界的约束进行验证

我们的操作员从未读过一行产出的代码。这之所以可以接受,是因为成功标准是 Agent 无法操纵的东西。我们在循环设计中看到的一个常见错误是验证薄弱——针对玩具规模的数据运行,或者容易受 Agent 影响,例如编辑它自己的单元测试。 主要的经验是设计一个能针对现实约束收敛的循环,包含以下组件:

  1. 针对大规模的真实生产数据进行迭代。 重要的失败在测试套件中是不可见的,只有在全规模生产数据中才能发现。
  2. 用外部 harness 进行验证。 这是让自主性可以接受的关键。操作员从未读过代码,而这之所以可以容忍,是因为正确性由 tiktoken 和 Hugging Face tokenizers 定义——这些软件不是 Agent 写的,也无法被它影响。如果我们接受它自己的测试套件作为证据,我们就会得到两个通过了各自测试、却悄悄产出不同词表的实现。要构建问题结构,让第三方能够评判产物。

如今的日常与展望

这些是我们在 2025 年底进行的一项实验的结果和经验:是的,编程 Agent 能够在没有人类监督的情况下,自主地从零开始解决一个生产级问题,但前提是它们必须在循环中运行。 我们学到的经验如今已成为工程团队的日常实践。半年过去,指定目标是我们花费最多心思的部分,而用真实数据和外部验证构建循环已成为标准做法。 如今我们运行的循环远不止像 tokenizer 训练器这样的一次性构建——后者有一个清晰、可验证的最终目标供循环收敛。我们现在运行的许多循环是开放式的,朝着没有唯一正确答案的目标进行爬山:调优 kernel、监控持续集成、分诊传入的 pull request,或扫描生产日志中的异常。在每一种情况下,我们检查的是指标而不是代码。 如今的模型明显更好了,但让这成为日常的原因是,它们已经足够可靠,可以把整个循环交给它们。如果这一点能够推广,它对 ML 和软件工程工作方式的改变,将比任何原始编程能力的提升都要大。

可用性

toktoktok 以 Apache 2.0 许可证在 https://github.com/Liquid4All/toktoktok 开源。它可以从零训练 tiktoken 兼容的 BPE 词表,也可以扩展现有词表;支持读取 .txt 和 .parquet;通过多阶段训练在语言和领域之间分配词表预算;并保持在你声明的内存预算之内。用于 Hugging Face 的转换脚本支持双向转换,并在写入任何内容之前验证等价性。 它的每一行代码都由 Agent 编写,而我们一行都没有读过。

致谢

由 Mathias Lechner 撰写,Leonie Monigatti 参与贡献。 我们感谢 AMD 的合作,使本实验所需的硬件得以提供。

  • 原文链接: liquid.ai/blog/agent-loo...
  • 鸿途知科网 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
版权声明

本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门