为什么 Claude 只吃 XML 不吃 Markdown?一个被忽视的训练数据秘密
这事儿是我去年底帮一个法律科技公司做合同条款抽取时遇到的。他们要从合同里抽出 “甲方名称 / 乙方名称 / 合同金额 / 签订日期 / 违约条款” 这五个字段,然后入库。
我一开始写的 prompt 是很标准的 Markdown 风格:
1 | ## 任务 |
跑了 500 个样本,准确率 71%。老板看完脸色不太好。
我折腾了一下午改 prompt,换措辞、加例子、调顺序,最多也就爬到 75%。然后我想起 Anthropic 官方文档里反复强调的一句话:”Claude was fine-tuned with XML tags.”。我就死马当活马医,把整个 prompt 的结构改成 XML:
1 | <task>从合同文本中抽取指定字段</task> |
同样的 500 个样本,准确率直接跳到 89%。我当时盯着屏幕看了很久,觉得不可思议——仅仅换了分隔符,效果差了将近 20 个百分点。
从那之后,我写 Claude 的 prompt 再也不用 Markdown 了。这篇把我理解的原因、可复制的模板、几个关键细节讲清楚。
一、为什么差这么多?训练数据的秘密
这个问题 Anthropic 没有官方给出技术解释,但从他们的文档、论文、和员工公开访谈里能拼出一个大概的图像。
Claude 在 Anthropic 内部训练时,大量使用 XML 标签作为结构分隔符。这是他们 Constitutional AI 训练流程里的一个工程习惯——用 <human>...</human> 和 <assistant>...</assistant> 分隔角色,用 <instruction>...</instruction> 分隔指令,用 <context>...</context> 分隔背景信息。
这些标签在训练数据里出现了数百万次,形成了强烈的分布偏好。模型看到 <xxx>...</xxx> 这种结构时,会非常明确地”知道”这是一段独立的、需要被单独对待的内容。
而 Markdown 的 # ## --- 这些符号呢?它们在训练数据里也出现很多,但它们同时出现在模型需要生成的文本里——模型在很多场景下就是在生成 Markdown 文档本身。这就导致了一个混淆:模型看到 ## 时,它不确定这是”输入的结构分隔符”还是”用户想让我生成的内容的一部分”。
相比之下,XML 标签在训练语料里几乎只作为结构分隔符出现,语义非常干净。这就是为什么 XML 的边界感更强。
GPT 系列的情况不太一样——OpenAI 训练时没有特别偏向 XML,所以对它来说 Markdown 和 XML 差别不大。这是 Claude 特有的属性。Gemini 的情况介于两者之间,XML 有一定效果但不如在 Claude 上显著。这也侧面说明了prompt 风格和模型是强绑定的,没有放之四海皆准的”最佳 prompt 格式”。
二、具体差在哪儿?我做过的消融实验
我后来做过一个小型消融实验,同一个任务分别用五种格式跑:
| 格式 | 准确率 |
|---|---|
| 纯文本(全部堆在一起) | 58% |
| Markdown 标题分段 | 71% |
| Markdown + 三连下划线分隔 | 74% |
| JSON 式大括号 | 79% |
| XML 标签 | 89% |
这个结果让我意识到几件事:
1. 任何结构都比没结构好。纯文本到 Markdown 就有 13 个百分点提升,说明”分段”本身就很重要。
2. XML 的优势主要体现在边界清晰。模型知道 <contract> 和 </contract> 之间的东西是一个完整的块,不会和外面的指令混起来。Markdown 的 ## 合同文本 开始了,但什么时候结束呢?下一个 ## 吗?模型要自己推断,容易出错。
3. 差距在输入越长时越明显。短 prompt(500 token 以内)Markdown 和 XML 差个 5-8 个百分点,长 prompt(3000+ token)就能拉到 15-20 个百分点。因为长输入里边界判断的重要性被放大。
4. 结构的语义信息也有加成。同样用 XML,把外层标签从 <data> 改成 <legal_contract>,准确率能再涨 2-3 个点。因为语义化的标签名本身给了模型关于内容性质的提示——模型知道”这是合同而不是随便的文本”,处理态度就不一样。
三、我现在用的标准 XML 模板
把这套经验固化一下,我现在写 Claude prompt 的基础模板长这样:
1 | <role> |
这个模板有几个原则:
1. 标签名要有语义。不要用 <tag1> <tag2> 这种无意义的名字。<contract> <resume> <invoice> 这种直接点明内容类型的最好——模型能用标签本身获取额外信息。
2. 可以嵌套。<examples> 里套 <example>,<example> 里再套 <input> 和 <output>。Claude 对嵌套结构识别很稳定,两到三层嵌套都没问题。
3. 输入放靠后的位置。研究表明 Claude 对 prompt 末尾的内容注意力最强(recency bias)。所以真正要处理的 <input> 放在靠后位置,更稳定。
4. 指令和数据严格分离。<instructions> 里只写”怎么做”,不要混入具体数据。具体数据放 <context> 或 <input>。这条原则在做 prompt injection 防御时也格外重要——指令和数据混在一起,用户注入攻击就容易得手。
5. 用空行增加可读性。XML 标签之间加空行不影响模型理解,但能让 prompt 人类看着舒服、方便后续维护。
四、几个容易翻车的点
1. 标签不要和要处理的内容冲突。
比如你要处理一份 HTML 文档,HTML 本身就有大量 <div> <span> 标签。这时候你包装数据的标签名要用不会出现在 HTML 里的,比如 <html_document> 而不是 <content>,避免混淆。
2. 不要用自闭合标签。
Claude 对 <tag/> 这种自闭合形式识别率不如 <tag></tag>。老老实实开闭配对。
3. 中文标签会翻车。
我试过用中文标签名(比如 <角色>...</角色>),准确率不如英文标签。因为训练数据里 XML 标签绝大多数是英文,模型的偏好是在英文上建立的。内容可以中文,标签名一定英文。
4. 和 Markdown 混用没问题,但别混淆层级。
XML 包外层结构,内部 <instructions> 里可以用 Markdown 列表,这是没问题的。但不要一个任务一半用 XML 框一半用 Markdown 标题框,那样模型会懵。
5. 标签不要太多也不要太少。
我见过两种极端:一种是整个 prompt 就一对 <task>...</task> 把所有东西包进去,这等于没分块;另一种是每一句话都包一个标签,过度工程化。一般 4-8 对顶层标签是比较舒服的量。
6. 不要在 XML 标签里写 markdown 反引号代码块的开头。
很少人会撞上但确实存在:如果你在 <code>...</code> 里直接写代码,大部分时候没问题;但如果代码里本身含有 < > 符号(比如 Go 的泛型或 HTML 片段),模型可能会错乱。这时候要么用 CDATA 风格(<![CDATA[...]]>,Claude 认),要么外层标签改名绕开冲突。
五、不仅仅是输入,输出也能用 XML
有个更进一步的技巧:让 Claude 用 XML 组织它的输出,再解析出来。
比如我要求 Claude 先思考再回答:
1 | <instructions> |
这比让它用 “思考:… 答案:…” 这种 Markdown 风格要稳定得多。后端解析也很简单,正则一抓一个准。
这招在 Agent 场景里特别好用——你可以让模型输出 <tool_call>、<reasoning>、<plan> 这种结构化标签,程序化地拆开。这部分实战我另一篇讲 Agent 的文章里有更多例子,想看可以翻 Prompt工程分类。
延伸的一个小 trick:给 Claude 预设输出开头。比如你在 API 调用里把 assistant 的开头预填为 <answer>,Claude 会自动从那里续写,不会再输出啰嗦的开场白。配合 stop sequence </answer> 使用,一次调用就能稳定拿到干净的答案内容,适合做结构化抽取的生产环境。
六、进阶:XML + Tool Use 的组合拳
如果你用的是 Claude 的 tool use 功能,其实你已经在用 XML 了——Anthropic 的 tool call 格式底层就是 XML。你在 system prompt 里用 XML 组织指令,和工具调用的格式天然一致,模型处理起来更流畅。
我最近在做的一个 Agent 项目就是这个玩法:
- system prompt 用 XML 定义角色、规则、工具使用准则
- tool schema 按 Anthropic 的 XML tool 格式定义
- 中间步骤让模型输出
<scratchpad>...</scratchpad>做思考 - 最终结果用
<final_answer>...</final_answer>包装
整套 prompt 从头到尾都是 XML 结构,模型的一致性特别好。转战 Claude 之后我再也不想回去搞 GPT 那套花里胡哨的 function calling schema 了。
七、最后说两句
XML over Markdown 这个小技巧看着不起眼,但在生产环境里能直接拉高 10-15 个百分点的准确率,值回票价。这种”训练数据偏好”导致的工程 trick 还有不少,比如 Claude 对 “Here is the answer:” 这种引导句的敏感度、对 <system> 标签的权重倾斜、对 “step by step” 这种链式思考触发词的反应等等。我会持续把踩到的这类坑整理出来。
如果你是 Claude 新手,建议把上面那个标准模板存下来,下次写 prompt 直接填空。光这一点,你 prompt 的效果就会比 80% 的同行好。想看更多 Claude 实战内容可以顺带访问一下 www.cocoloop.cn 和 openclaw.cocoloop.cn,后者是专门聚焦 Anthropic 生态的一个子站。
最后分享一个心得:prompt 格式和模型版本是绑死的。Claude 3 Opus 时代最有效的 XML 模板,到了 Sonnet 4.6 上效果会微妙地变化,新模型对结构的宽容度更高一些。每次换模型版本,建议把自己最常用的几个 prompt 拉出来回归测一遍,别想当然。
- 标题: 为什么 Claude 只吃 XML 不吃 Markdown?一个被忽视的训练数据秘密
- 作者: Claude 中文知识站
- 创建于 : 2026-04-02 09:25:00
- 更新于 : 2026-04-16 11:10:00
- 链接: https://claude.cocoloop.cn/posts/claude-xml-over-markdown/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。