🤖

なぜAnthropicはプロンプトにXMLタグを推奨するのか──Markdownとの構造的な違い

に公開1

はじめに

「Markdown で書けばAIが読みやすいはず」——そう思って CLAUDE.md や RAG のソースドキュメントを Markdown で整備してきた人は多いはずだ。

しかし実際にプロンプトエンジニアリングを突き詰めていくと、システムプロンプトの構造化や RAG のチャンク設計という特定の用途に絞った文脈では、構造が複雑なコンテキストほど HTML や XML ライクな構造で渡したほうが AI の解釈精度が上がる という経験則に直面することがある。

本稿では「なぜ Markdown より HTML が特定シナリオで AI に有利になりうるのか」を、言語設計・LLM の学習データ・実際のトークン解釈の三つの角度から整理する。あくまで 筆者の実務経験と公開情報に基づく考察・仮説 であり、定量的なベンチマーク結果ではない点を先に断っておく。「AI への情報の渡し方を最適化したい」「RAG のチャンク設計を見直したい」という人への考察として読んでもらえれば嬉しい。

5行まとめ(クリックで展開)

TL;DR(5行まとめ)

  1. Markdown は 人間の可読性を最優先 に設計された記法であり、同じ意味を複数の書き方で表現できる「曖昧性」を構造的に含む
  2. LLM の主要な学習データ源の一つは HTML(Webクロール) であり、HTMLのタグ構造はLLMにとって馴染みのあるパターンである(ただし近年はMarkdownの学習量も増加している)
  3. Markdown のパーサー依存(CommonMark / GFM / Obsidian 方言など)は構造の解釈に揺れを生む。HTML はMarkdownと比べてこの揺れが小さい
  4. HTML の明示的なタグ構造・属性・ネストは セマンティクスを自己記述 しており、AI が構造を誤解するリスクを下げる可能性がある
  5. 結論:AIへのコンテキスト渡しやプロンプト設計では、構造が複雑な箇所に HTML または XML ライクなカスタムタグ を使う選択肢が出力品質の改善策の一つになりうる(ただしトークン増加とのトレードオフあり)

1. Markdown の設計思想と「構造的曖昧性」

Markdown は 2004 年に John Gruber が「人間が書きやすく、読みやすいプレーンテキスト」として設計した。この思想は成功した——しかし 「機械が曖昧なく解釈できる」という目標は含まれていなかった

同じ意味を表す複数の記法

太字の書き方(4種類すべて合法)

**太字**
__太字__
<strong>太字</strong>
<b>太字</b>

水平線(3種類すべて合法)

---
***
___

見出し(ATX形式 vs Setext形式)

## 見出し2

見出し2
-------

人間にとってこれらは「どれでも同じ」だが、AI 側では 意図の確定コスト が発生する可能性がある。ここでいう「確定コスト」とは、AI が複数の記法から構造を一意に決めるために費やす推論ステップと、誤解するリスクの総体のことだ。実際、**bold**__bold__ ではパーサーによって扱いが異なるケースもある。

パーサー方言の乱立

方言 主な違い
CommonMark 仕様が厳密。_* の扱いを区別する
GFM (GitHub) テーブル・取り消し線・チェックリストを追加
Obsidian [[wikilink]]![[embed]] などを独自拡張
Zenn :::message :::details などの独自ブロック構文
MDX JSX コンポーネントを埋め込み可能

AI は「このドキュメントがどの Markdown 方言で書かれているか」を 明示されない限り推測するしかない。一方 HTML は Markdown と比べて方言の影響が小さく、タグの意味は仕様として定義されている(HTML4/5 や XHTML 間の差異は存在するが、プロンプト用途では現実的な問題になりにくい)。なお Liquid・EJS・JSX などのテンプレートエンジンは HTML に独自構文を持ち込むため、「HTML に方言が一切ない」わけではない。ただし 標準 HTML タグとしての解釈の安定性 に限定すれば、Markdown との比較優位はそのまま成立する。


2. LLM の学習データと HTML のなじみ深さ

GPT 系をはじめとする多くの主要 LLM は、Common Crawl(Webクロール)を主要な学習データ源 の一つとしている(Claude の学習データ構成は Anthropic 非公開のため、一般化には注意が必要だ)。Webページの実体は HTML であり、学習データ全体の量では HTML が大きなウェイトを占める。

ただし 近年は GitHub・HuggingFace・技術文書などの Markdown リポジトリの学習量も大幅に増加 しており、特にコーディング特化の文脈では Markdown も十分に学習されている。「HTML だけが特別」ではなく、「HTML のタグ構造パターンが最も学習量が多い形式の一つである」 という理解が正確だ。

