Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/geremyjampiersalasgarcia-eng/Caso_Practico_Semillero_IA/llms.txt

Use this file to discover all available pages before exploring further.

The ingestion script reads the three Patito S.A. knowledge-base documents from backend/data/raw/, splits them into overlapping chunks, vectorizes each chunk using the Gemini embedding model, and stores the results in three dedicated ChromaDB collections. This script must be run once after the backend environment is set up, and must be re-run whenever any source document changes — the agents cannot answer questions until their collections are populated.
If you start the FastAPI backend before running ingestion, all RAG agents will return errors similar to Collection 'col_catalogo' not found or produce empty responses because there are no vectors to retrieve. Always complete ingestion before directing traffic to the API.

Running ingestion

Activate your Python virtual environment, navigate to the backend/ directory, and run:
cd backend
source .venv/bin/activate      # or .venv\Scripts\activate on Windows
python scripts/ingest.py
The script prints structured log lines for every step. A successful run looks like:
============================================================
INGESTA DE DOCUMENTOS — Mesa de Ayuda Ventas Patito S.A.
============================================================
Cargando documentos desde: data/raw
Archivo cargado  file=01_Catalogo_Productos_Precios.txt          chunks=1
Archivo cargado  file=02_Politicas_Comerciales_Descuentos_Credito.txt  chunks=1
Archivo cargado  file=03_Proceso_Ventas_CRM.txt                  chunks=1
Total de documentos cargados: 3
Limpiando colecciones existentes...
--- Procesando colección: col_catalogo ---
Chunks generados: 42
✅ Colección 'col_catalogo' indexada con 42 chunks
--- Procesando colección: col_politicas ---
Chunks generados: 31
✅ Colección 'col_politicas' indexada con 31 chunks
--- Procesando colección: col_proceso_ventas ---
Chunks generados: 28
✅ Colección 'col_proceso_ventas' indexada con 28 chunks
============================================================
¡INGESTA FINALIZADA EXITOSAMENTE!
============================================================
Resumen de colecciones:
  • col_catalogo: 42 documentos indexados
  • col_politicas: 31 documentos indexados
  • col_proceso_ventas: 28 documentos indexados
Confirm success by verifying that all three collections show a non-zero document count in the summary block at the end.
GOOGLE_API_KEY must be set in backend/.env before running the ingestion script. Every chunk is vectorized by calling the Gemini Embeddings API (models/gemini-embedding-001), so the script will fail immediately with an authentication error if the key is missing or invalid.

What gets indexed

Source fileChromaDB collectionUsed by agent(s)
01_Catalogo_Productos_Precios.txtcol_catalogoCatalog & Prices agent, Multimodal Image agent
02_Politicas_Comerciales_Descuentos_Credito.txtcol_politicasCommercial Policies agent
03_Proceso_Ventas_CRM.txtcol_proceso_ventasSales Process & CRM agent
All source files must be present in backend/data/raw/ before ingestion is run. The script determines the target collection by matching filename prefixes (01_Catalogo, 02_Politicas, 03_Proceso) — files that do not match any prefix are skipped with a warning.

Ingestion pipeline steps

1

Load documents from disk

app.rag.loader.load_documents() scans data/raw/ recursively using pathlib. Each .txt file is read by LangChain’s TextLoader with UTF-8 encoding. PDF files are handled by PyPDFLoader. The filename is attached as doc.metadata["filename"] and doc.metadata["source"] for traceability downstream.
loader = TextLoader(str(file_path), encoding="utf-8")
docs = loader.load()
2

Split into overlapping chunks

app.rag.splitter.split_documents() passes the loaded documents through LangChain’s RecursiveCharacterTextSplitter with the following configuration drawn from app.config.settings:
splitter = RecursiveCharacterTextSplitter(
    chunk_size=settings.CHUNK_SIZE,      # default: 1000 characters
    chunk_overlap=settings.CHUNK_OVERLAP, # default: 200 characters
    separators=["\n\n", "\n", ".", " ", ""]
)
chunks = splitter.split_documents(documents)
The separator hierarchy ensures the splitter first tries to break on paragraph boundaries (\n\n), then line breaks (\n), then sentence endings (.), and finally word boundaries ( ) — preserving semantic coherence in each chunk.
3

Generate embeddings via Gemini

app.rag.vectorstore.get_vectorstore() initializes a Chroma instance with a GoogleGenerativeAIEmbeddings function:
from langchain_google_genai import GoogleGenerativeAIEmbeddings

embeddings = GoogleGenerativeAIEmbeddings(
    model=settings.EMBEDDING_MODEL_NAME  # default: models/gemini-embedding-001
)
Each chunk’s text is sent to the Gemini Embeddings API, and the resulting high-dimensional vector is associated with the chunk’s content and metadata.
4

Persist vectors to ChromaDB

app.rag.vectorstore.index_documents() calls vectorstore.add_documents(chunks) to write all chunk vectors and metadata into the named ChromaDB collection under data/chroma_db/:
vectorstore = Chroma(
    collection_name=collection_name,   # e.g. "col_catalogo"
    embedding_function=embeddings,
    persist_directory=settings.CHROMA_PERSIST_DIR  # default: data/chroma_db
)
vectorstore.add_documents(documents)
ChromaDB persists the collections to disk immediately — no separate save call is required.

Re-indexing

Because ingest.py clears every collection before re-indexing, it is safe to run the script multiple times. Old vectors are deleted before new ones are inserted, so there is no risk of duplicate or stale chunks accumulating:
# From scripts/ingest.py — clear_collection()
existing = vs.get()
if existing and existing.get("ids"):
    vs.delete(ids=existing["ids"])
To update the knowledge base after editing a source document, simply re-run the script:
cd backend
python scripts/ingest.py
No backend restart is needed after re-indexing — ChromaDB reads from disk on every query, so agents will pick up the new vectors immediately.

API-based ingestion

As an alternative to the command-line script, the FastAPI backend exposes a REST endpoint for triggering ingestion programmatically while the server is running:
POST /api/v1/documents/ingest
The endpoint accepts a JSON body specifying the source directory and the target collection. It processes one collection per request and runs the ingestion in the background:
{
  "directory_path": "data/raw",
  "collection_name": "col_catalogo"
}
Unlike scripts/ingest.py, this endpoint does not clear the existing collection before inserting new documents. To replace the contents of a collection via the API, you must clear it manually before calling the endpoint.
For the initial setup of a fresh environment, prefer the command-line script — it clears all collections, processes all three source files in one pass, and produces verbose step-by-step log output that makes it easy to spot missing files, Gemini API quota errors, or ChromaDB permission issues before the backend is serving traffic.

Build docs developers (and LLMs) love