同一串字符,两个读者
人怎么读,agent 怎么读,为什么这种对称就是全部的机关。
图表从设计上只考虑一个读者,而且不是那个拿着 API key 的人。
做图的渲染器是为「人」优化的:它挑一个适合数据形状的类型、一套扛得住投影仪的配色、 一个放得下最长类目的字号。然后那个人用它做点什么——看出趋势、提出问题、 决定要不要去打开那个仪表盘。
而 agent 拿到的是这份优化的产物。它拿到的是像素。
这种不对称是有代价的
代价并不隐晦,也不免费:
| 一张图 | 数据 | |
|---|---|---|
| 读者拿到的东西 | 为人眼挑选的渲染 | 精确的数字 |
| 精度 | 渲染器画到多少 | 测量到多少 |
| 对模型的代价 | 视觉 token,约每 750 平方像素 1 个 | 文本 token,约 4 字符 1 个 |
| 可核对 | 不可 | 可——它就是文本 |
拿一张 705×500 的图来说。作为图片大约是 470 个视觉 token; 同一张图的数据,作为 JSON 大约 40 个 token。这是一个数量级的差别, 但有意思的并不是这个差别。有意思的是图片根本没法告诉你的东西: 单位是多少、样本有多大、这个值是均值还是最大值、这条序列是不是在坐标轴上被截断了。
我们不是在拿有损格式和无损格式对比,然后说图片是个坏公民。 我们是在拿「碰巧为人类而做的格式」和「我们本来就应该为机器做的格式」对比, 然后发现后者对人一样够用。
两种读法,一串字符
解法不是给 agent 再造一套 API。而是意识到:一条 URL 可以有两种读法, 而且同一条 URL 可以同时被两种方式读。
GET /d?type=pie&labels=TS,Py,Go&values=4821,2312,980
→ image/svg+xml (人打开它)
→ 原样的规格 (agent 解析它)
渲染器的输出里嵌着它绘制自的那份规格,就放在一个 <metadata> 节点中——纯文本,
就住在 SVG 里面。所以这张图永远可以被拆回原样。我们把这条不变量叫做无损,
也正是它让第二种读法成为可能,而不需要第二个事实来源。
数据视图不是碰巧多出来的一个端点。它就是同一条链接换了读者, 所以它永远不会和图片说法不一:因为它们描述的只有一件事。
agent 该拿它怎么办
一份很短的契约,其中一句话就承载了大部分:
取链接。读数据,不要读图。
具体来说:
- 去取,不要去猜。 如果链接给你规格,规格就是答案。永远不要从像素里还原数值。
- 不要给数字化妆。 不悄悄四舍五入,不换单位,不重排顺序。数据说是 4.18,那就是 4.18。
- 改参数,不要改产物。 想要另一个切面,就改写链接再取一次。 不要去编辑一个渲染好的东西——它没什么可编辑的。
- 把链接交回去。 你用的那条链接,就该是人打开的那条。 它是唯一一个对你们双方含义相同的产物。
最后这一条,就是人机协作——不是功能,是协议。 agent 的产出和人的输入,是同一串字符。
可以直接粘贴的那句话
如果你的 agent 给你的是它从图片里读来的图,修复也许只需要一句话:
画一张饼图,把我们的错误预算按服务拆开,然后把精确的数值给我。 从链接里读,不要从图片里读——我要的是数值,不是你看图得到的印象。 最后把链接发给我,我自己想改参数。
第一句要一张图。第二句禁止了有损的那一步。第三句交回的是一件工具,而不是一张图片。