from datasets import Dataset
from app import retrieve_relevant_documents, emb_text, model, embedding_model
from langchain_classic.chains.combine_documents import create_stuff_documents_chain
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema.runnable import RunnableLambda
from langchain_core.documents import Document
def setup_standalone_rag_chain():
"""Setup a standalone RAG chain for testing without Chainlit session."""
def get_context_and_history(inputs):
"""Retrieve context without session history."""
query = inputs["question"]
relevant_docs = retrieve_relevant_documents(query, limit=5)
print("Relevant documents:", relevant_docs[0] if relevant_docs else "No documents found")
# Convert dictionaries to Document objects for LangChain
doc_objects = []
for doc in relevant_docs:
doc_obj = Document(
page_content=doc.get('text', ''),
metadata=doc.get('metadata', {})
)
doc_objects.append(doc_obj)
return {
"question": query,
"context": doc_objects,
"history": [] # Empty history for testing
}
system_prompt = """You are a helpful assistant specialising in developing non-discriminatory competence standards and disability support, reasonable adjustments, and equality legislation.
When answering questions, you should:
1. Use the provided context documents to inform your response
2. Be accurate and helpful
3. If the context doesn't contain relevant information, say so clearly
4. Always reply in English
5. Provide clear recommendations and examples wherever applicable
6. Do not make assumptions about the user's knowledge or background
7. If the user asks for a specific law or regulation, provide a brief explanation and cite relevant documents if available.
8. Do not overemphasize disability in your responses, but rather focus on the support and adjustments that can be made to ensure equality and inclusivity.
9. If the user query explicitly asks for a disability-related topic, provide a well-informed response based on the context documents.
Context documents:
{context}
Please provide a clear response using the above context
"""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
MessagesPlaceholder(variable_name="history"),
("human", "{question}"),
])
question_answer_chain = create_stuff_documents_chain(model, prompt)
# Use a custom chain that properly handles our context and history
def process_input_and_format(inputs):
context_data = get_context_and_history(inputs)
return {
"context": context_data["context"],
"question": context_data["question"],
"history": context_data["history"]
}
chain = RunnableLambda(process_input_and_format) | question_answer_chain
return chain
# Setup the RAG chain
rag_chain = setup_standalone_rag_chain()
questions = ["What is a 'reasonable adjustment'?",
"To whom do competence standards apply?",
"Do competence standards vary by subject?",
]
ground_truths = [
"""The reasonable adjustments duty contains three requirements, which relate to changing
how things are done, changing the built environment to avoid such a substantial
disadvantage and providing auxiliary aids and services. Specifically:
1. A duty to make reasonable adjustments to any provision, criterion or practice (PCP)
which places disabled students at a substantial disadvantage
2. A duty to make reasonable adjustments to physical features
3. A duty to provide auxiliary aids (including services) """,
"""The Act does not specify to whom competence standards may be applied but it is clear that
anti-discrimination provisions apply to prospective and current students (and in some cases
former students).
Providers commonly apply competence standards to:13
+ Applicants, to determine whether they have the knowledge and skills necessary to
participate in and complete a course of study
+ Students, to determine whether they are ready to progress to the next year/stage of
study, and to determine whether they have demonstrated the requirements in order to be
awarded a qualification that necessitates a competence standard to be applied.""",
"""Competence standards can - and should - vary between courses of study. What may
constitute a competence standard in one subject area may not be justifiable in another. """]
answers = []
contexts = []
def clean_answer(answer):
"""Remove tags and content from the answer."""
import re
# Remove everything between and tags, including the tags themselves
cleaned = re.sub(r'.*?\s*', '', answer, flags=re.DOTALL)
return cleaned.strip()
# Inference
for query in questions:
# Get answer from the RAG chain
answer = rag_chain.invoke({"question": query})
# Clean the answer to remove thinking content
cleaned_answer = clean_answer(answer)
answers.append(cleaned_answer)
# Get relevant documents for context
relevant_docs = retrieve_relevant_documents(query, limit=5)
context_texts = [doc['text'] for doc in relevant_docs]
contexts.append(context_texts)
# To dict
data = {
"question": questions,
"answer": answers,
"contexts": contexts,
"reference": ground_truths
}
# Convert dict to dataset
dataset = Dataset.from_dict(data)
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_recall,
context_precision,
)
result = evaluate(
llm=model,
embeddings=embedding_model,
dataset = dataset,
metrics=[
context_precision,
context_recall,
faithfulness,
answer_relevancy,
],
)
# df = result.to_pandas()
evaluation_results = result.to_pandas()
display_columns = ['user_input', 'answer_relevancy', 'faithfulness', 'context_precision', 'context_recall']
formatted_results = evaluation_results[display_columns].to_markdown(index=False, numalign="left", stralign="left")
print(formatted_results)