Claude 的 XML Prompt 技巧——不是噱头,真的有用
Claude 的 XML Prompt 技巧——不是噱头,真的有用
适读人群:使用 Claude 做开发的工程师 | 阅读时长:约 10 分钟 | 核心价值:用 XML 结构化 Prompt,理解真实提升效果的边界条件
我最开始看到有人说「给 Claude 用 XML 格式的 Prompt 效果更好」,说实话,第一反应是觉得这是营销话术。
当时我的想法是:模型又不是程序,凭什么 XML 包一下就能提升效果?不就是加了几个尖括号吗?有什么神秘的?
然后我在一个信息抽取项目里被现实打脸了。
那个项目是从合同文本里抽取关键信息——甲方乙方、合同金额、履约日期、违约条款这些。我用普通的自然语言 Prompt 写了一版,效果一直不稳定:有些字段能抽对,有些时候模型开始解释为什么某个字段不存在,有些时候它直接给你一段话而不是结构化数据。
抱着试试看的心态,我把 Prompt 改成了 XML 结构,基本什么都没变,就是加了标签。结果输出稳定性提升明显。我开始认真测这个事情。
我做的 A/B 测试
测试任务:从 200 份合同摘要里抽取 6 个字段(甲方、乙方、金额、签订日期、有效期、主要违约条款)。
评估标准:字段完整率(6个字段都有输出)、格式合规率(JSON格式可解析)、内容准确率(人工抽查50份)。
版本 A——普通自然语言 Prompt:
你是一个合同分析助手。请分析以下合同文本,提取关键信息,包括:
甲方名称、乙方名称、合同金额、签订日期、合同有效期、主要违约条款。
请以JSON格式返回结果。
合同文本:
{contract_text}版本 B——XML 结构化 Prompt:
<task>
<role>合同分析助手</role>
<objective>从合同文本中精确抽取结构化信息</objective>
<output_requirements>
<format>JSON</format>
<fields>
<field name="party_a" description="甲方完整名称" required="true"/>
<field name="party_b" description="乙方完整名称" required="true"/>
<field name="amount" description="合同总金额,含货币单位" required="true"/>
<field name="sign_date" description="签订日期,格式YYYY-MM-DD" required="true"/>
<field name="validity_period" description="合同有效期" required="true"/>
<field name="breach_clause" description="主要违约条款摘要,不超过100字" required="false"/>
</fields>
<missing_field_handling>如字段在文本中未提及,返回null,不得推断或虚构</missing_field_handling>
</output_requirements>
<contract_text>
{contract_text}
</contract_text>
</task>测试结果(200份合同,Claude 3.5 Sonnet):
| 指标 | 版本A | 版本B |
|---|---|---|
| 字段完整率 | 78% | 96% |
| JSON格式合规率 | 82% | 99% |
| 字段准确率(抽查50份) | 88% | 94% |
| 平均输出token数 | 312 | 287 |
字段完整率差了18个百分点,JSON合规率差了17个百分点。这不是小差异。
更有意思的是:版本 B 的输出 token 反而更少。原因很直接——XML Prompt 里说清楚了每个字段的定义和约束,模型不需要自己解释,直接给值就行。
为什么 XML 对 Claude 有效
这里我说一下我的理解,不一定完全准确,但逻辑上能自洽。
Claude 的训练数据里有大量结构化文档——HTML、XML、技术文档、API文档。这些文档的共同特征是:标签定义了内容的语义和边界。
当你用 XML 写 Prompt 时,模型能更清楚地识别哪部分是指令、哪部分是约束、哪部分是输入内容。这减少了歧义,也减少了模型需要「猜测」你想要什么的场景。
普通自然语言 Prompt 的问题是:「请提取金额、日期、甲方乙方」这句话里,模型要同时理解「你要什么」和「合同文本是什么」,这两件事混在一段文字里,边界不清晰。
XML 把这两件事分开了。
什么时候用 XML 有明显效果
不是所有场景都适合用 XML。我测下来,以下几种情况效果比较明显:
1. 多字段结构化抽取
就是上面说的场景。字段越多,XML 的优势越大。如果只抽一两个字段,普通 Prompt 也够用。
2. 有复杂约束条件的任务
比如:「翻译以下文本,但不翻译括号里的专有名词,金额格式保持原样,结尾的免责声明直接删除」。这种有多个约束的情况,用 XML 把约束单独列出来,比塞在一句话里清晰得多。
3. 有明确角色分离的多段输入
比如你同时传入「系统背景信息」、「用户历史行为」、「当前问题」三段内容,用 XML 标签区分三者,模型处理时不容易串。
4. 长 Prompt(超过500 tokens 的情况)
Prompt 越长,自然语言里的指令越容易被淹没。XML 的结构性有助于模型在长文本里找到重点指令。
什么时候用 XML 没什么差别甚至适得其反
简单的单任务 Prompt
「帮我把下面这段话翻译成英文:{text}」——加 XML 只是增加 token,没有收益。
需要模型发挥创意的任务
写故事、写营销文案、做头脑风暴——这些任务本身需要模型自由发挥,过度结构化反而会限制输出。
对话场景
多轮对话里加 XML 看起来很怪,体验也差。对话就是对话,不适合加一堆尖括号。
具体怎么写
说几个我在用的模式:
模式一:任务-输入-输出分离
<task>
<instruction>你要做什么</instruction>
<constraints>
<constraint>约束1</constraint>
<constraint>约束2</constraint>
</constraints>
</task>
<input>
{用户输入的内容}
</input>
<output_format>
{期望的输出格式或示例}
</output_format>模式二:角色定义 + 背景知识 + 任务
<system>
<role>你是一个专门处理医疗保险理赔的助手</role>
<knowledge>
<item>本保险产品的免赔额为1000元</item>
<item>报销比例:住院80%,门诊60%</item>
<item>慢性病门诊每年报销上限5000元</item>
</knowledge>
<behavior_rules>
<rule>不确定的情况下,引导用户联系人工客服</rule>
<rule>不得给出具体的医疗建议</rule>
</behavior_rules>
</system>
<user_query>{用户问题}</user_query>模式三:Few-shot 示例用 XML 标签包裹
<examples>
<example>
<input>2024年1月15日签订的采购合同,甲方北京科技有限公司,合同金额50万元</input>
<output>{"party_a": "北京科技有限公司", "sign_date": "2024-01-15", "amount": "50万元人民币"}</output>
</example>
<example>
<input>协议签署于2023.12,双方为A公司和B公司,总价款未明确</input>
<output>{"party_a": "A公司", "party_b": "B公司", "sign_date": "2023-12", "amount": null}</output>
</example>
</examples>
<new_input>{待处理文本}</new_input>一些细节
标签命名要语义化。<input> 比 <tag1> 好,<constraints> 比 <c> 好。模型能理解标签语义,好的命名有额外的提示效果。
不要过度嵌套。三层以内最好,超过三层的 XML 结构反而会让 Prompt 变复杂,不如拆成几个独立的标签。
内容里本身有尖括号时要转义。如果你的输入内容是 HTML 或代码,里面有 < > 时,要么转义成 < >,要么用 CDATA 包裹,不然会产生 XML 解析歧义。
<code_content><![CDATA[
def hello():
print("<Hello World>")
]]></code_content>不是 Claude 专属。我后来在 GPT-4o 上也做了类似测试,XML 结构化 Prompt 同样有效果,只是提升幅度比 Claude 小一点。
我的结论
XML Prompt 不是万能药,但对结构化输出任务来说,它是一个成本极低、收益稳定的工程实践。加几个标签,字段完整率提升 18%,这个买卖值得做。
但如果你用它来写对话助手、搞创意内容,不会有什么神奇效果。工具要用对地方。
