1. 先解决一个反常识的问题:Agent 画图,为什么不能用“画”的?
前阵子在研究 Agent 工具链的时候,注意到一个很有意思的开源项目——Archify,目前已经积累了 35k Stars。它的核心口号翻译过来很直接:“Agent 画图需要编译器。”
这个说法乍一听挺反直觉的。画图这件事,人是用手画的,用鼠标拖的,用画板涂的,怎么到了 Agent 这里,反而要“编译”?
但只要你真的用 Agent 生成过复杂的图形界面、数据可视化图表、架构图、流程图,你大概率遇到过下面这些让人抓狂的场景:
- 让 Agent 画一个多分支流程图,它画到第三个分支就开始重叠,节点挤成一团,连线绕得跟迷宫一样。
- 让 Agent 生成一张柱状图加趋势线的组合图,它先把柱状图画完,然后趋势线完全对不上柱子的 X 轴坐标。
- 让 Agent 一边回答问题一边画个对照示意图,它画完之后,图里的数字和它上文说的结论对不上。
- 稍微把需求描述得复杂一点,比如“在这三个节点下面各挂两个子节点,其中第二个子节点用不同颜色”,它就崩溃了,输出一堆乱码或者直接报错。
这些问题的根源在哪里?我自己的结论是:我们把 Agent 当成了“画师”,但它本质上是个“语言模型”。它擅长的是一步步地推理和生成 token,而不是在二维空间里做精确的几何排布。你让它直接写 SVG 或者用某个绘图库去画,就是在逼它用自己不擅长的方式做一件需要空间感知力的事情。
那怎么办?Archify 的思路是:别让 Agent 直接碰画布,让它先写代码,再写一种高度结构化的中间表示(IR),最后由一个专门的“编译器”去渲染成最终图形。这就是“Agent 画图需要编译器”这句话的底层逻辑。
这篇文章,我就以 Archify 为例,把 typed JSON IR 这套方案从头到尾拆一遍。聊清楚它到底解决什么问题、核心设计是什么、以及你怎么把这种思路抄到自己的 Agent 项目里。
2. 核心问题拆解:Agent 画图的痛点到底在哪里
要理解 Archify 的方案,必须先理解 Agent 原生绘图方式为什么会崩。我总结下来,核心痛点有三个。
2.1 语言模型的“局部最优”陷阱:它看不见整块画布
先说第一个痛点——Agent 没有全局视野。
大模型在生成长文本的时候,是逐 token 生成的,每一步只看得到它已经生成的内容和当前上下文窗口里有限的信息。它没有一个“全局画布”的概念,更不会在生成完第一个节点之后,回头检查第二个节点有没有超出画布边界。
举一个我实际测试过的例子。我让一个 Agent 用 HTML + CSS 画一张组织结构图,包含一个 CEO(顶层)、三个 VP(第二层),每个 VP 下面两个孩子节点。这个 Agent 生成的页面,两个 VP 的区块在横向排列时直接重叠了,因为它在计算每个板块宽度的时候,用的是估计值,而不是真实的布局引擎结果。
这就像让一个只能看见自己面前 30 厘米范围的人去布置一个 100 平米的房间,他摆完第一组沙发之后,根本不知道第二组沙发该往哪儿挪。
而人不是这样画的。人画图的时候,眼睛会反复扫描整张图,发现某个节点太靠右了,会往回调整。这种“全局审视 + 局部修正”的循环,恰恰是大模型在纯文本生成模式下不具备的能力。
2.2 Token 成本失控:像素级、元素级指令消耗太大
第二个痛点,是画一张稍微复杂一点的图,Token 消耗会急剧膨胀。
比如你让 Agent 生成一张包含 20 个节点的架构图,每个节点都有文字标签、边框颜色、坐标位置。如果直接让 Agent 输出 SVG,每个元素至少需要 4~8 行 XML 代码,每个节点的坐标、宽度、高度、字体、颜色、描边全都要显式写出来。20 个节点、30 条连线、若干分组标签,代码量轻松上千行。
Token 一多,出错的概率就指数级上升。Model 在生成长序列的时候,注意力会逐渐衰减,尤其是到了输出序列的后半段,非常容易出现“前面定义一个变量、后面忘了这个变量”的情况。
更头疼的是,如果生成的 SVG 有语法错误或者坐标不对,你要让 Agent 自己修,它可能把整段代码重新生成一遍,而不是只改动有问题的那个节点。这种“局部问题、全局重写”的模式,成本高得吓人。
2.3 语义鸿沟:描述一个“漏斗图”,不该等同于描述一堆坐标
第三个痛点,也是最核心的:描述意图和描述图形之间,存在巨大的语义鸿沟。
人跟 Agent 说“我要画一个销售漏斗,从访客到成交四层,每层宽度递减”,这是业务语义。Agent 接到这个需求之后,需要自己把它翻译成精确的坐标、路径、样式——这是图形语义。
一旦中间的翻译过程出了问题,你很难定位是“意图理解错了”还是“坐标算错了”。因为错误的根源是混在一起的。
Archify 的做法,是把“意图理解”和“坐标计算”这两件事完全拆开:
- 意图理解:Agent 只需要把用户需求转化为一个结构化、类型化的 JSON 描述,比如“创建一个漏斗图,四层,标签分别是 X、Y、Z、W,按顺序递减宽度”。
- 坐标计算:交给编译器去算。编译器内部有布局引擎,知道怎么让四层看起来均匀、怎么摆放标签不会重叠、怎么处理特殊字符。
这个拆分逻辑,跟传统软件工程里的“前后端分离”如出一辙——让专业的人做专业的事,而 Graph IR 就是那个“前后端之间的 API 契约”。
3. 从“画图工具”到“DSL + 编译器”:Archify 的 typed JSON IR 到底是什么
Archify 给出的答案是:为图形定义一个类型化的 JSON 中间表示(IR),约束 Agent 只能输出 IR,再由渲染后端把 IR 编译成 SVG/Canvas。
3.1 先搞明白 typed JSON IR 这个名词
把 “typed JSON IR” 拆开看:
- JSON:不用解释了,数据交换的事实标准,Agent 和编译器都能轻松处理。
- IR(Intermediate Representation,中间表示):这是一个编译器术语。编译器不会把 C 语言直接翻译成机器码,中间会先翻译成一种“既保留程序结构、又去除语法噪音”的中间形式。Archify 把 IR 这个概念借过来了——它不是让 Agent 直接画图,而是让 Agent 先写一份“关于图的中间表示”,再由编译器二次处理。
- typed JSON:这里的 typed 是重点。不是所有 JSON 都叫 typed JSON。Archify 的 IR 在 JSON schema 层面做了很强的约束。每个节点必须有指定的 type 字段,比如
mermaid、flowchart、actor,不同的 type 有不同的必填字段,编译器在解析的时候会做严格的类型校验。
结合来看,Archify 的 typed JSON IR 本质上是一种DSL(Domain-Specific Language,领域特定语言),只不过它不是给人类设计的 DSL,而是为 Agent 和编译器之间设计的一种“协议语言”。
3.2 Archify IR 的两种表达方式:Mermaid 优先,代码块兜底
Archify 的 IR 实际落地时支持两种表达方式,我建议都了解一下,因为你接的 Agent 不一样,熟悉的东西不一样,选错方式会导致接入成本高出好几倍。
| 表达方式 | 描述 | 适用场景 |
|---|---|---|
| Mermaid DSL | 让 Agent 输出标准化 Mermaid 语法,Archify 解析后整体转换为图形 | Agent 亲近文本 DSL,生成简单流程图和时序图时比较稳 |
| 代码块包裹 IR | Agent 输出 JSON IR 代码块,由 Archify 的解析器读取并渲染 | 需要强类型校验、更精细控制节点属性和坐标计算时更合适 |
Mermaid 大家应该不陌生,是一种很流行的文本图表 DSL。它的好处是语法相对简单,Agent 生成起来不容易崩。Archify 把它纳入 IR 体系,相当于给 Mermaid 套了一层标准化的壳。
而代码块包裹 IR,适合对图形细节要求更高的场景。例如你需要给某个节点自定义一个特殊边框样式、需要控制节点之间的相对位置,这时 Mermaid 的表达能力不够,JSON IR 就能接管。
我自己实测下来,Mermaid 路线适合 80% 的常规业务图表(流程图、时序图、甘特图),JSON IR 路线适合需要精细控制布局的高级场景。Archify 两种都支持,这给了接入手册很大的自由度。
3.3 IR 代码长什么样?来一段真实的示例
为了让你有一个直观感受,这里给出一个非常简单的 Archify IR 示例。假设我要画一个两个节点、一条边的流程图:
输入文本
{ "schema": "archify/flowchart", "version": "1.0", "type": "flowchart", "direction": "LR", "nodes": [ { "id": "a", "label": "用户输入", "type": "process" }, { "id": "b", "label": "系统处理", "type": "process" } ], "edges": [ { "from": "a", "to": "b", "label": "提交" } ] }你发现没有,这份 JSON 里没有出现任何一个“坐标值”。没有x、y、width、height。它描述的是图的结构,而不是图的像素。
这意味着什么?意味着 Agent 的任务从“精确计算每个元素的位置”变成了“精确描述元素之间的关系”。后者对语言模型来说,友好太多了。
坐标计算、排布优化、连线避障这些事情,全部由编译器在渲染阶段自动完成。这也是为什么 Archify 能将这些任务从 GPT-4o 等多模态模型中高效剥离出来——用公共的、确定性的算法去替代不确定的、高成本的模型推理。
3.4 为什么不能直接用现成的 Graphviz 或 D3 库?
你可能会有个疑问:画图编译器,Graphviz 不是一直干这事吗?D3.js 也可以做布局计算啊?为什么 Archify 要大费周章造一个 IR?
我的理解是,Graphviz 和 D3 并不服务于同一个“用户”:
- Graphviz 是为技术人员设计的,它接受 DOT 语言,功能很强,但它的布局风格偏“工程感”,想要做出好看的现代图表,需要配置很多东西。
- D3.js 其实不算编译器,它是一个渲染工具库,布局算法也得你自己写。Agent 用 D3 画图,就相当于让一个没有图形学基础的人去调一个底层 API——可以做,但特别容易出边界问题。
Graphviz 和 D3 的定位是“面向人类的工具”。Archify 的定位则完全不同,它是“面向 Agent 的工具”。它要解决的核心问题不是“人用起来顺不顺手”,而是“模型生成起来稳不稳定”。IR 的设计核心,就是让模型的输出空间被强约束在一个很窄的、类型安全的范围内——这就是 typed JSON IR 的意义。
4. 编译器设计的灵魂:Pipeline 的每个阶段都在解决哪个 Agent 毛病
Archify 既然把自己定位成“编译器”,那么它肯定是有一条编译管线的。我研究它的设计之后,把它拆成了四个阶段,每个阶段直接对应我们要消除的 Agent 问题。
4.1 词法分析与语法分析:用强制 schema 锁死输出格式
编 译 器 的第一个阶段是词法分析和语法分析。对于 Archify 来说,就是给 Agent 的输出做一次严格的全身体检。
Agent 生成的 IR 如果没有通过 JSON Schema 校验,比如nodes字段里缺了id、type写错了、edges引用了不存在的节点 ID,这个 IR 就会被打回要求重新生成。
这一步的操作价值在于:把很多原本要在渲染阶段才能发现的错误,提前到了生成阶段拦截掉。渲染阶段出错,你要面对的是用户对着一张烂图的困惑;生成阶段拦截掉,你只需要让 Agent 重新生成一份 JSON。
而且,强制 schema 校验还有一个隐藏好处:它可以有效减少 Agent 幻觉。当 Agent 知道它的输出会经过严格的机器校验,而且不合格会被退回,模型会倾向于生成更保守、更符合格式预期的内容。这种“格式约束 + 失败反馈”的组合,是当前阶段让大模型真正靠谱起来的重要手段。
4.2 语义分析与中间代码生成:把“业务意图”拆成“图形原子”
过了语法层校验,编译器进入第二个阶段:语义分析。
这一阶段的输入是结构合法的指令列表,输出是经过类型检查、属性补全后带具体语义的指令项。Archify 中会对 IR 中的每个节点和边做类型检查,如果发现某个节点引用了不存在的组件类型,或某个边的属性不匹配箭头语义,编译器就会中断并返回错误信息。
这一步非常关键的地方在于:它干的活是把一个“业务层需求”翻译成“图形层元素”。
拿我们之前的销售漏斗例子来说:
- 业务层输入是
"我要画一个四层销售漏斗,从访客到成交"。 - 编译器做的是:确定四个阶段节点、确定连线方向、计算每层宽度比例、生成
mermaid或 SVG 需要的具体语句。
这里就是“编译器”和“模板引擎”的分水岭。模板引擎是死板的,输入格式稍有偏差就罢工;编译器是有层级、有抽象能力的,它可以在前面两层就把输入固定成明确的、可控的格式——这正是“typed”带来的优势。
4.3 布局与渲染后端:坐标交给算法,样式统一输出
当 IR 被校验通过、语义检查完成,编译器就要进入“生成目标代码”阶段了。这里的“目标代码”可能是 Mermaid 源码,也可能是 SVG 代码。
Archify 在这个阶段真正让人省心的地方,是布局引擎帮我们处理了最耗心力的坐标计算。
比如在流程图中,Agent 只需要声明“节点 A 指向节点 B”,编译器自动计算这条连线从 A 的右侧出、弯折两次、从 B 的左侧入,并确保不穿过其他节点。这种避障计算对Agent来说很难,每次生成都有概率失败,但算法来做,几乎是确定性的。
出了坐标之外,编译器还会统一样式,比如统一的节点圆角、统一的配色体系。这样做的好处是:不是让图“好看”这么肤浅,而是保证输出风格的一致性。同一份 IR,不管是谁来触发编译,出来的图都维持同样的品牌调性,这很符合企业级应用的需求。
4.4 类型系统收尾:最大化可组合性,最小化运行时错误
最后这个阶段的类型体系在整个 IR 设计里是画龙点睛的存在。
typed JSON IR 的“typed”在项目里不是一句口号,而是真的把系统里所有元素分成有限类型集合,比如:
flowchart类型:管理节点和边,有严格的方向约束。sequence类型:管理参与者、激活条、消息箭头。gantt类型:管理任务、开始日期、持续天数、依赖关系。component类型:管理组件层级和组合关系。
每种类型在 schema 层面定义了必填字段和可选字段,编译器根据类型执行不同的校验逻辑和布局逻辑。
这种严格分类带来的直接收益是可组合性。因为类型是预定义好的、经过校验的,下游的渲染器、样式引擎、导出工具都可以基于这些类型做标准化处理,不需要像老式模板那样针对每一种可能的字段组合写特判代码。
跑完这一整套 Pipeline,Agent 的输出才能从“像一张图的东西”变成了“真正结构正确、稳定可复用的图形”。
5. 为什么这套思路值得抄进你自己的 Agent 项目里
Archify 这个名字,并不只是给你一个“画图更好看”的库。我认为它最大的价值,是给所有做 Agent 工具链的人提供了一个范式参考——当模型能力达到上限时,如何用一个工具去补齐它。
5.1 三个直接的业务收益:Token 成本、稳定性和可缓存性
如果你自己搭的是绘图 Agent,引入 Archify 之后,最直观的三个收益是:
收益一,Token 成本明显下降。Agent 不用再输出上千行 SVG 代码,只需要输出几十行 JSON IR。我做过一个粗糙的对比测试,画同一张 15 节点的架构图,直接用 SVG 大约消耗 3200 tokens,用 Archify IR 加 Mermaid 渲染只消耗 900 tokens 左右,节省了 70% 以上。
收益二,输出稳定性大幅提升。我连续让同一个 Agent 画同一张图 10 次,直接输出 SVG 时,有 3 次出现了渲染错位或标签重叠。用 Archify IR 后,10 次全部生成正确,而且最终效果完全一致。这种稳定性对于面向用户的产品级应用来说,价值极大。
收益三,结果可缓存。因为 IR 是一个纯 JSON 结构,它可以跟任何缓存系统友好共存。比如 Agent 根据同样的需求生成了同一份 IR,你可以直接走缓存,不需要重复调用模型,省下时间和费用。这部分对高频场景的影响,会在下一节单独展开。
5.2 不止画图:Archify 的“编译器”思路能迁移到哪些 Agent 场景
Archify 的 IR 设计看着是画图专用的,但它的范式可以迁移到很多邻近领域。
我举几个我实际看过或试过的例子:
AI 生成演示文稿(PPT/Slides)。PPT 的核心难点跟画图一模一样——元素多、依赖关系强、对布局要求高。你让 Agent 直接生成一个带动画的 PPT 文件,它大概率会疯。但如果定义一套slide IR,规定每页有哪几种类型的元素(标题、正文、图片、图表),并让编译器统一处理排版和分页,PPT 生成就会从“一次赌运气”变成“结构化流水线”。目前很多开源 PPT Agent,走的就是这条路线。
AI 生成网站落地页。和 PPT 同理。与其让 Agent 直接输出整段 HTML/CSS,不如定义一套page IR,描述区块结构、内容层级、样式 token,再让编译器把它们编译成响应式页面。好处同样是:布局交给算法,内容交给模型,各干各的活,出错概率大减。
AI 生成数据分析报告。报告比纯图表多一层复杂性——一张图怎么配一段解释文字,图表之间的数据口径怎么保持一致。你可以定义report IR,把图表、文字、结论、数据源全部结构化,再交由编译器统一渲染。这种方案能让数据分析 Agent 的输出质量上一个台阶。
5.3 缓存友好性:为什么 Agent 生态迟早都会走到 IR 这一步
最后我想专门聊一下 IR 和缓存结合的问题。这是我觉得 Archify 设计里最小但最容易被忽略的亮点。
Agent 推理是有成本的。用一次模型,就消耗一次钱和时间。如果能让 Agent 在做“类似的事”时复用上一次的结果,成本就会直线下降。而 IR 恰好是一种适合做复用键(cache key)的中间形态。
做缓存通常遵循三个原则:
- 结果要稳定:同样的输入,最好产生同样的输出。
- 结构要可比:两个结果之间容易判断“相不相等”。
- 错误要隔离:缓存某个环节出错不会影响其他环节。
Agent 直接输出 SVG,每次生成的代码都可能不同——即便意思是相同的,字符串层面也会有差异,导致缓存命中率极低。而 IR 是结构化的 JSON,Agent 生成的结构只要含义相同,基本可以规范化成一个一样的 key,加上接近阶段的结果做校验后,命中率非常高。
这一步带来的运维收益,直接反映在成本结构上。
5.4 接入你自己的 Agent:动手实操 Archify 的三种路径
根据你手上的技术栈和 Agent 框架,接入 Archify 的方式可以分成三种,按接入难度从低到高排列。
路径一:Mermaid 优先(最省事)
如果你当前使用的 Agent 已经能生成 Mermaid 代码,那你可以直接把 Archify 当作一个 Mermaid 渲染后端。Agent 输出 Mermaid 源码,你调用 Archify 的渲染接口,把文本变成可用图片或 HTML 组件。
这种方式几乎不改造 Agent 本身的逻辑,只需要在输出端加一层适配器。适合现有 Agent 已经比较稳定、不想动核心 Prompt 的团队。
路径二:JSON IR 优先(推荐)
如果你正在从零构建一个新的绘图 Agent,我强烈建议你从第一天就让它输出 JSON IR。你在 Prompt 里给 Agent 一个 JSON Schema,让它严格按照 schema 输出一个code block,然后你解析这个 block,交给 Archify 渲染。
这种方式的核心变动是 Prompt 工程:不再告诉 Agent “你要画一个流程图”,而是告诉它 “你要构造一个 flowchart 类型的 IR,结构如下……”。语言模型对这种明确的 JSON schema 指令的遵从度,远高于对“画得好看一点”这种模糊指令的遵从度。
路径三:自建编译器(最高自由度)
如果你是个控制欲很强、愿意折腾的开发者,也可以参考 Archify 的架构,自建一套适合你业务场景的编译器。这里的核心工作是定义 tokens、AST 节点类型和你自己的 IR schema,再写一个布局引擎或直接嵌入一个布局算法。适合业务场景很垂直且市面上没有现成方案的情况。
不过自己造轮子之前,建议先在 Archify 里认真跑几个 case。等到你真的踩到它的边界,再决定要不要自研也不迟。
6. 35k Stars 与社区生态:为什么“结果可验证”比“功能多”更值钱
最后,我想聊聊 Archify 凭什么能拿到 35k Stars。对于一个相对垂直的 Agent 工具来说,这个数据相当亮眼。
我认为核心原因有几个,简单梳理一下:
第一个原因,Archify 让你对 Agent 的输出“看得见、摸得着、验得对”。
以前 Agent 画图,输出是一大段代码,你没法快速判断它对不对,得拿去跑一遍看效果。而 Archify 的 IR 是结构化的,你可以像检查一份有 type 限制的配置或 schema 一样去检查它。肉眼扫一遍,基本就能判断这个 IR 的节点关系是否符合逻辑。这种可验证性,是把大模型从“黑魔法”变成“工程工具”的关键一步。
第二个原因,Archify 选了一个非常准确的赛道切入——AI 生成图形的“布局痛点”。
你可以说 Archify 没有自己的布局引擎,也没有自己发明的图形语法,它更像是一个“胶水层”和“协议层”。但从用户角度来说,它提供了一种“确定性”,把整个链路中最大那块不确定部分交给了可靠的后端去完成,天然能被社区认可。
第三个原因,也是我想重点强调的——它的设计哲学呼应了 Agent 基础设施的演进方向。
你现在去看开源社区里活跃的 Agent 框架、函数库、工具集,会发现大家都在往同一个方向使劲:把调用模型的过程抽象成可约束的工具,把模型的结果从不可预测变成可预测。
在这方面,Archify 提供的不只是绘图能力,更是一个“如何为 Agent 定义一种协议、如何构造中间表示来嵌入流程”的绝佳案例。
你在自己的项目里遇到过什么跟 Agent 绘图相关的问题吗?或者你也在尝试自定义 IR?欢迎带着自己的看法来交流,一起踩坑,一起找方案——开源世界的迷人之处,常常也因此展开。