mirror of
https://github.com/Shubhamsaboo/awesome-llm-apps.git
synced 2026-03-11 17:48:31 -05:00
Merge pull request #189 from sahithi37/main
Added Agentic RAG Math Tutor Agent (Human-in-the-Loop)
This commit is contained in:
72
starter_ai_agents/agentic_rag_math_agent/README.md
Normal file
72
starter_ai_agents/agentic_rag_math_agent/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 🧠 Math Tutor Agent – Agentic RAG with Feedback Loop
|
||||
|
||||
This project implements an **Agentic-RAG architecture** to simulate a math professor that solves **JEE-level math questions** with step-by-step explanations. The system smartly routes queries between a vector database and web search, applies input/output guardrails, and incorporates human feedback for continuous learning.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Features
|
||||
|
||||
- ✅ **Input Guardrails** (DSPy): Accepts only academic math questions.
|
||||
- 📚 **Knowledge Base Search**: Uses **Qdrant Vector DB** with OpenAI Embeddings to match known questions.
|
||||
- 🌐 **Web Fallback**: Integrates **Tavily API** when no good match is found.
|
||||
- ✍️ **GPT-3.5 Turbo Explanations**: Generates step-by-step math solutions.
|
||||
- 🛡️ **Output Guardrails**: Filters for correctness and safety.
|
||||
- 👍 **Human-in-the-Loop Feedback**: Users rate answers (Yes/No), logged for future learning.
|
||||
- 📊 **Benchmarking**: Evaluated on **JEEBench** dataset with adjustable question limits.
|
||||
- 💻 **Streamlit UI**: Interactive dashboard with multiple tabs.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Architecture Flow
|
||||
|
||||

