## コンテンツネゴシエーションとは?

コンテンツネゴシエーションとは、クライアントが求めるものに応じて異なるレスポンスを返すことです。AI エージェントの場合、エージェントからのリクエストに対して、重い HTML ではなく構造化されたテキスト(JSON、マークダウン、プレーンテキスト)を返すことを意味します。

## なぜ重要か

AI エージェントはモデルがコンテンツを見る前に HTTP ヘッダーを取り除きます。モデルは Content-Type もステータスコードもリダイレクトチェーンも見ることはなく、ボディテキストだけを見ます。HTML を返すと、エージェントは DOM 構造をパースし、テキストを抽出し、レイアウトを捨てる必要があります — トークンを浪費し、意味を失います。

## 何をチェックするか

**エージェント UA が非 HTML を受け取る** — 既知の AI エージェント User-Agent (例: `ClaudeBot`) でリクエストを送り、レスポンスの Content-Type が `text/html` 以外になっているかを確認します。エージェント UA を検出して `text/markdown`、`text/plain`、`application/json` を返すサイトはこのチェックに合格します。

**Accept: JSON で JSON が返る** — `Accept: application/json` を送り、レスポンスが有効な JSON かを確認します。これにより、プログラムベースのエージェントが構造化データに直接アクセスできます。

**Accept: text で text が返る** — `Accept: text/plain` を送り、レスポンスがプレーンテキストまたはマークダウンかを確認します。これは言語モデルが消費するもっともシンプルな形式です。

**Accept: markdown で markdown が返る** — `Accept: text/markdown` を送り、レスポンスがマークダウンコンテンツ(Content-Type が `text/markdown`、または本文がマークダウン)かを確認します。これは、エージェントが構造(見出し、リスト、リンク)を欲しいが HTML の重さは不要、というときに好む形式です。

## 実装方法

サーバーのミドルウェアでエージェントの User-Agent と `Accept` ヘッダーを検出します:

```javascript
app.get('/', (req, res) => {
  const ua = (req.get('user-agent') || '').toLowerCase();
  const accept = req.get('accept') || '';
  const isAgent = /claude|gpt|anthropic|perplexity|gptbot/i.test(ua);

  // 明示的に要求された場合は markdown を優先
  if (accept.includes('text/markdown')) {
    return res.type('text/markdown').sendFile('[llms.txt](/kb/ja/llms-txt)');
  }

  if (accept.includes('application/json')) {
    return res.json({ name: 'My Service', api: '/openapi.json' });
  }

  if (isAgent || accept.includes('text/plain')) {
    return res.type('text/plain').sendFile('llms.txt');
  }

  res.sendFile('index.html');
});
```

### マークダウンの詳細

`Accept: text/markdown` は比較的新しい慣習(llms.txt エコシステムによって広まった)で、まだ普遍的には実装されていません。要求されたときにマークダウンを返すというのは、次のことを意味します:

- 本文は有効なマークダウン(見出し、リスト、リンク — HTML タグなし)
- Content-Type ヘッダーは `text/markdown`(または本文がマークダウンの `text/plain`)
- ブラウザに HTML を返している URL と同じ URL が、エージェントにマークダウンを返せる — パスは変わらず、表現だけが変わる

ドキュメントページ、ブログ投稿、コンテンツページについては、通常すでにマークダウンソースがあるはずです。`Accept: text/markdown` が送られたら、HTML に変換せずにそのソースを直接配信してください。

## 仕様の成熟度

**確立済み。** コンテンツネゴシエーションは HTTP 自身で定義されています ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110))。User-Agent や Accept に応じてエージェントに優しい形式を返す慣習は、AI 対応サイトで広く使われています。

## さらに詳しく

- [RFC 9110 §12: Content Negotiation](https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation)
- [llmstxt.org](https://llmstxt.org/) — LLM 向けマークダウン慣習

## 関連

- [OpenAPI](/kb/ja/openapi)
