
AI 生成内容该怎么与人类协作是前后端工程师共同关心的问题。最近社区里流传一个具体观点Anthropic 工程师在开发 Claude 相关产品时更倾向用 HTML 而不是 Markdown 跟 AI 打交道。乍一听很反直觉因为 Markdown 已经是开发者写文档、写 README、写 Prompt 的主流格式。但如果把 AI 从“生成文本”的工具重新理解为“生成可交互界面”的引擎就能明白 HTML 为什么在特定场景下更有优势。这篇文章以 Claude / Anthropic API 的工作流为背景拆解三个问题Markdown 在 AI 交互中到底卡在哪里HTML 为什么能减少转译、可校验、可流式渲染真正把 HTML 引入 AI 工作流时提示词怎么写、渲染怎么防 XSS、哪些场景仍然应该用 Markdown。文中的代码和配置用于说明工程思路落地时请结合自己的项目结构、依赖版本和部署环境调整。1. 先说背景为什么 AI 工作流里会出现“HTML 替代 Markdown”的讨论1.1 讨论的源头来自 AI 内容的最终消费方式Anthropic 团队在公开工程分享中多次提到一个观察Claude 的许多能力最终都要落到网页上呈现无论是对话流、代码预览还是生成的图表和应用。HTML 是浏览器原生渲染格式也是这些内容的最终形态。当 AI 直接输出 HTML链路就变成模型 - HTML - 浏览器而使用 Markdown 时链路是模型 - Markdown - 解析器 - HTML - 浏览器第二条链路多了一步“转译”。每多一层转译就多一层出错的可能。Markdown 解析器对同一段文本的解释可能不同AI 生成的 Markdown 也可能不严格合法。对于面向人阅读的文档多一层转译可以接受对于要交给程序消费、要嵌进产品界面的内容直接输出 HTML 显然更靠近终点。1.2 “放弃 Markdown”更准确的理解是“按场景切换格式”这里的“放弃”不是否定 Markdown 的价值。Markdown 仍然是适合人写、人读、人维护的轻量标记格式README、技术文档、博客草稿、日常笔记都离不开它。Anthropic 工程师讨论的实质是AI 与系统、工具、界面交互时HTML 的可编程性更强。人读场景用 Markdown程序消费和界面渲染场景用 HTML这是同一份能力在不同工作流里的合理分工。判断格式选型的标准不是“哪个更好”而是“输出给谁消费”。给人看Markdown 更好给程序渲染HTML 更稳。2. Markdown 在 AI 交互中的几个真实痛点2.1 表格是重灾区生成简单渲染依赖方言Markdown 表格写起来很轻但能力边界很明显。最基本的 GFM 表格只能处理简单行列| 名称 | 数量 | 单价 | | ---- | ---- | ---- | | 苹果 | 2 | 5.5 | | 香蕉 | 3 | 3.2 |这段内容在 GitHub、VS Code 插件、Typora、语雀里可能都能正常显示。但 AI 生成表格时经常出现这些问题列数和分隔线数量不一致导致某一列内容串到相邻列。单元格里出现竖线字符|时没有转义表格结构被打乱。需要合并单元格或跨列时标准 Markdown 根本没有对应语法。中文内容较长时不同渲染器的自动换行表现差异很大。一旦 AI 在生成时多加了一个空格、少写了一个分隔线表格可能整体失效。而 HTML 的table、tr、td是显式结构浏览器按标签解析不存在“这一行到底属于哪一列”的猜谜问题。2.2 换行和嵌套列表规则细节多AI 容易产生歧义“Markdown 换行”是搜索量很高的一个关键词侧面反映这个问题非常普遍。Markdown 里换行的规则有很多细节段落内换行需要行尾加两个空格或者用一个空行分隔。列表项的换行和缩进在不同解析器里有不同要求。嵌套列表的缩进有的解析器要求 2 个空格有的要求 4 个空格。AI 生成的内容里经常出现行尾空格被吞、列表缩进不一致的情况。下面这段从语法上很难判断意图1. 第一层 1. 第二层 - 第三层 - 这到底是哪一层不同解析器对这段代码的解释可能完全不同。HTML 没有这种歧义嵌套结构完全由标签表达ol li第一层 ol li第二层 ul li第三层/li /ul /li /ol /li /ol2.3 解析器不统一同一段 Markdown不同平台显示不同Markdown 有 CommonMark 这样的规范但现实世界里各平台的实现并不完全一致。GitHub Flavored Markdown、Markdown Extra、Pandoc 的 Markdown 之间在表格、上下标、目录锚点、任务列表上都有差异。这就带来一个工程问题AI 生成的 Markdown 在测试平台渲染正常换到另一个平台可能完全变形。HTML 的标准由浏览器解析器统一实现只要输出合法的语义化 HTML跨平台表现基本一致。2.4 AI 转译到 HTML 时标记噪声会放大有些团队的做法是让 AI 继续输出 Markdown然后由前端把 Markdown 渲染成 HTML。这个方案在小规模场景可行但一旦内容包含复杂结构转译过程的损失会被放大代码块里的反引号数量被 AI 算错代码块提前闭合。行内代码里的_、*被当成强调符号。表格里有 URL 或特殊字符时渲染器报错或错位。这些问题在纯文本里很难被提前发现因为 Markdown 没有官方校验器。HTML 则可以直接交给 DOM 解析器检查结构是否合法甚至可以用 DOMParser 在运行时探测异常节点。3. HTML 与 AI 配合时改善了什么3.1 结构化可校验DOM 解析器是天然的检查器HTML 最大的优势是结构显式化。模型输出的每个标签都是一个明确的语义单元table表示表格li表示列表项blockquote表示引用。程序可以用标准解析器检查它const parser new DOMParser(); const doc parser.parseFromString(llmOutput, text/html); // 检查是否存在脚本或嵌套错误 const scripts doc.querySelectorAll(script); if (scripts.length 0) { // 命中风险策略进入清洗流程 }在 Node.js 侧可以用htmlparser2或parse5做同样的解析。校验通过后再进入渲染整个链路是可控的。3.2 流式输出可以增量渲染Claude 这类大模型接口普遍支持 SSE 流式输出。Markdown 流式渲染需要额外引入解析器而且在流式过程中还要处理代码块未闭合、表格未完成等中间状态。HTML 得益于浏览器的增量解析能力即使table还没有闭合浏览器也能先渲染已经到达的内容后续标签到达后再补充。前端只需要维护一个缓冲区配合防抖更新即可let buffer ; function onChunk(chunk) { buffer chunk; // 使用防抖避免每个 token 都触发 DOM 重绘 clearTimeout(timer); timer setTimeout(() { container.innerHTML DOMPurify.sanitize(buffer, cleanOptions); }, 80); }不过这里有一个前提不能每个 chunk 都把整个缓冲区重新覆盖一遍 innerHTML否则已展开的交互状态会被重置。更稳妥的方案是保留只读渲染区域或者使用专门的流式 HTML 渲染器。3.3 少一层转译少一层不一致Markdown 转 HTML 的过程中转义规则是最大的不确定性来源。AI 输出的内容进入 Markdown 解析器解析器按自己的规则处理一旦遇到不规范的输入结果就偏离预期。直接输出 HTML 时模型负责的是标签结构和文本内容浏览器负责的是渲染。模型和渲染器的职责边界清晰出问题时定位也更方便显示不对就查 HTML 结构样式不对就查 CSS交互不对就查脚本。3.4 工具调用和结构化输出的兼容性更好在实际项目中AI 的输出经常不只是给用户看还要被代码使用。比如生成一份发布检查清单后端要解析清单内容并存入数据库前端要渲染成页面。Markdown 需要额外解析出结构化数据而 HTML 本身就有 DOM 树按标签提取信息非常直接const rows [...doc.querySelectorAll(tbody tr)].map(tr [...tr.children].map(td td.textContent.trim()) );Anthropic 的 API 支持结构化输出和工具调用返回的字段也经常是 JSON 形式。把 HTML 片段作为 JSON 的一个字段返回既能保留展示格式又不干扰其他结构化字段这是实践中很常见的组合。4. 一个最小落地示例让 AI 输出 HTML 片段4.1 提示词里明确输出格式约束想让 AI 稳定输出 HTML必须先写清约束。一个可行的系统提示词结构如下你是内容生成助手。用户会给你一个问题或需求你负责输出一份用于页面展示的 HTML 内容片段。 要求 1. 使用语义化标签包括 h2、h3、p、ul、ol、li、table、thead、tbody、tr、th、td、blockquote、code、pre、strong、em。 2. 禁止输出完整 HTML 文档只输出 section 内的内容片段。 3. 禁止使用 style 属性禁止输出 script、iframe、style、object。 4. 禁止用 Markdown 语法包括 #、-、|、 代码围栏。 5. 链接只允许 http 和 https 协议。这里的关键是“禁止输出完整 HTML 文档”和“只输出 section 片段”。如果不做限制模型可能输出!DOCTYPE html整页结构前端拼接时反而麻烦。4.2 让模型返回 JSON 包装的内容生产环境推荐让模型返回 JSONHTML 片段放在一个字段里方便程序解析{ title: 发布检查清单, html: sectionh3发布前检查/h3ulli确认配置外置化/lili确认日志采样和告警/li/ul/section }配合 Anthropic API 的响应格式可以这样约束输出import anthropic client anthropic.Anthropic(api_keyyour-api-key) response client.messages.create( modelclaude-3-5-sonnet-latest, max_tokens2000, systemSYSTEM_PROMPT, messages[ { role: user, content: 请生成一份 MySQL 慢查询排查清单。 } ], # 示意实际以当前 SDK 支持的能力为准 )如果调用过程中遇到“unable to connect to anthropic services”这类连接错误第一步先确认网络、DNS 和 443 端口是否正常再确认 API Key 格式是否正确最后查看官方服务状态页确认区域可用性。生产环境调用前要明确重试策略和超时时间。4.3 保留一份给人读的 Markdown 摘要HTML 适合机器消费但不适合塞进聊天记录或邮件正文。建议在结构化输出中同时保留markdown字段给需要复制到文档、粘贴到 issue 的用户使用{ title: 发布检查清单, html: section.../section, markdown: ## 发布检查清单\n\n- 确认配置外置化\n- 确认日志采样和告警\n }这样一套输出同时满足“给人看”和“给程序看”两个场景比强行让所有场景统一成一种格式更实用。5. 渲染 AI 返回的 HTML 之前先解决安全清洗5.1 为什么不能直接把 AI 输出塞进 innerHTML大模型输出的内容本质上是不可信数据。虽然 Claude 在训练时做了大量对齐但在开放场景中模型可能被诱导输出恶意内容也可能因为训练数据里的网页片段而输出带事件的标签。直接把 AI 生成的 HTML 插入页面可能带来三类风险script标签或事件属性导致的 XSS。javascript:协议的链接。利用 CSS 判断用户行为的数据采集手段。所以安全清洗不是可选项而是 AI 生成内容渲染前的必要步骤。5.2 后端清洗使用白名单配置Node.js 项目里常用的方案是sanitize-html。核心是白名单机制只允许显式允许的标签和属性const sanitizeHtml require(sanitize-html); const cleanOptions { allowedTags: [ p, h2, h3, h4, ul, ol, li, table, thead, tbody, tr, th, td, strong, em, a, code, pre, blockquote, span, div, br, hr, section ], allowedAttributes: { a: [href, target, rel], th: [scope], td: [colspan, rowspan], span: [class] }, allowedSchemes: [http, https, mailto] }; const safeHtml sanitizeHtml(llmOutput, cleanOptions);注意几个关键点不要用黑名单思路黑名单永远列不全白名单才可控。a标签的target和rel要一起处理防止反向 Tabnabbing。allowedSchemes必须限制否则javascript:协议可能漏进来。class属性如果要放行必须由自己维护的 CSS 类控制不能让模型任意定义样式类。5.3 前端兜底DOMPurify 与 CSP前端渲染时建议再叠加一层 DOMPurify 清洗双保险降低风险import DOMPurify from dompurify; const clean DOMPurify.sanitize(llmOutput, { USE_PROFILES: { html: true }, FORBID_TAGS: [style, script, iframe, object, embed], FORBID_ATTR: [onerror, onclick, onload, style] }); container.innerHTML clean;同时给页面加上 CSP 响应头限制脚本执行来源Content-Security-Policy: default-src self; script-src self; style-src self unsafe-inline; img-src self https:CSP 的存在是为了兜底即使某次清洗漏掉了脚本浏览器也会因为 CSP 策略拒绝执行。安全清洗和 CSP 是两层独立防线。清洗负责移除不允许的内容CSP 负责在清洗失效时拦截执行。两层都要配不能只依赖其中一层。6. 什么时候继续用 Markdown什么时候换成 HTML6.1 关键判断依据选型不需要一刀切可以根据输出消费方式判断输出给人阅读、进入文档系统优先 Markdown。输出要展示在自研 Web 页面优先 HTML。输出要被后端程序解析并入库优先 HTML 或 JSON。输出要发邮件两种都可以但 HTML 版更接近邮件客户端渲染需求。输出要进入聊天窗口且平台自带 Markdown 渲染器优先 Markdown。6.2 Markdown 与 HTML 对比速查表维度MarkdownHTML人读可读性好接近纯文本差标签噪声多表格能力简单表格可用复杂结构受限单元格合并、表头分组都支持结构校验无统一校验器可用 DOM 解析器校验流式渲染需要额外解析器处理中间态浏览器可增量解析跨平台一致性不同解析器差异大浏览器实现相对统一安全要求需要过滤链接和图片需要更强的标签白名单清洗Prompt 上下文占用小相对更大程序化解析需要额外转换直接操作 DOM 树6.3 混合方案Markdown 里允许受限 HTML 子集很多 Markdown 解析器本身支持内嵌 HTML例如 CommonMark 允许在 Markdown 中写 HTML 标签。这意味着可以设计一个混合策略对话展示层用 Markdown方便人阅读、复制。当检测到需要精细表格、提示框、折叠面板时让模型输出受限 HTML 子集。渲染前统一走一次清洗把details、summary、table这类标签保留其余按白名单处理。details summary查看完整排查步骤/summary ol li确认配置文件路径/li li确认日志级别/li /ol /detailsdetails和summary是 HTML 里很方便的折叠组件Markdown 没有对应语法。在混合方案里这种标签既满足展示需求又不破坏整体 Markdown 的可读性。7. 常见问题与排查路径7.1 AI 返回 HTML 后样式丢失现象是标签结构都在但页面看起来没有层次标题不大、表格没边框、列表没缩进。可能原因是模型被要求“不使用 style 属性”而项目又没有全局样式表覆盖这些标签。检查页面是否引入了针对h2、table、ul的全局 CSS。若没有方案是二选一不禁止 style 但走属性白名单清洗或者维护一套语义化标签的默认样式。7.2 流式输出时表格或列表渲染错乱现象是打字过程中表格时而出现、时而消失最终内容稳定后显示正常。原因是流式更新时直接把半截 HTML 塞进 innerHTML浏览器对未闭合标签的容错处理导致中间态异常。处理方式是累积缓冲区、加入防抖不要每个 token 都全量重绘let buffer ; let timer null; stream.on(data, (chunk) { buffer chunk; clearTimeout(timer); timer setTimeout(() { container.innerHTML DOMPurify.sanitize(buffer, cleanOptions); }, 100); }); stream.on(end, () { clearTimeout(timer); container.innerHTML DOMPurify.sanitize(buffer, cleanOptions); });7.3 API 连接失败unable to connect to anthropic services现象是请求api.anthropic.com时报错常见提示包括unable to connect to anthropic services或failed to connect to api.anthropic.com。按顺序排查本地网络是否正常能否访问外部 HTTPS 站点。DNS 解析是否正常使用nslookup api.anthropic.com检查。443 端口是否可达使用curl -v https://api.anthropic.com检查连接过程。API Key 是否有有效格式、是否过期。企业内网环境确认是否放行了该域名的访问。服务可用性以官方状态页为准遇到区域性波动时先等待恢复同时做好接口超时和重试。排查表格如下问题现象常见原因检查方式处理建议请求一直超时本地网络不通或防火墙拦截curl -v https://api.anthropic.com修复网络确认 443 端口可达DNS 解析失败本地 DNS 配置异常nslookup api.anthropic.com切换公共 DNS 后重试401/403API Key 错误或权限不足检查请求头的 Authorization重新生成密钥并核对权限请求成功但响应流中断网络不稳定或超时设置过短查看服务端返回码和日志增加超时时间实现指数退避重试7.4 Markdown 表格复制后错位现象是从页面复制 Markdown 表格到 Excel 或在线文档列内容错位。原因是原始 Markdown 表格里的分隔线和单元格内容不够规范或者前端渲染时重新解析引入了差异。解决方式是涉及表格时优先让模型输出 HTML 表格渲染层直接使用 DOM 结构如果必须用 Markdown先做一次表格规范化确保列数和分隔线一致。8. 最佳实践清单与扩展方向8.1 接入 AI 内容渲染前的基本检查清单把以下清单贴到项目验收文档里每次改动都过一遍[ ] 确定 AI 输出的消费方给人、给程序还是给两种场景都提供字段。[ ] 提示词中明确禁止输出完整 HTML 文档只输出片段。[ ] 提示词中明确禁用script、iframe、style、事件属性和javascript:链接。[ ] 后端使用白名单清洗配置allowedTags、allowedAttributes、allowedSchemes。[ ] 前端渲染前再经过一次 DOMPurify 清洗。[ ] 页面配置 CSP 响应头禁止非预期脚本执行。[ ] 流式输出使用缓冲区累积和防抖更新避免半截标签破坏页面。[ ] API 调用有超时、重试和失败兜底提示。[ ] 表格、折叠面板等复杂组件使用语义化 HTML 标签渲染。[ ] 保留 Markdown 字段供用户复制到文档或 issue 中使用。8.2 进一步扩展的方向第一条方向是把 HTML 当作工具调用的标准返回格式。在 Agent 场景中工具返回的 HTML 片段可以直接作为上下文传给模型模型根据已有结构继续生成减少“解析 Markdown 再改结构”的损耗。第二条方向是组件化模板。让模型输出受控的 HTML 片段前端用 React 或 Vue 解析后映射成组件。HTML 在这种场景下相当于一种轻量 DSL校验通过后可以安全地渲染成受控组件而不是直接插入任意 DOM。第三条方向是做渲染一致性回归。因为 HTML 结构可以用标准解析器校验可以在 CI 里对模型输出样例跑快照测试捕获表格结构、标签闭合、危险标签清理等回归问题。这比用 Markdown 做回归测试可靠得多。回到最初的问题Anthropic 工程师并不是要消灭 Markdown而是把“AI 输出”和“界面渲染”之间那条不确定的转译链路去掉。Markdown 继续服务人读场景HTML 接管程序消费和界面渲染场景。实际项目里最值得做的是先明确每一段 AI 输出的最终消费方再决定是输出 Markdown、HTML 还是两者都保留。格式选型不是一个纯审美问题它直接决定渲染稳定性、安全检查成本和排查难度。