Como Otimizar o Uso de Tokens com ChromaDB (Passo a Passo)
Se você não prestar atenção ao uso de tokens em suas consultas de banco de dados vetorial, consumirá créditos e desempenho mais rapidamente do que pode perceber—portanto, aqui está como otimizar o uso de tokens com chromadb como se realmente quisesse economizar dinheiro e tempo.
O Que Você Irá Construir e Por Que É Importante
Estamos construindo um pipeline mínimo, mas eficaz, que pega documentos reais e desordenados, os armazena no ChromaDB e os interroga com embeddings OpenAI, minimizando o desperdício de tokens.
Pré-requisitos
- Python 3.11+
- pip install chroma-core==0.10.0 (última versão a partir de março de 2026)
- Chave API OpenAI com acesso aos pontos de término dos embeddings
- Conhecimentos básicos sobre bancos de dados vetoriais e APIs de modelos de linguagem avançados
Passo 1: Configurar Seu Ambiente ChromaDB
Primeiramente, você precisa instalar o ChromaDB e fazê-lo funcionar de uma forma que se integre bem com seu ambiente. O chroma-core, o motor principal do ChromaDB, está atraindo muita atenção no GitHub: mais de 26.759 estrelas e 2.140 forks, portanto, não é um simples projeto de nicho. Isso significa muita assistência da comunidade, mas também alguns problemas abertos inevitáveis (e o ChromaDB tem 513 abertos a partir de março de 2026).
A última versão, licenciada sob Apache-2.0, foi atualizada em 21-03-2026—portanto, está ativamente mantida, e isso é importante porque você a usará intensamente para gerenciar seus embeddings de maneira inteligente.
# Instalar chroma-core se ainda não foi feito
pip install chroma-core==0.10.0
Configurar um ChromaDB persistente geralmente significa executar este mínimo trecho de código:
from chromadb import Client
client = Client() # Usa as configurações padrão - SQLite + disco local
collection = client.get_or_create_collection(name="mydocs")
Por que fazer isso primeiro? Porque cada passo seguinte gira em torno da gestão das variáveis de orçamento dos tokens — e a gestão das dependências do ChromaDB é prioritária.
Problemas comuns: Se você encontrar erros como ModuleNotFoundError, verifique suas versões. As atualizações do Chroma-core costumam mudar os internos, então bloqueando uma versão específica você evita falhas aleatórias.
Passo 2: Fragmentar o Conteúdo para a Eficiência dos Tokens
Seus documentos não estão bem organizados—vêm com cabeçalhos, tabelas, notas de rodapé e elementos indesejados. Alimentar longas strings nas APIs de embeddings é uma maneira certa de se privar de tokens. Cada token conta.
Em vez disso, fragmentar seu conteúdo de maneira inteligente. Não muito grande, não muito pequeno. Um tamanho de chunk que corresponda ou seja ligeiramente inferior aos limites de tokens da sua API de embedding permite economizar muito processamento e custos desnecessários.
import tiktoken # Para a contagem de tokens, o tokenizer da OpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Inicializa um divisor para chunks de cerca de 500 tokens (seguro para os embeddings OpenAI)
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
length_function=lambda text: len(tiktoken.encoding_for_model("text-embedding-3-small").encode(text))
)
def chunk_text(text):
chunks = splitter.split_text(text)
print(f"Dividido em {len(chunks)} chunks")
return chunks
# Exemplo de uso
doc_text = open("messy_doc.txt").read()
chunks = chunk_text(doc_text)
Por que a fragmentação economiza tokens: Se você injetar documentos completos na API de embedding, obterá enormes embeddings, mas principalmente ruído—além disso, você pode ultrapassar os limites de tokens ou ativar os limites de velocidade. Chunks pequenos, mas significativos, produzem de maneira confiável embeddings direcionados para uma pesquisa vetorial precisa.
Erros a serem observados: Chunks que se sobrepõem às vezes parecem redundantes nos resultados de pesquisa—ajuste chunk_overlap de acordo. E esteja atento à escolha do tokenizer. Se você usar modelos de tokenizers diferentes, suas contagens de tokens podem variar em 20-30%, arruinando assim seu plano de orçamento de tokens.
Passo 3: Embedding com ChromaDB – Otimize, Não Oculte Tudo
É aqui que muitos desenvolvedores ultrapassam seu orçamento de tokens. Passar cada chunk pelo ponto de término dos embeddings da OpenAI esgota seu orçamento.
Em vez disso, você deseja pré-filtrar os chunks antes do embedding. Use um filtro de similaridade de texto de baixo custo. Como um controle rápido de TF-IDF, depois embede apenas os melhores chunks nos 30–40%. Isso reduz o espaço de armazenamento, o tempo de consulta e o custo dos tokens.
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
# Uma aproximação de baixo custo para filtrar chunks significativos antes de embeddings caros
def filter_chunks(chunks, query, keep_ratio=0.4):
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(chunks + [query])
query_vec = X[-1]
chunk_vecs = X[:-1]
similarities = (chunk_vecs @ query_vec.T).toarray().flatten()
threshold = np.quantile(similarities, 1 - keep_ratio)
filtered = [chunk for chunk, sim in zip(chunks, similarities) if sim >= threshold]
print(f"Filtrado de {len(chunks)} para {len(filtered)} chunks antes do embedding")
return filtered
chunks_to_embed = filter_chunks(chunks, "O que é a otimização do uso dos tokens?")
Agora, embede apenas chunks_to_embed no ChromaDB:
from openai import OpenAI
import chromadb
client = chromadb.Client()
collection = client.get_or_create_collection("mydocs")
embedding_model = OpenAI()
for chunk in chunks_to_embed:
embedding = embedding_model.embeddings.create(input=chunk).data[0].embedding
collection.add(
documents=[chunk],
embeddings=[embedding],
ids=[hash(chunk) % (10 ** 8)] # ID único mas simples
)
Por que essa abordagem? Porque os embeddings consomem muitos tokens. Um único chunk de 500 tokens custa 500 tokens apenas para ser vetorizado. Você realmente quer embutir fragmentos desnecessários? Não. Filtre de forma inteligente e economize tokens.
Erros que você pode encontrar: Limites de taxa da API. A inserção em lote no ChromaDB pode ajudar a reduzir as chamadas da API—mais sobre isso abaixo.
Passo 4: Inserção em Lote para Reduzir Chamadas da API
Não se trata apenas de tokens—suporte latência e acabe pagando mais por muitas chamadas de pequeno porte. As inserções em lote acertam em cheio: melhor taxa de transferência e menos chamadas de API redundantes.
O método collection.add do ChromaDB suporta vários documentos & embeddings simultaneamente. Agrupe seus chunks filtrados em lotes de 50 ou 100 para economizar tempo.
BATCH_SIZE = 50
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
for chunk_batch in batch(chunks_to_embed, BATCH_SIZE):
embeddings = [embedding_model.embeddings.create(input=chunk).data[0].embedding for chunk in chunk_batch]
collection.add(
documents=chunk_batch,
embeddings=embeddings,
ids=[hash(chunk) % (10 ** 8) for chunk in chunk_batch]
)
print(f"Indexados {len(chunk_batch)} chunks no lote")
Por que fazer batching? Uma solicitação = um evento de cobrança de tokens e uma viagem de rede. Não seja aquele desenvolvedor que espera 100 chamadas individuais da API na fila.
Fique atento a:
- Lotes muito grandes—mais de 100 por chamada pode te desacelerar.
- Falhas parciais—circunde suas chamadas com try/except para lidar com erros intermitentes, como timeouts ou 429.
Passo 5: Contagem Inteligente de Tokens Antes das Solicitações — Não Adivinhe
Durante a execução das solicitações, você precisa ter uma noção do número de tokens que todo o pipeline consome. Isso é crítico, especialmente se suas solicitações em si são longos passos ou uma combinação de entrada do usuário e contexto.
Em vez de adivinhar o número de tokens, confie no tiktoken ou equivalente para contar exatamente os tokens em cada fase. Desta forma, você pode truncar ou ajustar as inserções rapidamente antes de gastar essa solicitação.
def count_tokens(text, model_name="gpt-4o-mini"):
tokenizer = tiktoken.encoding_for_model(model_name)
tokens = tokenizer.encode(text)
return len(tokens)
query = "Explique a otimização dos tokens no ChromaDB da forma mais simples possível."
tokens_used = count_tokens(query)
print(f"Contador de tokens para a solicitação: {tokens_used}")
Por que se dar ao trabalho? Porque os embeddings da OpenAI e as conclusões de chat têm limites rigorosos de tokens. Exceder os 4.096 tokens geralmente resulta em truncamento, erros ou custos adicionais que você preferiria evitar.
Erros que você pode encontrar: O temido OpenAIError: O comprimento máximo do contexto para este modelo é de 4097 tokens. Gerencie esses erros contando os tokens antes de enviar as consultas e ajustando, em consequência, a entrada do usuário ou o contexto (detalhado na seção seguinte).
Passo 6: Truncar o Contexto e Cache dos Embeddings
Quando você alimenta documentos e um histórico de chats em seu modelo de linguagem, o total de tokens utilizados é de imensa importância. Um erro comum entre iniciantes é enviar sempre o documento completo ou todo o histórico de chats sem qualquer discernimento. Você pode rapidamente exceder os limites de tokens em poucos segundos.
Sua melhor opção: truncar e colocar em cache.
- Coloque em cache os embeddings para documentos estáticos (não re-embedar o mesmo texto)
- Truncar a história dos chats de maneira inteligente, priorizando entradas recentes importantes
- Utilize uma janela móvel de tokens de cerca de 3.000 tokens para o contexto em chats/completions
Aqui está um exemplo que ilustra o controle de cache e o truncamento:
embedding_cache = {}
def get_embedding(text):
if text in embedding_cache:
print("Acesso ao cache para o embedding")
return embedding_cache[text]
embedding = embedding_model.embeddings.create(input=text).data[0].embedding
embedding_cache[text] = embedding
return embedding
def trim_context(contexts, max_tokens=3000, model_name="gpt-4o-mini"):
trimmed = []
token_count = 0
for c in reversed(contexts): # começa pelo mais recente
tcount = count_tokens(c, model_name)
if (token_count + tcount) <= max_tokens:
trimmed.insert(0, c)
token_count += tcount
else:
break
print(f"Contexto reduzido a {len(trimmed)} mensagens totalizando {token_count} tokens")
return trimmed
Essa abordagem de cache fará você economizar centenas, se não milhares, de tokens a cada mês.
As Armadilhas
Aqui é onde o código ideal do tutorial colide com a realidade:
| Armadilha | O que acontece | Como evitar |
|---|---|---|
| Incoerência nos limites de tokens | Seus contagens de tokens estão incorretos devido a uma incoerência entre o tokenizer ou o modelo; você excede ou usa muito poucos tokens | Utilize sempre tiktoken.encoding_for_model() que corresponda exatamente ao modelo de embedding ou completion que você está usando |
| Embeddings duplicados | Re-embedar a mesma peça várias vezes consome tokens e espaço de armazenamento | Implemente o cache e o hashing dos checksums dos documentos |
| Erro de sobreposição de peças | Uma sobreposição excessiva cria vetores redundantes; uma sobreposição muito fraca perde o contexto em documentos fragmentados | Experimente o parâmetro chunk_overlap, mantendo entre 10-15% do tamanho das peças |
| Morte mútua de concorrência | Múltiplas chamadas assíncronas a ChromaDB ou OpenAI podem levar a condições de corrida ou inserções parciais | Use código síncrono ou um bom sistema de fila assíncrona; inserções em lote o protegem disso |
| Contagem de tokens não confiável em textos não ingleses | Os tokenizadores podem contar mal devido a caracteres de múltiplos bytes ou scripts não comuns | Teste com idiomas representativos, ajuste o tamanho das peças em consequência |
Exemplo de Código Completo: Colocando Tudo Junto
Este modelo combina todos os passos anteriores em um pipeline funcional:
```html
import tiktoken
from chromadb import Client
from openai import OpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
# Constantes
MODEL_NAME = "text-embedding-3-small"
EMBEDDING_BATCH_SIZE = 50
CHUNK_SIZE = 500
CHUNK_OVERLAP = 50
# Configuração
client = Client()
collection = client.get_or_create_collection(name="mydocs")
openai_client = OpenAI()
tokenizer = tiktoken.encoding_for_model(MODEL_NAME)
def count_tokens(text):
return len(tokenizer.encode(text))
def chunk_text(text):
splitter = RecursiveCharacterTextSplitter(
chunk_size=CHUNK_SIZE,
chunk_overlap=CHUNK_OVERLAP,
length_function=count_tokens
)
return splitter.split_text(text)
def filter_chunks(chunks, query, keep_ratio=0.4):
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(chunks + [query])
query_vec = X[-1]
chunk_vecs = X[:-1]
sims = (chunk_vecs @ query_vec.T).toarray().flatten()
thresh = np.quantile(sims, 1 - keep_ratio)
return [chunk for chunk, sim in zip(chunks, sims) if sim >= thresh]
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
def embed_and_index(chunks):
for chunk_batch in batch(chunks, EMBEDDING_BATCH_SIZE):
embeddings = []
for chunk in chunk_batch:
response = openai_client.embeddings.create(input=chunk)
embeddings.append(response.data[0].embedding)
ids = [str(hash(chunk) % (10**8)) for chunk in chunk_batch]
collection.add(documents=chunk_batch, embeddings=embeddings, ids=ids)
print(f"Lote indexado de {len(chunk_batch)} pedaços")
# Pipeline principal
doc_text = open("messy_doc.txt").read()
print("Fragmentação do documento...")
chunks = chunk_text(doc_text)
print(f"Gerado {len(chunks)} pedaços")
# Simular uma consulta de exemplo
query = "Como é otimizado o uso de tokens com ChromaDB?"
print("Filtragem dos pedaços antes da incorporação...")
chunks_to_embed = filter_chunks(chunks, query)
print(f"Incorporando e indexando {len(chunks_to_embed)} pedaços...")
embed_and_index(chunks_to_embed)
print("Pipeline concluída.")
O que há de Novo
Se você conseguiu implementar isso com sucesso, seu próximo passo deve ser integrar a recuperação classificada com os complementos do GPT da OpenAI para construir um sistema de geração aumentada pela recuperação (RAG) que obtém respostas do seu banco de dados vetorial com custos de tokens mínimos.
Mais especificamente, concentre-se na combinação das suas consultas ChromaDB com um gerador de respostas que tronca inteligentemente o contexto, aplicando idealmente a reformulação de consultas para reduzir o uso de tokens na engenharia de prompts.
FAQ
P: Por que não simplesmente enviar o documento inteiro para a API de incorporação de uma só vez?
R: Porque os limites de tokens da API de incorporação geralmente não excedem alguns milhares de tokens—demais para documentos grandes—e você paga linearmente pelo token, então desperdiça dinheiro e obtém incorporações menos precisas que prejudicam a precisão da recuperação.
P: Como lidar com documentos que mudam com frequência no ChromaDB?
R: Você deve implementar incorporações delta—reincorporar apenas novos ou modificados. Uma abordagem ingênua é hardcodar o texto de cada pedaço e compará-lo com os IDs armazenados para saber o que atualizar.
P: Como posso depurar erros na contagem de tokens na minha aplicação?
R: Use a biblioteca oficial tiktoken da OpenAI e certifique-se de que o nome do modelo em encoding_for_model() corresponda exatamente ao que você envia para a API. Verifique sua contagem imprimindo os arrays de tokens e verificando as dimensões dos pedaços.
Recomendações para Diferentes Perfis de Desenvolvedores
Desenvolvedores Júnior: Comece entendendo os limites dos tokens e a fragmentação. Não tente otimizar tudo de uma vez. Sua prioridade deve ser dividir os documentos em pedaços de ~500 tokens e garantir que as chamadas da API funcionem sem erros.
Desenvolvedores de Nível Intermediário: Implemente a filtragem e coleta depois. Use TF-IDF para pré-selecionar quais pedaços incorporar. Adicione caching para não reincorporar duplicatas. Neste ponto, você realmente economizará dinheiro e tempo.
Engenheiros Seniores: Automatize o monitoramento dos tokens de uma ponta à outra. Crie dashboards que avise quando o uso aumenta. Explore segmentadores personalizados adaptados ao seu tipo de documento. Integre métricas de uso com dashboards de custo e experimente com a engenharia de prompts para o truncamento do contexto.
```
Dados a partir de 22 de março de 2026. Fontes: https://github.com/chroma-core/chroma, https://community.openai.com/t/issue-chromadb-document-and-token-openai-limitations/317378
Artigos Relacionados
- Funcionalidades de segurança da toolbox para agentes IA
- Opções open source da toolbox para agentes IA
- Guia da toolbox AutoGen
🕒 Published: