당신의 LLM은 파일 전체를 읽고 있습니다. 그럴 필요는 없습니다.
요약
코딩 에이전트가 파일 전체를 컨텍스트에 로드하여 발생하는 토큰 낭비와 품질 저하 문제를 해결하기 위한 방법을 제시합니다. Markdown의 헤딩 구조를 활용해 문서를 인덱스와 섹션으로 분할하는 md2idx 도구를 소개합니다.
핵심 포인트
- 파일 전체 로딩은 불필요한 토큰 비용을 발생시키고 답변 품질을 낮춤
- Markdown의 계층 구조를 활용해 필요한 섹션만 선택적으로 읽을 수 있음
- md2idx 도구를 사용하면 컨텍스트 사용량을 최대 98%까지 절감 가능
- CLI 환경에서 jq와 함께 사용하여 효율적인 데이터 처리가 가능함
코딩 에이전트(Coding agents)는 매일 사양서(specs), 설계 문서(design docs), 그리고 긴 README 파일을 읽습니다. 대부분의 경우, 이들은 단 몇 개의 섹션만 필요로 합니다. 하지만 이들은 파일 전체를 컨텍스트(context)에 로드합니다.
"그냥 파일을 읽으세요"의 숨겨진 비용
여기서 끊임없이 발생하는 시나리오가 있습니다. 당신이 에이전트에게 5,000줄짜리 API 사양서의 에러 처리(error handling) 섹션을 확인해 달라고 요청합니다. 에이전트는 파일을 열고, 5,000줄 전체를 자신의 컨텍스트 윈도우(context window)로 읽어 들인 뒤, 필요한 80줄을 찾아내어 당신의 질문에 답합니다.
결과는 정확합니다. 하지만 에이전트는 필요하지 않은 4,920줄에 대해서도 방대한 양의 토큰(tokens)을 소비했습니다. 세션 내에서 파일을 읽을 때마다 이 과정을 반복하면, 낭비는 빠르게 누적됩니다.
비용이 토큰뿐만이 아닙니다. 무관한 내용으로 가득 찬 컨텍스트 윈도우는 에이전트의 답변 품질을 저하시킵니다.
인간은 어떻게 다르게 행동하는가
사람이 300페이지짜리 기술 서적을 집어 들었을 때, 인증(authentication)에 관한 장을 찾기 위해 표지부터 끝까지 읽지는 않습니다. 목차를 넘겨보고, 장 제목들을 훑어본 뒤, 47페이지로 바로 건너뜁니다. LLM도 똑같은 일을 할 수 있습니다.
Markdown은 이미 구조화되어 있습니다
Markdown 문서는 헤딩(headings)이라는 내장된 구조를 가지고 있습니다. # Title 다음에 ## Section A, 그 다음에 ### Subsection A.1이 이어지면 책의 목차를 반영하는 계층 구조가 생성됩니다.
Markdown 파일을 헤딩 경계에서 분할하면, 자연스러운 "목차 + 섹션" 구조를 얻을 수 있습니다. 각 헤딩은 새로운 섹션을 시작하고, 헤딩 텍스트는 인덱스 항목이 되며, 섹션 번호는 주소가 됩니다.
이것이 CLI 도구인 md2idx의 핵심 아이디어입니다.
md2idx 사용법
md2idx는 Markdown 파일을 두 개의 필드를 가진 JSON으로 변환합니다:
index: 각 줄이<# 깊이 표시> <일련번호>. <헤딩 텍스트>형식으로 구성된 번호가 매겨진 목차sections: 각 헤딩당 하나의 원본 Markdown 문자열을 담은 평탄한(flat) 배열
$ npx md2idx spec.md | jq -r '.index'
# 0. API Specification
## 1. Authentication
...
일련번호는 배열 인덱스(array indices)와 일치합니다. Error Handling 섹션을 읽으려면 다음과 같이 입력합니다:
$ npx md2idx spec.md | jq -r '.sections[5]'
## Error Handling
...
하나의 헤딩(heading)과 그 하위 항목들을 함께 읽으려면 다음과 같이 입력합니다:
$ npx md2idx spec.md | jq -r '.sections[2:5][]'
# Endpoints, GET /users, 그리고 POST /users — 총 3개의 섹션
에이전트(agent)가 2개의 섹션만 필요로 하는 5,000라인 규모의 명세서(spec)의 경우, 컨텍스트(context) 사용량은 약 5,000라인에서 약 100라인(20라인의 인덱스 + 80라인의 본문)으로 줄어듭니다. 문서의 종류와 필요한 섹션에 따라 다르지만, 일반적으로 80~98%의 감소 효과가 있습니다.
출력 결과는 jq와 함께 작동하도록 설계되었습니다. 기본적으로는 파이프(pipe) 처리에 용이한 한 줄 JSON 형식을 제공하며, --pretty 옵션을 통해 포맷팅된 출력을 얻을 수 있습니다. 파일 인자(argument) 또는 표준 입력(stdin)으로부터 읽어옵니다.
왜 단순히 grep으로 헤딩을 찾지 않나요?
grep -nE '#{1,6} ' spec.md를 사용하면 헤딩 목록을 얻을 수 있습니다. 단순한 경우에는 이 방법도 작동합니다. 하지만 md2idx는 grep이 해결할 수 없는 문제들을 다룹니다:
- 섹션 본문 추출 (Section body retrieval): grep은 헤딩 라인만 반환합니다. 본문을 가져오려면 라인 범위를 계산하고 오프셋/제한(offset/limit)을 사용하여 읽어야 합니다. md2idx를 사용하면
jq '.sections[N]'만으로 충분합니다. - Setext 헤딩 (
===/---): grep의#패턴으로는 인식할 수 없습니다. - 코드 펜스(code fences) 내부의
#: grep은 잘못된 결과(false positives)를 반환합니다. md2idx는 펜스 블록을 건너뜁니다. - 인라인 마크업 (Inline markup): grep은
[link](url)등을 있는 그대로 포함합니다. md2idx는 인덱스에서는 마크업을 제거하면서 섹션 본문 내의 마크업은 그대로 보존합니다.
Claude Code 스킬로 자동화하기
md2idx-read 스킬을 사용하면, 에이전트가 인덱스 가져오기부터 섹션 선택까지 모든 과정을 자율적으로 처리합니다.
- 에이전트가 파일 크기를 확인하고, 파일이 크면 인덱스를 가져오기 위해
md2idx를 호출합니다. - 인덱스를 읽고 현재 작업과 관련된 섹션이 무엇인지 식별합니다.
jq슬라이싱 (slicing)을 통해 해당 섹션들만 가져옵니다.- 더 많은 섹션이 필요한 경우, 3단계로 돌아갑니다 (인덱스는 이미 컨텍스트에 포함되어 있습니다).
# 스킬 설치
gh skill install oubakiou/md2idx md2idx-read --agent claude-code --scope project
...
설치가 완료되면, 에이전트는 대규모 Markdown 파일을 만날 때마다 선제적으로 이 스킬을 사용합니다. 수동 호출은 필요하지 않습니다. 먼저 인덱스를 읽고, 섹션을 선택한 뒤, 나머지는 건너뜁니다.
폴백 (fallback) 메커니즘도 포함되어 있습니다. md2idx를 사용할 수 없는 경우(네트워크 제한 환경, 권한 문제 등), 제목 검색을 위한 grep과 오프셋/제한 (offset/limit) 기능이 있는 Read 도구로 전환합니다. 정확도는 다소 떨어지지만 기능은 수행할 수 있습니다.
지금 바로 시도해보세요
# 모든 Markdown 파일의 인덱스 읽기
npx md2idx README.md | jq -r '.index'
...
md2idx는 외부 의존성이 전혀 없습니다. Markdown AST 파서 (parser)가 아닌, 독립적인 라인 스캐너 (line scanner)입니다. ATX 헤딩 (# 스타일), setext 헤딩 (=== / --- 밑줄), 코드 펜스 (code fence) 건너뛰기, 인라인 마크업 제거를 처리합니다.
md2idx는 MIT 라이선스이며 완전한 오픈 소스입니다. 만약 당신의 LLM 에이전트가 대규모 Markdown 파일 전체를 읽고 있다면, 한 번 사용해 보세요:
- GitHub repo →
- npm →
npx md2idx your-file.md | jq -r '.index' - Claude Code skill →
gh skill install oubakiou/md2idx md2idx-read
에이전트 워크플로에서 사용해 보셨다면, 결과가 어땠는지 정말 궁금합니다. 아래에 댓글을 남겨주시거나 GitHub에서 이슈를 생성(open an issue)해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기