返回

文章详情

WorldTUI: 我训练了一个360M模型来伪装成终端

Hacker News2026年10月22日 02:18

TL;DR: 我微调了一个360M参数的语言模型以模拟终端。它后面没有shell或文件系统:每次按键都会被输入,模型预测屏幕如何变化。它可以创建文件,运行vim和tmux,玩贪吃蛇,并且通常会记住你几条命令之前输入的内容。最大的收获是教会它修复自己的错误和并行解码屏幕行。你可以在浏览器中试试(208 MB),输入pythoon可以看到它不是一个真正的shell。这个演示是为配备WebGPU的桌面浏览器和物理键盘设计的。Chrome或Edge是最好的尝试平台。在现代手机上也应该能够正常工作,但速度会非常慢。去年我第一次看到Genie 3时,就开始想象一个未来,应用程序不是用代码编写的,而是通过学习来实现的。不是一个游戏引擎渲染场景,而是模型根据用户的输入预测下一个最可能的帧。自然地,我想训练自己的世界模型。但我没有巨大的GPU集群或大量的视频数据,所以我降低了我的期望:不再是游戏世界,而是一个终端。终端被证明是一个很合适的选择。它只是一个字符网格,而不是像素,我可以通过运行真实的shell生成任意多的完美标记的训练数据。预训练的语言模型也对ls或cat应该打印的内容有很好的理解。我真正想知道的是,它是否能够维持一个一致的世界,或者仅仅是生成令人信服的终端输出。最终模型基于Qwen2.5-Coder-0.5B,微调了在Docker内部运行的真实程序记录的终端会话。在这里跳转到示例视频。它如何看待终端。标准的LLM接受一个提示,然后一个一个地在末尾附加标记。这与终端不太匹配。单个按键可以单独完成某些操作,例如在vim中的esc,并且输出不总是显示在底部:clear会清空屏幕并将光标送回顶部。因此,我需要预测屏幕的变化,而不是预测文本流。我将终端视为一个字符网格,每个单元一个字符。模型并不是直接查看网格,而是查看描述其内容和所做更改的标记序列。每个会话开始于一个快照:屏幕大小、内容和光标位置。大小是输入的一部分,而不是固定的32×96。在演示中,你可以在创建自定义起始屏幕时设置行数和列数。BOS SCREEN_START 32 96 ROW_0 0 'simedw@laptop:~$ ' CURSOR 0 17 1 SCREEN_END 这也让我可以从应用程序中间开始。给它一个bash提示符、vim缓冲区或一局贪吃蛇,模型会尝试从那里继续(在bash中表现更好)。之后,每次按键都作为一个真实终端会发送的原始字节输入。字母本身就是,Enter是 ,Escape是0x1b,左箭头是ESC [ D等等。INPUT_START 'l' INPUT_END 模型反馈的内容是需要重写的行和光标的位置:OUTPUT_START ROW_0 17 'l' CURSOR 0 18 1 OUTPUT_END 用语言来说:在第0行,从第17列开始,写l,然后将光标移动到第0行,第18列。最后的1意味着光标可见,因为全屏应用有时会隐藏它。没有任何内容在此之前被清除。新字符只是覆盖在旧字符上。我不需要为字符创建新标记。Qwen已经为所有256字节值提供了标记,我将其重新用于字符、坐标和其他小数字。因此,一个坐标如17只占用一个标记,而不是两个。时间也是输入之一。如果没有按键,模型会得到一个WAIT标记和一个持续时间,而不是按键,这就是贪吃蛇如何自己继续移动的原因。复制行 当你到达终端窗口底部并按回车时,每一行都必须上移一行。我可以要求模型重新输出每一行在它的新位置,但对于单个按键来说,这大约需要3000个标记。因此,我添加了一个COPY操作:ROW_0 COPY 1 ROW_1 COPY 2 ROW_2 COPY 3 ...每个操作从上一个屏幕复制一行。在这个示例中,旧的行1变为行0,行2变为行1,依此类推。滚动现在每行只需消耗三个标记,而不是大约96个。这个小把戏也适用于清屏、在vim中插入和删除行,以及浏览man页面。你也可以复制一行,然后覆盖其中的部分内容。总的来说,模型使用一个小词汇量的333个标记:256个字节标记、64个行标记和少数特殊操作。解码是语法约束的,因此每个预测都是有效的屏幕更新。这个小词汇量在我将模型压缩到浏览器中时再次派上用场。生成训练数据 我最初寻找现有的终端录制数据集,包括asciinema,但找不到具有我所需的精确按键到屏幕对齐的数据集。幸运的是,创建我自己的并不太难。基本思路是通过在Docker容器中运行真实命令,生成可信的终端会话,记录每次按键和每次按键后的屏幕。

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

☕请我喝杯咖啡