数据链接规范
一份草案。它的作用是让一个想法可以被检验:一个 URL 可以装着数据, 而渲染器能把这条 URL 同时变成给人看的图和给机器读的规格。 下面写的要么是渲染器必须兑现的承诺,要么是我们还没解决的问题。
状态:草案 v0.1 · 最后修订 2026-11-12 · 讨论在仓库的 issue 上进行。
1 · 定义
- 数据链接(datalink)
- 参数里装着「渲染某样东西所需的全部数据」的 URL。不是数据的指针,就是数据本身。
- 数据规格(data spec)
- 对那份数据的规范化描述:测的是什么、单位是什么、区间是什么。
- 渲染器(renderer)
- 把数据链接变成给人看的输出的服务;并且——按照下面的不变量——把同一份数据规格也给机器。
- 上下文(context)
- 模型据以推理的东西。数据链接就是上下文:它不指向上下文,也不需要「先抓取、再转述」这一轮往返。
2 · 结构
https://datalink.ac/d?type=pie&labels=TS,Py,Go&values=4821,2312,980&v=1
└─ host ──┘└path┘└────────── parameters ──────────────┘ └ver┘
- host —— 渲染器。换一个 host 也可以实现同一套契约。
- path —— 渲染的种类。
/d覆盖扁平参数那一类;/d/arch2、/d/seq、/d/erd……覆盖结构图那一类。 - parameters —— 扁平、有名字、URL 编码。它们就是数据。
- v —— 钉住渲染器版本,让输出不再变动。
关于参数的两条规矩。 第一,它们必须自足:渲染的时候不允许去查任何东西、
问任何人、或者依赖服务器上的会话。第二,它们必须可以公开:数据链接就是对它自己
内容的公开声明。
3 · 不变量
这五条承诺就是规范本身。破坏其中任何一条的渲染器,不是数据链接渲染器。
I1 · 自包含
链接里装着数据。渲染它不需要查表、不需要登录、不需要会话,服务器上也不存任何状态。
I2 · 双读者
同一条链接给出两种读法:给人看的渲染,和给 agent 用的机器可读规格。两者之间没有任何有损的转换步骤。
I3 · 参数化
输出是「参数 + 版本」的纯函数。没有时钟、没有随机、没有用户画像,也不会有一条链接背后藏着「最近」的未定义行为。
I4 · 可版本化
版本可以写进链接(
v=N)。钉住版本的链接永远渲染出同样的字节;没钉的跟随最新渲染器,并且会说明这一点。
I5 · 无损
输出里嵌着它渲染自的那份规格。解析输出就能还原规格——所以一张图永远能被还原成数字。
4 · 数据规格
规范形态是 JSON。目前有两种编码方式,两者必须表达同一件事:
- 扁平参数 ——
labels=A,B,C、values=1,2,3。人眼能读,agent 拼起来毫无障碍,也没有转义的坑。这是默认。 d=—— URL 编码的 JSON,用于有嵌套的情况。同一份规格,一个块。
// 单系列
{"title":"","data":[{"label":"A","value":1},{"label":"B","value":2}]}
// 多系列
{"labels":["A","B"],"series":[{"name":"x","values":[1,2]},{"name":"y","values":[3,4]}]}
// 流向
{"labels":["A","B"],"links":[{"from":"A","to":"B","value":30}]}
规格说的是「测了什么」,不说「该怎么画」——那是渲染器的事。 也正因为如此,同一份规格可以是图、是表、是日历、也可以是幻灯片。
5 · 渲染器
注册表是开放的。以下是今天已经存在的种类:
| 种类 | 路径 | 参数 |
|---|---|---|
| 图表 | /d?type=pie、bar、hbar、line、area、radar、gauge、scatter、combo、sankey、butterfly | labels、values、series、title、unit |
| 结构图 | /d/arch2、/d/seq、/d/uc、/d/dataflow、/d/lifecycle、/d/erd、/d/class | n=、e=、b= |
| 示意图 | /d/mindmap、/d/mermaid、/d/gantt | n=、m= |
| 表格 | /d?type=table | cols=、rows= |
| 日历 | /d?type=calendar | start=、ev= |
| 幻灯片 | /deck | data=(markdown) |
渲染器可以增加新的种类。但不变量不可协商:满足不了 I2 和 I5 的新种类, 不是数据链接渲染器。
6 · agent 契约
agent 可以依赖什么,以及绝对不能做什么。
可以
- 取这条链接,得到一个渲染——然后不要把它当图片读。
- 取同一条链接的数据视图,原样拿到规格。
- 改写参数,得到一条新链接,再取一次。
- 引用它用过的链接,让人打开的正是它看到的东西。
不可以
- 从像素里还原数值——不 OCR、不目测、不「大概」。
- 悄悄四舍五入、换算单位或重排顺序。
- 为了让链接跑通,去改动服务器上的任何东西。链接是纯的。
承载整个想法的那句话:把链接给 agent,让它给数字——不要给图。
其余都是细节。
7 · HTTP 语义
- GET,可缓存。新鲜度由渲染器决定:没钉版本的链接缓存较短,钉了版本的链接不可变。
- 钉版本 ——
v=N让字节稳定,贴进文档里的链接不会过期。 - 短链接 —— 渲染器可以接受用 POST 提交同一份规格,返回一个短而稳定的 URL。相同的数据必须永远得到相同的短链接——这才是短链接可分享的原因,而不是因为它不可解析。
- 错误 —— 4xx,纯文本,并附一个改对了的例子。解释不了自己的渲染器,agent 也用不了。
- 数据视图 —— 规格必须能从同一条链接以 JSON 取到。本站在
/d.json提供;按Accept协商输出是下面那个待决问题。
8 · 隐私
数据链接天生是公开的。拿到字符串就拿到了数据——而字符串比数据走得更远: 聊天记录、referer 头、浏览器历史、CDN 缓存、地址栏截图、issue 追踪。
- 绝不要把密钥、令牌、个人信息或内部标识放进链接。
- 短链接藏住的是数据,不是数据的存在。它不是隐私工具。
- 查询串会被缓存、会被记录。如果某个参数敏感,它就不该是参数。
- 经验法则:如果它不该出现在别人地址栏的截图里,它就不该在数据链接里。
这一节是起点,不是成文的政策。更大的问题——一条公开的数据链接对数据所描述的人意味着什么—— 记在仓库 issue 和博客里。
9 · 待决问题
- 规格是否应该与渲染器分开版本化?钉住渲染器还不够,语法也得钉住。
- 规格要不要签名——好让 agent 分得出一张真图和一张伪造图?
- URL 装不下的数据怎么办?以及,把数据存到服务器上的隐私代价是什么?
- 要不要有一个公开的渲染器注册表,让「数据链接」成为标准而不是约定?
- 一条链接该不该按
Accept协商输出——浏览器给 SVG,agent 给 JSON——而不是另开一条路径? - 怎么表达不确定性?估算出来的图和事实的图不是一回事,规格应该能说出自己是哪一种。
把这些答上来就是这份草案的目的。讨论开在 仓库 issue。