Retrieval Augmented Generation (RAG) with Feast
Last updated
Was this helpful?
Was this helpful?
project: rag
provider: local
registry: data/registry.db
online_store:
type: milvus
path: data/online_store.db
vector_enabled: true
embedding_dim: 384
index_type: "IVF_FLAT"
offline_store:
type: file
entity_key_serialization_version: 3
# By default, no_auth for authentication and authorization, other possible values kubernetes and oidc. Refer the documentation for more details.
auth:
type: no_authfrom datetime import timedelta
from feast import Entity, FeatureView, Field, FileSource
from feast.types import Array, Float32, Int64, String, UnixTimestamp, ValueType
# Define entities
document = Entity(
name="document_id",
description="Document ID",
value_type=ValueType.INT64,
)
# Define data source
source = FileSource(
path="data/embedded_documents.parquet",
timestamp_field="event_timestamp",
created_timestamp_column="created_timestamp",
)
# Define the view for retrieval
document_embeddings = FeatureView(
name="embedded_documents",
entities=[document],
schema=[
Field(
name="vector",
dtype=Array(Float32),
vector_index=True, # Vector search enabled
vector_search_metric="COSINE", # Distance metric configured
),
Field(name="document_id", dtype=Int64),
Field(name="created_timestamp", dtype=UnixTimestamp),
Field(name="sentence_chunks", dtype=String),
Field(name="event_timestamp", dtype=UnixTimestamp),
],
source=source,
ttl=timedelta(hours=24),
)feast applyfrom feast import FeatureStore
import pandas as pd
import numpy as np
from transformers import AutoTokenizer, AutoModel
import torch
import torch.nn.functional as F
# Initialize FeatureStore
store = FeatureStore(".")
# Function to generate embeddings
def mean_pooling(model_output, attention_mask):
token_embeddings = model_output[0]
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(
input_mask_expanded.sum(1), min=1e-9
)
def generate_embeddings(sentences, tokenizer, model):
encoded_input = tokenizer(
sentences, padding=True, truncation=True, return_tensors="pt"
)
with torch.no_grad():
model_output = model(**encoded_input)
sentence_embeddings = mean_pooling(model_output, encoded_input["attention_mask"])
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
return sentence_embeddings.detach().cpu().numpy()
# Example data
data = {
"document_id": [1, 2, 3],
"sentence_chunks": [
"New York City is the most populous city in the United States.",
"Los Angeles is the second most populous city in the United States.",
"Chicago is the third most populous city in the United States."
],
"event_timestamp": pd.to_datetime(["2023-01-01", "2023-01-01", "2023-01-01"]),
"created_timestamp": pd.to_datetime(["2023-01-01", "2023-01-01", "2023-01-01"])
}
# Load model and tokenizer
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
# Generate embeddings
embeddings = generate_embeddings(data["sentence_chunks"], tokenizer, model)
# Create DataFrame with embeddings
df = pd.DataFrame(data)
df["vector"] = embeddings.tolist()
# Write to online store
store.write_to_online_store(feature_view_name='embedded_documents', df=df)from feast import FeatureStore
# Initialize FeatureStore
store = FeatureStore(".")
# Generate query embedding
query = "What is the largest city in the US?"
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
query_embedding = generate_embeddings([query], tokenizer, model)[0].tolist()
# Retrieve similar documents
context_data = store.retrieve_online_documents_v2(
features=[
"embedded_documents:vector",
"embedded_documents:document_id",
"embedded_documents:sentence_chunks",
],
query=query_embedding,
top_k=3,
distance_metric='COSINE',
).to_df()
print(context_data)from openai import OpenAI
import os
client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY"),
)
# Format documents for context
def format_documents(context_data, base_prompt):
documents = "\n".join([f"Document {i+1}: {row['embedded_documents__sentence_chunks']}"
for i, row in context_data.iterrows()])
return f"{base_prompt}\n\nContext documents:\n{documents}"
BASE_PROMPT = """You are a helpful assistant that answers questions based on the provided context."""
FULL_PROMPT = format_documents(context_data, BASE_PROMPT)
# Generate response
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": FULL_PROMPT},
{"role": "user", "content": query}
],
)
print(response.choices[0].message.content)