📌 内容摘要

  • Claude 默认使用 Markdown 格式输出,但在 API 环境或纯文本场景中这往往是问题而非优势。
  • 本文覆盖4种输出格式的完整控制方法:Markdown、JSON、XML、纯文本,附每种格式的 Prompt 模板。
  • 重点解决开发者最常遇到的问题:如何获得稳定可解析的 JSON、如何防止 Claude 在不该用 Markdown 的地方乱用。
  • 文末提供完整的格式解析和容错代码,处理 Claude 输出格式不规范的边界情况。

一、Claude 的默认格式行为

了解 Claude 的默认行为,是控制输出格式的第一步。

Claude 在判断输出格式时,会根据对话上下文做出推断:在 claude.ai 网页端,它倾向于使用 Markdown(因为界面会渲染);通过 API 调用时,它的格式行为相对中性。但无论哪种环境,Claude 对明确的格式指令响应非常好——你告诉它用什么格式,它就用什么格式。

场景 Claude 默认行为 推荐做法
claude.ai 网页对话 倾向使用 Markdown 通常不需要干预,Markdown 会被正常渲染
API 调用(展示给用户) 可能带 Markdown 标记 明确指定格式,或在前端渲染 Markdown
API 调用(程序解析) Markdown 标记会干扰解析 强制要求 JSON 或纯文本
批量数据处理 格式可能不一致 严格约束输出格式,加容错解析

二、Markdown 格式控制

2.1 开启/增强 Markdown(适合文档和报告)

请用 Markdown 格式撰写以下报告,要求:
- 用 ## 作为主标题,### 作为子标题
- 重要数字和关键词用 **粗体** 标注
- 对比数据用表格呈现
- 操作步骤用有序列表
- 注意事项用无序列表
- 代码示例用代码块包裹

报告主题:[主题]

2.2 禁用 Markdown(适合 API 程序处理或纯文本场景)

