能不能把大脑塞进浏览器
这个页面最早的版本,是想验证一件很直接的事:Agent 的"大脑"能不能完全塞进浏览器里,不依赖任何后端。WebLLM 用 WebGPU 在本地跑一个十亿参数量级的小模型,工具调用直接读写页面自己的 DOM——这部分很快就跑通了,模型自己决定该调用哪个工具、拿到真实的页面数据、给出总结,全程没有服务器参与协调。
跨过同源策略这道墙
跑通同页操作之后,很自然地想再往前一步:能不能让这个 Agent 跨过浏览器最基本的一道防线——同源策略——去操作另一个域名下的真实网页?答案是可以,但要靠 postMessage 搭一座桥:目标页面得自己放一小段"接收器脚本",只信任来自这边域名的消息。我们真的把它接到了 xiaopingfeng.com 上一篇正式发布的文章,隔着两个域名读它的小节、数它的关键词、高亮它的段落——跟 Google/GitHub 登录弹窗背后用的是同一套 postMessage 手法。
把复杂度收回自己身上
但那个版本有它自己的重量:要管理一个独立弹出窗口的生命周期,要在两边分别写握手协议,还要应对 Cloudflare 边缘缓存把旧版接收器脚本缓存四小时的意外——修好代码不代表用户能立刻用上新代码。这一版把这些全部拆掉:Agent 现在操作的就是它自己所在的这张页面。少了一次跨域桥接,也少了一整类只有跨域场景才会出现的 bug。
小模型没有那么听话
本地小模型不太守规矩。1B 参数的 Llama 会把系统提示词里当占位符写的"推理"两个字原样抄进输出;1.7B 的 SmolLM2 拿到真实数据后不知道什么时候该停,或者把整个观察对象塞进本该是一句话总结的字段里;两个模型都出现过要求"对比两个词出现次数",结果编一个数字应付了事——跟它之前明明调用工具拿到的真实数字对不上。
修的不是模型,是脚手架
真正让任务稳定跑起来的,不是换一套更聪明的措辞,是把容易出错的部分挪出模型的职责范围:数字比较这种事交给一段确定性的代码,而不是指望模型心算;给格式占位符套上尖括号提醒"这是要替换的",而不是直接给一个容易被原样抄走的样板;在代码里硬性拦截"没有真的调用过工具就想给最终答案"这种半真半假的输出。换成本机跑着的一个三十亿参数级别以上的 Ollama 模型后,同样的任务第一次全部一次做对——但这层保险还是留着,因为没人能保证下一个模型不会有自己的新花样。
三种大脑,同一套手脚
现在这个 Agent 可以换三种大脑:浏览器本地跑的小模型(完全离线,WebGPU 推理,不发送任何数据)、任意 OpenAI 兼容的云端接口(自己填 key,只存在你浏览器的 localStorage)、或者你自己电脑上跑着的 Ollama。三种背后跑的是完全相同的一套工具和同一个循环——真正变化的,只是"谁在做决定"。右边试试看,比如让它数一下这页提到了几次"数据"。