← All ivy-nodes
IVYXSTUDIO · IVY NODE
K

Knowledge Base Ingest

ivy.node.kb-ingest · v0.0.0

ivyx

Ingests text documents into a Milvus collection for retrieval. Embeds each document with a Hugging Face model (CLS pooling + L2 normalize — identical to ivy.node.rag-kb-answer so query and index vectors match), (re)creates the target collection sized to the embedding dimension, and inserts {vector, text} rows. Run this once to populate the knowledge base before querying with rag-kb-answer. Demonstrates the multi-cell program layout (input / implementation / run cells share one kernel session).

#rag#kb#ingest#milvus

Inputs

FieldTypeDescription
docsrequiredarrayText documents/passages to index.
model_namerequiredstringHugging Face embedding model id (must match the query node).
hugging_face_tokenstringHugging Face token; empty string for public models.
milvus_urirequiredstringMilvus connection URI (e.g. /tmp/kb.db).
collection_namerequiredstringTarget Milvus collection name.
drop_existingbooleanDrop the collection first if it already exists.
featuresobjectFeatures
labelsobjectLabels

Outputs

FieldTypeDescription
inserted_countrequiredintegerNumber of documents inserted.
dimintegerEmbedding dimension of the created collection.
collection_namestringThe collection that was populated.
featuresobjectFeatures
labelsobjectLabels

Source

python

# Cell 1 — input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
docs = inp["docs"]
model_name = inp["model_name"]
hugging_face_token = inp.get("hugging_face_token", "") or None
milvus_uri = inp["milvus_uri"]
collection_name = inp["collection_name"]
drop_existing = bool(inp.get("drop_existing", True))

# Cell 2 — implementation (shares the session with cell 1)
from typing import List
import torch
from transformers import AutoTokenizer, AutoModel
from pymilvus import MilvusClient

class KbIngest:
    """Embeds documents and inserts them into a Milvus collection."""

    def __init__(self, model_name: str, hugging_face_token, milvus_uri: str):
        self.tokenizer = AutoTokenizer.from_pretrained(model_name, token=hugging_face_token)
        self.model = AutoModel.from_pretrained(model_name, token=hugging_face_token)
        self.milvus = MilvusClient(uri=milvus_uri)

    def embed(self, text: str) -> List[float]:
        inputs = self.tokenizer(text, return_tensors="pt", padding=True, truncation=True)
        with torch.no_grad():
            outputs = self.model(**inputs)
        emb = outputs.last_hidden_state[:, 0, :]
        return torch.nn.functional.normalize(emb, p=2, dim=1).squeeze().tolist()

    def ingest(self, docs: List[str], collection_name: str, drop_existing: bool):
        if not docs:
            raise ValueError("docs is empty")
        vectors = [self.embed(d) for d in docs]
        dim = len(vectors[0])
        if drop_existing and self.milvus.has_collection(collection_name):
            self.milvus.drop_collection(collection_name)
        if not self.milvus.has_collection(collection_name):
            self.milvus.create_collection(collection_name=collection_name, dimension=dim, auto_id=True)
        rows = [{"vector": v, "text": d} for v, d in zip(vectors, docs)]
        self.milvus.insert(collection_name, rows)
        return len(rows), dim

# Cell 3 — run + output collection
ingestor = KbIngest(model_name=model_name, hugging_face_token=hugging_face_token, milvus_uri=milvus_uri)
inserted_count, dim = ingestor.ingest(docs, collection_name, drop_existing)

out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["inserted_count"] = inserted_count
out["dim"] = dim
out["collection_name"] = collection_name

Tests

Requires: python:3.11

  • basic-ingest

    Embed and insert a few docs (network; tolerate success or environment error).

    ragingestbasic
  • empty-docs

    Empty docs list should fail.

    ragingesterror