# System Prompt(推荐方式,在 API 中设置)
你的输出将被程序直接处理,请严格遵守:
- 不使用任何 Markdown 格式(不用 **、##、`、- 等符号)
- 不使用 emoji
- 使用纯文本输出
- 段落之间用换行符分隔

---

# 对话中临时禁用(次优方式)
请用纯文本回答,不要使用任何 Markdown 格式符号。

2.3 精确控制 Markdown 使用范围

格式规则:
- ✅ 允许使用:代码块(```)、行内代码(`)、表格
- ✅ 允许使用:有序/无序列表
- ❌ 禁止使用:标题(#、##、###)
- ❌ 禁止使用:粗体(**)和斜体(*)
- ❌ 禁止使用:分隔线(---)

理由:输出会显示在不支持标题渲染的环境中,但代码需要高亮显示。

三、JSON 格式输出(开发者最常用)

JSON 是 API 开发中最常需要的输出格式,也是最容易出问题的格式——Claude 有时会在 JSON 前后加解释文字,或者用 Markdown 代码块包裹。以下是确保获得纯净 JSON 的完整方案。

3.1 基础 JSON 输出

分析以下产品评论,以 JSON 格式返回结果。

严格要求:
- 只输出 JSON,不要任何前缀说明或后缀总结
- 不要用 Markdown 代码块(不要 ```json``` 包裹)
- 严格遵守以下 schema,不增减任何字段

JSON schema:
{
  "sentiment": "positive | negative | neutral | mixed",
  "score": -1.0 到 1.0 的浮点数(-1最负面,1最正面),
  "key_issues": ["问题1", "问题2"],
  "key_praises": ["优点1", "优点2"],
  "recommended_action": "reply | escalate | ignore"
}

评论内容:[粘贴评论]

3.2 复杂嵌套 JSON

从以下职位描述中提取结构化信息,只输出 JSON,不要其他内容:

{
  "job_title": "职位名称",
  "company": "公司名称",
  "location": {
    "city": "城市",
    "is_remote": true 或 false
  },
  "salary": {
    "min": 最低薪资数字(元/月,没有则 null),
    "max": 最高薪资数字(元/月,没有则 null),
    "currency": "CNY"
  },
  "requirements": {
    "years_of_experience": 最低年限数字,
    "education": "学历要求",
    "skills": ["技能1", "技能2"]
  },
  "job_type": "full-time | part-time | contract | internship",
  "posted_date": "YYYY-MM-DD 格式,无法确定则 null"
}

职位描述:[粘贴 JD]

3.3 JSON 数组批量处理

对以下 5 条评论逐一分析,返回 JSON 数组。

只输出 JSON 数组,格式:
[
  {"id": 1, "sentiment": "positive|negative|neutral", "score": 数字},
  {"id": 2, ...},
  ...
]

评论列表:
1. 物流很快,商品完好,好评!
2. 假货,和描述完全不符,差评。
3. 还可以,价格偏贵。
4. 包装很精致,送礼不错。
5. 质量一般,但客服态度好。

3.4 Python 健壮解析代码

import anthropic
import json
import re
from typing import Any, Optional

client = anthropic.Anthropic()


def extract_json(text: str) -> Optional[Any]:
    """
    从 Claude 输出中提取 JSON,处理各种不规范情况:
    1. 纯 JSON
    2. ```json ... ``` 代码块包裹
    3. JSON 前后有多余文字
    4. 单引号替代双引号(非标准但有时出现)
    """
    text = text.strip()

    # 情况1:尝试直接解析
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        pass

    # 情况2:提取代码块中的 JSON
    code_block = re.search(r'```(?:json)?\s*([\s\S]*?)\s*```', text)
    if code_block:
        try:
            return json.loads(code_block.group(1))
        except json.JSONDecodeError:
            pass

    # 情况3:提取第一个完整的 JSON 对象或数组
    json_pattern = re.search(r'(\{[\s\S]*\}|\[[\s\S]*\])', text)
    if json_pattern:
        try:
            return json.loads(json_pattern.group(1))
        except json.JSONDecodeError:
            pass

    # 情况4:修复单引号并重试
    fixed = text.replace("'", '"')
    try:
        return json.loads(fixed)
    except json.JSONDecodeError:
        pass

    return None  # 所有尝试失败


def call_with_json_output(
    prompt: str,
    schema_description: str,
    system: str = "",
    max_retries: int = 3,
) -> Optional[Any]:
    """
    调用 Claude 并确保获得有效 JSON
    失败时自动重试,最多 max_retries 次
    """
    system_prompt = f"""{system}
你的输出将被程序直接解析,必须严格遵守:
1. 只输出 JSON,不要任何解释文字
2. 不要使用 Markdown 代码块包裹
3. 确保输出是合法的 JSON 格式""".strip()

    full_prompt = f"""{prompt}

输出 JSON schema:
{schema_description}

记住:只输出 JSON,没有其他任何内容。"""

    for attempt in range(max_retries):
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            system=system_prompt,
            messages=[{"role": "user", "content": full_prompt}]
        )

        result = extract_json(response.content[0].text)
        if result is not None:
            return result

        print(f"第{attempt+1}次尝试解析失败,原始输出:{response.content[0].text[:100]}...")
        # 重试时加强格式要求
        full_prompt += "\n\n⚠️ 上次输出格式不正确,请只输出纯 JSON,不要任何其他内容。"

    return None


# 使用示例
result = call_with_json_output(
    prompt="分析评论:'产品不错,但发货太慢了,等了5天'",
    schema_description='{"sentiment": "string", "score": "number -1 to 1", "issues": ["string"]}'
)
print(result)  # {'sentiment': 'mixed', 'score': 0.1, 'issues': ['发货速度慢']}

四、XML 格式输出

Claude 对 XML 标签有特别好的响应性——Anthropic 官方文档明确推荐使用 XML 标签来结构化复杂 Prompt 和输出。XML 适合需要清晰层次结构、或者需要同时包含多种类型内容的场景。

4.1 基础 XML 输出

分析以下代码,以 XML 格式返回审查结果:

<code_review>
  <summary>整体评价(一句话)</summary>
  <score>0-100的整数</score>
  <issues>
    <issue severity="critical|high|medium|low">
      <location>行号或函数名</location>
      <description>问题描述</description>
      <fix>修复建议</fix>
    </issue>
    (可能有多个 issue 标签)
  </issues>
  <approved>true 或 false</approved>
</code_review>

代码:[粘贴代码]

4.2 XML 解析代码

import xml.etree.ElementTree as ET
import re
from typing import Optional


def extract_xml(text: str, root_tag: str) -> Optional[ET.Element]:
    """
    从 Claude 输出中提取并解析 XML
    root_tag: 根标签名,如 'code_review'
    """
    # 提取 XML 片段
    pattern = rf'<{root_tag}[\s\S]*?'
    match = re.search(pattern, text, re.DOTALL)

    if not match:
        return None

    try:
        return ET.fromstring(match.group(0))
    except ET.ParseError:
        return None


def parse_code_review(xml_output: str) -> dict:
    """解析代码审查 XML 结果"""
    root = extract_xml(xml_output, "code_review")
    if root is None:
        return {}

    issues = []
    for issue in root.findall(".//issue"):
        issues.append({
            "severity": issue.get("severity"),
            "location": issue.findtext("location", ""),
            "description": issue.findtext("description", ""),
            "fix": issue.findtext("fix", ""),
        })

    return {
        "summary": root.findtext("summary", ""),
        "score": int(root.findtext("score", "0")),
        "issues": issues,
        "approved": root.findtext("approved", "false").lower() == "true",
    }


# 使用示例
xml_response = """
<code_review>
  <summary>代码结构合理,但存在SQL注入风险</summary>
  <score>62</score>
  <issues>
    <issue severity="critical">
      <location>第15行 get_user函数</location>
      <description>直接拼接用户输入到SQL查询中,存在SQL注入风险</description>
      <fix>使用参数化查询替代字符串拼接</fix>
    </issue>
  </issues>
  <approved>false</approved>
</code_review>
"""

result = parse_code_review(xml_response)
print(result)
# {'summary': '...', 'score': 62, 'issues': [...], 'approved': False}

4.3 XML 在 Prompt 中标记不同部分(Anthropic 推荐用法)

<task>
  分析以下两个合同版本的差异,找出对甲方不利的变化
</task>

<contract_v1>
  [原合同文本]
</contract_v1>

<contract_v2>
  [修改后合同文本]
</contract_v2>

<output_format>
  以 XML 格式返回:
  <analysis>
    <change risk="high|medium|low">
      <clause>条款名称</clause>
      <v1>原文</v1>
      <v2>修改后</v2>
      <impact>对甲方的影响</impact>
    </change>
  </analysis>
</output_format>

五、纯文本格式控制

5.1 完全禁用所有格式(语音/短信场景)

# System Prompt
你的输出将被转换为语音播报(TTS),必须严格遵守:
- 禁止所有 Markdown 符号(* # ` - = > 等)
- 禁止使用项目列表
- 禁止使用表格
- 使用完整的自然语言句子,用句号分隔
- 数字写成文字(3 → 三,100% → 百分之百)
- 英文缩写展开(API → 接口,AI → 人工智能)
- 每段话不超过50字,方便听众理解

5.2 控制纯文本的段落结构

用纯文本格式回答(不用 Markdown),但遵守以下排版规则:
- 每个主要观点单独成段
- 段落之间空一行
- 每段不超过4句话
- 如果需要列举,用中文括号加序号:(1)(2)(3)
- 如需强调,用书名号或引号包裹关键词

六、多格式混合输出

某些场景需要在同一个响应中混合使用多种格式——比如分析报告的正文用 Markdown,提取的数据用 JSON:

分析以下财务报告,分两个部分输出:

**第一部分:分析报告**
用 Markdown 格式,包含概述、关键发现、风险提示三个章节。

**第二部分:结构化数据**
在报告后,输出以下 JSON 数据块(用 ```json 包裹):
{
  "revenue": 数字(万元),
  "profit_margin": 百分比数字,
  "risk_level": "low|medium|high",
  "key_metrics": {"指标名": 数值}
}

报告内容:[财务报告文本]

混合输出解析代码

import json
import re


def parse_mixed_output(text: str) -> dict:
    """
    解析包含 Markdown 报告 + JSON 数据的混合输出
    """
    # 提取 JSON 代码块
    json_match = re.search(r'```json\s*([\s\S]*?)\s*```', text)
    structured_data = None
    if json_match:
        try:
            structured_data = json.loads(json_match.group(1))
        except json.JSONDecodeError:
            pass

    # 提取 Markdown 报告(去掉 JSON 部分)
    markdown_report = re.sub(r'```json[\s\S]*?```', '', text).strip()

    return {
        "report_markdown": markdown_report,
        "structured_data": structured_data,
    }


# 使用示例
output = """
## 财务分析报告

### 概述
公司本季度营收增长显著...

### 关键发现
- **营收**:达到 1200 万元,同比增长 23%
- **利润率**:维持在 18% 左右
```json
{
  "revenue": 1200,
  "profit_margin": 18,
  "risk_level": "low",
  "key_metrics": {"growth_rate": 23, "cash_ratio": 2.1}
}
```
"""

result = parse_mixed_output(output)
print("报告:", result["report_markdown"][:50])
print("数据:", result["structured_data"])

七、格式一致性保障(批量处理场景)

在需要处理大量数据的场景,格式一致性至关重要。以下是确保批量输出格式统一的最佳实践:

import anthropic
import json
from typing import Any

client = anthropic.Anthropic()

# 把格式要求放在 System Prompt 里,对所有请求统一生效
STRICT_JSON_SYSTEM = """
你是一个数据处理助手,所有输出都必须是合法的 JSON。

严格规则:
1. 只输出 JSON,绝对不要有任何前后缀文字
2. 不使用 Markdown 代码块(```)
3. 所有字符串值用双引号(不用单引号)
4. 数值不要加引号
5. 布尔值用 true/false(小写)
6. 空值用 null
"""


def batch_classify(texts: list[str]) -> list[dict]:
    """批量分类,确保每条输出格式一致"""
    results = []
    schema = '{"text_id": integer, "category": "string", "confidence": float_0_to_1}'

    for i, text in enumerate(texts):
        response = client.messages.create(
            model="claude-haiku-4-5-20251001",  # 批量分类用 Haiku 节省成本
            max_tokens=128,
            system=STRICT_JSON_SYSTEM,
            messages=[{
                "role": "user",
                "content": f"分类文本(id={i}):{text}\n输出schema:{schema}"
            }]
        )

        raw = response.content[0].text.strip()
        # 去掉可能的代码块标记
        raw = re.sub(r'^```(?:json)?\s*|\s*```$', '', raw).strip()

        try:
            result = json.loads(raw)
            results.append(result)
        except json.JSONDecodeError:
            # 解析失败时返回错误占位
            results.append({
                "text_id": i,
                "category": "parse_error",
                "confidence": 0.0,
                "raw_output": raw
            })

    return results

八、常见格式问题速查表

问题现象 原因 解决方案
JSON 前后有解释文字 Claude 默认习惯加说明 System Prompt 强调”只输出JSON”,或用代码提取 JSON 部分
JSON 被 ` ` ` 包裹 Claude 认为代码块更清晰 明确禁止代码块,或在解析时用正则提取
纯文本场景出现 **粗体** Claude 在没有指令时倾向美化输出 System Prompt 明确禁止 Markdown
批量处理格式不一致 每次请求可能有微小的格式差异 固定 System Prompt + 健壮的解析容错逻辑
XML 标签属性用单引号 两种引号都合法,Claude 随机选择 在 Prompt 中明确”属性值用双引号”
JSON 数字字段被加了引号 Claude 不确定时可能保守处理 在 schema 中明确标注”数字类型,不加引号”

常见问题

Q:JSON 和 XML 怎么选?
JSON 更适合程序间数据交换(解析库丰富,语法更简洁);XML 更适合包含大量文本内容的结构化文档(能更自然地嵌套长文本,Claude 对 XML 标签响应也特别好)。API 开发通常选 JSON;文档处理、内容标注选 XML。两者都没有绝对优劣,按你的下游系统来决定。

Q:Claude 偶尔还是会输出不符合格式的内容,怎么办?
接受一定的失败率,做好容错处理。生产环境中,建议设置最多3次重试,每次失败后在 Prompt 里加强格式强调。同时维护一个”解析失败”的记录,定期审查这些案例,优化你的格式 Prompt。完全零失败率的格式约束在生产中很难实现,重要的是失败时程序不崩溃。

Q:用 claude.ai 网页端时,能关闭 Markdown 渲染吗?
目前 claude.ai 网页端没有关闭 Markdown 渲染的开关。如果你不想看到渲染后的格式,可以在 Prompt 里要求”用纯文本输出,不使用任何 Markdown 符号”,这样输出本身就不会有格式符号。

总结

格式控制的核心原则只有一条:明确告诉 Claude 你要什么格式,而不是期望它猜。最有效的位置是 System Prompt——在这里设置格式规则,对整个会话生效,不需要每次重复。生产环境中,JSON 解析一定要加容错逻辑,因为完全稳定的格式输出在实践中难以实现。XML 标签不只用于输出,还是组织复杂 Prompt 的有效工具——这一点很多人没有充分利用。