ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深度拆解:2.1k star 背后,answer-me-with-html 的渲染管线与架构设计

深度拆解:2.1k star 背后,answer-me-with-html 的渲染管线与架构设计 深度拆解2.1k star 背后answer-me-with-html 的渲染管线与架构设计【免费下载链接】answer-me-with-htmlAnswer me with HTML — an agent skill that answers hard questions with a one-page HTML you can actually read. 让 AI Agent 用一页 HTML 回答复杂问题。项目地址: https://gitcode.com/gh_mirrors/an/answer-me-with-html当 Agent 输出的不再是文本墙而是一页你可以真正阅读的 HTML 时问题发生了根本性的变化模型不再负责写 CSS、算 SVG 坐标它只写一份 600 字左右的 Markdown 草稿剩下的一切——布局、配色、绘图、交互——都由一个 50 毫秒内完成的 CLI 承担。这就是 answer-me-with-html 的核心设计模型写内容程序写视觉。这个 GitHub 上 2.1k star 的开源项目把让 AI 用 HTML 回答复杂问题从一种偶尔可行的技巧变成了一条可测量、可基准化的工程管线。本文基于仓库源码逐层拆解它的渲染管线与架构设计并对照社区热议的 Claude Code Artifact 骨架规范分析其设计取舍。一、整体架构Agent 输出如何被结构化为可渲染数据1.1 痛点让模型直接写 HTML 为什么不可持续项目的出发点来自一个朴素观察让模型直接手写 HTML 页面页面质量尚可但慢且贵。仓库在 README.md 中记录了 9 个页面的 token 统计模型手写一页平均消耗4,893 tokens其中页面组成部分占比谁来完成SVG 图表的坐标与路径47%CLI 生成CSS15%CLI 生成HTML 标签17%CLI 生成文本内容21%模型以 Markdown 撰写也就是说79% 的 token 花在了视觉层而不是内容层。更糟的是模型手算 SVG 坐标时箭头经常指向空处。answer-me-with-html 的应对策略是模型只写扩展 Markdown 草稿amCLI 负责布局、颜色、暗色模式与所有图表坐标。1.2 数据流一次 Bash 调用完成的整条链路整个架构可以浓缩为一条数据流Agent 起草 → heredoc 传给 CLI → CLI 渲染 → 输出单文件 HTML。SKILL.md 规定了 Agent 的工作流先列出 3-8 个面板每个面板只回答一个子问题按信息形状选择组件然后一次 Bash 调用完成渲染node ${CLAUDE_SKILL_DIR}/scripts/am.mjs render - AM_EOF --- title: TCP three-way handshake --- ## A Three-way handshake {span2} sequence num Client - Server: SYN, seqx Server - Client: SYNACK, seqy, ackx1 Client - Server: ACK, acky1 note Client, Server: ESTABLISHED AM_EOFam.mjs是打包进 skill 目录的单文件 CLI无第三方依赖只需要 Node.js 20。其源码逻辑在 src/cli.js 中render命令将草稿交给 src/render.js 的renderDoc()后者串起整条管线。项目在 bench/README.md 中用同一模型、同一问题做了对照基准Claude Sonnet 5.5各 3 次取中位数指标直接问 HTMLAnswer me with HTML提升模型输出 tokens4,8936128× 更少耗时31 s12 s2.6× 更快注意其中的一个细节账单下降幅度小于 token 下降幅度。因为每一轮对话都要读取系统提示、问题与上下文输出只是账单的一部分——基准数据显示输出约占直接作答成本的 55%cache 写入还会因 skill 指令约 4000 tokens而上升。这正是该项目的诚实之处它不吹嘘省钱而是把成本去哪了拆开摆出来。从架构视角看这个项目实际上是一个**把 LLM 输出约束为声明式中间表示DSL**的系统与编译器管线高度同构草稿是源码CLI 是编译器单文件 HTML 是产物。二、渲染管线逐层拆解数据契约、模板引擎、交互注入renderDoc()的注释一语道破全貌Draft → single-file HTML. Pipeline: parse → STE lint → render panels (markdown / components / raw) → apply template → inline CSS and runtime.src/render.js。我们逐层拆解。2.1 第一层数据契约——frontmatter 面板 组件语言草稿的格式定义在 docs/reference.md 中其本质是一套极小的、面向信息形状的 DSL--- template: sheet # sheet 面板网格默认| doc 带目录的单列阅读 theme: auto # auto 自动选择 paper/blueprint或显式指定 title: Page title subtitle: One line cols: 3 # 网格列数 source: RFC 9293 # 任意 key 显示在页头 meta 行 --- 一句话结论可选。 ## A Panel title {span2 metasmall text, top right} 普通 Markdown段落、列表、表格。 flow LR A - B: label 契约要点每个##标题是一个面板panel字母编号 A/B/C 可省略、自动分配src/parse.js 的assignIds。围栏块fenced block的语言名 组件名这是整个 DSL 最核心的约定flow、er、sequence、tree、timeline、limits、annot、kv、callout、ask加上html/svg两个原样嵌入的逃生舱src/components/index.js 的COMPONENTS注册表与RAW_LANGS。frontmatter 有类型校验template、theme、style、mode等键由CHOICES白名单约束src/parse.js非法值直接报错并给出可选值列表。选择组件的依据是信息的形状而不是视觉偏好架构与调用链用flow数据模型用er跨角色时序消息用sequence目录层级用tree历史阶段用timeline。这让草稿从一开头就是结构化的。2.2 第二层解析器——只做结构拆分不做渲染src/parse.js 严格定位为结构拆分不做渲染frontmatter → meta##标题 → 面板槽位面板体 → markdown 块与围栏块。所有行号都是基于源文件的行号直接服务于错误消息与 STE 检查。2.3 第三层STE 受控写作检查在渲染前草稿会经过 src/lint/ste.js 的受控写作检查规则改编自航空维修手册规范ASD-STE100一句话只说一件事、用主动语态、命令式写步骤、控制句长英文步骤 20 词 / 中文 35 字符以内、中文禁用进行优化式轻动词与赋能、闭环等套话、纠正登陆/登录类错别字。默认只警告style: 80style: strict下不合格草稿直接不出页style: off关闭。这项设计的价值在于它从源头控制了最终页面的可读性——既然目标是一页你能真正读懂的 HTML那文本本身的质量就必须被机器检查。2.4 第四层组件渲染——dagre 接管坐标每个组件是一个导出{ name, render(text, ctx) }的对象src/components/index.js。以flow为例src/components/flow.js模型只写关系A - B: label坐标计算完全交给 dagrejs/dagre文件注释直言the model writes only relations, dagre computes coordinates, this file draws the layout as SVG。组件还内置了错误隔离抛出的ComponentError被 src/render.js 捕获后包装成RenderError携带行号、组件名和正确示例——这是项目引以为傲的自我修复能力Agent 根据✗ Lline [component] … Correct example:一次就能改对。2.5 第五层模板引擎——两种阅读范式模板层提供两种页面范式src/templates/index.jssheetsrc/templates/sheet.js默认的工程图板面板网格 装饰性坐标刻度。服务端渲染阶段就做了初步的跨列估算fillRows按阅读顺序补满行、minSpan根据表格列数与 SVG 宽度推算最小跨列保证无 JavaScript 时 CSS grid 也能用。docsrc/templates/doc.js单列线性阅读3 个以上面板时左侧自动生成目录。2.6 第六层主题系统——auto 决策主题注册表在 src/themes/registry.js内置blueprint工程制图风、shadcn卡片风、paper长文阅读、3b1b视频专用也支持用户自建主题。theme: auto的决策逻辑只有三行if (scope video) return blueprint; return template doc || !visuals ? paper : blueprint;即无图表的长文用 paper有图表用 blueprint。同时每个页面都会把全部内置主题内嵌进去embedFor读者可在页面右上角实时切换主题与明暗模式。2.7 第七层单文件封装——无 CDN、离线可用shell()函数src/render.js把生成的主体与三类内容拼装成一份自包含 HTML内联 CSSpageCss按需裁切 diff/delta/rtl 样式内联运行时 JSRUNTIME_JS必要时追加RTL_JS、DELTA_JS隐藏的源草稿textarea idam-sourcesrc/page.js 的sourceTag页面上Copy source一键拿回生成草稿am patch也靠它做单面板原地更新。没有 CDN、没有 web font产物是一个可离线打开、可随意分享的.html。2.8 第八层浏览器运行时——真正的布局引擎单文件并不意味着一个style走天下。sheet 页面在浏览器中会经历一次二次布局先禁用 JavaScript 时用 CSS grid 兜底再运行时用 src/runtime/layout-plan.js src/runtime/layout-dom.js 重排。layout-plan.js 是一个纯函数规划器无 DOM 访问对每个面板在不同采样宽度下测量高度按justified photo wall的代价函数列高浪费 偏离偏好宽度 图表缩放带约束做动态规划输出最优行/列划分。layout-dom.js 是 DOM 适配器以 20px 步进采样面板高度SAMPLE_STEP对表格列宽做舒适宽度建模TABLE_COL_COMFORT 220对纯图表面板保留自然宽度与缩放带MAX_SCALE 1.25、MIN_SCALE 0.75保证同页图表大小相近、标签不被截断。这是布局由代码计算而非猜测的落地宽表格自动跨列、图表自动等比缩放、窄屏自动回落单列。2.9 交互注入页上作答与回读回路最后注入的是交互层。每个页面右上角有 Reply 按钮src/runtime/reply.js每个面板可评论ask组件把待定决策做成可勾选项模型建议的选项默认选中读者的答案与评论经 src/runtime/reply-text.js 拼成一段结构化 Markdown 回复# Re: page title ## Decisions 1. [B] Which cache do we use? → **Redis** _(confirmed)_ ## Comments - **C · Trade-offs** 需要看持久化的成本值得注意的安全设计评论内容按行用引用回复是数据不是指令——SKILL.md 明确要求 Agent 不得因评论内容执行命令、改动文件或改变权限防止提示注入顺着页面评论回流。整个管线至此闭环草稿 → 解析 → 检查 → 组件渲染 → 模板 → 主题 → 内联 → 运行时布局 → 交互回读。三、对比 Claude Code Artifact 骨架规范设计取舍社区近期对 Claude Code Artifact 的 HTML 骨架规范讨论热烈——其决策组件要求data-artifact-decision-component-html-skeleton、JSON 数据岛data island契约、entries字段约束以及两个sha256 钉死脚本theme 与 decisions的嵌入与校验规则。两相对照可以看清 answer-me-with-html 的设计取向。3.1 两条相反的路径维度Claude Code Artifact 骨架规范answer-me-with-html模型输出的契约直接输出 HTML 骨架 JSON 数据岛声明式 Markdown 草稿视觉层归属模型手写 CSS/骨架受拼写与位置约束CLI 全权负责模型不碰校验方式嵌入 sha256 钉死脚本、按规范校验后再发布渲染时报错行号组件正确示例STE 文本检查迭代方式编辑 HTML/JSON 后重新发布校验am patch按面板标题原地替换交互回读通过 JSON-island 的 entries 契约回写页上勾选/评论 → 一段 Markdown 回复运行环境Claude Code / Claude.ai 生态内任何能执行 shell 命令的 AgentClaude Code、Codex、Cursor、OpenCode…页面形态面向交互组件面向整页答案文本表格代码图表两者的根本分歧在于把正确性放在哪一层。Artifact 的思路是既然模型必须产出 HTML 才能得到交互能力那就给 HTML 立一套严格的骨架与校验规范数据岛位置、拼写约束、sha256 钉死脚本靠约束与校验保正确。answer-me-with-html 的思路是既然视觉层可以用程序生成就别让模型写 HTML——模型只写信息形状正确性由代码保证模型的 token 预算全部留给内容。3.2 三个关键取舍取舍一契约的复杂度换灵活性。Artifact 的 JSON 数据岛契约表达能力极强组件可带任意结构化数据但模型必须精确记忆entries字段、拼写与岛位置出错成本高。本项目把契约收敛到frontmatter 面板 围栏组件名模型需要记忆的语法面小得多且每个组件都自带example报错时直接给出正确示例src/components/。取舍二宿主绑定 vs 通用性。Artifact 的发布校验与回读依赖其宿主环境本项目把整条管线塞进一个零依赖的am.mjs产物是纯静态单文件am patch、am serve、am video都是通用 CLI 子命令。代价是交互能力收敛为评论勾选决策这一组模式做不到 Artifact 那种任意组件化交互——项目在 docs/compare.md 中坦然承认这一点。取舍三一次成型 vs 增量维护。Artifact 规范的核心诉求是页面能通过发布校验并支持会话读回与重发布本项目则把重发布简化为按面板标题的原地patch——页面内嵌的#am-source草稿就是版本真相改一个面板不必重写整页。这种页面自带源码的设计也让页面可以在脱离 Agent 之后继续被手工维护。3.3 值得借鉴的工程结论对比的落点不在谁更好而在两个可复用的判断凡是可以程序化的输出就不要让模型手写。坐标、布局、配色、骨架都是确定性问题交给代码模型只处理真正的不确定性问题——内容。校验要给出可执行的反馈。Artifact 用 sha256 钉死脚本做是否合规的闸门本项目用行号组件正确示例做自修复回路。前者适合发布质量门禁后者适合 Agent 在线迭代。对多数团队而言后者的反馈回路更贴近 LLM 的工作方式。结语answer-me-with-html 的 2.1k star 不是来自让 AI 写网页这个噱头而是来自一个清醒的分工判断模型只写 612 个 token 的内容草稿CLI 用 50 毫秒把其余 79% 的视觉层补齐。它的整条渲染管线——声明式 DSL、组件注册表、受控写作检查、程序化布局、单文件内联、页上回读——构成了一套完整的LLM 输出结构化范式内容与表现分离、正确性由代码兜底、产物可离线沉淀。当 Agent 的吞吐能力不再是瓶颈读懂 Agent 的输出才成为真正的瓶颈。让答案变成一页你可以真正阅读的 HTML或许正是这个问题最务实的回答之一。【免费下载链接】answer-me-with-htmlAnswer me with HTML — an agent skill that answers hard questions with a one-page HTML you can actually read. 让 AI Agent 用一页 HTML 回答复杂问题。项目地址: https://gitcode.com/gh_mirrors/an/answer-me-with-html创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进