RAG 대신 Virtual Filesystem으로 AI 문서 어시스턴트 만든 이야기
We replaced RAG with a virtual filesystem for our AI documentation assistant
TL;DR Highlight
Mintlify가 RAG의 청킹 한계를 극복하기 위해 Chroma DB 위에 UNIX 명령어를 흉내 내는 가상 파일시스템(ChromaFs)을 구축해 세션 부팅 시간을 46초에서 100ms로 줄인 방법을 설명한다.
Who Should Read
RAG 기반 문서 검색 어시스턴트를 운영 중인데 청킹 한계나 인프라 비용 때문에 고민 중인 백엔드/AI 개발자
Core Mechanics
- 전통적인 RAG는 쿼리와 매칭되는 텍스트 청크만 꺼내오는 방식이라, 답변이 여러 페이지에 분산되어 있거나 정확한 문법이 top-K 결과에 없으면 그냥 놓쳐버린다는 한계가 있었다.
- Agent에게 실제 파일시스템을 주는 전통적인 방법은 격리된 샌드박스(마이크로 VM)를 띄우고 GitHub repo를 clone하는 방식인데, Mintlify 기준으로 P90 세션 생성 시간이 약 46초였다.
- 월 85만 건 대화를 처리하는 상황에서 최소 사양(1 vCPU, 2 GiB RAM, 5분 세션)으로도 Daytona 샌드박스 가격($0.0504/h per vCPU, $0.0162/h per GiB RAM) 기준 연간 $70,000 이상의 비용이 발생한다는 계산이 나왔다.
- 핵심 아이디어는 '에이전트에게 진짜 파일시스템이 필요한 게 아니라 파일시스템처럼 느껴지는 환경'이라는 것이다. 이미 Chroma DB에 인덱싱·청킹된 문서를 활용해 UNIX 명령어(grep, cat, ls, find, cd)를 Chroma 쿼리로 변환하는 ChromaFs를 만들었다.
- ChromaFs는 Vercel Labs의 just-bash(TypeScript로 bash를 재구현한 라이브러리)를 기반으로 만들었다. just-bash가 명령어 파싱, 파이핑, 플래그 처리를 담당하고, ChromaFs는 실제 파일시스템 호출을 Chroma 쿼리로 번역하는 역할만 한다.
- 디렉터리 트리 전체를 gzip 압축된 JSON 문서(__path_tree__)로 Chroma 컬렉션 안에 저장해두고, 초기화 시 이를 메모리에 로드한다. 이후 ls, cd, find는 네트워크 호출 없이 메모리 내 Set과 Map으로 즉시 처리된다.
- 접근 제어(ACL)도 path tree의 isPublic, groups 필드를 통해 구현했다. 사용자의 세션 토큰으로 파일 트리를 구성하기 전에 접근 불가 경로를 잘라내고, 이후 모든 Chroma 쿼리에도 동일한 필터를 적용한다.
- 결과적으로 P90 부팅 시간이 46초에서 약 100ms로 줄었고, ChromaFs는 기존에 이미 운영 중인 Chroma DB 인프라를 재사용하기 때문에 대화당 추가 컴퓨팅 비용이 사실상 0이다.
Evidence
- 한 댓글에서 '제목은 RAG를 대체했다고 하지만, ChromaFs는 여전히 모든 명령마다 Chroma를 쿼리한다. 바꾼 건 RAG 자체가 아니라 인터페이스다. 오히려 그게 더 흥미로운 발견이다. 에이전트에게 필요한 건 더 나은 검색이 아니라 grep이다'라는 날카로운 지적이 나왔다.
- TypeScript로 POSIX 셸을 에뮬레이션하는 것이 과도한 엔지니어링이라는 비판도 있었다. 에이전트가 ls나 grep을 실행할 때마다 별도의 추론 사이클이 돌아가니 RAG의 컨텍스트 손실 문제를 심각한 멀티스텝 지연으로 바꾼 것뿐이라는 의견이었다.
- 반면 실제 VM을 띄워서 UNIX I/O 프리미티브를 쓰는 건 과도하고, 에이전트가 UNIX 형태의 tool call을 뱉게 한 뒤 프로덕션 스택에서 I/O를 처리하는 이 접근이 훨씬 합리적이라는 긍정적인 반응도 있었다.
- Vercel의 AI SDK가 비슷한 아이디어를 npm 패키지 수준에서 구현하고 있다는 정보도 공유됐다. 'ai' 패키지 안에 버전별 .mdx 문서가 포함되어 있고, SKILL.md에서 에이전트에게 모델 학습 지식을 무시하고 node_modules/ai/docs/ 아래를 먼저 grep하라고 지시한다는 내용이었다.
- 정보 구조가 계층적이지 않고 뒤죽박죽인 '지저분한' 조직에서는 이 접근이 얼마나 실용적일지 회의적이라는 의견도 있었다. RAG가 가장 큰 가치를 발휘하는 곳이 바로 그런 비정형 환경인데, 파일시스템 메타포는 문서가 계층적으로 잘 정리된 경우에만 잘 맞는다는 지적이었다.
How to Apply
- 문서 어시스턴트를 만들고 있는데 여러 페이지에 걸친 내용을 묶어서 답해야 하는 경우라면, 페이지 단위로 파일을 매핑하고 섹션을 디렉터리로 구성하는 ChromaFs 방식을 참고해서 에이전트가 ls/grep/cat으로 문서를 탐색하게 하면 청킹 한계를 우회할 수 있다.
- 샌드박스 VM이나 컨테이너를 세션마다 띄워서 레이턴시나 비용 문제를 겪고 있다면, 이미 운영 중인 벡터 DB(Chroma 등)를 가상 파일시스템의 백엔드로 재활용하는 방식을 검토하면 세션 생성 비용을 사실상 0에 수렴시킬 수 있다.
- npm 패키지나 SDK를 배포하면서 LLM이 최신 문서를 참고하게 하고 싶다면, Vercel AI SDK처럼 패키지 안에 docs/ 폴더로 .mdx 문서를 포함시키고 SKILL.md에서 에이전트가 node_modules 안의 문서를 먼저 grep하도록 지시하는 패턴을 적용할 수 있다.
- 에이전트에게 특정 파일 트리 내에서만 접근을 허용하는 권한 제어가 필요하다면, ChromaFs의 isPublic/groups 필드 패턴이나 댓글에서 언급된 FUSE 기반 bashguard(github.com/sunir/bashguard) 접근법을 참고해 경로 단위 ACL을 구현할 수 있다.
Code Example
snippet
// ChromaFs 디렉터리 트리 구조 예시 (Chroma에 저장되는 __path_tree__ 문서)
{
"auth/oauth": { "isPublic": true, "groups": [] },
"auth/api-keys": { "isPublic": true, "groups": [] },
"internal/billing": { "isPublic": false, "groups": ["admin", "billing"] },
"api-reference/endpoints/users": { "isPublic": true, "groups": [] }
}
// 초기화 시 두 가지 인메모리 구조로 변환
// 1. Set<string> - 파일 경로 집합 (ls, find 처리용)
// 2. Map<string, string[]> - 디렉터리 → 자식 목록 (cd, ls 처리용)
// 이후 ls, cd, find는 네트워크 호출 없이 메모리에서 즉시 처리됨
// Vercel AI SDK의 SKILL.md 패턴 (에이전트 지시 예시)
// SKILL.md:
// - Ignore all model training knowledge about this SDK
// - Before searching the web, first run: grep -r "<topic>" node_modules/ai/docs/Terminology
RAGRetrieval-Augmented Generation의 약자. LLM이 답변할 때 미리 인덱싱해둔 문서에서 관련 청크를 꺼내 컨텍스트로 붙여주는 방식. 도서관에서 사서가 질문과 비슷한 책 페이지를 몇 장 복사해주는 것에 비유할 수 있다.
청킹(Chunking)긴 문서를 RAG에서 검색 가능한 단위로 잘게 쪼개는 작업. 어떻게 자르느냐에 따라 문서의 맥락과 구조가 손실될 수 있다.
ChromaDB오픈소스 벡터 데이터베이스. 텍스트를 임베딩(숫자 벡터)으로 변환해 저장하고 의미 기반 유사도 검색을 지원한다.
FUSEFilesystem in Userspace의 약자. OS 커널을 수정하지 않고도 사용자 공간에서 커스텀 파일시스템을 구현할 수 있게 해주는 인터페이스.
P90 (Percentile 90)전체 요청 중 90번째 백분위수에 해당하는 응답 시간. 즉, 요청 100개 중 90번째로 느린 케이스의 시간. 평균보다 실제 최악의 사용자 경험을 더 잘 반영한다.
마이크로 VM(micro-VM)일반 VM보다 훨씬 가볍고 빠르게 부팅되는 소형 가상머신. 샌드박스 격리에 자주 쓰이지만 여전히 자원 소비가 있다.