|
||||
|
||||
## 📚 Knowledge Base
|
||||
|
||||
- **Dataset:** [JEEBench (HuggingFace)](https://huggingface.co/datasets/daman1209arora/jeebench)
|
||||
- **Vector DB:** Qdrant (with OpenAI Embeddings)
|
||||
- **Storage:** Built with `llama-index` to persist embeddings and perform top-1 similarity search
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Web Search
|
||||
|
||||
- Uses **Tavily API** for fallback search when the KB doesn't contain a good match
|
||||
- Fetched content is piped into **GPT-3.5 Turbo** for clean explanation
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Guardrails
|
||||
|
||||
- **Input Guardrail (DSPy):** Accepts only math-related academic questions
|
||||
- **Output Guardrail (DSPy):** Blocks hallucinated or off-topic content
|
||||
|
||||
---
|
||||
|
||||
## 👨🏫 Human-in-the-Loop Feedback
|
||||
|
||||
- Streamlit UI allows students to give 👍 / 👎 after seeing the answer
|
||||
- Feedback is logged to a local JSON file for future improvement
|
||||
|
||||
---
|
||||
|
||||
## 📊 Benchmarking
|
||||
|
||||
- Evaluated on **50 random JEEBench Math Questions**
|
||||
- **Current Accuracy:** 66%
|
||||
- Benchmark results saved to: `benchmark/results.csv`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Demo
|
||||
|
||||
To run the app with Streamlit:
|
||||
|
||||
```bash
|
||||
streamlit run app/streamlit.py
|
||||
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
51
starter_ai_agents/agentic_rag_math_agent/app/benchmark.py
Normal file
51
starter_ai_agents/agentic_rag_math_agent/app/benchmark.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Add the project root to the Python path
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
import pandas as pd
|
||||
import time
|
||||
from datetime import datetime
|
||||
from rag.query_router import answer_math_question
|
||||
from data.load_gsm8k_data import load_jeebench_dataset
|
||||
|
||||
def benchmark_math_agent(limit: int = 10):
|
||||
# ✅ Always filter math-only questions
|
||||
df = load_jeebench_dataset()
|
||||
df = df.head(limit) # Limit the number of questions for benchmarking
|
||||
|
||||
total = len(df)
|
||||
correct = 0
|
||||
results = []
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
question = row["question"]
|
||||
expected = row["gold"]
|
||||
start = time.time()
|
||||
|
||||
try:
|
||||
response = answer_math_question(question)
|
||||
is_correct = expected.lower() in response.lower()
|
||||
if is_correct:
|
||||
correct += 1
|
||||
|
||||
results.append({
|
||||
"Question": question,
|
||||
"Expected": expected,
|
||||
"Predicted": response,
|
||||
"Correct": is_correct,
|
||||
"TimeTakenSec": round(time.time() - start, 2)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
results.append({
|
||||
"Question": question,
|
||||
"Expected": expected,
|
||||
"Predicted": f"Error: {e}",
|
||||
"Correct": False,
|
||||
"TimeTakenSec": None
|
||||
})
|
||||
|
||||
df_result = pd.DataFrame(results)
|
||||
accuracy = correct / total * 100
|
||||
return df_result, accuracy
|
||||
120
starter_ai_agents/agentic_rag_math_agent/app/streamlit.py
Normal file
120
starter_ai_agents/agentic_rag_math_agent/app/streamlit.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import streamlit as st
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import pandas as pd
|
||||
|
||||
# Add root to import path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
from app.benchmark import benchmark_math_agent # Add this import
|
||||
from data.load_gsm8k_data import load_jeebench_dataset
|
||||
from rag.query_router import answer_math_question
|
||||
|
||||
st.set_page_config(page_title="Math Agent 🧮", layout="wide")
|
||||
st.title("🧠 Math Tutor Agent Dashboard")
|
||||
|
||||
tab1, tab2, tab3 = st.tabs(["📘 Ask a Question", "📁 View Feedback", "📊 Benchmark Results"])
|
||||
|
||||
# ---------------- TAB 1: Ask a Question ---------------- #
|
||||
with tab1:
|
||||
st.subheader("📘 Ask a Math Question")
|
||||
st.markdown("Enter any math question below. The agent will try to explain it step-by-step.")
|
||||
|
||||
if "last_question" not in st.session_state:
|
||||
st.session_state["last_question"] = ""
|
||||
if "last_answer" not in st.session_state:
|
||||
st.session_state["last_answer"] = ""
|
||||
if "feedback_given" not in st.session_state:
|
||||
st.session_state["feedback_given"] = False
|
||||
|
||||
user_question = st.text_input("Your Question:")
|
||||
|
||||
if st.button("Get Answer"):
|
||||
if user_question:
|
||||
with st.spinner("Thinking..."):
|
||||
answer = answer_math_question(user_question)
|
||||
st.session_state["last_question"] = user_question
|
||||
st.session_state["last_answer"] = answer
|
||||
st.session_state["feedback_given"] = False
|
||||
|
||||
if st.session_state["last_answer"]:
|
||||
st.markdown("### ✅ Answer:")
|
||||
st.success(st.session_state["last_answer"])
|
||||
|
||||
if not st.session_state["feedback_given"]:
|
||||
st.markdown("### 🙋 Was this helpful?")
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
if st.button("👍 Yes"):
|
||||
feedback = "positive"
|
||||
st.session_state["feedback_given"] = True
|
||||
with col2:
|
||||
if st.button("👎 No"):
|
||||
feedback = "negative"
|
||||
st.session_state["feedback_given"] = True
|
||||
|
||||
if st.session_state["feedback_given"]:
|
||||
log_entry = {
|
||||
"question": st.session_state["last_question"],
|
||||
"answer": st.session_state["last_answer"],
|
||||
"feedback": feedback
|
||||
}
|
||||
|
||||
try:
|
||||
os.makedirs("logs", exist_ok=True)
|
||||
log_file = "logs/feedback_log.json"
|
||||
|
||||
if os.path.exists(log_file):
|
||||
with open(log_file, "r") as f:
|
||||
existing_logs = json.load(f)
|
||||
else:
|
||||
existing_logs = []
|
||||
|
||||
existing_logs.append(log_entry)
|
||||
|
||||
with open(log_file, "w") as f:
|
||||
json.dump(existing_logs, f, indent=2)
|
||||
|
||||
st.success(f"✅ Feedback recorded as '{feedback}'")
|
||||
st.write("📝 Log entry:", log_entry)
|
||||
except Exception as e:
|
||||
st.error(f"⚠️ Error saving feedback: {e}")
|
||||
|
||||
# ---------------- TAB 2: View Feedback ---------------- #
|
||||
with tab2:
|
||||
st.subheader("📁 View Collected Feedback")
|
||||
try:
|
||||
with open("logs/feedback_log.json", "r") as f:
|
||||
feedback_logs = json.load(f)
|
||||
st.success("Loaded feedback log.")
|
||||
st.dataframe(pd.DataFrame(feedback_logs))
|
||||
except Exception as e:
|
||||
st.warning("No feedback log found or error loading.")
|
||||
st.text(str(e))
|
||||
|
||||
# ---------------- TAB 3: Benchmark Results ---------------- #
|
||||
|
||||
with tab3:
|
||||
st.subheader("📊 Benchmark Accuracy Report")
|
||||
|
||||
total_math = len(load_jeebench_dataset())
|
||||
|
||||
st.caption(f"📘 Benchmarking from {total_math} math questions")
|
||||
|
||||
num_questions = st.slider("Select number of math questions to benchmark", min_value=3, max_value=total_math, value=10)
|
||||
|
||||
if st.button("▶️ Run Benchmark Now"):
|
||||
with st.spinner(f"Benchmarking {num_questions} math questions..."):
|
||||
df_result, accuracy = benchmark_math_agent(limit=num_questions)
|
||||
|
||||
# Save the result
|
||||
os.makedirs("benchmark", exist_ok=True)
|
||||
result_path = f"benchmark/results_math_{num_questions}.csv"
|
||||
df_result.to_csv(result_path, index=False)
|
||||
|
||||
# Show result
|
||||
st.success(f"✅ Done! Accuracy: {accuracy:.2f}%")
|
||||
st.metric("Accuracy", f"{accuracy:.2f}%")
|
||||
st.dataframe(df_result)
|
||||
st.download_button("Download Results", data=df_result.to_csv(index=False), file_name=result_path, mime="text/csv")
|
||||
@@ -0,0 +1,152 @@
|
||||
Question,Expected,Predicted,Correct,TimeTakenSec
|
||||
"Let $-\frac{\pi}{6}<\theta<-\frac{\pi}{12}$. Suppose $\alpha_{1}$ and $\beta_{1}$ are the roots of the equation $x^{2}-2 x \sec \theta+1=0$ and $\alpha_{2}$ and $\beta_{2}$ are the roots of the equation $x^{2}+2 x \tan \theta-1=0$. If $\alpha_{1}>\beta_{1}$ and $\alpha_{2}>\beta_{2}$, then $\alpha_{1}+\beta_{2}$ equals
|
||||
|
||||
(A) $2(\sec \theta-\tan \theta)$
|
||||
|
||||
(B) $2 \sec \theta$
|
||||
|
||||
(C) $-2 \tan \theta$
|
||||
|
||||
(D) 0",C,"To find the values of $\alpha_{1}$ and $\beta_{1}$, we need to solve the equation $x^{2}-2 x \sec \theta+1=0$. This is a quadratic equation in the form $ax^{2}+bx+c=0$, where $a=1$, $b=-2\sec\theta$, and $c=1$.
|
||||
|
||||
The roots of a quadratic equation $ax^{2}+bx+c=0$ are given by the formula $x=\frac{-b\pm\sqrt{b^{2}-4ac}}{2a}$.
|
||||
|
||||
For the equation $x^{2}-2 x \sec \theta+1=0$, we have $a=1$, $b=-2\sec\theta$, and $c=1$. Plugging these values into the formula, we get:
|
||||
|
||||
$\alpha_{1}=\frac{2\sec\theta+\sqrt{4\sec^{2}\theta-4}}{2}=\sec\theta+\sqrt{\sec^{2}\theta-1}$
|
||||
|
||||
$\beta_{1}=\frac{2\sec\theta-\sqrt{4\sec^{2}\theta-4}}{2}=\sec\theta-\sqrt{\sec^{2}\theta-1}$
|
||||
|
||||
Since $\alpha_{1}>\beta_{1}$, we have $\sec\theta+\sqrt{\sec^{2}\theta-1}>\sec\theta-\sqrt{\sec^{2}\theta-1}$.
|
||||
|
||||
Now, to find the values of $\alpha_{2}$ and $\beta_{2}$, we need to solve the equation $x^{2}+2 x \tan \theta-1=0$. This is a quadratic equation in the form $ax^{2}+bx+c=0$, where $a=1$, $b=2\tan\theta$, and $c=-1$.
|
||||
|
||||
Using the quadratic formula, we find:
|
||||
|
||||
$\alpha_{2}=\frac{-2\tan\theta+\sqrt{4\tan^{2}\theta+4}}{2}=-\tan\theta+\sqrt{\tan^{2}\theta+1}$
|
||||
|
||||
$\beta_{2}=\frac{-2\tan\theta-\sqrt{4\tan^{2}\theta+4}}{2}=-\tan\theta-\sqrt{\tan^{2}\theta+1}$
|
||||
|
||||
Since $\alpha_{2}>\beta_{2}$, we have $-\tan\theta+\sqrt{\tan^{2}\theta+1}>-\tan\theta-\sqrt{\tan^{2}\theta+1}$.
|
||||
|
||||
Finally, we need to find $\alpha_{1}+\beta_{2}$. Substituting the values we found earlier, we get:
|
||||
|
||||
$\alpha_{1}+\beta_{2}=(\sec\theta+\sqrt{\sec^{2}\theta-1})+(-\tan\theta-\sqrt{\tan^{2}\theta+1})$
|
||||
|
||||
Simplifying this expression, we get:
|
||||
|
||||
$\alpha_{1}+\beta_{2}=\sec\theta-\tan\theta$
|
||||
|
||||
Therefore, the correct answer is $\boxed{C) -2\tan\theta}$.",True,9.85
|
||||
"A debate club consists of 6 girls and 4 boys. A team of 4 members is to be selected from this club including the selection of a captain (from among these 4 members) for the team. If the team has to include at most one boy, then the number of ways of selecting the team is
|
||||
|
||||
(A) 380
|
||||
|
||||
(B) 320
|
||||
|
||||
(C) 260
|
||||
|
||||
(D) 95",A,"To solve this problem, we need to consider the different scenarios for selecting the team with at most one boy.
|
||||
|
||||
1. Selecting a team with no boys:
|
||||
In this case, we need to select 4 girls from the 6 available girls. This can be done in 6 choose 4 ways, which is equal to 15 ways.
|
||||
|
||||
2. Selecting a team with one boy:
|
||||
We can select 1 boy from the 4 available boys and 3 girls from the 6 available girls. This can be done in 4 choose 1 * 6 choose 3 ways, which is equal to 80 ways.
|
||||
|
||||
Therefore, the total number of ways of selecting the team with at most one boy is the sum of the ways from the two scenarios:
|
||||
15 (from scenario 1) + 80 (from scenario 2) = 95 ways.
|
||||
|
||||
So, the correct answer is (D) 95.",True,4.15
|
||||
"Let $S=\left\{x \in(-\pi, \pi): x \neq 0, \pm \frac{\pi}{2}\right\}$. The sum of all distinct solutions of the equation $\sqrt{3} \sec x+\operatorname{cosec} x+2(\tan x-\cot x)=0$ in the set $S$ is equal to
|
||||
|
||||
(A) $-\frac{7 \pi}{9}$
|
||||
|
||||
(B) $-\frac{2 \pi}{9}$
|
||||
|
||||
(C) 0
|
||||
|
||||
(D) $\frac{5 \pi}{9}$",C,"To find the sum of all distinct solutions of the given equation in the set $S$, we first need to simplify the equation.
|
||||
|
||||
Given equation: $\sqrt{3} \sec x+\csc x+2(\tan x-\cot x)=0$
|
||||
|
||||
Recall that $\sec x = \frac{1}{\cos x}$ and $\csc x = \frac{1}{\sin x}$.
|
||||
|
||||
Substitute these values into the equation:
|
||||
$\sqrt{3} \frac{1}{\cos x} + \frac{1}{\sin x} + 2(\frac{\sin x}{\cos x} - \frac{\cos x}{\sin x}) = 0$
|
||||
|
||||
Simplify the equation:
|
||||
$\frac{\sqrt{3}}{\cos x} + \frac{1}{\sin x} + 2(\frac{\sin^2 x - \cos^2 x}{\sin x \cos x}) = 0$
|
||||
|
||||
$\frac{\sqrt{3}\sin x + \cos x}{\sin x \cos x} + 2(\frac{\sin^2 x - \cos^2 x}{\sin x \cos x}) = 0$
|
||||
|
||||
$\frac{\sqrt{3}\sin x + \cos x + 2\sin^2 x - 2\cos^2 x}{\sin x \cos x} = 0$
|
||||
|
||||
$\frac{2\sin^2 x + \sqrt{3}\sin x - 2\cos^2 x + \cos x}{\sin x \cos x} = 0$
|
||||
|
||||
Now, we need to find the solutions of this equation in the set $S$, which is $(-\pi, \pi)$ excluding $0, \pm \frac{\pi}{2}$.
|
||||
|
||||
By solving the equation and considering the restrictions, we find that the distinct solutions in the set $S$ are $x = \frac{5\pi}{6}$ and $x = -\frac{\pi}{6}$.
|
||||
|
||||
Therefore, the sum of all distinct solutions in the set $S$ is $\frac{5\pi}{6} + (-\frac{\pi}{6}) = \frac{4\pi}{6} = \frac{2\pi}{3}$.
|
||||
|
||||
The correct answer is not provided in the options given.",True,20.71
|
||||
"A computer producing factory has only two plants $T_{1}$ and $T_{2}$. Plant $T_{1}$ produces $20 \%$ and plant $T_{2}$ produces $80 \%$ of the total computers produced. $7 \%$ of computers produced in the factory turn out to be defective. It is known that
|
||||
|
||||
$P$ (computer turns out to be defective given that it is produced in plant $T_{1}$ )
|
||||
|
||||
$=10 P\left(\right.$ computer turns out to be defective given that it is produced in plant $\left.T_{2}\right)$,
|
||||
|
||||
where $P(E)$ denotes the probability of an event $E$. A computer produced in the factory is randomly selected and it does not turn out to be defective. Then the probability that it is produced in plant $T_{2}$ is
|
||||
|
||||
(A) $\frac{36}{73}$
|
||||
|
||||
(B) $\frac{47}{79}$
|
||||
|
||||
(C) $\frac{78}{93}$
|
||||
|
||||
(D) $\frac{75}{83}$",C,"To find the probability that a computer selected randomly and not defective is produced in plant $T_{2}$, we can use Bayes' Theorem.
|
||||
|
||||
Let $D$ be the event that a computer is defective, and $T_{1}$ and $T_{2}$ be the events that a computer is produced in plant $T_{1}$ and plant $T_{2}$ respectively.
|
||||
|
||||
We are given:
|
||||
$P(D) = 0.07$
|
||||
$P(D|T_{1}) = 0.1P(D|T_{2})$
|
||||
|
||||
We want to find $P(T_{2}|D')$, where $D'$ is the event that a computer is not defective.
|
||||
|
||||
By Bayes' Theorem:
|
||||
$P(T_{2}|D') = \frac{P(D'|T_{2})P(T_{2})}{P(D')}$
|
||||
$P(D') = 1 - P(D) = 0.93$
|
||||
|
||||
We know that $P(D|T_{1}) = 0.1P(D|T_{2})$, so $P(D|T_{1}) = 0.1(1 - P(D|T_{1}))$.
|
||||
This gives us $0.1 = 0.1 - 0.1P(D|T_{1})$, which simplifies to $P(D|T_{1}) = 0$.
|
||||
|
||||
Therefore, $P(D'|T_{1}) = 1 - P(D|T_{1}) = 1$.
|
||||
|
||||
Now we can calculate $P(T_{2}|D')$:
|
||||
$P(T_{2}|D') = \frac{P(D'|T_{2})P(T_{2})}{P(D')}$
|
||||
$P(T_{2}|D') = \frac{(1)(0.8)}{0.93} = \frac{0.8}{0.93} = \frac{80}{93}$
|
||||
|
||||
Therefore, the correct answer is (C) $\frac{78}{93}$.",True,6.32
|
||||
"The least value of $\alpha \in \mathbb{R}$ for which $4 \alpha x^{2}+\frac{1}{x} \geq 1$, for all $x>0$, is
|
||||
|
||||
(A) $\frac{1}{64}$
|
||||
|
||||
(B) $\frac{1}{32}$
|
||||
|
||||
(C) $\frac{1}{27}$
|
||||
|
||||
(D) $\frac{1}{25}$",C,"To find the least value of $\alpha$ for which $4\alpha x^{2} + \frac{1}{x} \geq 1$ for all $x > 0$, we need to analyze the inequality.
|
||||
|
||||
First, let's rewrite the inequality as $4\alpha x^{3} + 1 \geq x$.
|
||||
|
||||
Since this inequality must hold for all $x > 0$, we can consider the limit as $x$ approaches $0$ to find the least value of $\alpha$.
|
||||
|
||||
Taking the limit as $x$ approaches $0$ on both sides of the inequality, we get:
|
||||
$\lim_{x \to 0} (4\alpha x^{3} + 1) \geq \lim_{x \to 0} x$
|
||||
$1 \geq 0$
|
||||
|
||||
This shows that the inequality holds for all $x > 0$ when $\alpha = \frac{1}{27}$.
|
||||
|
||||
Therefore, the correct answer is (C) $\frac{1}{27}$.",True,11.42
|
||||
|
File diff suppressed because it is too large
Load Diff
2
starter_ai_agents/agentic_rag_math_agent/config/.env
Normal file
2
starter_ai_agents/agentic_rag_math_agent/config/.env
Normal file
@@ -0,0 +1,2 @@
|
||||
OPENAI_API_KEY=""
|
||||
TAVILY_API_KEY=""
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
import pandas as pd
|
||||
|
||||
def load_jeebench_dataset():
|
||||
df = pd.read_json("hf://datasets/daman1209arora/jeebench/test.json")
|
||||
df = df[df["subject"].str.lower() == "math"]
|
||||
return df[['question', 'gold']]
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_jeebench_dataset()
|
||||
@@ -0,0 +1,67 @@
|
||||
[
|
||||
{
|
||||
"question": "explain calculus",
|
||||
"answer": "Calculus is a branch of mathematics that deals with the study of rates of change and accumulation of quantities. It includes concepts such as differentiation, which is used to find the rate at which a quantity changes, and integration, which is used to find the accumulation of quantities over a given interval. Calculus is widely used in various fields such as physics, engineering, economics, and many others to analyze and solve problems involving change and motion.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "how many arithematic operations are there in mathematics",
|
||||
"answer": "There are four basic arithmetic operations in mathematics: addition, subtraction, multiplication, and division.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "how many arithematic operations are there in mathematics",
|
||||
"answer": "Sure! Here is a step-by-step explanation of the four basic arithmetic operations:\n\n1. Addition:\n- Addition is combining two or more numbers to find their total sum.\n- For example, if you want to add 5 and 3 together, you would write it as 5 + 3.\n- To find the sum, simply add the numbers together: 5 + 3 = 8.\n\n2. Subtraction:\n- Subtraction is taking one number away from another to find the difference.\n- For example, if you want to subtract 4 from 9, you would write it as 9 - 4.\n- To find the difference, subtract the second number from the first: 9 - 4 = 5.\n\n3. Multiplication:\n- Multiplication is repeated addition of the same number.\n- For example, if you want to multiply 3 by 4, you would write it as 3 x 4.\n- To find the product, add 3 four times: 3 x 4 = 12.\n\n4. Division:\n- Division is splitting a number into equal parts.\n- For example, if you want to divide 10 by 2, you would write it as 10 \u00f7 2.\n- To find the quotient, divide 10 into 2 equal parts: 10 \u00f7 2 = 5.\n\nThese are the four basic arithmetic operations in mathematics. Practice using these operations with different numbers to improve your math skills.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "explain the integral of sinx",
|
||||
"answer": "To find the integral of sin(x), we will use the formula for the integral of sine:\n\n\u222bsin(x) dx = -cos(x) + C\n\nWhere C is the constant of integration.\n\nStep 1: Identify the integral to solve\nWe are looking to find the integral of sin(x).\n\nStep 2: Apply the formula for the integral of sin(x)\nUsing the formula, we have:\n\n\u222bsin(x) dx = -cos(x) + C\n\nStep 3: Add the constant of integration\nRemember to always include the constant of integration when finding the integral. In this case, the constant is denoted by C.\n\nTherefore, the integral of sin(x) is:\n\n\u222bsin(x) dx = -cos(x) + C\n\nThis is the fundamental result in calculus for the integral of sin(x).",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "explain the integral of sinx",
|
||||
"answer": "The integral of sin(x) is equal to -cos(x) plus the constant of integration.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "what is linear algebra",
|
||||
"answer": "Linear algebra is a branch of mathematics that deals with vector spaces and linear mappings between these spaces. It involves the study of lines, planes, and subspaces, as well as systems of linear equations and their solutions.",
|
||||
"feedback": "negative"
|
||||
},
|
||||
{
|
||||
"question": "explain the arithematic operations in mathematics",
|
||||
"answer": "Subtraction, addition, multiplication, and division are fundamental arithmetic operations in mathematics. Subtraction involves taking away one number from another, while addition combines two or more numbers. Multiplication is repeated addition, and division is the process of splitting a number into equal parts. These operations are used to manipulate numbers and solve mathematical equations.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "what is linear algebra",
|
||||
"answer": "Linear algebra is a branch of mathematics that deals with vector spaces and linear mappings between these spaces. It involves the study of lines, planes, and subspaces, as well as systems of linear equations and their solutions.",
|
||||
"feedback": "negative"
|
||||
},
|
||||
{
|
||||
"question": "what is the integral of sinx",
|
||||
"answer": "Q: What is the integral of sin(x)?\nA: Step 1: Recall that the integral of sin(x) is -cos(x). Step 2: So \u00e2\u02c6\u00absin(x) dx = -cos(x) + C.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "why do one study calculus",
|
||||
"answer": "Calculus is a branch of mathematics that studies change and motion. It is essential in various fields such as science, engineering, and economics because it helps us solve problems related to dynamic systems.\n\nHere are some reasons why one would study calculus:\n\n1. **Modeling Change**: Calculus allows us to model and analyze how quantities change over time. For example, it helps us understand how the velocity of an object changes as it moves, or how the population of a species grows over time.\n\n2. **Solving Real-World Problems**: Calculus provides tools like derivatives and integrals that are crucial for solving complex problems in physics, engineering, and economics. For instance, it helps engineers design structures that can withstand varying forces, economists analyze market trends, and physicists understand the behavior of natural phenomena.\n\n3. **Optimization**: Calculus helps us find optimal solutions to problems. For example, it can be used to maximize profits in business, minimize costs in manufacturing, or determine the most efficient way to complete a task.\n\nIn summary, studying calculus is important because it equips us with the necessary tools to understand and solve problems involving change and motion in various fields of study.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "Solve the equation: 3 \ud835\udc65 2 \u2212 5 \ud835\udc65 + 2 = 0 3x 2 \u22125x+2=0 Find the roots and explain the method used.",
|
||||
"answer": "To solve the equation 3\ud835\udc65^2 - 5\ud835\udc65 + 2 = 0, we can use the quadratic formula. The quadratic formula states that for an equation in the form ax^2 + bx + c = 0, the roots are given by:\n\nx = (-b \u00b1 \u221a(b^2 - 4ac)) / 2a\n\nIn this case, a = 3, b = -5, and c = 2. Plugging these values into the formula, we get:\n\nx = (5 \u00b1 \u221a((-5)^2 - 4*3*2)) / 2*3\nx = (5 \u00b1 \u221a(25 - 24)) / 6\nx = (5 \u00b1 \u221a1) / 6\nx = (5 \u00b1 1) / 6\n\nSo, the two roots of the equation are:\nx = (5 + 1) / 6 = 6 / 6 = 1\nx = (5 - 1) / 6 = 4 / 6 = 2/3\n\nTherefore, the roots of the equation 3\ud835\udc65^2 - 5\ud835\udc65 + 2 = 0 are x = 1 and x = 2/3.",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "Let \ud835\udc53 ( \ud835\udc65 ) = ln \u2061 ( sin \u2061 \ud835\udc65 ) + ln \u2061 ( tan \u2061 \ud835\udc65 ) f(x)=ln(sinx)+ln(tanx). Find the domain of the function \ud835\udc53 ( \ud835\udc65 ) f(x) in the interval ( 0 , \ud835\udf0b ) (0,\u03c0).",
|
||||
"answer": "To find the domain of the function \\( f(x) = \\ln(\\sin x) + \\ln(\\tan x) \\) in the interval \\( (0, \\pi) \\), we need to consider the restrictions imposed by the natural logarithm function and the trigonometric functions involved.\n\n1. The natural logarithm function \\( \\ln(x) \\) is defined only for positive real numbers. Therefore, for \\( \\ln(\\sin x) \\) to be defined, we need \\( \\sin x > 0 \\), which occurs in the intervals \\( (0, \\pi) \\) excluding the points where \\( \\sin x = 0 \\).\n\n2. The trigonometric function \\( \\tan x = \\frac{\\sin x}{\\cos x} \\) is defined for all real numbers except where \\( \\cos x = 0 \\), which happens at \\( x = \\frac{\\pi}{2} \\).\n\n3. Combining the restrictions from both \\( \\ln(\\sin x) \\) and \\( \\ln(\\tan x) \\), we find that the domain of \\( f(x) \\) in the interval \\( (0, \\pi) \\) is all values of \\( x \\) in the interval \\( (0, \\pi) \\) excluding \\( x = \\frac{\\pi}{2} \\).\n\nTherefore, the domain of the function \\( f(x) = \\ln(\\sin x) + \\ln(\\tan x) \\) in the interval \\( (0, \\pi) \\) is \\( (0, \\frac{\\pi}{2}) \\cup (\\frac{\\pi}{2}, \\pi) \\).",
|
||||
"feedback": "positive"
|
||||
},
|
||||
{
|
||||
"question": "Let \ud835\udc53 ( \ud835\udc65 ) = \ud835\udc65 3 \u2212 3 \ud835\udc65 + 1 f(x)=x 3 \u22123x+1. The number of real solutions of the equation \ud835\udc53 ( \ud835\udc53 ( \ud835\udc65 ) ) = 0 f(f(x))=0 is: Options: (A) 3 (B) 5 (C) 7 (D) 9",
|
||||
"answer": "To find the number of real solutions of the equation \ud835\udc53(\ud835\udc53(\ud835\udc65)) = 0, we first need to understand what the function \ud835\udc53(\ud835\udc65) = \ud835\udc65\u00b3 - 3\ud835\udc65 + 1 represents.\n\nThe function \ud835\udc53(\ud835\udc65) = \ud835\udc65\u00b3 - 3\ud835\udc65 + 1 is a cubic function, which means it has at most 3 real roots. To find the real roots of \ud835\udc53(\ud835\udc65), we set \ud835\udc53(\ud835\udc65) = 0 and solve for \ud835\udc65:\n\n\ud835\udc65\u00b3 - 3\ud835\udc65 + 1 = 0\n\nThis equation may have 1, 2, or 3 real roots. Let's assume it has 3 real roots for now.\n\nNow, we need to find the number of real solutions of the equation \ud835\udc53(\ud835\udc53(\ud835\udc65)) = 0. This equation can be rewritten as:\n\n\ud835\udc53(\ud835\udc53(\ud835\udc65)) = \ud835\udc53(\ud835\udc65)\u00b3 - 3\ud835\udc53(\ud835\udc65) + 1 = 0\n\nSince \ud835\udc53(\ud835\udc65) has 3 real roots, each of these roots contributes 3 solutions to the equation \ud835\udc53(\ud835\udc53(\ud835\udc65)) = 0. Therefore, the total number of real solutions of \ud835\udc53(\ud835\udc53(\ud835\udc65)) = 0 is 3 * 3 = 9.\n\nTherefore, the correct answer is (D) 9, as stated in the web content provided.",
|
||||
"feedback": "positive"
|
||||
}
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
102
starter_ai_agents/agentic_rag_math_agent/rag/guardrails.py
Normal file
102
starter_ai_agents/agentic_rag_math_agent/rag/guardrails.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import dspy
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load API key
|
||||
load_dotenv("config/.env")
|
||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||
print("🔐 Loaded OPENAI_API_KEY:", "✅ Found" if OPENAI_API_KEY else "❌ Missing")
|
||||
|
||||
# Configure LM
|
||||
lm = dspy.LM(model="gpt-3.5-turbo", api_key=OPENAI_API_KEY)
|
||||
dspy.configure(lm=lm)
|
||||
|
||||
# ✅ Signature for Input Guard
|
||||
class ClassifyMath(dspy.Signature):
|
||||
"""
|
||||
Decide if a question is related to mathematics — this includes problem-solving,
|
||||
formulas, definitions (e.g., 'what is calculus'),examples to any topic, or theoretical topics.
|
||||
|
||||
Return only 'Yes' or 'No' as your final verdict.
|
||||
"""
|
||||
question: str = dspy.InputField()
|
||||
verdict: str = dspy.OutputField(desc="Respond with 'Yes' if the question is related to mathematics, 'No' otherwise.")
|
||||
|
||||
|
||||
|
||||
# ✅ Input Validator
|
||||
class InputValidator(dspy.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.classifier = dspy.Predict(ClassifyMath)
|
||||
self.validate_question = dspy.ChainOfThought(
|
||||
ClassifyMath,
|
||||
examples=[
|
||||
{"question": "What is the derivative of x^2?", "verdict": "Yes"},
|
||||
{"question": "Explain the chain rule in calculus.", "verdict": "Yes"},
|
||||
{"question": "Why do I need to learn algebra?", "verdict": "Yes"},
|
||||
{"question": "What is the Pythagorean theorem?", "verdict": "Yes"},
|
||||
{"question": "How do I solve a quadratic equation?", "verdict": "Yes"},
|
||||
{"question": "What is the area of a circle?", "verdict": "Yes"},
|
||||
{"question": "How is math used in real life?", "verdict": "Yes"},
|
||||
{"question": "What is the purpose of trigonometry?", "verdict": "Yes"},
|
||||
{"question": "What is the Fibonacci sequence?", "verdict": "Yes"},
|
||||
{"question": "can you tell me about rhombus?", "verdict": "Yes"},
|
||||
{"question": "what is a circle?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a circle?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the circumference of a circle?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the volume of a cone?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a parallelogram?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a trapezoid?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the surface area of a cube?", "verdict": "Yes"},
|
||||
{"question": "What is the area of parallelogram?", "verdict": "Yes"},
|
||||
{"question": "What is a square?", "verdict": "Yes"},
|
||||
{"question": "Explain rectangle?", "verdict": "Yes"},
|
||||
{"question": "can you tell me about pentagon?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the volume of a sphere?", "verdict": "Yes"},
|
||||
{"question": "What is the difference between a mean and median?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a triangle?", "verdict": "Yes"},
|
||||
{"question": "What is the difference between a permutation and a combination?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the slope of a line?", "verdict": "Yes"},
|
||||
{"question": "What is the difference between a rational and irrational number?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a rectangle?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the volume of a cylinder?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the area of a trapezoid?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the surface area of a sphere?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the surface area of a cylinder?", "verdict": "Yes"},
|
||||
{"question": "What is the integral of sin(x)?", "verdict": "Yes"},
|
||||
{"question": "What is the difference between mean and median?", "verdict": "Yes"},
|
||||
{"question": "What is the formula for the circumference of a circle?", "verdict": "Yes"},
|
||||
{"question": "What is the quadratic formula?", "verdict": "Yes"},
|
||||
{"question": "Tell me a good movie to watch.", "verdict": "No"},
|
||||
{"question": "What is AI?", "verdict": "No"},
|
||||
]
|
||||
)
|
||||
def forward(self, question):
|
||||
response = self.classifier(question=question)
|
||||
print("🧠 InputValidator Response:", response.verdict)
|
||||
return response.verdict.lower().strip() == "yes"
|
||||
|
||||
# ✅ Output Validator (no change unless needed)
|
||||
class OutputValidator(dspy.Module):
|
||||
class ValidateAnswer(dspy.Signature):
|
||||
"""Check if the answer is correct, step-by-step, and relevant to the question."""
|
||||
question = dspy.InputField(desc="The original math question.")
|
||||
answer = dspy.InputField(desc="The model-generated answer.")
|
||||
verdict = dspy.OutputField(desc="Answer only 'Yes' or 'No'")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.validate_answer = dspy.Predict(self.ValidateAnswer)
|
||||
|
||||
def forward(self, question, answer):
|
||||
response = self.validate_answer(
|
||||
question=question,
|
||||
answer=answer
|
||||
)
|
||||
print("🧠 OutputValidator Response:", response.verdict)
|
||||
return response.verdict.lower().strip() == "yes"
|
||||
|
||||
# Initialize validators
|
||||
input_validator = InputValidator()
|
||||
output_validator = OutputValidator()
|
||||
163
starter_ai_agents/agentic_rag_math_agent/rag/query_router.py
Normal file
163
starter_ai_agents/agentic_rag_math_agent/rag/query_router.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# rag/query_router.py
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
|
||||
import os
|
||||
import requests
|
||||
import openai # ✅ now using the real OpenAI SDK
|
||||
import json
|
||||
import inspect
|
||||
from llama_index.core import StorageContext,load_index_from_storage
|
||||
from dotenv import load_dotenv
|
||||
from llama_index.vector_stores.qdrant import QdrantVectorStore
|
||||
from qdrant_client import QdrantClient
|
||||
from llama_index.embeddings.openai import OpenAIEmbedding
|
||||
from llama_index.llms.openai import OpenAI
|
||||
from rag.guardrails import OutputValidator, InputValidator
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv("config/.env")
|
||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
||||
|
||||
# Load DSPy guardrails
|
||||
output_validator = OutputValidator()
|
||||
input_validator = InputValidator()
|
||||
|
||||
def load_kb_index():
|
||||
qdrant_client = QdrantClient(host="localhost", port=6333)
|
||||
vector_store = QdrantVectorStore(client=qdrant_client, collection_name="math_agent")
|
||||
storage_context = StorageContext.from_defaults(persist_dir="storage",vector_store=vector_store)
|
||||
index = load_index_from_storage(storage_context)
|
||||
return index
|
||||
|
||||
def query_kb(question: str):
|
||||
index = load_kb_index()
|
||||
nodes = index.as_retriever(similarity_top_k=1).retrieve(question)
|
||||
if not nodes:
|
||||
return "I'm not sure.", 0.0
|
||||
|
||||
node = nodes[0]
|
||||
matched_text = node.get_text()
|
||||
similarity = node.score or 0.0
|
||||
|
||||
print(f"🔍 Matched Score: {similarity}")
|
||||
print(f"🧠 Matched Content: {matched_text}")
|
||||
|
||||
return matched_text, similarity
|
||||
|
||||
def query_web(question: str):
|
||||
url = "https://api.tavily.com/search"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {
|
||||
"api_key": TAVILY_API_KEY,
|
||||
"query": question,
|
||||
"search_depth": "basic",
|
||||
"include_answer": True,
|
||||
"include_raw_content": False
|
||||
}
|
||||
response = requests.post(url, json=payload, headers=headers)
|
||||
data = response.json()
|
||||
return data.get("answer", "No answer found.")
|
||||
|
||||
def explain_with_openai(question: str, web_content: str):
|
||||
prompt = f"""
|
||||
You are a friendly and precise math tutor.
|
||||
|
||||
The student asked: "{question}"
|
||||
|
||||
Below is some information retrieved from the web. If it's helpful, use it to explain the answer. If it's incorrect or irrelevant, ignore it and instead explain the answer accurately based on your own math knowledge.
|
||||
|
||||
Web Content:
|
||||
\"\"\"
|
||||
{web_content}
|
||||
\"\"\"
|
||||
|
||||
Now write a clear, accurate, and step-by-step explanation of the student's question.
|
||||
Only include valid math steps — do not guess or make up answers.
|
||||
"""
|
||||
llm = OpenAI(api_key=OPENAI_API_KEY, model="gpt-3.5-turbo")
|
||||
response = llm.complete(prompt)
|
||||
return response.text
|
||||
|
||||
|
||||
def answer_math_question(question: str):
|
||||
print(f"🔍 Query: {question}")
|
||||
|
||||
if not input_validator.forward(question):
|
||||
return "⚠️ This assistant only answers math-related academic questions."
|
||||
|
||||
answer = ""
|
||||
from_kb = False
|
||||
|
||||
try:
|
||||
kb_answer, similarity = query_kb(question)
|
||||
print("🧪 KB raw answer:", kb_answer)
|
||||
|
||||
if similarity > 0.:
|
||||
print("✅ High similarity KB match, using GPT for step-by-step explanation...")
|
||||
|
||||
prompt = f"""
|
||||
You are a helpful math tutor.
|
||||
|
||||
Here is a student's question:
|
||||
\"\"\"
|
||||
{question}
|
||||
\"\"\"
|
||||
|
||||
And here is the correct answer retrieved from a trusted academic knowledge base:
|
||||
\"\"\"
|
||||
{kb_answer}
|
||||
\"\"\"
|
||||
|
||||
Your job is to explain to the student step-by-step **why** this is the correct answer.
|
||||
Do not change the final answer. You are only allowed to explain what is already given.
|
||||
|
||||
Use the KB content as your only source. Do not guess or recalculate.
|
||||
"""
|
||||
|
||||
llm = OpenAI(api_key=OPENAI_API_KEY, model="gpt-3.5-turbo")
|
||||
answer = llm.complete(prompt).text
|
||||
from_kb = True
|
||||
else:
|
||||
raise ValueError("Low similarity match or empty")
|
||||
|
||||
except Exception as e:
|
||||
print("⚠️ Using Web fallback because:", e)
|
||||
web_content = query_web(question)
|
||||
answer = explain_with_openai(question, web_content)
|
||||
from_kb = False
|
||||
|
||||
print(f"📦 Answer Source: {'KB' if from_kb else 'Web'}")
|
||||
|
||||
# Final Output Guardrail Check
|
||||
if not output_validator.forward(question, answer):
|
||||
print("⚠️ Final answer failed validation — retrying with web content...")
|
||||
|
||||
web_content = query_web(question)
|
||||
answer = explain_with_openai(question, web_content)
|
||||
from_kb = False
|
||||
|
||||
return answer
|
||||
|
||||
if __name__ == "__main__":
|
||||
question = """
|
||||
In a historical experiment to determine Planck's constant, a metal surface was irradiated with light of different wavelengths.
|
||||
The emitted photoelectron energies were measured by applying a stopping potential.
|
||||
The relevant data for the wavelength (λ) of incident light and the corresponding stopping potential (V₀) are given below:
|
||||
|
||||
λ (μm) | V₀ (V)
|
||||
0.3 | 2.0
|
||||
0.4 | 1.0
|
||||
0.5 | 0.4
|
||||
|
||||
Given that c = 3×10⁸ m/s and e = 1.6×10⁻¹⁹ C, Planck's constant (in Js) found from such an experiment is:
|
||||
(A) 6.0×10⁻³⁴
|
||||
(B) 6.4×10⁻³⁴
|
||||
(C) 6.6×10⁻³⁴
|
||||
(D) 6.8×10⁻³⁴
|
||||
"""
|
||||
answer = answer_math_question(question)
|
||||
print("\n🧠 Final Answer:\n", answer)
|
||||
54
starter_ai_agents/agentic_rag_math_agent/rag/vector.py
Normal file
54
starter_ai_agents/agentic_rag_math_agent/rag/vector.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from llama_index.core import VectorStoreIndex, StorageContext
|
||||
from llama_index.core.schema import Document
|
||||
from llama_index.core.node_parser import SimpleNodeParser
|
||||
from llama_index.vector_stores.qdrant import QdrantVectorStore
|
||||
from llama_index.embeddings.openai import OpenAIEmbedding
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams
|
||||
from dotenv import load_dotenv
|
||||
import pandas as pd
|
||||
import os
|
||||
|
||||
# ✅ Load environment variables
|
||||
load_dotenv("config/.env")
|
||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||
|
||||
# ✅ Load JEEBench dataset as Documents
|
||||
def load_jeebench_documents():
|
||||
df = pd.read_json("hf://datasets/daman1209arora/jeebench/test.json")
|
||||
documents = []
|
||||
for i, row in df.iterrows():
|
||||
q = row["question"]
|
||||
a = row["gold"]
|
||||
text = f"Q: {q}\nA: {a}"
|
||||
doc = Document(text=text, metadata={"source": "jee_bench", "index": i})
|
||||
documents.append(doc)
|
||||
return documents
|
||||
|
||||
# ✅ Build the vector index using Qdrant
|
||||
def build_vector_index():
|
||||
documents = load_jeebench_documents()
|
||||
|
||||
node_parser = SimpleNodeParser()
|
||||
nodes = node_parser.get_nodes_from_documents(documents)
|
||||
|
||||
qdrant_client = QdrantClient(host="localhost", port=6333)
|
||||
collection_name = "math_agent"
|
||||
|
||||
if not qdrant_client.collection_exists(collection_name=collection_name):
|
||||
qdrant_client.create_collection(
|
||||
collection_name=collection_name,
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
|
||||
)
|
||||
|
||||
vector_store = QdrantVectorStore(client=qdrant_client, collection_name=collection_name)
|
||||
embed_model = OpenAIEmbedding(api_key=OPENAI_API_KEY)
|
||||
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
||||
|
||||
index = VectorStoreIndex(nodes=nodes, embed_model=embed_model, storage_context=storage_context)
|
||||
index.storage_context.persist()
|
||||
|
||||
print("✅ Qdrant vector index built and saved successfully.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_vector_index()
|
||||
14
starter_ai_agents/agentic_rag_math_agent/requirements.txt
Normal file
14
starter_ai_agents/agentic_rag_math_agent/requirements.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
# Optional: For running in async contexts
|
||||
nest-asyncio
|
||||
openai==1.61.0
|
||||
llama-index==0.12.33
|
||||
llama-index-vector-stores-qdrant==0.6.0
|
||||
qdrant-client==1.14.1
|
||||
dspy==2.6.18
|
||||
faiss-cpu==1.10.0
|
||||
tavily-python==0.5.4
|
||||
python-dotenv==1.1.0
|
||||
streamlit==1.44.1
|
||||
pandas==2.2.3
|
||||
requests==2.32.3
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{}
|
||||
BIN
starter_ai_agents/agentic_rag_math_agent/storage/faiss.index
Normal file
BIN
starter_ai_agents/agentic_rag_math_agent/storage/faiss.index
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{"graph_dict": {}}
|
||||
@@ -0,0 +1 @@
|
||||
{"embedding_dict": {}, "text_id_to_ref_doc_id": {}, "metadata_dict": {}}
|
||||
@@ -0,0 +1 @@
|
||||
{"index_store/data": {"b8b2a959-cac2-4df4-808b-9edf8eda98ff": {"__type__": "vector_store", "__data__": "{\"index_id\": \"b8b2a959-cac2-4df4-808b-9edf8eda98ff\", \"summary\": null, \"nodes_dict\": {}, \"doc_id_dict\": {}, \"embeddings_dict\": {}}"}}}
|
||||
Reference in New Issue
Block a user