Pular para o conteúdo principal
MongoDB

Como buscar imagens e texto usando MongoDB Vector Search com FastAPI

Crie um app de busca vetorial de ponta a ponta com FastAPI e MongoDB Atlas. Aprenda a gerar, armazenar e consultar embeddings de texto e imagem neste tutorial prático.
Moses Anumadu's photo
Moses Anumadu
Actualizado · 10 min leer

Explore com IA

ChatGPTClaudePerplexity

Crie sua conta gratuita

Pratique e programa seu progresso.

Continuar Com O Google
Ao continuar, você aceita nossos Termos de Uso, nossa Política de Privacidade e que seus dados serão armazenados nos EUA.

A busca por palavras-chave funciona bem para consultas simples, mas rapidamente falha quando o que importa é o significado e não a redação exata. Se um documento menciona “aumentar o tempo de resposta” e outro fala em “melhorar a performance”, um mecanismo de busca tradicional os trata como não relacionados — apesar de abordarem a mesma ideia. Perdemos as relações semânticas só porque a formulação é diferente.

A busca vetorial resolve essa limitação ao representar textos e imagens como embeddings: vetores numéricos gerados por modelos de machine learning que capturam contexto, intenção e similaridade semântica. Depois que armazenamos esses embeddings no MongoDB, podemos consultá-los para encontrar itens genuinamente relacionados, independentemente dos termos usados.

Neste tutorial, vamos construir um exemplo prático de ponta a ponta desse fluxo usando FastAPI e MongoDB Atlas Vector Search. Vamos gerar embeddings de texto com SentenceTransformers e embeddings de imagem com um modelo baseado em CLIP, armazenar ambos no MongoDB e executar buscas por similaridade. No fim, você terá uma base funcional que pode sustentar busca semântica de artigos, recomendações de produtos, ferramentas de similaridade visual e muitas outras aplicações reais.

Dito isso, vamos começar.

Pré-requisitos

Antes de construir, precisamos de alguns itens. Este tutorial pressupõe familiaridade básica com Python, FastAPI e MongoDB, mas não vamos depender de nada avançado — tudo que usarmos será apresentado ao longo do caminho.

Veja o que vamos precisar:

  • Python 3.10+
  • Um cluster do MongoDB Atlas com Vector Search habilitado
  • Ambiente FastAPI
  • Postman ou cURL
  • Acesso à internet para baixar e usar os modelos de embedding

Bibliotecas Python que usaremos

Vamos instalá-las na etapa de setup:

  • FastAPI: nosso framework web
  • uvicorn: servidor de desenvolvimento
  • pymongo: driver do MongoDB
  • sentence-transformers: modelo de embedding de texto
  • open_clip: modelo de embedding de imagem baseado em CLIP
  • torch: requerido por CLIP e SentenceTransformers
  • Pillow: suporte a processamento de imagem (PIL)

Essas ferramentas nos dão tudo o que precisamos para gerar embeddings, armazená-los no MongoDB e consultá-los de forma eficiente com busca vetorial.

Entendendo a busca vetorial

Antes de escrever código, ajuda entender o que acontece por trás do fluxo. Vector search não é complicado quando o dividimos em partes, e conhecer os fundamentos facilita o restante do tutorial.

O que é um embedding?

Um embedding é simplesmente uma lista de números (um vetor) que representa o significado de um dado.

Para texto, o embedding captura aspectos como contexto e intenção. Para imagens, ele captura padrões e características visuais.

Um exemplo bem simplificado de um embedding seria assim:

[0.21, -0.17, 0.89, ...]

Duas coisas semanticamente semelhantes — por exemplo, duas frases que descrevem a mesma ideia ou duas imagens com objetos parecidos — acabam com vetores matematicamente próximos. A busca vetorial mede essa proximidade.

Como o MongoDB usa embeddings

O MongoDB em si não gera embeddings. Em vez disso, ele foca no que faz melhor:

  • Armazenar vetores de embedding
  • Indexá-los usando um índice vetorial
  • Recuperar vizinhos mais próximos com eficiência

