Agent画图为何需要编译器:Archify的typed JSON IR设计解析
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 和编译器都能轻松处理。IRIntermediate 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 本质上是一种DSLDomain-Specific Language领域特定语言只不过它不是给人类设计的 DSL而是为 Agent 和编译器之间设计的一种“协议语言”。3.2 Archify IR 的两种表达方式Mermaid 优先代码块兜底Archify 的 IR 实际落地时支持两种表达方式我建议都了解一下因为你接的 Agent 不一样熟悉的东西不一样选错方式会导致接入成本高出好几倍。表达方式描述适用场景Mermaid DSL让 Agent 输出标准化 Mermaid 语法Archify 解析后整体转换为图形Agent 亲近文本 DSL生成简单流程图和时序图时比较稳代码块包裹 IRAgent 输出 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 层面定义了必填字段和可选字段编译器根据类型执行不同的校验逻辑和布局逻辑。这种严格分类带来的直接收益是可组合性。因为类型是预定义好的、经过校验的下游的渲染器、样式引擎、导出工具都可以基于这些类型做标准化处理不需要像老式模板那样针对每一种可能的字段组合写特判代码。跑完这一整套 PipelineAgent 的输出才能从“像一张图的东西”变成了“真正结构正确、稳定可复用的图形”。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 是结构化的 JSONAgent 生成的结构只要含义相同基本可以规范化成一个一样的 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欢迎带着自己的看法来交流一起踩坑一起找方案——开源世界的迷人之处常常也因此展开。