Uso OpenRouter (OR) como camada de roteamento, porque é onde fallback e multi-provider ficam triviais.
1. Ingestão (offline). Chunking semântico com metadados (fonte, data, tenant/permissão). Embeddings: escolha um provider e fixe — não troque de modelo de embedding sem reembeddar tudo, vetores ficam incompatíveis. Cada modelo no OR tem tokenizer próprio: use o usage real retornado, não confie num tokenizer único pra todo o catálogo.
2. Retrieval (online). Híbrido (vetorial + BM25) com rerank. O rerank é onde se corta token: só os top-k de verdade entram no prompt. É a maior alavanca de custo — chunk irrelevante é input pago em toda chamada.
3. Orquestração multi-agente. Mapeie papel → modelo e force custo/throughput pelo provider: roteador → gemini-flash ou um :nitro barato com sort: "price"; workers de extração → sonnet/deepseek (custo-benefício); síntese → opus/gpt-4o com sort: "throughput". O OR não tem "subagente com cache compartilhado" da Anthropic — multi-agente aqui é orquestração do seu lado: chamadas paralelas, junção na aplicação.
4. Custo por token. Roteamento por preço (sort: "price"), teto por requisição (max_price), e prompt caching repassado pelo provider — system + docs estáveis no prefixo cacheável, pergunta volátil no fim. Peça usage: { include: true } pra ter custo real e fazer budget por tenant.
5. Fallback (onde o OR brilha). Dois níveis automáticos: entre modelos (models é lista ordenada, cai pro próximo na mesma requisição) e entre provedores do mesmo modelo (allow_fallbacks: true). No Claude direto você coda a cascata na mão e distingue refusal de 529.
Cuidado: ao cair pra outro modelo o cache se perde (é por modelo/provider) e o comportamento muda. Ordene a lista por similaridade de comportamento, não só por preço.