Em outras palavras, nossos modelos geram os embeddings e o MongoDB cuida da busca.

Essa separação clara torna o sistema flexível e escalável.

Tipos de modelos de embedding

Podemos escolher qualquer modelo de embedding, desde que ele gere um vetor numérico. Modelos diferentes se especializam em tipos diferentes de dados:

Tipo de dado

Modelo de exemplo

Observações

Texto

all-MiniLM-L6-v2

Leve e amplamente usado em PLN

Imagem

CLIP/OpenCLIP

Converte imagens em vetores semânticos

Multimodal

Multimodal

Lida com texto e imagem juntos

Esse é o fluxo que vamos implementar com FastAPI e MongoDB Atlas.

Depois de configurado, você poderá buscar textos e imagens por significado — algo que a busca por palavra-chave não faz.

Configurando o MongoDB Atlas

Antes de construir a aplicação FastAPI, precisamos de um lugar para armazenar e consultar nossos embeddings. MongoDB Atlas torna isso simples, e criar índices vetoriais leva só alguns minutos.

1. Crie um cluster

Se você ainda não tem, crie um novo cluster no MongoDB Atlas. O nível gratuito (M0) é perfeito para este tutorial. Consulte a documentação do MongoDB para mais detalhes sobre como criar um cluster.

2. Crie um banco e coleções

Dentro do cluster:

  1. Crie um banco de dados. Vamos chamá-lo de vector_db. Para mais detalhes, consulte a documentação.
  2. Crie duas coleções nele:
    • texts: onde vamos armazenar documentos de texto e seus embeddings
    • images: onde vamos armazenar nomes de arquivos de imagem e embeddings de imagem

Veja a documentação para mais detalhes sobre como criar uma coleção.

Mantivemos as coleções de imagem e de texto separadas porque elas usam modelos e dimensões de vetores diferentes.

3. Crie índices vetoriais

O MongoDB precisa de um índice vetorial para rodar buscas por similaridade rápidas. Vamos criar um índice para embeddings de texto e outro para embeddings de imagem.

Você pode criá-los em Atlas → Collections → Search Indexes. Vamos começar configurando a coleção de texto.

A imagem a seguir explica melhor o processo.

Painel do MongoDB Atlas explicando o processo para criar um índice de busca

Na próxima tela, clique em Vector Search -> JSON Editor -> Next. A imagem a seguir deve ajudar a entender melhor o processo

Painel do MongoDB Atlas explicando o processo para criar um índice de busca. Etapa um do processo.

Painel do MongoDB Atlas explicando o processo para criar um índice de busca. Etapa dois do processo.

Índice vetorial para textos

No índice de busca vetorial, ajuste o JSON para corresponder ao nosso código.

Estamos usando o modelo all-MiniLM-L6-v2 para texto, que produz embeddings de 384 dimensões.

Veja a definição JSON:

{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 384,
      "similarity": "cosine"
    }
  ]
}

Dê a este índice o nome: vector_texts_search e salve.

Isso permite que o MongoDB execute buscas por similaridade por cosseno entre embeddings de texto. A imagem abaixo ilustra o processo em mais detalhes.Painel do MongoDB Atlas explicando o processo para criar um índice de busca. Etapa três do processo.

Image contains a JSON text editor for the JSON definition of the text search.

Índice vetorial para imagens

Para imagens, usamos um modelo baseado em CLIP que gera vetores de 512 dimensões, então o índice de imagens precisa refletir essa dimensão. A definição JSON deve corresponder ao código abaixo. Fora isso, o restante do fluxo é o mesmo. 

{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 512,
      "similarity": "cosine"
    }
  ]
}

Nomeie esse índice: vector_images_search.

Quando ambos os índices estiverem ativos, o MongoDB Atlas estará pronto para consultas de busca vetorial.

Configurando o projeto FastAPI

