llms.txtの設置と検証:Astroでの生成、配信・リンク確認、クロールの観察
llms.txt v2の提案を基に、書式と設置場所、Astroでの自動生成、配信・書式・リンクの検証、Search Consoleでの観察を整理します。検索効果とは分けて扱います。
llms.txtは、サイトの資料を見つけやすくするためのMarkdownの案内ファイルです。導入するときは、誰が何のために読むのかを決め、リンク先を維持できる範囲に絞ります。検索順位やAI引用を保証する仕組みとしては扱いません。
後半では、codeagent.jpがAstroでllms.txtとllms-full.txtを生成している実装、生成物の検証、Search Consoleで見えた取得の記録を載せます。実測値と観察は、いずれも2026年9月14日時点のものです。
v2提案で確認した書式と設置場所
提案元は2026年8月にv2へ更新されています。H1のサイト名を基本に、概要、見出しごとのリンク、説明を書きます。設置場所はルートだけでなくサブパスも想定され、その配下の資料を案内します。資料には読みやすいMarkdown版へのリンクを使う提案も含まれます。
以下は実在するサービスの一覧ではなく、書式を試すための架空例です。
# Example Tools
> 小さなCSV変換ツールの公開ドキュメント。
## 利用ガイド
- [入力形式](https://example.com/docs/input.md): 列名、文字コード、許容する空欄- [エラー一覧](https://example.com/docs/errors.md): メッセージ別の確認手順
## Optional
- [変更履歴](https://example.com/docs/changelog.md): バージョンごとの変更実サイトへ設置するときは、例のドメインをそのまま残さず、公開済みの資料へ置き換えます。サブパスに限定するなら /docs/llms.txt のように管理対象に近い場所を選べます。
Astroで配信して確かめる
静的ファイルとして置く
静的ファイルとして扱う場合は public/llms.txt、サブパスなら public/docs/llms.txt に保存します。ビルド後の出力と公開URLの両方を確認してください。確認の手順は次の節にまとめます。
記事コレクションから生成する
記事が増えるサイトでは、手書きのリンク一覧は更新が漏れやすくなります。Astroの静的ファイルエンドポイントは、src/pages/ に .ts を置いて GET をexportする仕組みです。公式ドキュメントのとおり、ファイル名がそのまま出力パスになり(llms.txt.ts → /llms.txt)、静的ビルドではビルド時に呼ばれて本文がファイルとして書き出されます。
codeagent.jpの src/pages/llms.txt.ts の骨格です(固定リンクの部分は省略)。
import { getCollection } from 'astro:content';import type { APIContext } from 'astro';import { SITE } from '@/consts';import { CATEGORIES } from '@/data/categories';
export async function GET(context: APIContext) { const baseUrl = (context.site ?? new URL(SITE.url)).toString().replace(/\/$/, '');
// 除外ルール: draft: true の記事は載せない。新しい順に並べる const posts = (await getCollection('posts', ({ data }) => !data.draft)).sort( (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(), );
const lines: string[] = []; lines.push(`# ${SITE.name}`); // H1: サイト名 lines.push(''); lines.push(`> ${SITE.description}`); // 引用ブロックの概要 lines.push(''); lines.push('## サイト基本情報'); lines.push(''); lines.push(`- 名称: ${SITE.name}`); lines.push(`- URL: ${baseUrl}/`); lines.push(`- Sitemap: ${baseUrl}/sitemap-index.xml`); lines.push('');
// カテゴリごとに H2 を切り、[title](url): description のリストにする for (const category of CATEGORIES) { const inCategory = posts.filter((p) => p.data.category === category.name); if (inCategory.length === 0) continue; lines.push(`## ${category.name}`); lines.push(''); lines.push(category.description); lines.push(''); for (const post of inCategory) { lines.push(`- [${post.data.title}](${baseUrl}/posts/${post.id}/): ${post.data.description}`); } lines.push(''); }
lines.push('## ツール'); lines.push(''); // ...ツール・固定ページのリンクが続く
return new Response(lines.join('\n'), { headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'public, max-age=3600' }, });}設計上の判断は3つです。
- 除外ルールはfrontmatterに寄せる。
draft: trueなら載せません。noindexのタグページなどはそもそもpostsコレクションに無いので、ここでは扱いません。 - URLは
context.siteから作る。astro.config.mjsのsiteを変えれば全リンクが追従します。相対パスにしないのは、読み手がファイルをどこから取得したか分からない場合でも、リンクを解決できるようにするためです。 - 説明文は
descriptionをそのまま使う。 提案の「:の後の説明」に当たります。記事のdescriptionを100〜160字で書く運用にしているので、1行が長くなりすぎません。
llms-full.txtを追加する場合
全文をまとめるllms-full.txtを追加する場合は、対象範囲と更新処理を先に決めます。本文を二重に保守すると訂正漏れが起きるため、同じ原稿から生成し、下書き・非公開情報が混ざらないことをビルド時に検査します。
2026年9月14日に確認した提案にはllms-full.txtの定義がなく、全文を1ファイルに連結する慣行として扱っています。出さなくてもllms.txtは成立します。codeagent.jpの llms-full.txt.ts は、同じコレクションを本文ごと連結します。要点だけ抜きます。
function stripMdxImports(body: string): string { return body .replace(/^import\s+.+from\s+['"][^'"]+['"];?\s*$/gm, '') .replace(/^\s*\n+/, '');}
// ...posts の取得は llms.txt.ts と同じfor (const post of posts) { out.push(`# ${post.data.title}`); out.push(`URL: ${baseUrl}/posts/${post.id}/`); out.push(`Published: ${post.data.pubDate.toISOString().slice(0, 10)}`); if (post.data.updatedDate) out.push(`Updated: ${post.data.updatedDate.toISOString().slice(0, 10)}`); out.push(`Category: ${post.data.category}`); out.push(`Tags: ${post.data.tags.join(', ')}`); out.push(''); out.push(`> ${post.data.description}`); out.push(''); out.push(stripMdxImports(post.body ?? '')); out.push('---');}post.body はレンダリング前のMDXテキストです。import行だけ落としても、本文中の部品タグは残ります。この問題は後の節で扱います。
生成物を配信・書式・リンクの3段で検証する
生成しているからといって、出力が正しいとは限りません。公開URLから取得したファイルで、配信、書式、リンクの順に確認します。
配信
curl.exe -I https://example.com/llms.txtcurl.exe https://example.com/llms.txtこのコマンドは自分の公開URLに置き換えて実行します。成功時の確認点は、200応答、期待する本文、適切なテキストのContent-Type、ログイン画面やエラーページでないことです。
codeagent.jpで確認したときの応答ヘッダーは次のとおりでした。
HTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8Cache-Control: public, max-age=0, must-revalidateContent-Type は期待どおりでしたが、Cache-Control はソースに書いた max-age=3600 ではありませんでした。静的ビルドではエンドポイントの戻り値のうち本文だけがファイルになり、ヘッダーはホスティング側(ここではCloudflare Pages)の設定で決まります。変えたい場合は public/_headers に書きます。Response に書いても反映されません。
書式
llmstxt.orgの提案を項目に分け、codeagent.jpの生成物と突き合わせました。
必須要素と基本形は満たしていました。満たしていないのはOptionalセクションと各ページの .md 版の2つで、どちらも任意です。.md 版はAstroなら src/pages/posts/[slug].md.ts のような動的エンドポイントで出せますが、全文版の抽出品質を直してから着手する予定です。
リンク
llms.txt内のURLをすべて抜き出して確認しました。
curl -s https://codeagent.jp/llms.txt > llms-live.txtgrep -o '](https://codeagent.jp[^)]*)' llms-live.txt | sed 's/^](//; s/)$//' | sort -u > llms-urls.txtwc -l llms-urls.txt # 116
fail=0while read u; do c=$(curl -s -o /dev/null -w '%{http_code}' "$u") [ "$c" != "200" ] && { echo "$c $u"; fail=$((fail+1)); }done < llms-urls.txtecho "non-200: $fail"116 llms-urls.txtnon-200: 0116 URL(記事106件、ツール・固定ページ、全文版へのリンク)はすべて200でした。記事のリンクはコレクションから作るため古くなりにくい一方、ツールや固定ページは手書きの文字列なので、ページを消したときにここが古くなります。
デプロイ後にまとめて回す
3段の確認を一つにまとめると、次の形になります。
#!/usr/bin/env bash# llms.txt 検証: 配信 / 書式の最低条件 / リンク生存set -eBASE="https://codeagent.jp"curl -sf "$BASE/llms.txt" -o /tmp/llms.txthead -1 /tmp/llms.txt | grep -q '^# ' || { echo "H1 がない"; exit 1; }sed -n 3p /tmp/llms.txt | grep -q '^> ' || echo "warn: 引用ブロックがない"grep -o '](https://[^)]*)' /tmp/llms.txt | sed 's/^](//; s/)$//' | sort -u > /tmp/urls.txtfail=0while read u; do c=$(curl -s -o /dev/null -w '%{http_code}' "$u") [ "$c" != "200" ] && { echo "$c $u"; fail=$((fail+1)); }done < /tmp/urls.txtecho "links: $(wc -l < /tmp/urls.txt), non-200: $fail"[ "$fail" -eq 0 ]デプロイ前後の確認全体はAstro × Cloudflare Pagesのリリースゲートで扱っています。
全文版に残るMDXの部品タグ
全文版の中で行頭が < の行は581行、うち大文字で始まる部品タグの行が299行ありました。内訳は <Callout 120、<StatGrid 48、<Compare 44、<Timeline 33、<BarChart 26、<DiagramFrame 14、<PullQuote 11など。加えて <div class="summary-box"> が45箇所です。
StatGrid の stats 配列のようなJSX属性は、Markdownとしては意味のない文字列です。全文版を出していても、部品の中の数値や比較表は構造として伝わっていません。部品を使う編集方針と、全文版の作り方がかみ合っていない状態です。
部品タグを落とす案(本番には未適用)
本番のコードはまだ変えていません。取得した全文版に対して、部品の種類ごとに処理を分ける関数を手元で試しました。
// 自己閉じで使う構造部品は、開始行から行末が "/>" の最初の行までを丸ごと落とす// 開閉タグ型 (Callout など) はタグ行だけ落として中身の本文は残すconst stripped = body .replace(/^<(StatGrid|Compare|Timeline|BarChart)\b[\s\S]*?\/>[ \t]*$/gm, '') .replace(/^<(Callout|PullQuote|DiagramFrame)\b[^\n]*>[ \t]*$/gm, '') .replace(/^<\/(Callout|PullQuote|DiagramFrame)>[ \t]*$/gm, '') .replace(/^<div class="summary-box">[ \t]*$/gm, '') .replace(/^<\/div>[ \t]*$/gm, '') .replace(/\n{3,}/g, '\n\n');before: 行頭 < の行 581 / 部品タグ行 299 / 1,661,810 bytesafter : 行頭 < の行 55 / 部品タグ行 10 / 1,531,703 bytes残り: DiagramFrame 7, svg 8, figure 6, script 3 ほか(インライン SVG と生 HTML)タグ行は299行から10行に減り、130KBほど軽くなりました。残るのは DiagramFrame(caption属性が複数行)と、記事内に直接書いたSVGやHTMLです。
最初に試した「<大文字 から次の /> まで」という大まかな正規表現は、<Callout> の開始行から遠く離れた別部品の /> までを飲み込み、1.66MBが0.90MBになりました。本文を消していたわけです。部品の種類ごとに閉じ方を分けないと危険だということが、手元の試行で分かりました。
正規表現には限界があります。確実にするなら、StatGrid の stats や Compare の rows をMarkdownの表に変換する処理を書くか、MDXを一度レンダリングしてからテキスト化するかのどちらかです。前者は部品の中身まで伝わるため、次の改修候補にしています。全文版を出すなら、本文の抽出品質を一度は目で確認し、月に1回程度は行頭 < の行数を数えて増えていないかを見ます。
アクセス許可とは別に管理する
llms.txtにリンクを書いても、認証やrobots.txtのアクセス方針が変わるわけではありません。検索用botと学習用botの扱いは用途別のクローラー解説で確認します。
逆に、クローラー側がllms.txtをどう扱うかは、確認した範囲では書かれていません。2026年9月14日に4社のクローラーの公式ページを読んだ時点では、他サイトのllms.txtを読む、尊重する、引用に使うという記述はありませんでした。
| 事業者 | 確認したクローラー | 他サイトのllms.txtへの言及 |
|---|---|---|
| OpenAI | GPTBot、OAI-SearchBot、ChatGPT-User | なし |
| Anthropic | ClaudeBot、Claude-User、Claude-SearchBot | なし |
| Perplexity | PerplexityBot、Perplexity-User | なし |
| Google-Extended | なし |
OpenAIとPerplexityのページには自社ドキュメントのllms.txtへの案内がありますが、それは自社の資料の案内です。クローラーが第三者のllms.txtをどう扱うかの説明ではありません。
codeagent.jpのrobots.txtは主要なAIクローラーを個別に列挙しています。同日に照合すると、Anthropicの現行ページに載っていない Claude-Web と anthropic-ai が残り、現行の Claude-User と Claude-SearchBot は列挙されていませんでした。列挙していないbotには User-agent: * のグループが適用されます。列挙した一覧は古くなるため、公式ページと定期的に照合します。
社内資料や秘密情報の保護をrobots.txtだけに任せることも避けます。公開してよい資料だけを案内し、アクセス制限が必要な資料には認証を使います。
観察記録:Search Consoleで見えた取得
インデックス登録状況の「クロール済み・インデックス未登録」に、/llms.txt と /llms-full.txt が含まれていました。URL検査で開くと、どちらにも前回のクロールが記録されていました。
この観察から言えるのは2つです。Googlebotが両ファイルを取得していること、そして検索インデックスには登録されていないことです。llms.txtはサイトマップに載せていませんが、取得されていました。どの経路で見つかったかは確認していません。案内ファイルとして使う目的では、未登録であることを不具合として扱っていません。
言えないのは、AIサービスに読まれた、引用されたということです。Search Consoleが示すのはGooglebotの取得です。GPTBotやClaudeBot、PerplexityBotが /llms.txt を取得したかは、サーバー側でUser-Agent別のアクセスログを取らないと分かりません。codeagent.jpはCloudflare Pagesで配信していて、この時点では生ログを集計する仕組みを持っていなかったため、観測できていません。
「配信できた」と「効果があった」を分ける
Googleの説明では、AI機能への掲載に特別なAI用テキストファイルは不要です。llms.txtが無いことだけで検索上の不備とは判断できません。
「取得された」「読まれた」「効いた」は別の事実です。前の節の観察で言えるのは最初の一つだけです。llms.txtの有無だけを変えた比較もしていないため、効果は切り出せません。効果を断定している説明を見たら、その根拠が観測データなのか、提案文の言い換えなのかを確認してください。
導入を評価するなら、まず「この案内を渡された利用者が必要な資料へ到達できるか」を試します。質問、使用したファイル、参照されたページ、誤った参照を記録してください。これは案内の使いやすさの試験です。自然検索やAI検索の引用増加を示す試験とは別です。
アクセスログの取得も、ページが引用された証拠ではありません。チェッカーのllms.txt欄も配信状況の参考表示で、加点対象にはしていません。
観測できる状態に近づける
codeagent.jpが両ファイルを置いているのは、記事コレクションから生成していて手作業の保守が小さいためで、効果を確認したからではありません。全文版の抽出品質という保守課題も残っています。観測できていないものについては、次の順で記録を増やす予定です。
- User-Agent別のアクセスログを取る。 Cloudflareのログ機能か、
/llms.txtへのリクエストをWorkersで数える仕組みを足します。AIクローラーが取得したかどうかは、これでしか分かりません。 - AI検索での引用を定期的に手動で確認する。 サービス名、日付、質問文、引用URLを残します。llms.txtの有無との因果は分かりませんが、そもそも引用されているかの基準線になります。記録の取り方はAI検索向けのサイト点検と共通です。
- robots.txtのUser-Agent一覧を公式ページと照合する。 半年に1回を目安に、各社のページと突き合わせます。
- Search Consoleで前回のクロールを定点で見る。
/llms.txtの記録が更新され続けていれば、Googlebot側の取得は続いています。
必要性と保守コストを比べ、使い道がある場合に導入してください。
関連して読む
aeo・ai-searchを続けて読む
· 参考リンク 16件AIクローラーのUser-Agent一覧とrobots.txtの書き方【2026年9月版】
OpenAI・Anthropic・Perplexity・Google・Apple・Meta・Amazon・Common Crawl・BingのAIクローラーを、目的・robots.txtの扱い・IP範囲の公開有無とともに公式ページで一覧化。方針別の書き方とCloudflareでの制御も2026年9月14日に確認。
aeo・llms-txtを続けて読む
· 参考リンク 3件AI検索向けのサイト点検:取得・本文・根拠と、流入が少ない原因の切り分け
AI検索対策の必須条件と任意の整備を分け、robots.txt、本文、測定記録を点検します。流入が少ないときの切り分け方と、CodeAgentの診断ツールを修正した例も掲載。
この記事の情報・検証メモ
- 公開日
- 情報確認
- 参考リンク
- 7件
- 更新性
- 長く使える
仕様・料金・提供範囲が変わりやすいテーマは、公開日・更新日・情報確認日を分けて管理します。 導入前には必ず記事末尾の一次情報と公式ドキュメントで最新状況を確認してください。
一次情報・参考リンク
- The /llms.txt file v2 https://llmstxt.org/
- Google検索のAI機能 https://developers.google.com/search/docs/appearance/ai-features?hl=ja
- Astro Docs: Endpoints (Static File Endpoints) https://docs.astro.build/en/guides/endpoints/
- OpenAI: Overview of OpenAI Crawlers https://developers.openai.com/api/docs/bots
- Anthropic: Does Anthropic crawl data from the web https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler
- Perplexity: Crawlers https://docs.perplexity.ai/guides/bots
- Google Search Central: Google common crawlers https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers