Playwright로 LLMO 자동 테스트

llms.txt, JSON-LD, URL.md를 CI에서 지속 검증하기

by AI개발자
ChatGPT, Claude, Gemini에게 인용되는 사이트 설계법.png

1. 왜 테스트가 필요한가?

LLMO는 설정이 아니라 “지속적으로 검증해야 하는 시스템”입니다.

llmo-035.png

Playwright 자동 테스트를 GitHub Actions에 통합하면

git push마다 LLMO 대응 상태를 자동으로 검증할 수 있습니다.

09-01-01.png

그리고 이 챕터에 이 문장 하나 추가하면 굉장히 좋습니다.

그래프 아래에 넣는 것을 추천합니다.


LLMO 테스트는 “AI가 사이트를 정상적으로 읽을 수 있는가”를 검증하는 테스트입니다.


왜냐하면 이 문장이 들어가면 독자가 바로 이해합니다.


기존 테스트 → UI 동작 확인

LLMO 테스트 → AI 접근성 확인


LLMO 사이트는 “AI 친화적 설계 + 자동 검증” 두 가지가 함께 있어야 완성됩니다.



2. 테스트 구성

이 테스트들은 “AI가 사이트를 정상적으로 발견하고, 읽고, 이해할 수 있는가”를 자동으로 검증합니다.

llmo-036.png

그리고 이 부분 아래에 한 줄 더 추가하면 구조가 매우 명확해집니다.

각 테스트는 LLMO의 핵심 구성요소 하나를 검증합니다.


robots.txt → AI 크롤러 접근 가능 여부

llms.txt → AI 사이트 가이드 존재 여부

JSON-LD → 구조화 데이터 정상 여부

URL.md → AI용 Markdown API 존재 여부

/ai/ → AI 요약 데이터

/docs/ → 기술 상세 문서


LLMO 사이트는 “AI가 읽을 수 있는 구조”와 “그 구조가 깨지지 않았음을 보장하는 테스트” 두 가지로 완성됩니다.



3. 공통 헬퍼

GitHub Pages는 /repo-name/ 같은 서브패스를 사용하기 때문에, 테스트에서 URL을 자동으로 보정하는 헬퍼가 필요합니다.


Playwright 테스트에서는 로컬 환경(http://localhost:4321)과 GitHub Pages(https://user.github.io/repo-name/) 두 가지 URL 구조를 모두 지원해야 합니다.


이를 위해 BASE_PATH 환경 변수를 기반으로 URL을 생성하는 공통 헬퍼 함수를 사용합니다.


tests/helpers.ts


export const BASE = process.env.BASE_PATH ?? '';


export function url(path: string): string {

const base = BASE || '';


if (path.startsWith('/')) {

return `${base}${path}`;

}


return path ? `${base}/${path}` : base || '/';

}


동작 방식


로컬 개발 환경

BASE_PATH = ""


url("/robots.txt")

→ /robots.txt


GitHub Pages

BASE_PATH = "/repo-name"


url("/robots.txt")

→ /repo-name/robots.txt



왜 필요한가?

GitHub Pages는 다음과 같은 서브패스 URL 구조를 사용합니다.


https://username.github.io/repository-name/


따라서 테스트 코드에서 단순히


request.get('/robots.txt')


처럼 작성하면 GitHub Pages 환경에서는 404가 발생할 수 있습니다.

공통 헬퍼를 사용하면 테스트 코드를 다음처럼 환경에 독립적으로 작성할 수 있습니다.


request.get(url('/robots.txt'))


테스트 코드는 환경에 의존하지 않아야 합니다.



4. robots.txt 테스트

이 테스트는 AI 크롤러가 사이트에 접근할 수 있는지 자동으로 검증합니다.


LLMO 사이트에서는 robots.txt가 매우 중요한 파일입니다.

AI 크롤러가 사이트를 크롤링하려면 robots.txt에서 접근이 허용되어 있어야 하기 때문입니다.


따라서 다음 항목을 자동으로 검증합니다.

robots.txt 존재 여부

GPTBot 허용 여부

ClaudeBot 허용 여부

네이버 Yeti 허용 여부

Sitemap URL 포함 여부


tests/llmo/robots-txt.spec.ts


import { test, expect } from '@playwright/test';

import { url } from '../helpers';


test.describe('robots.txt', () => {

test('robots.txt 가 존재한다', async ({ request }) => {

const res = await request.get(url('/robots.txt'));

expect(res.status()).toBe(200);

});


test('GPTBot 이 허가되어 있다', async ({ request }) => {

const res = await request.get(url('/robots.txt'));

const text = await res.text();

expect(text).toContain('GPTBot');

expect(text).toContain('Allow');

});


test('ClaudeBot 이 허가되어 있다', async ({ request }) => {

const res = await request.get(url('/robots.txt'));

const text = await res.text();

expect(text).toContain('ClaudeBot');

});


// ⭐ 한국 환경 추가 — 네이버 크롤러 검증

test('Yeti (네이버 봇) 가 허가되어 있다', async ({ request }) => {

const res = await request.get(url('/robots.txt'));

const text = await res.text();

expect(text).toContain('Yeti');

});


test('Sitemap URL이 포함되어 있다', async ({ request }) => {

const res = await request.get(url('/robots.txt'));

const text = await res.text();

expect(text).toContain('Sitemap:');

});

});


검증 포인트

llmo-037.png


5. llms.txt 테스트

이 테스트는 AI가 사이트 구조를 올바르게 발견할 수 있는지 검증합니다.

LLMO에서 llms.txt는 AI가 사이트를 처음 이해할 때 읽는 “입구 파일(entry point)”입니다.

따라서 다음 항목들이 정상적으로 동작하는지 자동으로 검증합니다.


llms.txt 존재 여부

llms-full.txt 존재 여부

/ai/ 디렉토리 링크 존재

/docs/ 디렉토리 링크 존재

지금 바로 작가의 멤버십 구독자가 되어
멤버십 특별 연재 콘텐츠를 모두 만나 보세요.

brunch membership
AI개발자작가님의 멤버십을 시작해 보세요!

AI Workflow Architect, LLM Engineer, Vibe Engineering, Claude Code, AI 업무 자동화 컨설팅/AI강의

82 구독자

오직 멤버십 구독자만 볼 수 있는,
이 작가의 특별 연재 콘텐츠

  • 최근 30일간 14개의 멤버십 콘텐츠 발행
  • 총 34개의 혜택 콘텐츠
최신 발행글 더보기
이전 08화URL.md 패턴이란?