Com o cluster do MongoDB Atlas e os índices vetoriais prontos, podemos configurar a aplicação FastAPI que vai gerar embeddings e armazená-los no MongoDB. Vamos manter a estrutura do projeto pequena e focada, já que o objetivo aqui é entender o fluxo, não construir um serviço de produção completo.

1. Instale as dependências necessárias

Vamos instalar FastAPI, Uvicorn, o driver Python do MongoDB e as bibliotecas para gerar embeddings de texto e imagem. Rode:

pip install fastapi uvicorn pymongo python-dotenv sentence-transformers torch pillow open_clip_torch python-multipart

Resumo rápido do porquê de cada uma:

  • fastapi — nosso framework de API
  • uvicorn — servidor ASGI para rodar FastAPI
  • pymongo — driver do MongoDB
  • python-dotenv — carrega variáveis de ambiente do .env
  • sentence-transformers — modelo de embedding de texto
  • torch — requerido pelos modelos de embedding
  • pillow — manipulação básica de imagens
  • open_clip_torch — modelo de embedding de imagem baseado em CLIP
  • python-multipart — necessário para upload de arquivos no FastAPI

Instalado isso, podemos estruturar o projeto.

2. Estrutura do projeto

Vamos manter tudo em um único arquivo Python, com a configuração via variáveis de ambiente:

fastapi-mongodb-vector-search/
│── main.py
│── .env
│── venv/

main.py vai conter toda a aplicação: os endpoints de texto, de imagem e a conexão com o MongoDB.

MONGODB_URI="your connection string"
DB_NAME="vector_db"
TEXT_COLLECTION="texts"
IMAGE_COLLECTION="images"
  • MONGODB_URI — a URI do Atlas do seu cluster
  • DB_NAME — o banco que criamos
  • TEXT_COLLECTION — onde texto + embeddings serão armazenados
  • IMAGE_COLLECTION — onde os embeddings de imagem serão salvos

O FastAPI vai carregar isso na inicialização, mantendo a configuração separada do código.

Implementando a busca em textos

Com o projeto FastAPI pronto, começamos pela busca em textos. Esta parte introduz a ideia central da busca vetorial: geramos embeddings para o texto, armazenamos no MongoDB e consultamos usando o índice vetorial criado antes.

Vamos dividir em duas etapas pequenas para facilitar os testes e depuração.

 a. Adicionar texto e gerar embeddings

O primeiro endpoint vai receber um título e um conteúdo de texto. Vamos combinar ambos em uma única string, gerar um embedding com SentenceTransformers e salvar o documento junto com o vetor de embedding.

Veja como fica no código:

# main.py (trecho)

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from pymongo import MongoClient
from sentence_transformers import SentenceTransformer
from dotenv import load_dotenv
import os

load_dotenv()

app = FastAPI()

# --- Configuração do BD ---
client = MongoClient(os.getenv("MONGODB_URI"))
db = client[os.getenv("DB_NAME")]
texts_coll = db[os.getenv("TEXT_COLLECTION")]
Images_coll = db[os.getenv("IMAGE_COLLECTION")]


# --- modelo de embedding de texto ---
MODEL_NAME = "all-MiniLM-L6-v2"
text_model = SentenceTransformer(MODEL_NAME)

# --- schema da requisição ---
class AddTextRequest(BaseModel):
    title: str
    content: str

