首先构建仪表盘

开发 Ax3l 时,我从 Fr3d 教给我的架构经验出发。

提示词系统变得模块化、数据驱动。与 LLM 的不同交互采用独立的提示词类。实验数据、提示词构建、模拟控制和报告分别承担不同职责。

更重要的是,我把可观测性视为应用本身的一部分,而不是事后加上的功能。

Ax3l 拥有自己的报告服务器,以及由数据库支持的新事件日志系统。事件按类别和子类别组织,日志本身也变得可交互。

不再只是看到:

模拟已完成。

现在,我可以点开事件,查看模拟、运行配置、生成配置的提示词、模型的推理过程和最终数据。

日志不再只是一串文本。

它成为探索实验过程的导航工具。

事实证明,这一点极其重要。Ax3l 不会只运行一场实验让我在旁边观看,而是会无人值守地运行数百场,持续几天乃至几周。如果我想知道 AI 做了什么,就必须能够事后重建它的决策过程。


接着,我想看看蛇

到了某个时候,成排的数字已经不能满足我了。

Snake Lab 本来就知道何时刷新最高分,所以我修改了程序,在那个时刻捕获游戏棋盘状态,并随模拟结果一起保存。

随后,我通过 Snake Lab 的 ZeroMQ API 暴露了这份快照。

现在,Ax3l 可以获取模拟中最好成绩所对应的实际棋盘,并在报告中显示。

突然之间,47 分不再只是 47。

蛇就在眼前。

你能看到它走过的路径、身体长到多长、食物在哪里,以及取得成绩时棋盘的状态。

从技术上讲,这是个很小的改动,却改变了项目的气质。实验不再只是产生数据库记录,里面还有一条小小的 AI 蛇,正在慢慢掌握自己的工作。

本实验没有伤害任何真正的蛇,不过不少虚拟蛇确实做出了值得商榷的人生选择!


它真的进步了吗?画图!!!

单看最高分,是回答这个问题的糟糕方法。

强化学习充满噪声。某个配置可能只是走运。一次特别出色的运行,并不一定说明底层系统真的进步。

所以,我添加了直方图,显示模拟分数的分布情况。

然后又加了一层叠加显示。

把实验中最早一半数据的直方图,覆盖在全部数据的直方图上。由于前者是后者的子集,每一根柱子只能等高或更短。

如果 Ax3l 毫无进展,新增结果应该只是继续堆积在大致相同的分布上。

但如果实验真的有效,就会发生更有意思的变化。

分布会逐渐向右移动。

你可以看到实验逐渐探索到配置空间中表现更好的区域。

这个可视化对我来说,远比盯着一个不断变化的最高分数字有用。


最高分从 38 到 53

最初可用的贪吃蛇配置,大约能拿到 38 分。

我从之前的实验中知道,RNN 的表现还可以更好。问题在于:如果给 LLM 合适的工具、历史记录和实验框架,它能不能系统地找到那些更好的配置?

写作时,Ax3l 已经完成超过 500 次模拟。

目前最高分是 53。

更重要的是,分数分布也移动了。

Ax3l 并不是不断乱扔飞镖,直到某一次刚好命中 53。随着实验推进,结果整体逐渐偏向性能更好的配置。

而实验仍然在运行。


实时实验数据:Snake Web

最后还有一个问题。

在我自己的网络中,Ax3l 报告服务器很好用,但我希望公众也能看到实验进展。

我不想为了发布几个图表,就把生产数据库或应用服务器直接暴露在互联网中。

所以,我又构建了一个小项目:Snake Web。

每隔半小时,Snake Web 查询实验数据库,生成静态 GitHub Pages 网站所需的 CSV 文件并发布。公开网站随后显示实验的最新状态。

可以看到最高分。

可以看到直方图。

可以看到每场模拟的结果。

甚至连随机种子轮换都看得见。Ax3l 换用新的随机种子、表现突然下降时,曲线也会忠实地跌下悬崖,再慢慢向上爬。

这不是一篇只展示成功结果、精心修饰的回顾。

这是实验的真实面貌,连伤疤也一并展示。


观察实验

做到这里,我认为项目完成了。

不是因为再也没有功能可加,想加的东西永远还有一百个。

它完成了,是因为我最初想要的系统已经存在。

现在有一个专门的强化学习实验室,能够运行受控的贪吃蛇实验并记录结果。

有一个自主 LLM 代理,能够检查结果、进行推理、选择新配置,再提交后续实验。

有一个可观测性层,让我能够查看它做了什么,以及为什么这么做。

还有一条公开发布管道,能够展示实验进展,而不暴露底层机器。

在这整套架构、数据库、ZeroMQ 消息、提示词、PyTorch 张量、CSV 文件和图表的深处,住着一条曾经只能得 38 分的蛇。

如今它能得 53 分。

我觉得这是个很不错的收尾。


链接

博客系列