llms.txt 파일이 말하는 내용과 실제 사이트가 보여주는 수치 차이
요약
본 기사는 웹사이트에 배포되는 가상의 `llms.txt` 파일을 분석하며, 이 파일이 실제 사이트의 수치와 불일치하는 지점을 탐구합니다. 특히 LLM이 마케팅 페이지를 추측하지 않고 서비스 내용을 설명하도록 돕는 역할을 하는 '프롬프트 엔지니어링' 관점의 사례를 제시합니다.
핵심 포인트
- LLMs가 웹사이트 정보를 잘못 해석할 수 있음을 보여주는 예시입니다.
- 파일 내의 숫자가 서로 일관되지 않거나 오래된 정보일 수 있습니다.
- AI 모델이 생성한 텍스트도 내부적인 불일치성을 가질 수 있습니다.
CogniPrep은 llms.txt 파일을 배포합니다. 이 파일은 웹사이트의 루트 디렉토리에 위치하며, 해당 페이지에 접속한 어시스턴트가 마케팅 페이지를 추측하는 대신 그 서비스가 무엇인지 짧고 평이하게 설명할 수 있도록 하는 역할을 합니다. 저희 파일은 약 14KB 크기이며 읽기도 좋습니다. 물론 잘못된 정보도 포함하고 있으며, 몇 달 동안 계속 그렇게 되어 왔습니다.
다음 내용을 열어 다섯 번째 줄을 읽어보세요:
https://cogniprep.app/llms.txt
CogniPrep은 채용 전 평가를 앞둔 지원자를 위한 실습 플랫폼입니다. 14개의 평가 제공업체를 다루며, 85개의 브라우저에서 플레이 가능한 테스트 시뮬레이션을 포함합니다.
이제 다른 탭에서 카탈로그 페이지를 열어보세요:
제목 아래의 헤딩에는 "모든 56개가 다루어지고 있습니다"라고 적혀 있습니다. 각 제공업체 카드에는 고유한 개수가 표시되어 있으며, 이들을 콘솔에 붙여넣으면 총합을 얻을 수 있습니다:
const n = document.body.innerText.match(/(\d+)\s+games?\b/g).map(Number);
console.log(n.length, n.reduce((a, b) => a + b, 0));
// 56 372
56개의 제공업체, 372개의 테스트 시뮬레이션입니다. 기계가 추측할 필요가 없도록 존재하기 위해 만들어진 이 파일은 제품을 42개 제공업체와 287개 테스트만큼 과소평가하고 있습니다.
파일이 자기 자신과도 불일치하는 경우
흥미로운 점은 단순히 수치가 변동했다는 것이 아닙니다. 문제는 개시 문장의 숫자가 같은 파일의 나머지 부분, 심지어 다른 어떤 것에서도 파생되지 않았다는 것입니다.
llms.txt에는 18개의 ### 헤딩이 있습니다. 그중 네 개가 가격 섹션입니다. 나머지 14개는 제공업체이며, 각각은 제목에 고유한 개수를 가지고 있습니다. 예를 들어, ### Arctic Shores (14 games)와 같습니다. 이 14개 헤딩을 모두 더해 보세요:
const t = document.body.innerText; // /llms.txt에서
const secs = [...t.matchAll(/^### (.+)$/gm)].map(m => m[1]);
const counts = secs.map(s => (s.match(/\((\d+)\s+(?:tests?|games?)\)/) || [])[1]).filter(Boolean).map(Number);
...
89번째 항목입니다. 첫 줄에는 85라고 적혀 있습니다. 같은 파일의 제목과 본문 모두 손으로 작성되었지만, 마지막으로 진실했던 시점이 달랐습니다.
이것을 놓치기 쉬운 우연한 점은 다음과 같습니다. 제목에는 14개 제공업체가 있다고 되어 있고 실제로도 14개의 제공업체 섹션이 있다는 것입니다. 이 문서는 독자가 헤딩(heading) 개수를 세어 확인하기 가장 쉬운 숫자에 대해서는 내부적으로 일관성이 있지만, 중요한 두 가지 숫자는 모두 잘못되었습니다.
편집되는 동안 어떻게 오래되었는지
이번 주 커밋에서 하나의 제공업체에 세 개의 게임이 추가되었고, 그 커밋은 llms.txt를 건드렸습니다. Aon 헤딩은 ### Aon / cut-e (6 tests)에서 ### Aon / cut-e (10 tests)로 변경되었고, 새로운 자료 목록을 나열하는 문장이 아래에 추가되었습니다.
첫 줄은 건드려지지 않았는데, 첫 줄이 편집되는 헤딩보다 23줄 위에 있고 둘 사이에 연결된 것이 없기 때문입니다. 현재 보고 있는 섹션을 정확하게 업데이트하는 diff는 가장 설득력 있게 오래된 파일의 예시가 됩니다. 최근 git log가 있기 때문에 관리되고 있는 것처럼 보입니다.
다른 모든 표면이 이를 도출함
이 파일을 특이하게 만드는 점은, 이 파일이 리포지토리 내에서 생성된 것이 아니라 작성된 유일한 공개 표면이라는 것입니다.
제공업체 슬러그(provider slugs)는 하나의 내보내기 배열(exported array)에 존재합니다. /games는 이를 매핑하여 카드들을 렌더링합니다. 사이트맵은 동일한 배열을 사용하여 /games/<provider> 항목들에 대한 엔트리를 매핑하는데, 이것이 현재 사이트맵에 총 375개의 URL이 있고 그중 정확히 56개가 제공업체 페이지인 이유입니다:
const xml = await (await fetch('/sitemap.xml')).text();
console.log(xml.match(/<loc>/g).length); // 375
console.log(xml.match(/>/games/[a-z0-9-]+</g).length); // 56
제공되는 공급자별 테스트 카운트는 공급자별 카탈로그 모듈에서 가져오며, 이것이 /games의 372라는 수치가 나오는 곳입니다. 공급자를 추가하면 랜딩 페이지, 카탈로그, 사이트맵, 검색 인덱스, 그리고 공급자별 허브가 업데이트되지만, 기억해야 할 목록은 없습니다. 슬러그 배열(slug array)과 메타데이터 객체(metadata object)의 멤버십이나 순서에 불일치가 생기면 테스트가 실패합니다.
llms.txt는 public/ 내의 정적 파일입니다. 이 파일은 디스크에서 바이트 범위를 제공하는 Vercel을 통해 정확히 하나의 코드 경로로 접근할 수 있습니다.
과거에는 페이지와 동일한 배열로부터 구축된 생성형 보조 파일인 llms-full.txt가 있었습니다. 그 파일은 오래되지 않았고, 현재는 사라졌습니다:
GET https://cogniprep.app/llms-full.txt -> 404
따라서 생성된 파일은 제거되었고 수동으로 작성된 파일만 남아 있게 되었는데, 이는 정확히 잘못된 방식입니다.
제가 단순히 숫자를 수정하지 않는 이유
85를 372로 편집하는 것은 다음 공급자가 출시될 때까지 파일을 고치지만, 현재 속도로는 며칠이 걸립니다. 그 첫 줄의 숫자들은 /games가 렌더링 시점에 동일한 진실의 원천(source of truth)으로부터 이미 계산하는 두 개의 숫자와 같습니다. llms.txt를 출력하는 라우트는 이 둘을 보간하여 다시는 틀릴 일이 없게 만들 수 있으며, 그 아래의 ### 공급자 (N 테스트) 제목들은 같은 배열에 대한 동일한 맵입니다.
이 코드베이스에서 제가 계속 배우는 교훈은
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기