Content-Signal: AI에게 허용 범위 알리기
robots.txt가 답하는 질문은 하나뿐이고, 지금껏 그것 하나만 답해 왔습니다. 이걸 가져가도 되는가. 경로별로, 봇별로, 예 아니면 아니오. 그런데 사이트 운영자 대부분이 실제로 취하는 입장, 그러니까 "색인해도 좋고 인용해도 좋고 독자를 보내 주면 좋겠지만, 내가 쓴 글로 모델을 학습시키지는 마라"를 표현할 어휘가 없습니다.
그래서 다들 손에 있는 유일한 레버를 당깁니다. Disallow로 전부 막고, 학습과 함께 유입까지 잃습니다.
가져갈 권한과 사용할 권한은 다릅니다
이 둘은 정말로 별개의 질문이고, 대역폭 이야기인 쪽은 하나뿐입니다. 누군가 무엇을 사야 하냐고 물었을 때 여러분의 가격 페이지를 읽고 인용해 주는 크롤러는 여러분을 돕는 쪽입니다. 같은 바이트가 학습 데이터셋에 부어지는 것은 완전히 다른 거래이고, 거기에 여러분은 없습니다.
전부 막으면 이 둘이 하나의 "아니오"로 짓눌립니다. 유료 아카이브라면 그게 맞을 수도 있습니다. 하지만 발견되고 추천받고 싶은 사업이라면 잘못된 기본값입니다. 답변에서 사라지는 쪽은 여러분이고, 경쟁사는 사라지지 않습니다.
Content-Signal은 그 둘을 갈라 놓는 층입니다.
세 가지 신호
Content-Signal: search=yes, ai-input=yes, ai-train=no
search— 검색 색인을 만들고 결과를 돌려주는 것, 즉 링크와 짧은 발췌입니다. AI가 생성한 요약은 포함되지 않습니다. 그건 다음 신호의 몫입니다.ai-input— 답변을 만드는 시점에 페이지를 모델에 넣는 것. RAG, 그라운딩, 생성된 답변 아래 붙는 출처 목록.ai-train— 여러분의 콘텐츠로 모델을 학습하거나 미세 조정하는 것.
셋은 서로 독립적입니다. 어떤 조합이든 유효하고, 그중 여럿은 실수가 아니라 숙고한 입장입니다.
값은 yes와 no 둘뿐입니다. maybe도, 경로별 문법도, 만료일도 없습니다.
신호를 빼놓는 것은 no가 아닙니다. 이 약속에 따르면 아무 말도 하지 않은 용도는 허용된 것도 제한된 것도 아니고, 그냥 답하지 않은 상태입니다. 저희 생성기는 언제나 셋을 모두 적습니다. 그게 옳은 습관이고, 침묵이야말로 아무도 어떻게 할 수 없는 유일한 대답이기 때문입니다.
어디에 넣는가
두 군데이고, 둘 다 값이 쌉니다.
robots.txt 안, user-agent 그룹 내부에 넣습니다.
User-agent: *
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=no
Sitemap: https://example.com/sitemap.xml
그리고 HTTP 응답 헤더로도 넣습니다.
Content-Signal: search=yes, ai-input=yes, ai-train=no
agentready.md는 둘 다 내보냅니다. 바로 저 헤더가 모든 응답에 실려 나갑니다. 모든 페이지, 모든 .md 버전, 모든 API 응답에.
nginx라면:
add_header Content-Signal "search=yes, ai-input=yes, ai-train=no" always;
Apache라면:
<IfModule mod_headers.c>
Header set Content-Signal "search=yes, ai-input=yes, ai-train=no"
</IfModule>
헤더는 제값을 합니다. robots.txt는 루트에서 이따금 가져가는 파일이고, 누가 붙여 넣은 링크를 따라 깊은 URL에 바로 내려앉은 에이전트는 끝내 읽지 않을 수도 있습니다. 헤더는 가져가는 대상에 붙어서 함께 움직입니다.
메타 태그 형태도 있습니다. <meta name="content-signal" content="search=yes, ai-input=yes, ai-train=no">. 서버 설정에 손댈 수 없을 때 쓰세요. 헤더 쪽이 낫습니다. HTML이 아닌 응답까지 덮기 때문입니다.
실제 세 가지 입장
출처 표기를 원하는 매체.
Content-Signal: search=yes, ai-input=yes, ai-train=no
링크와 함께 답변 안에 등장하는 건 유통이고, 요즘 방식의 "인용됨"입니다. 학습은 아무도 대가를 치르지 않는 부분이고, 게다가 아무도 돌려보내 주지 않습니다.
추천받고 싶은 SaaS.
Content-Signal: search=yes, ai-input=yes, ai-train=yes
문서, 가격, 변경 이력. 어떤 일에 무엇을 쓰면 되냐고 누가 어시스턴트에게 물을 때, 여러분이 그 답이 되고 싶을 겁니다. 학습 데이터에 들어가 있다는 건 모델이 아무것도 가져가지 않는 순간에도 이름이 불릴 수 있다는 뜻입니다. 여기엔 지킬 것이 없습니다. 그 자료는 그 자체로 마케팅입니다.
유료 아카이브.
Content-Signal: search=yes, ai-input=no, ai-train=no
발견은 되어야 합니다. 검색 결과 자체가 판매 문구니까요. 원치 않는 건 기사의 알맹이가 남의 답변 안에 공짜로 실리는 일입니다. 바로 이 경우가 Disallow로는 못 하는 일을 신호가 해내는 자리입니다. 크롤링을 막으면 검색 노출까지 함께 사라지니까요.
특정 봇에만 다른 조건을 주고 싶다면 그 봇 전용 그룹을 씁니다.
User-agent: *
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=no
User-agent: GPTBot
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=yes
robots.txt의 평소 우선순위 규칙 그대로입니다. 자기 이름을 찾은 봇은 그 그룹만 읽고 *는 통째로 무시합니다.
이게 실제로 무엇인가
젊은 관행입니다. RFC도 아니고 W3C 표준도 아니며, 어떤 크롤러도 지킬 의무가 없습니다. 여러분이 근거로 삼을 만한 형태로 준수를 약속한 곳도 없습니다. Content-Signal이 콘텐츠를 지켜 준다는 글을 읽었다면 그건 광고입니다.
그러면 왜 한 줄을 쓰는가.
기계가 읽을 수 있고 비용이 거의 없기 때문입니다. 이미 서빙하는 파일에 한 줄, 이미 갖고 있는 설정 블록에 헤더 하나. 이 관행에 딸린 서문은 no를 EU 지침 2019/790 제4조에 따른 명시적 권리 유보, 즉 텍스트·데이터 마이닝 옵트아웃으로 규정합니다. 그것이 여러분의 관할에서 통하는지는 변호사에게 물을 일입니다. 표명하지 않은 의사는 어느 관할에서도 통하지 않습니다.
그리고 Disallow에는 표현할 말이 아예 없는 것을 말해 주기 때문입니다. "나로 학습하지 마라"와 "꺼져라"는 다른 문장인데, 지금까지 보낼 수 있는 건 뒤쪽뿐이었습니다.
제대로 나가는지 확인하기
curl -sI https://example.com/ | grep -i content-signal
curl -s https://example.com/robots.txt | grep -i content-signal
첫 명령을 첫 페이지가 아닌 곳에도 한 번 더 돌려 보세요. 헤더를 location 블록 안에 설정했다면 생각보다 좁은 범위에만 붙어 있을 수 있습니다.
CDN 뒤에 있다면 하나 더:
curl -sI https://example.com/robots.txt | grep -i "server\|cf-cache-status"
돌아온 robots.txt가 여러분 것인지 확인하세요. 저희 오리진은 몇 달 동안 404를 돌려주고 있었고, 그동안 Cloudflare가 엣지에서 저희가 쓴 적 없는 관리형 정책 파일로 답하고 있었습니다. 저희가 돌린 모든 점검은 그럴듯하기 짝이 없는 200을 받았습니다.