AI が「HTML を知っている」理由

<!-- AI が大量に学習したWebページの構造例 -->
<article>
  <h1>記事タイトル</h1>
  <section>
    <h2>セクション見出し</h2>
    <p>本文テキスト。<strong>重要な部分</strong>は strong タグで囲まれている。</p>
    <pre><code class="language-python">print("コードブロック")</code></pre>
  </section>
  <table>
    <thead><tr><th>列A</th><th>列B</th></tr></thead>
    <tbody><tr><td>データ1</td><td>データ2</td></tr></tbody>
  </table>
</article>

このパターンを AI は大量に学習しており、HTML のタグとその役割の関係は、AI にとって馴染みのある構造 の一つだ。

Markdown はそれを人間向けに簡略化したものだが、LLM がMarkdownを処理する際にはHTMLの構造パターンとは異なるトークン列として扱われる。一般的な実装では「内部でHTMLに変換している」わけではなく(実装はモデルによって異なる)、「HTMLパターンの学習量が多い分、構造の認識が安定しやすい可能性がある」 というのが実態に近い仮説だ。

なお BPE などのトークナイザーの観点では、<div></p><strong> といった頻出 HTML タグは一部の tokenizer で単一トークンとして収録されている場合がある(ただし tokenizer の実装・バージョンによって異なるため、実際の挙動は cl100k_base 等で手元確認を推奨する)。これはタグ全体が意味的単位として認識されやすい可能性を示唆するが、「学習量が多い = 構造認識が安定する」は必ずしも同値ではなく、あくまで 確率的な優位性の仮説 として捉えるのが正確だ。


3. 構造の自己記述性:HTML が持つセマンティクス

1節で整理した Markdown の曖昧性と対照的に、HTML は 構造がタグ自体に意味を持つ という強みがある。

HTML の構造的明瞭性

<ul>
  <li>アイテム1
    <ul>
      <li>ネストアイテム
        <ul>
          <li>さらにネスト</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<pre><code class="language-python">
# コードブロックの開始と終了は明確
def hello():
    print("hello")
</code></pre>

開始タグと終了タグがあるため、構造の開始・終了が一意に決まる。AI が「このブロックがどこで終わるか」を迷う余地がない。


4. 属性による「メタデータの埋め込み」

HTML タグは属性によって 追加コンテキストを明示的に付与 できる。これは Markdown には存在しない機能だ。

コードブロックの言語指定と追加コンテキスト

❌ Markdown(言語は指定できるが、追加コンテキストを属性で付与できない)

```sql
SELECT * FROM users WHERE id = 1;
```

✅ HTML(言語に加えてバージョン情報などの追加コンテキストを属性で明示)

<pre><code class="language-sql" data-context="PostgreSQL 15">
SELECT * FROM users WHERE id = 1;
</code></pre>

