← All ivy-nodes
IVYXSTUDIO · IVY NODE
R
RAG Knowledge Base Answer
ivy.node.rag-kb-answer · v0.0.0
ivyx✓
Single-node retrieval-augmented generation: embeds the question with a Hugging Face model, retrieves the most similar passages from a Milvus collection, assembles a grounded context, and asks an OpenAI chat model for a context-grounded answer. The whole external call is governed (policy risk:high, approval:step) so an agent cannot answer from the knowledge base without approval. All third-party calls run inside the node's Python (compute kernel), matching the existing node library convention.
#rag#kb#llm#retrieval
Inputs
| Field | Type | Description |
|---|---|---|
| questionrequired | string | The user question to answer from the knowledge base. |
| hugging_face_tokenrequired | string | Hugging Face access token for loading the embedding model. |
| model_namerequired | string | Hugging Face embedding model id (e.g. sentence-transformers/all-MiniLM-L6-v2). |
| milvus_urirequired | string | Milvus connection URI (e.g. /tmp/kb.db). |
| collection_namerequired | string | Milvus collection holding the indexed embeddings. |
| openai_api_keyrequired | string | OpenAI API key for the answer generation step. |
| openai_model | string | OpenAI chat model id. |
| system_message | string | System prompt for the answer model. |
| top_k | integer | Number of passages to retrieve. |
| max_tokens | integer | Max tokens for the answer. |
| features | object | Features |
| labels | object | Labels |
Outputs
| Field | Type | Description |
|---|---|---|
| answerrequired | string | The grounded answer generated from retrieved context. |
| context | string | The retrieved context passages used to ground the answer. |
| features | object | Features |
| labels | object | Labels |
Source
python
# Input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
question = inp["question"]
hugging_face_token = inp["hugging_face_token"]
model_name = inp["model_name"]
milvus_uri = inp["milvus_uri"]
collection_name = inp["collection_name"]
openai_api_key = inp["openai_api_key"]
openai_model = inp.get("openai_model", "gpt-4o")
system_message = inp.get("system_message", "You are a helpful assistant. Answer strictly from the provided context. If the answer is not in the context, say you do not know.")
top_k = int(inp.get("top_k", 4))
max_tokens = int(inp.get("max_tokens", 1024))
# Compute
from typing import List
import torch
from transformers import AutoTokenizer, AutoModel
from pymilvus import MilvusClient
from openai import OpenAI
class RagKbAnswer:
"""
Single-node RAG: embed question -> Milvus search -> grounded OpenAI answer.
"""
def __init__(self, model_name: str, hugging_face_token: str, milvus_uri: str, openai_api_key: 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)
self.openai = OpenAI(api_key=openai_api_key)
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 retrieve(self, collection_name: str, vector: List[float], top_k: int) -> str:
hits = self.milvus.search(
collection_name=collection_name,
data=[vector],
limit=top_k,
output_fields=["text"],
)
passages = []
for group in hits:
for item in group:
entity = item.get("entity", {}) if isinstance(item, dict) else {}
text = entity.get("text")
if text:
passages.append(text)
return "\n\n".join(passages)
def generate(self, system_message: str, context: str, question: str, model: str, max_tokens: int) -> str:
user_content = f"Context:\n{context}\n\nQuestion: {question}"
completion = self.openai.chat.completions.create(
model=model,
max_tokens=max_tokens,
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": user_content},
],
)
return completion.choices[0].message.content or ""
def run(self, question: str, collection_name: str, system_message: str, model: str, top_k: int, max_tokens: int):
vector = self.embed(question)
context = self.retrieve(collection_name, vector, top_k)
answer = self.generate(system_message, context, question, model, max_tokens)
return answer, context
rag = RagKbAnswer(model_name=model_name, hugging_face_token=hugging_face_token, milvus_uri=milvus_uri, openai_api_key=openai_api_key)
answer, context = rag.run(question, collection_name, system_message, openai_model, top_k, max_tokens)
# Output collection (runner reads __ivy_ctx__)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["answer"] = answer
out["context"] = contextTests
Requires: python:3.11
- basic-rag-answer
Answer a question against a knowledge base (network; tolerate success or environment error).
ragkbllmbasic - missing-question
Missing required question should fail.
ragerror