@app.post("/add-text")
def add_text(payload: AddTextRequest):
    try:
        # Combina os campos para gerar embeddings mais ricos
        text = f"{payload.title}\n\n{payload.content}"

        # Gera o embedding de texto
        embedding = text_model.encode(text).tolist()

        # Armazena o documento no MongoDB
        doc = {
            "title": payload.title,
            "content": payload.content,
            "embedding": embedding,
            "model": MODEL_NAME,
        }

        result = texts_coll.insert_one(doc)

        return {
            "inserted_id": str(result.inserted_id),
            "title": payload.title
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Como testar este endpoint

cURL, Postman e outros podem ser usados para testar. Neste tutorial, vamos usar o Postman.

Também precisamos expor nosso endpoint FastAPI na internet para testar o Postman na web. Vamos usar o Ngrok para isso. Se você é novo no Ngrok, visite a documentação. Para testar, primeiro rode o FastAPI com o comando abaixo:

uvicorn main:app --reload

Depois, crie um túnel do seu localhost para a internet usando o comando do Ngrok abaixo:

Ngrok http 8000

Isso vai gerar uma URL para testes, como na imagem abaixo:

Imagem de um terminal com o servidor Ngrok em execução. 
Contém a URL do localhost e a URL pública do túnel

Envie uma requisição POST com o Postman para o endpoint add-text. A imagem abaixo ilustra o envio e a resposta esperada.

Imagem de uma chamada de API feita no Postman, URL do Ngrok e resposta da API.

Resposta esperada:

{
  "inserted_id": "65f...",
  "title": "Why FastAPI is great."
}

Isso confirma que seu modelo de embedding carregou corretamente e que o MongoDB armazenou o vetor. Se isso funcionou, seu pipeline de texto está operacional.

b. Buscar texto com busca vetorial

Agora que podemos adicionar texto, o próximo passo é buscá-lo usando o estágio $vectorSearch do MongoDB. Aqui, vamos:

  1. Converter a consulta do usuário em um embedding.
  2. Pedir ao MongoDB para recuperar os vetores mais próximos.
  3. Retornar os documentos mais similares.

Adicione o endpoint abaixo ao main.py:

class SearchTextRequest(BaseModel):
    query: str
    limit: int = 5

@app.post("/search-text")
def search_text(payload: SearchTextRequest):
    try:
        # Converte a consulta em embedding
        query_vector = text_model.encode(payload.query).tolist()

        # Pipeline de busca vetorial
        pipeline = [
            {
                "$vectorSearch": {
                    "queryVector": query_vector,
                    "path": "embedding",
                    "numCandidates": 100,
                    "limit": payload.limit,
                    "index": "vector_texts_search" # o nome DEVE ser exatamente o mesmo do índice no Atlas


                }
            },
            {
                "$project": {
                    "title": 1,
                    "content": 1,
                    "score": {"$meta": "vectorSearchScore"},
                    "_id": 0
                }
            }
        ]

        results = list(texts_coll.aggregate(pipeline))
        return {"results": results}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

> O parâmetro numCandidates determina quantos potenciais matches são avaliados antes de retornar os melhores resultados. 

> Valores maiores melhoram a precisão, mas aumentam o tempo da consulta. Uma boa regra prática é 10–20x o seu limit.

Como testar a busca em texto

Depois de adicionar um ou mais documentos, faça uma requisição POST ao endpoint /search-text pelo Postman usando o link gerado pelo Ngrok, como na imagem abaixo:

Imagem de uma chamada de API feita no Postman, URL do Ngrok e resposta da API.

Saída esperada:

{
  "results": [
    {
      "title": "Why FastAPI is great",
      "content": "FastAPI makes building APIs simple and fast.",
      "score": 0.85
    }
  ]
}

Se você vir um resultado com pontuação de similaridade, sua pipeline de busca vetorial em texto está funcionando de ponta a ponta. Com essa parte estável, podemos partir para o fluxo de imagens.

Implementando a busca em imagens

Com o fluxo de texto rodando bem, vamos estender a ideia para imagens. O fluxo geral é similar — a grande diferença é como geramos os embeddings. Em vez de SentenceTransformers, usaremos um modelo baseado em CLIP, feito para converter imagens em vetores de 512 dimensões.

Assim como antes, vamos implementar passo a passo para facilitar testes e depuração.

a. Adicionar imagem e gerar embeddings

Este endpoint aceita um arquivo de imagem, converte para um tensor que o CLIP entende, gera um embedding de 512 dimensões e o armazena no MongoDB.

Veja como fica:

# --- configuração do modelo CLIP ---
import torch
import open_clip
from PIL import Image
import io
from fastapi import UploadFile, File

# Carrega o modelo CLIP uma vez na inicialização
clip_model, _, preprocess = open_clip.create_model_and_transforms(
    "ViT-B-32",
    pretrained="openai"
)
device = "cuda" if torch.cuda.is_available() else "cpu"
clip_model.to(device)

@app.post("/add-image")
async def add_image(file: UploadFile = File(...)):
    """
    Faça upload de uma imagem, gere o embedding com CLIP e armazene no MongoDB.
    """
    try:
        # Lê o conteúdo do arquivo
        image_bytes = await file.read()
        image = Image.open(io.BytesIO(image_bytes)).convert("RGB")

        # Pré-processa para o CLIP e codifica
        image_tensor = preprocess(image).unsqueeze(0).to(device)
        with torch.no_grad():
            image_embedding = clip_model.encode_image(image_tensor)

        # Normaliza o embedding (importante para similaridade por cosseno)
        image_embedding /= image_embedding.norm(dim=-1, keepdim=True)
        vector = image_embedding.cpu().numpy().flatten().tolist()

        # Armazena no MongoDB
        doc = {
            "filename": file.filename,
            "embedding": vector
        }
        result = images_coll.insert_one(doc)

        return {
            "inserted_id": str(result.inserted_id),
            "filename": file.filename
        }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Por que a normalização importa

Embeddings do CLIP funcionam melhor com similaridade por cosseno. Para deixar as comparações mais precisas e estáveis, nós normalizamos os vetores:

image_embedding /= image_embedding.norm(dim=-1, keepdim=True)

Isso garante que a distância por cosseno reflita a similaridade real.

Teste o endpoint de upload de imagem

Para testar no Postman, faça um POST para o endpoint /add-image. Envie um form-data no corpo da requisição com qualquer imagem .jpg ou .png. A imagem abaixo demonstra o processo.

Imagem de uma chamada de API feita no Postman, URL do Ngrok e resposta da API.

Se tudo estiver certo, você verá algo como:

{
  "inserted_id": "692454f6156fbb762ed865a0",
  "filename": "file-name.png"
}

Neste ponto, seus embeddings de imagem estão armazenados com sucesso no MongoDB.

b. Buscar imagens com busca vetorial

Agora, vamos construir o endpoint que recebe uma imagem de consulta, converte em embedding e encontra as imagens armazenadas mais próximas usando nosso índice vetorial de imagens.

Adicione isto ao main.py:

@app.post("/search-image")
async def search_image(file: UploadFile = File(...)):
    """
    Faça upload de uma imagem e encontre as mais visualmente similares no MongoDB.
    """
    try:
        # Lê o arquivo enviado
        image_bytes = await file.read()
        image = Image.open(io.BytesIO(image_bytes)).convert("RGB")

        # Gera o embedding para a imagem de consulta
        image_tensor = preprocess(image).unsqueeze(0).to(device)
        with torch.no_grad():
            query_embedding = clip_model.encode_image(image_tensor)

        query_embedding /= query_embedding.norm(dim=-1, keepdim=True)
        query_vector = query_embedding.cpu().numpy().flatten().tolist()

        # Pipeline de busca vetorial
        pipeline = [
            {
                "$vectorSearch": {
                    "queryVector": query_vector,
                    "path": "embedding",
                    "numCandidates": 100,
                    "limit": 5,
                    "index": "vector_images_search"
                }
            },
            {
                "$project": {
                    "filename": 1,
                    "score": {"$meta": "vectorSearchScore"},
                    "_id": 0
                }
            }
        ]

        results = list(images_coll.aggregate(pipeline))
        return {"results": results}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Teste o endpoint de busca por imagem

Para testar no Postman, faça um POST para o endpoint /search-image. Envie o form-data no corpo da requisição com alguma imagem similar às que você armazenou antes. A imagem abaixo demonstra o processo.

Imagem de uma chamada de API feita no Postman, URL do Ngrok para a rota /search-image e resposta da API.

A saída esperada deve ser assim:

{
  "results": [
    {
      "filename": "image1.png",
      "score": 1.0
    },
    {
      "filename": "image2.png",
      "score": 0.81
    }
  ]
}

Uma pontuação de 1,0 significa que corresponde à mesma imagem. Qualquer valor próximo (0,7–0,9) indica forte similaridade visual.

Se você vir um array com resultados, sua busca vetorial por imagens está funcionando.

Neste ponto, se tudo funcionou, temos um sistema de busca semântica completo para texto e imagem.

Conclusão

Neste tutorial, construímos um workflow completo de busca semântica com FastAPI e MongoDB Atlas. Geramos embeddings de texto com SentenceTransformers, criamos embeddings de imagem com um modelo CLIP, armazenamos tudo no MongoDB e consultamos usando o Vector Search do MongoDB e o Postman. Esse padrão é a base para aplicativos como busca semântica de documentos, ferramentas de similaridade de imagens, sistemas de recomendação e recursos de IA multimodal.

O que torna essa arquitetura poderosa é a flexibilidade: o MongoDB não prende você a modelos específicos. Desde que os embeddings sejam vetores numéricos e as dimensões batam com a configuração do índice, você pode plugar qualquer modelo de texto, imagem ou multimodal que seu caso de uso exigir.

Com essa base, você pode expandir o projeto — armazenar metadados, criar lógica de ranqueamento ou integrar com apps para usuários finais. E o mesmo fluxo escala facilmente com os serviços gerenciados do MongoDB Atlas.

Você encontra o projeto completo em funcionamento no GitHub.


Moses Anumadu's photo
Author
Moses Anumadu

Engenheiro de Software

Temas
MongoDB

Top DataCamp Courses

Curso

Introdução ao MongoDB em Python

3 h
24.4K
Aprenda a mexer e analisar dados estruturados de forma flexível com o MongoDB.
Ver detalhesComeçar Curso

Crie sua conta gratuita

Pratique e programa seu progresso.

Continuar Com O Google
Ao continuar, você aceita nossos Termos de Uso, nossa Política de Privacidade e que seus dados serão armazenados nos EUA.
Ver mais
Relacionado

blog

O que são embeddings vetoriais? Uma explicação intuitiva

As incorporações de vetores são representações numéricas de palavras ou frases que capturam seus significados e relacionamentos, ajudando os modelos de machine learning a entender o texto com mais eficiência.

blog

Os 7 melhores bancos de dados vetoriais em 2026

Um guia completo com os melhores bancos de dados vetoriais. Domine o armazenamento de dados de alta dimensão, decifrar informações não estruturadas e aproveitar as incorporações vetoriais para aplicações de IA.
Moez Ali's photo

Moez Ali

14 min

Tutorial

Tutorial pgvector: Integrar a Pesquisa Vetorial no PostgreSQL

Descubra como melhorar o PostgreSQL com recursos de pesquisa vetorial usando o pgvector. Este tutorial te mostra como instalar, usar as funções básicas e integrar com ferramentas de IA.
Moez Ali's photo

Moez Ali

10 min

Tutorial

Tutorial FastAPI: Uma introdução ao uso da FastAPI

Explore a estrutura FastAPI e descubra como você pode usá-la para criar APIs em Python
Moez Ali's photo

Moez Ali

13 min

Tutorial

Introdução ao Text Embeddings com a API OpenAI

Explore nosso guia sobre como usar a API OpenAI para criar incorporações de texto. Descubra suas aplicações na classificação de textos, recuperação de informações e detecção de similaridade semântica.
Zoumana Keita 's photo

Zoumana Keita

7 min

Tutorial

Tutorial do Chroma DB: Um guia passo a passo

Com o Chroma DB, você pode gerenciar facilmente documentos de texto, converter texto em embeddings e fazer pesquisas de similaridade.
Abid Ali Awan's photo

Abid Ali Awan

10 min

Ver mais