emerald-rag / helpers.py
ben-wang's picture
Update helpers.py
bf2ce8d verified
Raw
History Blame Contribute Delete
3.65 kB
"""
helpers.py - RAG Orchestration & Document Processing
This module defines the utility functions for the Pokémon Emerald knowledge base.
It manages the end-to-end retrieval pipeline, including:
- Document Ingestion: Recursive character splitting optimized for technical manuals.
- Vector Management: Integration with ChromaDB for semantic search.
- Prompt Engineering: Context-aware prompt construction with strict Pydantic
formatting instructions to ensure structured JSON output.
"""
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import PydanticOutputParser
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from model import load_embedding_model
from schema import PokemonEmeraldResponse
MANUAL_PATH = "emerald_manual.txt"
def load_vector_store(filename):
"""
Load, split, and index the game manual into a ChromaDB vector store.
Args:
filename: Path to the source .txt manual.
Returns:
Initialised vector store for similarity search.
"""
print("Loading vector store...")
loader = TextLoader(MANUAL_PATH)
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
chunks = text_splitter.split_documents(data)
embedding_model = load_embedding_model()
print(f"Created {len(chunks)} chunks.")
store = Chroma.from_documents(documents=chunks, embedding=embedding_model)
return store
def find_similar_documents(vector_store, message, k=5):
"""
Queries the vector store for manual snippets matching the user's message.
Args:
vector_store: Initialized Chroma/FAISS instance.
message: The user's natural language question.
k: Number of context chunks to retrieve (default=5 for high density).
Returns:
List of Document objects containing page_content and metadata.
"""
print("Retrieving relevant documents...")
context = vector_store.similarity_search(message, k=k)
for i, x in enumerate(context):
print(f"i={i}" + "-"*20)
print(x)
print()
return context
def create_prompt(message, history, context):
"""
Constructs a grounded, instruction-tuned prompt for the LLM.
Integrates retrieved manual context with a strict system persona to
mitigate hallucinations. Injects Pydantic-generated format instructions
to ensure the model's response is a valid JSON object matching the
PokemonEmeraldResponse schema.
"""
parser = PydanticOutputParser(pydantic_object=PokemonEmeraldResponse)
context_text = "\n---\n".join([d.page_content for d in context])
format_instructions = parser.get_format_instructions()
prompt = f"""
System: You are a precise Pokémon Emerald Research Assistant. Your goal is to answer questions using
ONLY the provided context. If the answer is not contained within the context, state: No relevant
sources found. Citations should be sufficient to keep context and at least a couple of sentences.
Include all relevant documents in citations.
Context: {context_text}
Question: {message}
{format_instructions}
Follow the format instructions exactly. The output will be parsed as a single JSON.
If the answer cannot be found in the provided context, or if you do not know the answer,
state exactly: "I do not have enough information to answer this."
Do not repeat previous responses, and do not attempt to guess.
"""
return prompt