요약
- LLM 에이전트의 파일 Read 도구는 줄 단위로 슬라이싱한다 (
offset,limit모두 줄 번호 기준). - 따라서 데이터 단위와 줄 단위가 일치하는 포맷이 이긴다.
- JSONL은 1줄 = 1엔트리. indented JSON은 1엔트리가 ~13줄에 분산되어 슬라이싱 시 엔트리 경계가 깨진다.
본문
같은 데이터, 두 가지 포맷
667개 wiki 메타데이터 엔트리 ({ path, title, type, tags, created, updated })를 두 포맷으로 직렬화하면:
| Format A (indented JSON) | Format B (JSONL) | |
|---|---|---|
| 줄 수 | 8,956 | 667 |
| 바이트 | 222,666 | 170,657 |
| Read(limit=2000) 1회 커버 | 152개 (22.8%) | 667개 (100%) |
| 전부 보려면 | 5회 호출 | 1회 |
왜 차이가 나는가
JSON.stringify(entries, null, 2)는 엔트리당 평균 ~13줄을 차지한다. 객체 시작 {, 각 필드 줄, 배열의 경우 대괄호와 원소들, 닫는 }, 콤마… 들여쓰기와 줄바꿈이 줄 수를 인플레이션시킨다.
JSONL은 entries.map(JSON.stringify).join("\n"). 엔트리당 정확히 1줄. 들여쓰기 없이 컴팩트하므로 바이트도 더 작다.
본질: Read 도구가 줄 단위로 슬라이싱하기 때문
Read는 cat -n처럼 줄 번호 기반으로 동작한다. offset, limit 둘 다 줄 단위. 만약 바이트 단위(head -c)거나 JSON 구조를 이해해서 엔트리 단위로 잘라줬다면 두 포맷 차이가 없었을 것이다. 하지만 줄 단위이기 때문에 데이터 단위와 슬라이싱 단위가 일치하는 포맷이 이긴다.
도구가 Read(file, offset, limit) 형태로 파일을 부분적으로 읽는다고 할 때:
- indented JSON:
limit=N줄 → 엔트리 ~N/13개 + 끝부분에 잘린 JSON 조각. 파싱 불가. - JSONL:
limit=N줄 → 정확히 N개 엔트리. 각 줄을 독립적으로JSON.parse가능.
즉 JSONL은 부분 읽기가 의미 있는 단위로 떨어진다. 슬라이싱이 데이터 구조를 깨지 않는다.
추가 함정
토큰 한도(예: 25k)는 별개다. 667개 규모에서 두 포맷 모두 한 번에 다 읽기는 불가능하다. JSONL 우위는 "전부 한 번에 읽는다"가 아니라 **"부분 읽기가 깔끔하게 떨어진다"**는 데 있다.
적용
LLM 에이전트가 소비할 메타데이터 인덱스/매니페스트/로그/덤프는 기본적으로 JSONL을 선택한다. 사람이 가끔 보는 설정 파일은 indented JSON이 여전히 낫다.