ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 확장자 없는 R2 파일을 AI Search가 읽게 하려면
    AI Agent 2026. 9. 23. 09:05
    728x90
    반응형

    사진과 직물 조각이 각각 담긴 이름 없는 봉투 두 개
    파일 이름과 실제 내용 형식을 구분하는 AI 생성 이미지입니다.

    확장자 없는 R2 객체를 검색에 넣으려면 실제 내용과 맞는 Content-Type 메타데이터와 지원 형식을 함께 확인하세요.

    R2에 문서를 올렸는데 객체 이름이 긴 ID이고 .pdf나 .md가 없습니다. 파일은 존재하지만 AI Search에 들어가지 않는다면 본문이 사라졌다고 생각하기 전에 형식 판정에 필요한 메타데이터를 확인할 수 있습니다.

    Cloudflare는 2026년 9월 11일 지원되는 Content-Type 메타데이터가 있는 확장자 없는 R2 객체를 AI Search가 색인할 수 있다고 안내했습니다. 파일 이름을 유지할 수 있다는 변화이지 모든 바이트를 자동으로 읽을 수 있게 됐다는 뜻은 아닙니다. 이 글은 2026년 9월 13일 공식 문서 기준이며 실제 버킷이나 검색 인스턴스를 변경하지 않았습니다. 지원 변경 안내

    확장자가 없다면 명시적인 형식 정보가 필요합니다

    AI Search의 R2 문서는 알려진 파일 확장자를 우선적인 형식 판정 경로로 사용한다고 설명합니다. 확장자가 없는 객체에는 지원되는 MIME 타입의 Content-Type을 명시하도록 안내합니다. R2 데이터 소스의 Content-Type

    이 조건에서는 Content-Type이 없거나 지원하지 않는 값, 잘못된 형식, application/octet-stream이면 지원되지 않는다고 명시돼 있습니다. octet-stream은 특정 문서 형식을 알려 주는 값이 아니므로 확장자 없는 문서의 해석 단서로 충분하지 않습니다.

    그렇다고 모든 객체의 Content-Type을 일괄로 text/plain으로 바꾸면 안 됩니다. 실제 PDF나 이미지 바이트를 텍스트라고 표시한다고 내용이 텍스트로 변환되지는 않습니다. 타입 표시와 본문의 실제 형식이 맞아야 합니다.

    이미 확장자가 있는 파일도 불일치를 방치할 이유는 없습니다. 다만 이번 변경을 “모든 경우에 Content-Type이 확장자보다 우선한다”는 규칙으로 확대하지 않습니다. 문서가 설명하는 우선 경로와 확장자 없는 경우의 조건을 구분합니다.

    같은 메타데이터라도 HTTP 정보와 사용자 정의 정보는 다릅니다

    R2 Workers API에는 httpMetadata와 customMetadata가 따로 있습니다. 전자는 객체에 연결된 HTTP 헤더 정보를, 후자는 사용자가 정한 추가 키·값을 담습니다. Content-Type을 지정할 위치와 검색 필터용 분류를 넣을 위치를 혼동하면 안 됩니다. R2 객체 메타데이터

    예를 들어 customMetadata에 contentType이라는 문자열을 넣었다고 HTTP Content-Type이 설정된 것으로 판단하지 않습니다. 이름이 비슷한 사용자 정의 키와 실제 응답 형식 메타데이터는 다른 항목입니다.

    AI Search의 사용자 정의 메타데이터는 검색 결과 필터에 사용할 수 있고, 읽어 들일 스키마 설정도 관련됩니다. 이번 확장자 없는 객체 지원과 같은 기능으로 묶어 이해하지 않는 편이 좋습니다. AI Search의 사용자 정의 메타데이터

    메타데이터를 진단할 때는 어떤 도구 화면에서 어느 필드를 보고 있는지까지 기록합니다. 파일 이름, 사용자가 붙인 분류 태그, HTTP Content-Type 중 무엇을 바꿨는지 명확해야 수정 결과를 설명할 수 있습니다.

    가상의 handbook 객체를 먼저 읽기 전용으로 확인합니다

    예시에서는 docs/handbook이라는 객체 키에 공개용 Markdown 문서가 있다고 하겠습니다. 내용에는 “프로젝트 자료는 매주 금요일에 내보냅니다”라는 가상의 안내가 들어 있습니다. 이 객체와 문장은 설명용이며 실제 운영 자료가 아닙니다.

    다음은 R2 바인딩 env.DOCS가 준비된 Worker 내부에서 메타데이터를 확인하는 코드 일부입니다. 실제 실행하지 않았으며 HTTP 요청을 받는 공개 엔드포인트를 만드는 코드도 아닙니다.

    const object = await env.DOCS.head("docs/handbook");
    if (object === null) {
      throw new Error("대상 객체가 없습니다.");
    }
    
    console.log({
      key: object.key,
      size: object.size,
      contentType: object.httpMetadata?.contentType ?? null,
    });
    

    head는 본문 없이 객체 메타데이터를 읽고 객체가 없으면 null을 반환합니다. 이 예시의 contentType:null은 확인한 HTTP 메타데이터에 값이 없다는 표현이지, 파일 형식을 자동으로 추측한 결과가 아닙니다. R2 head의 반환 범위

    메타데이터 조회만으로 내용이 Markdown이라는 사실까지 증명하지는 못합니다. 원본을 만든 프로그램의 출력 형식이나 별도로 확인한 본문을 대조해야 합니다. 확장자가 없다는 이유로 감으로 MIME 타입을 고르지 않습니다.

    이 가상 객체의 실제 내용이 Markdown이라고 확인됐다면 공식 지원 목록에서 text/markdown을 검토할 수 있습니다. 지원 목록은 파일 형식과 MIME 타입을 함께 제시합니다. 문서 확인일에는 Markdown과 text/markdown 조합이 포함돼 있습니다. 지원 파일 형식

    새 테스트 객체에는 Content-Type을 명시해 저장합니다

    기존 객체를 바로 덮어쓰기보다 별도의 새 테스트 키로 본문과 메타데이터의 관계를 확인하는 편이 좋습니다. 다음 코드는 공개 예시 문자열을 새 키에 쓰는 형태이며 실행하지 않았습니다. 실제 사용한다면 쓰기 권한과 대상 버킷을 먼저 확인해야 합니다.

    const created = await env.DOCS.put(
      "docs/content-type-demo",
      "# 자료 내보내기\n\n프로젝트 자료는 매주 금요일에 내보냅니다.\n",
      {
        httpMetadata: { contentType: "text/markdown" },
        onlyIf: new Headers({ "If-None-Match": "*" }),
      },
    );
    
    if (created === null) {
      throw new Error("조건이 맞지 않아 저장하지 않았습니다. 기존 객체를 확인하세요.");
    }
    

    httpMetadata.contentType에 본문과 맞는 MIME 타입을 지정했습니다. 조건부 저장은 같은 키의 기존 객체를 덮어쓰지 않도록 한 것이며, 조건이 실패하면 null을 확인하고 멈춥니다. 코드가 끝까지 예외 없이 지나갔다는 사실 대신 실제 반환값을 봅니다. R2 put과 조건부 작업

    이 코드는 기존 문서의 메타데이터만 수정하는 도구가 아닙니다. put에는 본문과 저장할 메타데이터를 전달하므로 운영 객체를 수정한다면 원본 보존과 동시 수정 방지, 기존 메타데이터 유지가 별도 요구입니다. 예시 키를 실제 객체 이름으로 바꿔 무작정 실행하지 않습니다.

    저장 뒤에는 같은 키를 다시 head로 읽어 의도한 Content-Type이 남았는지 확인합니다. 본문이 의도한 문서인지도 따로 확인합니다. 이 두 결과가 맞아야 다음 색인 단계의 입력 조건을 준비한 것입니다.

    R2 저장 성공과 AI Search 색인 완료는 별개입니다

    R2에 객체가 있다는 사실만으로 검색에 즉시 반영됐다고 판단하지 않습니다. R2 같은 외부 데이터 소스는 AI Search의 동기화 작업을 거쳐 새 파일과 변경·삭제를 처리합니다. 작업 상태와 이력은 대시보드나 API에서 확인할 수 있습니다. 외부 데이터 소스 동기화

    인덱싱이 일시 중지됐거나 아직 해당 변경을 처리하지 않았다면 메타데이터를 고친 뒤에도 검색 결과가 같을 수 있습니다. 필요하면 문서에 안내된 동기화나 개별 파일 재색인 흐름을 검토하되, 요청을 넣었다는 사실과 완료 상태를 구분합니다.

    형식이 지원돼도 크기 한도나 경로 제외 규칙, 데이터 소스 접근 권한 때문에 파일을 처리하지 못할 수 있습니다. Content-Type 하나를 고쳤다고 다른 조건까지 통과한 것은 아닙니다.

    특히 버킷에 있는 문서를 모두 검색 가능하게 만들어도 되는지 먼저 확인해야 합니다. 형식 지원을 확인하려고 경로 필터나 접근 제한을 무작정 해제하면 비공개 초안까지 검색에 들어갈 수 있습니다. 새 지원 기능은 자료의 공개 범위를 넓혀도 된다는 허가가 아닙니다.

    검색 결과에서 원문 근거까지 확인합니다

    가상 문서의 확인 질문은 “자료를 내보내는 요일은 언제인가”로 정할 수 있습니다. 테스트 검색 결과에서 해당 객체와 금요일 안내가 있는 근거 조각을 찾는 것이 목적입니다. 이 질문으로 실제 검색을 실행한 결과는 제시하지 않습니다.

    AI가 “금요일”이라고 답했다는 사실만으로 원하는 객체가 색인됐다고 결론 내리면 안 됩니다. 다른 문서에 같은 안내가 있을 수도 있고, 생성 모델이 근거 없이 답했을 수도 있습니다. 반환된 출처와 문서 조각이 docs/handbook 또는 별도 테스트 객체의 내용과 연결되는지 확인해야 합니다.

    반대로 색인 작업이 완료됐는데 해당 질문의 상위 결과에 안 보인다면 그때는 청크 분리나 검색 방식·필터·순위 문제를 살펴볼 수 있습니다. “객체를 읽지 못함”과 “읽었지만 원하는 질문에 잘 검색되지 않음”은 다른 단계입니다.

    진단 기록에는 객체 키, 확인한 실제 형식, 저장된 Content-Type, 동기화 작업과 파일 처리 결과, 검색에서 확인한 근거를 연결합니다. 각 단계의 성공을 따로 남겨야 다음 변경 때 어느 단계가 달라졌는지 찾기 쉽습니다.

    적용 범위는 작게 시작하고 기존 자료는 보존합니다

    확장자 없는 객체가 많다면 먼저 서로 다른 실제 형식의 소수 샘플을 골라 검토합니다. 모든 파일에 같은 MIME 타입을 붙이는 작업보다 원본 생성 경로별로 올바른 타입을 넣는 방법을 정하는 편이 좋습니다.

    기존 객체를 고치는 경우에는 원문과 메타데이터의 변경 전 상태를 남기고 대상 키를 확정합니다. 메타데이터 변경만 의도했는데 본문이나 캐시 설정까지 바뀌지 않았는지도 확인합니다. 새 테스트 키에서 잘 동작했다는 이유로 서로 다른 운영 자료에 같은 설정을 바로 일괄 적용하지 않습니다.

    Content-Type은 파일을 해석할 단서입니다. 확장자 없는 R2 객체라도 지원 형식과 맞는 메타데이터를 제공하면 이름을 유지한 채 색인할 수 있습니다. 그 뒤에도 실제 본문, 저장 결과, 색인 상태와 검색 근거를 차례로 확인해야 원하는 문서가 제대로 검색된다고 말할 수 있습니다.

    728x90
    반응형
Designed by Tistory.