robots.txtがWebクローラへの「立入禁止」の看板だとすれば、llms.txtはAIクローラへの「案内図」です。 どのページが重要で、サイトが何を提供しているかを、AIが読みやすい形で伝えます。

2024年後半に提唱されたllms.txtは、まだ仕様策定の初期段階にあります。 しかし、AIクローラがWebコンテンツをどう理解するかを考えると、早期に対応しておく価値のある仕組みです。

この記事では、llms.txtの仕様、記述方法、robots.txtとの違い、そして実際の導入手順を解説します。

llms.txtが生まれた背景

AI検索サービスは、Webページをクロールして情報を取得します。 しかし、従来のWebの仕組みには「AIにとって読みやすい形でサイト全体の概要を伝える手段」がありませんでした。

robots.txtはアクセス制御に特化しており、「このサイトはマーケティング支援の記事を提供している」「この10記事が特に重要」といった情報は伝えられません。 sitemap.xmlはURLの一覧と更新日を提供しますが、各ページの内容説明は含みません。

llms.txtは、これらの隙間を埋めるために提唱されました。

llms.txtの仕様

llms.txtの仕様は llmstxt.org で公開されています。 Markdown形式のテキストファイルで、サイトのルートディレクトリに配置します。

基本構造

# サイト名

> サイトの概要説明(1〜2文)

サイトの詳細な説明をここに書きます。

## セクション名

- [ページタイトル](URL): ページの簡潔な説明
- [ページタイトル](URL): ページの簡潔な説明
要素記法役割
サイト名H1(#サイトの名称。1つだけ
概要ブロック引用(>サイトの1行説明
セクションH2(##ページのカテゴリ分け。複数可
ページリンクMarkdownリンク個別ページへのリンクと説明

具体的な記述例

# Example Marketing Blog

> AI検索時代のマーケティング戦略を、技術的な根拠とともに解説するメディアです。

GEO(Generative Engine Optimization)に関する実践的な記事を中心に提供しています。

## GEO対策の基礎

- [OGPとメタタグのGEO最適化](https://example.com/blog/ogp-meta-geo): AIクローラが参照するメタ情報の設定方法
- [構造化データでAI検索の引用率を上げる](https://example.com/blog/knowledge-graph-structured-data): Schema.orgの実装ガイド

## 技術的な対策

- [IndexNowの導入方法](https://example.com/blog/indexnow-setup): 記事公開をAIにリアルタイムで通知する方法
- [CDN設定とAIクローラの相性](https://example.com/blog/cdn-ai-crawler): キャッシュがクロールを妨げるケースの対処法

## About

- [会社概要](https://example.com/about): 運営会社の情報

robots.txtとllms.txtの違い

観点robots.txtllms.txt
目的クロールの許可・拒否サイト内容の案内
対象すべてのクローラAIクローラ(LLM向け)
記述内容Allow / Disallow ルールサイト概要、ページ一覧、説明
フォーマット独自書式Markdown
標準化状況RFC 9309(2022年)提唱段階(llmstxt.org)

両方を設置するのが推奨です。 robots.txtでアクセス制御を行い、llms.txtでサイトの案内を行うという使い分けになります。

llms-full.txtとの違い

llms.txtの仕様には、llms-full.txtという拡張版も定義されています。 llms-full.txtは、サイト全体のコンテンツをMarkdownで結合したファイルです。

AIクローラが個別ページをクロールしなくても、1ファイルでサイト全体の情報を取得できます。 ただし、ファイルサイズが大きくなるため、主要なページのみを含める運用が現実的です。

コンテンツの無断利用リスクもあるため、ライセンスを明記した上で提供するかどうかを判断してください。

導入手順

手順1: llms.txtファイルを作成する

前述の記述例を参考に、サイトのルートディレクトリにllms.txtを作成します。

手順2: Webサーバーで配信する

Next.jsではpublic/llms.txtにファイルを配置するだけで配信されます。 動的に生成する場合は、Route Handlerを使います。

// app/llms.txt/route.ts
import { NextResponse } from 'next/server'

export async function GET() {
  const posts = await getAllPosts()
  const sections = posts.reduce((acc, post) => {
    const category = post.category || 'その他'
    if (!acc[category]) acc[category] = []
    acc[category].push(post)
    return acc
  }, {} as Record<string, typeof posts>)

  let content = `# My Marketing Blog\n\n`
  content += `> マーケティングの実践的な知見を提供するメディアです。\n\n`

  for (const [category, categoryPosts] of Object.entries(sections)) {
    content += `## ${category}\n\n`
    for (const post of categoryPosts) {
      content += `- [${post.title}](https://example.com/blog/${post.slug}): ${post.description}\n`
    }
    content += `\n`
  }

  return new NextResponse(content, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}

Astroではsrc/pages/llms.txt.tsにエンドポイントを作成します。

// src/pages/llms.txt.ts
import { getCollection } from 'astro:content'
import type { APIRoute } from 'astro'

export const GET: APIRoute = async () => {
  const posts = await getCollection('blog')
  const sorted = posts.filter(p => !p.data.draft)
    .sort((a, b) => new Date(b.data.publishedAt).getTime() - new Date(a.data.publishedAt).getTime())

  let content = `# Example Marketing Blog\n\n`
  content += `> AI検索時代のマーケティング戦略を解説するメディアです。\n\n`

  const categories = [...new Set(sorted.map(p => p.data.category))]
  for (const cat of categories) {
    content += `## ${cat}\n\n`
    for (const post of sorted.filter(p => p.data.category === cat)) {
      content += `- [${post.data.title}](https://example.com/blog/${post.slug}): ${post.data.description}\n`
    }
    content += `\n`
  }

  return new Response(content, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}

手順3: 配信を確認する

curl -s https://example.com/llms.txt
curl -sI https://example.com/llms.txt | grep -i content-type
# 期待値: Content-Type: text/plain; charset=utf-8

手順4: CIで自動更新する

手動管理では更新漏れが発生するため、デプロイ時の自動生成を推奨します。

# .github/workflows/generate-llms-txt.yml
name: Generate llms.txt
on:
  push:
    branches: [main]
    paths: ['src/content/**']
jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: node scripts/generate-llms-txt.mjs
      - run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git add public/llms.txt
          git diff --cached --quiet || git commit -m "chore: update llms.txt"
          git push

対応状況と注意点

2025年8月時点では、各AIサービスのllms.txt対応は明示的に公表されていないケースが多いです。 ただし、llms.txtはMarkdown形式の平文であるため、専用対応がなくても通常のWebページとしてクロールされれば内容は読み取られます。

ファイルサイズには注意が必要です。 ページ数は50〜100程度に絞り、各ページの説明文は具体的に記述します。

<!-- 推奨 -->
- [IndexNowの導入方法](URL): APIキーの取得からCMS別設定まで15分で完了する手順

<!-- 非推奨 -->
- [IndexNowの導入方法](URL): IndexNowについて解説します

まとめ

llms.txtは、AIクローラに対してサイトの構造と内容を効率的に伝えるための仕組みです。 robots.txtが「立入禁止の看板」なら、llms.txtは「フロアマップ」の役割を果たします。

仕様はまだ策定段階ですが、導入コストは低いため、GEO対策の一環として早期に対応しておくことを推奨します。