Markdown も ```sql のように言語指定は可能だ。HTML の優位性は言語指定の有無ではなく、data-context="PostgreSQL 15" のような 追加コンテキストを属性として明示 できる点にある。AI はコードブロックの内容から言語を推測できるが、属性があれば「どのバージョンのどの文脈で書かれたか」まで確定できる。

セクションへのメタデータ付与:data-* 属性

HTML でセクションに付加情報を持たせたい場合は data-* 属性を使うのが基本だ(role 属性は ARIA 仕様で定義されており、独自値を割り当てると仕様外の使い方になる)。ただし AI の解釈という観点では話が異なる。LLM は ARIA セマンティクスを豊富に学習しているため、<section role="constraints"> のように書くと「このセクションの役割は constraints だ」という意味が直接的に伝わる可能性がある。HTML 仕様への準拠を重視するなら data-*、AI への意味伝達を優先するなら role 属性も選択肢に入る という使い分けになる。

<!-- HTML で付加情報を付ける場合は data-* 属性を使う -->
<section data-role="constraints">
  <h2>制約条件</h2>
  <ul>
    <li>応答は日本語で行うこと</li>
    <li>コードは TypeScript のみ使用</li>
  </ul>
</section>

プロンプト構造化:XML ライクなカスタムタグ

プロンプト構造化においては、HTML タグではなく カスタム XML タグ を使うアプローチも有力だ。data-* 属性による HTML と、カスタム XML タグは用途が異なる。前者はドキュメントの構造化、後者はプロンプト内のセマンティクスの明示が主な用途だ。Anthropic の公式ドキュメントでも、Claude へのプロンプト構造化に XML ライクなタグを推奨している。

<!-- XML ライクなタグによる構造化(Anthropic推奨アプローチ) -->
<constraints>
  <rule>応答は日本語で行うこと</rule>
  <rule>コードは TypeScript のみ使用</rule>
</constraints>

<examples>
  <!-- 具体的な例 -->
</examples>

<task>
  上記の制約に従って、以下を実装せよ。
</task>

5. 実際に差が出るシナリオ

シナリオ①:RAG のチャンク境界

RAG(Retrieval Augmented Generation)でドキュメントをチャンク分割するとき、Markdown は「どこで切るべきか」の判断がパーサー実装依存になる。

HTML の場合、<section> <article> <div> タグを境界として使えるため、意味のある単位でのチャンク分割 が容易だ。

# HTML ベースのチャンク分割(意味的な境界を利用)
from bs4 import BeautifulSoup

soup = BeautifulSoup(html_content, "html.parser")

# ① HTML 構造を保持したまま LLM に渡す場合(推奨)
# タグ・属性・ネスト構造がコンテキストとして残り、HTML で渡す利点を最大化できる
chunks_with_tags = [str(section) for section in soup.find_all("section")]

# ② 埋め込みベクトル化など、テキストのみ必要な場合
# get_text() を使うとタグ・属性などの構造情報はすべて失われる
# AI に構造ごと渡す用途では必ず①を使うこと
chunks_text = [s.get_text(separator=" ", strip=True) for s in soup.find_all("section")]

Markdown で同等の境界を定義するには、見出しレベルや空行など「あいまいな手がかり」に頼るしかない。HTMLタグは境界を明示的に宣言しているため、チャンク分割ツールが誤解する余地がない。

シナリオ②:システムプロンプトへの構造化コンテキスト渡し

<!-- XML ライクなタグによるシステムプロンプト構造化 -->
<persona>
  あなたはシニアバックエンドエンジニアです。
</persona>
<guidelines>
  <rule priority="high">型安全を最優先する</rule>
  <rule priority="medium">パフォーマンスより可読性を重視する</rule>
</guidelines>
<context>
  <codebase language="TypeScript" framework="Next.js 15" />
  <database type="PostgreSQL" orm="Prisma" />
</context>

priority 属性や自己閉鎖タグによるメタデータ付与は、Markdown では表現できない。

シナリオ③:テーブルの複雑な構造

財務比較表・仕様マトリクスなど、セル結合を含む複雑なテーブルを AI に渡して分析・変換させる場面では、Markdown ではその構造が正確に伝わらないことがある。

❌ Markdown テーブル(セル結合不可・複数行セル不可)

| A | B | C |
|---|---|---|
| 1 | 2 | 3 |

✅ HTML テーブル(完全な構造表現)

<table>
  <thead>
    <tr>
      <th colspan="2">グループA</th>
      <th>グループB</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="2">統合セル</td>
      <td>B1</td>
      <td>C1</td>
    </tr>
    <tr>
      <td>B2</td>
      <td>C2</td>
    </tr>
  </tbody>
</table>

シナリオ④:Markdown の構造誤解が積み重なるパターン

以下は RAG ドキュメントでよく遭遇する Markdown の構造的曖昧性の例だ。

## パラメータ

- `userId` — ユーザーID

    型: `string`(UUID形式)

    ```
    "550e8400-e29b-41d4-a716-446655440000"
    ```

CommonMark パーサーは 型: 以降をリストアイテムの継続として扱うが、パーサーによっては独立した段落として切り離す。RAG のチャンク境界がこのあたりに入ると「パラメータ名とその型情報が別チャンクに分断される」という問題が発生し、検索精度が落ちる。

HTML で書けばこの曖昧性はない:

<dl>
  <dt><code>userId</code> — ユーザーID</dt>
  <dd>
    型: <code>string</code>(UUID形式)
    <pre><code>"550e8400-e29b-41d4-a716-446655440000"</code></pre>
  </dd>
</dl>

<dt><dd> の対応関係はタグで明示されており、チャンク分割ツールが誤解する余地がない。


6. 「ではMarkdownはどこで使うべきか」

HTML が優れているからといって、すべてを HTML で書くべきというわけではない。HTML はMarkdownより冗長でトークン数が増える ため、コンテキスト窓の制限がある場面では逆にコストになる。

また、多くのMarkdownパーサーはHTMLタグを直接埋め込める。CLAUDE.md の中で <task><constraints> タグを Markdown に混在させる「ハイブリッドアプローチ」はその典型で、MarkdownとHTMLは排他的な選択ではない点も覚えておきたい。

トークンコストの具体例

同じ制約リストを Markdown と HTML で書いた場合の差を見てみよう。

Markdown(シンプルな制約リスト)

## 制約条件
- 応答は日本語で行うこと
- コードは TypeScript のみ使用
- テストは jest を使用

HTML(同等の内容)

<section data-role="constraints">
  <h2>制約条件</h2>
  <ul>
    <li>応答は日本語で行うこと</li>
    <li>コードは TypeScript のみ使用</li>
    <li>テストは jest を使用</li>
  </ul>
</section>

目安として、HTML 版は Markdown 版の 1.2〜2倍程度のトークン数 になることが多い。英語中心のコンテンツでは 1.5〜2倍に近づきやすいが、日本語では本文テキスト側のトークン比率が高くなるため 1.2〜1.5倍程度に収まるケースも多い。また cl100k_base(GPT-4系)と o200k_base(GPT-4o系)など tokenizer が異なると同じテキストでもトークン数が変わるため、精度が必要な場面では使用モデルの tokenizer で手元計測を推奨する。

# tiktoken による実計測例
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
print(f"Markdown: {len(enc.encode(md_sample))} tokens")
print(f"HTML:     {len(enc.encode(html_sample))} tokens")

ドキュメント全体で積み重なると数百〜数千トークンの差になる。適材適所の整理が重要だ。

構造化データには JSON も有力

構造化データを LLM に渡す用途では JSON も重要な選択肢だ。Function Calling / Tool Use の入力形式として標準的であり、JSON Schema とセットで使えば LLM が値の型・制約を把握しやすい。ただし JSON はプロセス間通信・ツール連携向きであり、人間が読む指示書や RAG ドキュメントには向かない。

ユースケース別の推奨形式

なお Claude は Anthropic 公式ドキュメントで XML ライクなタグを明示推奨している。他モデル(GPT、Gemini 等)では公式の推奨形式が異なる場合があるため、使用するモデルのドキュメントも参照してほしい。

ユースケース 推奨形式 理由
人間が手書きするドキュメント Markdown 可読性・編集効率
Git 管理の README Markdown GitHub/GitLab の描画
AI へのシステムプロンプト XML ライクなタグ / HTML 構造的明瞭性(Claudeの公式推奨はXMLタグ。他モデルは各ドキュメント参照)
RAG のソースドキュメント HTML or 構造化 Markdown チャンク精度(ただしトークンコストに注意)
AI が出力するレポート Markdown / HTML(明示指定時) デフォルトはMarkdown。HTML明示指定時は構造が安定しやすい
CLAUDE.md などの AI 指示書 構造化 Markdown + XMLブロック混在 可読性と精度の両立
構造化データ(Tool Use / Function Calling) JSON LLMのFunction Calling入力形式として標準。スキーマ定義とセットで使える

CLAUDE.md のような「AIが読む指示書」 については、完全 HTML 移行は現実的でない。しかし「構造が複雑なセクション(制約・優先度・メタデータ)だけ XML ライクなタグで記述する」ハイブリッドアプローチが現状ベストに近い。


まとめ

Markdown が「AI に有利」と思われてきた理由は、「人間が書きやすい = AI にも読みやすい」という等号が成立すると思われていたからだ。しかしこれは 「わかりやすく書かれたメモ = 機械が正確に解析できるフォーマット」 という混同だ。

AI の解釈精度を高めるには、構造的曖昧性が少なく、自己記述的な形式 を選ぶことが一つの指針になる。HTML や XML ライクなタグはその候補の一つだ。ただし「HTML が常に優れている」のではなく、トークン効率・可読性・編集のしやすさとのトレードオフ の中で選択する問題だ。

AI 時代のドキュメント設計では「人間が読みやすいか」と「AI が誤解しにくいか」を 別軸として評価する 必要がある。

Markdown は人間向け可読性で圧勝する。しかし AI への指示・コンテキスト・知識ベースという用途では、HTML や XML ライクな構造の方が適した場面が確実に存在する。その使い分けを意識するだけで、AI の出力品質は改善できる可能性がある。


参考

Discussion

okikusanokikusan

私個人はYAMLがAIが読みやすい形ですかね!
人間が読みやすいのはhtmlでこちらはAnthropicのブログでも推奨されております
人間が読みやすい優先順位は、

  1. Html
  2. MD
  3. YAML/XML
    といった形ですかね
1