Você já tentou perguntar algo para um chatbot de documentação e recebeu uma resposta que claramente não tinha nada a ver com a sua dúvida? Eu já. Várias vezes. E a culpa, quase sempre, é do RAG.
RAG — Retrieval-Augmented Generation — virou o padrão da indústria para dar contexto a modelos de linguagem. A ideia é simples: você fatia seus documentos em pedaços, transforma em vetores, e quando alguém pergunta algo, busca os pedaços mais parecidos e joga no prompt. Funciona? Às vezes. Mas quando a resposta está espalhada por três páginas diferentes ou depende de um trecho de código que não apareceu no top-K dos resultados, o agente simplesmente inventa ou admite que não sabe.
A Mintlify, plataforma de documentação usada por empresas como Anthropic, Cloudflare e Vercel, decidiu que já tinha aguentado o suficiente. Eles substituíram o pipeline de RAG inteiro por um filesystem virtual — e os resultados foram absurdos: boot 460x mais rápido e custo zero por conversa.
O Problema Real do RAG em Documentação
Antes de mergulhar na solução, vale entender por que o RAG falha tanto em documentação técnica.
O RAG tradicional funciona assim: você pega toda a sua base de docs, divide em chunks de 500-1000 tokens, gera embeddings e armazena num banco vetorial. Quando chega uma pergunta, você faz uma busca semântica, pega os top-K resultados mais relevantes e enfia tudo no contexto do LLM.
O problema? Documentação técnica não é uma Wikipedia. Ela tem:
- Referências cruzadas: a resposta para “como autenticar via OAuth” pode depender de informações em 3 páginas diferentes (setup, configuração e troubleshooting)
- Código exato: se o usuário precisa de um comando específico ou um snippet de configuração, a busca semântica pode trazer um chunk que fala sobre o comando, mas não contém o comando em si
- Hierarquia de informação: docs têm estrutura — seções, subseções, tabelas, exemplos. Quando você fatia em chunks, essa estrutura se perde
- Contexto sequencial: às vezes a resposta é “leia a seção X e depois a Y, nessa ordem”. RAG não sabe fazer isso.
A Mintlify tinha um assistente de documentação servindo 30.000 conversas por dia. Com RAG, a taxa de respostas insatisfatórias era alta o suficiente para incomodar. O agente não conseguia explorar a documentação — ele só conseguia buscar nela.
E aí vem a sacada: desenvolvedores não usam busca semântica para entender um codebase. Eles usam grep, cat, find, ls. Navegam pela estrutura de diretórios. Leem arquivos inteiros quando precisam. Por que o agente de IA não poderia fazer o mesmo?
ChromaFs: Um Filesystem em Cima do Banco Vetorial
A resposta da Mintlify foi o ChromaFs — uma camada de filesystem virtual que intercepta comandos UNIX e os traduz em queries no banco vetorial Chroma que eles já usavam.
A arquitetura é elegante na sua simplicidade:
| Camada | Responsabilidade |
|---|---|
| Agente LLM | Decide quais comandos executar (grep, cat, ls) |
| just-bash | Parser de bash em TypeScript (by Vercel Labs) que interpreta os comandos |
| ChromaFs | Traduz chamadas de filesystem em queries no ChromaDB |
| ChromaDB | Banco vetorial onde os docs já estavam armazenados |
O agente não sabe que está interagindo com um banco de dados. Para ele, é um diretório normal com arquivos .mdx. Ele pode rodar ls /auth/ para ver o que tem na seção de autenticação, cat /auth/oauth.mdx para ler o conteúdo completo, ou grep -r "API_KEY" / para encontrar todas as menções a uma chave de API.
A Implementação Por Baixo dos Panos
O ChromaFs começa carregando uma árvore de caminhos (path tree) que fica armazenada como JSON comprimido no próprio Chroma:
{
"auth/oauth": { "isPublic": true, "groups": [] },
"api/endpoints": { "isPublic": true, "groups": [] },
"internal/billing": { "isPublic": false, "groups": ["admin", "billing"] }
}
Na inicialização, isso vira duas estruturas em memória:
- Um
Setcom todos os caminhos de arquivo - Um
Mapmapeando diretórios para seus filhos
Comandos como ls, cd e find resolvem inteiramente em memória local, sem nenhuma chamada de rede. É instantâneo.
Quando o agente executa um cat /auth/oauth.mdx, aí sim o ChromaFs vai ao Chroma:
- Busca todos os chunks com o slug
page: auth/oauth - Ordena por
chunk_index - Junta tudo num documento completo
- Cacheia o resultado — leituras repetidas não tocam o banco
Isso resolve um dos maiores problemas do RAG: o agente lê a página inteira, não um fragmento descontextualizado. Se a resposta depende do parágrafo 3 e do exemplo de código no parágrafo 8, ele tem ambos.
O Grep de Duas Fases
A parte mais engenhosa é como o grep funciona. Quando o agente roda grep -r "OAuth" /, o ChromaFs executa um processo em duas etapas:
Fase 1 — Filtro grosso (Chroma):
O sistema parseia as flags do grep, traduz a string de busca em uma query $contains ou $regex no Chroma, e identifica quais arquivos podem conter resultados.
Fase 2 — Filtro fino (em memória):
Os chunks dos arquivos candidatos são pré-carregados em batch para um cache Redis. O comando grep é reescrito para buscar apenas nesses arquivos. O just-bash então executa a regex com precisão.
O resultado? Buscas recursivas em toda a documentação completam em milissegundos. Não segundos. Milissegundos.
Os Números Que Importam
Antes do ChromaFs, a Mintlify usava uma abordagem de sandbox: cada conversa recebia um container com os docs copiados para disco. Funcionava, mas era lento e caro.
| Métrica | Sandbox (antes) | ChromaFs (depois) |
|---|---|---|
| Boot P90 | ~46 segundos | ~100 milissegundos |
| Custo por conversa | $0.0137 | $0 |
| Mecanismo de busca | Scan linear em disco | Query por metadata no DB |
| Custo anual (850K conversas/mês) | ~$70.000 | $0 |
Leu certo: $70.000 por ano em compute eliminados. O ChromaFs reutiliza a infraestrutura do banco vetorial que já existia — não precisa provisionar nada novo.
E o boot de 46 segundos caindo para 100ms não é só uma métrica bonita. Significa que o usuário não espera. Ele abre o chat, pergunta, e a resposta começa a chegar quase instantaneamente. Experiência de produto completamente diferente.
Controle de Acesso de Graça
Um benefício inesperado do ChromaFs é o controle de acesso. Como a árvore de caminhos contém metadados de permissão, é trivial filtrar o que cada usuário pode ver:
Usuário "Público" → Acessa /auth/oauth.mdx ✓
Usuário "Equipe Billing" → Não acessa /internal/audit-log.mdx ✗
Usuário "Admin" → Acessa tudo ✓
No modelo sandbox, isso exigiria containers diferentes por tier ou gerenciamento de grupos Linux. Com ChromaFs, é um filtro na hora de montar a árvore de caminhos. Simples.
E como o filesystem é read-only por design (qualquer tentativa de escrita retorna EROFS), não existe risco do agente modificar ou deletar documentação. Ele explora livremente, mas não pode quebrar nada.
Por Que Isso Importa Além da Mintlify
A real é que essa abordagem não é só uma otimização de produto da Mintlify. Ela aponta para uma mudança maior na forma como pensamos sobre agentes de IA e acesso a informação.
O Filesystem Como Interface Universal
Pesquisadores têm argumentado que agentes convergem para filesystems como sua interface primária. Faz sentido: o filesystem é a abstração mais antiga e mais testada da computação. Todo desenvolvedor sabe usar ls, cat, grep. Todo sistema operacional implementa essas operações.
Quando você dá a um agente de IA acesso a um filesystem (real ou virtual), você está dando a ele a mesma interface que humanos usam há 50 anos. Não precisa inventar APIs novas, formatos proprietários ou protocolos de busca. O agente já sabe navegar — ele foi treinado em milhões de exemplos de interação com terminal.
RAG Não Está Morto — Mas Tem Limites
Eu não vou dizer que RAG é inútil. Para bases de conhecimento enormes e heterogêneas — pense em milhões de documentos sem estrutura clara — a busca semântica ainda é a melhor abordagem. Você não vai fazer grep em 10 terabytes de dados.
Mas para documentação estruturada, codebases, e bases de conhecimento organizadas, o modelo de filesystem virtual faz muito mais sentido. O agente pode:
- Explorar a estrutura antes de buscar conteúdo
- Ler documentos inteiros em vez de fragmentos
- Combinar múltiplas fontes de informação num único raciocínio
- Usar ferramentas familiares (grep, find) em vez de depender de embeddings
A Tendência dos “Agentic” Frameworks
O ChromaFs da Mintlify se encaixa numa tendência maior: agentic RAG. Em vez do modelo passivamente receber chunks de contexto, ele ativamente decide o que precisa ler, busca, avalia se é suficiente, e decide se precisa buscar mais.
Frameworks como LangChain e LlamaIndex já estão incorporando essa filosofia. O agente não é mais um consumidor passivo de resultados de busca — é um explorador ativo com ferramentas à disposição.
Como Implementar Algo Parecido
Se você tem uma base de documentação e quer experimentar essa abordagem, aqui vai um caminho prático.
Opção 1: Filesystem Real com Sandbox
A forma mais simples é dar ao agente acesso a um diretório real com seus docs em markdown:
import subprocess
def agent_tool_cat(filepath: str) -> str:
"""Lê um arquivo de documentação."""
result = subprocess.run(
["cat", filepath],
capture_output=True, text=True,
cwd="/docs"
)
return result.stdout
def agent_tool_grep(pattern: str, path: str = "/docs") -> str:
"""Busca um padrão nos docs."""
result = subprocess.run(
["grep", "-rn", pattern, path],
capture_output=True, text=True
)
return result.stdout
def agent_tool_ls(path: str = "/docs") -> str:
"""Lista arquivos e diretórios."""
result = subprocess.run(
["ls", "-la", path],
capture_output=True, text=True
)
return result.stdout
Funciona para documentações pequenas. Para documentações grandes, você vai precisar de algo como o ChromaFs.
Opção 2: Filesystem Virtual com Banco Vetorial
Se já tem um banco vetorial (Chroma, Pinecone, Weaviate), você pode criar uma camada de abstração:
class VirtualFS:
def __init__(self, collection):
self.collection = collection
self.path_tree = self._load_path_tree()
def ls(self, path: str) -> list[str]:
"""Resolve localmente na árvore de caminhos."""
return self.path_tree.get(path, [])
def cat(self, filepath: str) -> str:
"""Busca chunks no banco vetorial e reconstrói."""
results = self.collection.get(
where={"page": filepath},
include=["documents", "metadatas"]
)
# Ordena por chunk_index e junta
chunks = sorted(
zip(results["documents"], results["metadatas"]),
key=lambda x: x[1]["chunk_index"]
)
return "\n".join(doc for doc, _ in chunks)
def grep(self, pattern: str, path: str = "/") -> list[str]:
"""Busca em duas fases: DB + regex local."""
# Fase 1: busca candidatos no banco
candidates = self.collection.get(
where={"$contains": pattern}
)
# Fase 2: regex precisa nos resultados
import re
matches = []
for doc, meta in zip(candidates["documents"], candidates["metadatas"]):
if re.search(pattern, doc):
matches.append(f"{meta['page']}: {doc[:200]}")
return matches
Opção 3: Usar o just-bash Diretamente
O just-bash da Vercel Labs é open source. Você pode implementar a interface IFileSystem com seu próprio backend:
interface IFileSystem {
readFile(path: string): Promise<string>;
readdir(path: string): Promise<string[]>;
stat(path: string): Promise<{ isDirectory: boolean }>;
// ... outros métodos
}
Essa interface aceita qualquer backend: banco de dados, API REST, S3, ou até um filesystem real.
O Que Eu Tiraria Disso se Estivesse Começando Um Projeto Hoje
Se eu estivesse construindo um chatbot de documentação hoje, meu approach seria diferente de 6 meses atrás.
Para docs até 100 páginas: filesystem real. Copia tudo para um diretório, dá acesso ao agente com tools de cat, grep e ls. Sem banco vetorial, sem embeddings, sem complicação. O custo de armazenamento é negligenciável e a latência é zero.
Para docs de 100 a 10.000 páginas: filesystem virtual no estilo ChromaFs. Usa o banco vetorial para armazenamento e busca, mas apresenta tudo como um filesystem para o agente. Melhor dos dois mundos.
Para bases enormes e desestruturadas (10.000+ docs): RAG tradicional com agentic search. O agente decide quando buscar, mas a busca em si é semântica. Não tem como fazer grep em 10 mil documentos de forma eficiente.
A chave é escolher a ferramenta certa para o tamanho do problema. RAG virou um martelo e todo mundo começou a ver pregos por toda parte. Às vezes o que você precisa é de um simples cat arquivo.md.
O Futuro É Híbrido
A Mintlify não abandonou completamente a busca vetorial — ela ainda está lá, por baixo do ChromaFs, potencializando o grep e armazenando os chunks. O que mudou foi a interface. Em vez de expor a mecânica de embeddings e top-K para o agente, eles embrulharam tudo numa metáfora que o agente (e qualquer desenvolvedor) já entende.
30.000 conversas por dia. 460x mais rápido. $70K por ano economizados. E, mais importante, respostas melhores — porque o agente pode finalmente ler a documentação em vez de receber fragmentos aleatórios dela.
Se o seu pipeline de RAG está te frustrando, talvez o problema não seja o modelo, nem os embeddings, nem o tamanho dos chunks. Talvez o problema seja que você está tentando resolver com busca semântica algo que se resolve melhor com grep.
Fonte de inspiração: How We Built a Virtual Filesystem for Our Assistant — Mintlify Blog















