
# Markdown для агентов: Accept: text/markdown

Агент запрашивает вашу страницу и получает HTML. Затем выбрасывает почти всё: навигацию, подвал, баннер о куках, встроенные скрипты, атрибуты классов, иконки SVG. Остаётся несколько абзацев текста.

Та версия, которая ему была нужна, у вас уже есть. Просто почти никто её не отдаёт.

## Во что обходится разметка

Сравните то, что вы отправляете, с тем, что выживает:

```bash
curl -s https://example.com/about | wc -c
curl -s -H "Accept: text/markdown" https://example.com/about | wc -c
```

Если числа совпали, значит вы отдаёте одно представление всем подряд, а вычищать приходится самому агенту. Эта работа не бесплатна. Всё содержимое `<head>`, каждый обёрточный `<div>`, каждый атрибут `data-` и каждый фрагмент аналитики попадают в контекстное окно раньше, чем что-либо решит, что это был шум. На странице, реальное содержимое которой — заголовок и восемь абзацев, большая часть байтов приходится на леса.

Двойник в Markdown сохраняет уровни заголовков, ссылки, списки, таблицы и блоки кода. Он теряет навигацию, оформление и скрипты, из которых всё равно ничего никогда не процитировали бы.

## Как работает согласование через Accept

Клиент сообщает, что он умеет читать:

```
GET /about HTTP/1.1
Host: example.com
Accept: text/markdown
```

Сервер выбирает представление для того же самого URL:

```
HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept
```

Браузер отправляет `Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8` и получает HTML. Клиент, запросивший `text/markdown`, получает Markdown. Канонический URL не меняется, поэтому по-прежнему есть один адрес для ссылки и одна страница, которой можно поделиться.

## Vary: Accept, или как браузер скачивает текстовый файл

`Vary` не опция, и именно эту часть обычно пропускают.

Любой кеш между вами и читателем — ваш CDN, обратный прокси, хранилище самого браузера — индексирует ответы по URL. Если вы отдаёте по одному URL два разных тела и не сообщаете об этом, первый закешированный ответ достанется всем. Агент запрашивает `/about` с `Accept: text/markdown`, ваш CDN сохраняет Markdown, и следующий человек, открывший `/about`, видит страницу из звёздочек или окно загрузки файла.

```
Vary: Accept
```

Эта строка велит кешу включить заголовок `Accept` в ключ, и тогда HTML и Markdown хранятся раздельно. Отправляйте её в **обоих** ответах, а не только в том, что с Markdown.

Плата вполне реальна: заголовки `Accept` сильно различаются между клиентами, поэтому варьирование по ним дробит кеш. Это честный довод в пользу следующего варианта.

## Двойник .md

Более простой путь — второй URL. `/about` отдаёт HTML, `/about.md` отдаёт то же содержимое в Markdown. Никакого согласования, никакого `Vary`, нечему ломаться в кеше. Это обычный URL, значит его можно поставить ссылкой, положить в закладки, включить в карту сайта и скачать любым клиентом, в том числе таким, который вообще не присылает пригодного заголовка `Accept`.

А потом сообщите, что он существует. В HTML:

```html
<link rel="alternate" type="text/markdown" href="https://example.com/about.md">
```

И в заголовках ответа — для тех, кто делает `HEAD` и никогда не разбирает тело:

```
Link: <https://example.com/about.md>; rel="alternate"; type="text/markdown"
```

Сделать оба варианта стоит по одной строке и покрывает клиентов, которые смотрят только в одно место.

## Проверьте свой сайт

```bash
# 1. Отвечает ли один и тот же URL по-разному?
curl -s -H "Accept: text/markdown" https://example.com/about | head -20

# 2. Признаёт ли HTML-ответ, что двойник существует?
curl -sI https://example.com/about | grep -i "vary\|link"

# 3. Работает ли URL с .md сам по себе?
curl -sI https://example.com/about.md | grep -i "content-type\|vary"
```

Вторая команда ловит самую распространённую поломку. У сайта может быть безупречный двойник `.md`, которого никто никогда не найдёт, потому что на него не указывают ни заголовок, ни тег.

## Что делаем мы

У каждой страницы этого сайта есть двойник в Markdown, и весь механизм умещается в `packages/web/src/lib/content-negotiation.js` — около девяноста строк.

Фиксированная таблица перечисляет статические пути и их двойников: `/` → `/index.md`, `/about` → `/about.md`, каждая страница инструмента и так далее. Пути с идентификатором или слагом — отчёты вида `/r/<uuid>`, руководства, записи блога вроде этой — определяются по шаблону и получают `<путь>.md`.

Проверка запроса намеренно грубая: если заголовок `Accept` содержит строку `text/markdown`, отдаём Markdown. Никакого ранжирования по значениям `q`. Браузер эту строку не присылает никогда, так что на практике случаи разделяются чисто, но клиент, указавший `text/markdown` с низким приоритетом, тоже получит Markdown.

Каждый ответ в Markdown уходит с такими заголовками:

```
Content-Type: text/markdown; charset=utf-8
Content-Signal: search=yes, ai-input=yes, ai-train=no
Vary: Accept
X-Markdown-Tokens: 4213
Cache-Control: public, max-age=3600
```

`Content-Signal` говорит, что можно делать с содержимым, а не только можно ли его скачать. `X-Markdown-Tokens` — метка размера: сегодня в ней число символов тела, а не настоящий подсчёт токенов.

HTML-ответы страницы, у которой есть двойник, получают `Vary: Accept` и заголовок `Link`, а в `<head>` попадает тег `rel="alternate"` из той же таблицы.

Эта последняя деталь нас укусила. Шаблон брал данные из таблицы, но маршруты, определяемые по шаблону, в таблицу не входили. Поэтому каждый отчёт об анализе отдавал свой двойник в Markdown и объявлял его в заголовке `Link`, а его HTML не говорил об этом ни слова. Двойник существовал и оставался невидимым для всего, что читает разметку.

## Это соглашение, а не стандарт

`Accept: text/markdown` — обычное согласование содержимого HTTP, и вот оно как раз стандарт. Использовать его для Markdown — соглашение, выросшее из предложения llms.txt, и ни один краулер не обязан о нём спрашивать. Честная позиция такая: надёжно работает именно двойник `.md`, потому что это URL как любой другой и скачать его может что угодно, а согласование стоит одного заголовка и окупается на тех клиентах, которые спрашивают. Ни то ни другое вам не повредит, а узнать, что из этого используется, можно по логам, а не по объявлениям.

[Проверьте своё согласование Markdown](/ru/tools/markdown-tester) · [Сгенерируйте свой llms.txt](/ru/tools/llms-txt-generator)
