Skip to content

Commit 3837594

Browse files
pavanjavapavanmantha
andauthored
Advanced rag tech (#96)
* -deep evals base * crewai agents for prompting * -skeleton code for adv RAG techniques like recursive retriever and sub question query * -dummy commit to make the branch upto date * -fully funtional recursive retrieval agents --------- Co-authored-by: pavanmantha <pavan.mantha@thevaslabs.io>
1 parent 3470980 commit 3837594

19 files changed

Lines changed: 536 additions & 1 deletion

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
DB_URL='http://localhost:6333'
2+
DB_API_KEY='th3s3cr3tk3y'
3+
COLLECTION_NAME='RECURSIVE_COLLECTION'
4+
5+
OPENAI_API_KEY='sk-proj-'
6+
OPENAI_EMBED_MODEL='gpt-4o'
7+
8+
# use this incase you are prefering to experiment with local models.
9+
OLLAMA_BASE_URL='http://localhost:11434'
10+
OLLAMA_LLM_MODEL='llama3.1'
11+
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'
12+
13+
CHUNK_SIZE=256
14+
CHUNK_OVERLAP=20
15+
16+
# logger can be controlled usiing env
17+
CRITICAL = 50
18+
FATAL = 50
19+
ERROR = 40
20+
WARNING = 30
21+
WARN = 30
22+
INFO = 20
23+
DEBUG = 10
24+
NOTSET = 0
25+
26+
LIT_SERVER_PORT=8000
27+
LIT_SERVER_WORKERS_PER_DEVICE=4
28+
29+
IS_EVALUATION_NEEDED=true
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from dotenv import load_dotenv, find_dotenv
2+
from recursive_retriever_agents_core import RecursiveAgentManager
3+
import litserve as lit
4+
import os
5+
6+
7+
class RecursiveAgentsAPI(lit.LitAPI):
8+
def __init__(self):
9+
load_dotenv(find_dotenv())
10+
self.agent_names = ['mlops', 'attention', 'orthodontics']
11+
self.agent_manager = None
12+
13+
def setup(self, device):
14+
self.agent_manager = RecursiveAgentManager(self.agent_names)
15+
16+
def decode_request(self, request, **kwargs):
17+
return request['query']
18+
19+
def predict(self, x, **kwargs):
20+
return self.agent_manager.query(x)
21+
22+
def encode_response(self, output, **kwargs):
23+
return {'Agent': output}
24+
25+
26+
if __name__ == "__main__":
27+
lit_api = RecursiveAgentsAPI()
28+
server = lit.LitServer(lit_api=lit_api, api_path='/api/v1/chat-completion',
29+
workers_per_device=int(os.environ.get('LIT_SERVER_WORKERS_PER_DEVICE')))
30+
server.run(port=os.environ.get('LIT_SERVER_PORT'))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from recursive_retriever_agents_core import RecursiveAgentManager
2+
3+
4+
agent_names = ['mlops', 'attention', 'orthodontics']
5+
agent_manager = RecursiveAgentManager(agent_names)
6+
7+
# Usage example:
8+
if __name__ == "__main__":
9+
while True:
10+
# Get user input
11+
user_query = input("Enter your question (or 'quit' to exit): ")
12+
13+
# Check for quit command
14+
if user_query.lower() == 'quit':
15+
print("Exiting program...")
16+
break
17+
18+
# Process query and print response
19+
try:
20+
response = agent_manager.query(user_query)
21+
print("\nResponse:")
22+
print(response)
23+
print("\n" + "-"*50 + "\n") # Separator for readability
24+
except Exception as e:
25+
print(f"Error processing query: {str(e)}")
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import os
2+
from typing import Dict, List
3+
4+
from llama_index.agent.openai import OpenAIAgent
5+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings, StorageContext
6+
from llama_index.core import SummaryIndex
7+
from llama_index.core.schema import IndexNode
8+
from llama_index.core.tools import QueryEngineTool, ToolMetadata
9+
from llama_index.llms.openai import OpenAI
10+
from llama_index.embeddings.openai import OpenAIEmbedding
11+
from dotenv import load_dotenv, find_dotenv
12+
import qdrant_client
13+
from llama_index.vector_stores.qdrant import QdrantVectorStore
14+
15+
16+
class RecursiveAgentManager:
17+
def __init__(self, agent_names: List[str], data_dir: str = 'data'):
18+
"""
19+
Initialize the AgentManager with a list of agent names and optional data directory path.
20+
21+
Args:
22+
agent_names (List[str]): List of agent names to initialize
23+
data_dir (str): Directory containing the PDF files (default: 'data')
24+
"""
25+
self.agent_names = agent_names
26+
self.data_dir = data_dir
27+
self.document_data = {}
28+
self.agents = {}
29+
self.query_engine = None
30+
31+
# Load environment variables
32+
load_dotenv(find_dotenv())
33+
34+
# Initialize settings
35+
self._initialize_settings()
36+
37+
# Setup components
38+
self._load_documents()
39+
self._setup_vector_store()
40+
self._build_agents()
41+
self._setup_query_engine()
42+
43+
def _initialize_settings(self):
44+
"""Initialize LlamaIndex settings."""
45+
Settings.llm = OpenAI(model=os.environ.get("OPENAI_EMBED_MODEL"), temperature=0.0)
46+
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
47+
Settings.chunk_size = int(os.environ.get("CHUNK_SIZE"))
48+
Settings.chunk_overlap = int(os.environ.get("CHUNK_OVERLAP"))
49+
50+
def _load_documents(self):
51+
"""Load PDF documents for each agent."""
52+
for agent_name in self.agent_names:
53+
self.document_data[agent_name] = SimpleDirectoryReader(
54+
input_files=[f'{self.data_dir}/{agent_name}.pdf']
55+
).load_data()
56+
57+
def _setup_vector_store(self):
58+
"""Setup Qdrant vector store and storage context."""
59+
client = qdrant_client.QdrantClient(
60+
url=os.environ['DB_URL'],
61+
api_key=os.environ['DB_API_KEY']
62+
)
63+
self.vector_store = QdrantVectorStore(
64+
client=client,
65+
collection_name=os.environ['COLLECTION_NAME']
66+
)
67+
self.storage_context = StorageContext.from_defaults(
68+
vector_store=self.vector_store
69+
)
70+
71+
def _create_query_engine_tools(self, agent_name: str, vector_index: VectorStoreIndex,
72+
summary_index: SummaryIndex) -> List[QueryEngineTool]:
73+
"""Create query engine tools for an agent."""
74+
return [
75+
QueryEngineTool(
76+
query_engine=vector_index.as_query_engine(),
77+
metadata=ToolMetadata(
78+
name="vector_tool",
79+
description=f"Useful for retrieving specific context from {agent_name}"
80+
),
81+
),
82+
QueryEngineTool(
83+
query_engine=summary_index.as_query_engine(),
84+
metadata=ToolMetadata(
85+
name="summary_tool",
86+
description=f"Useful for summarization questions related to {agent_name}"
87+
),
88+
),
89+
]
90+
91+
def _build_agents(self):
92+
"""Build agents with their respective tools."""
93+
for agent_name in self.agent_names:
94+
# Build indices
95+
vector_index = VectorStoreIndex.from_documents(
96+
self.document_data[agent_name],
97+
storage_context=self.storage_context
98+
)
99+
summary_index = SummaryIndex.from_documents(
100+
self.document_data[agent_name],
101+
storage_context=self.storage_context
102+
)
103+
104+
# Create tools
105+
query_engine_tools = self._create_query_engine_tools(
106+
agent_name, vector_index, summary_index
107+
)
108+
109+
# Build agent
110+
function_llm = OpenAI(model=os.environ.get("OPENAI_EMBED_MODEL"))
111+
agent = OpenAIAgent.from_tools(
112+
query_engine_tools,
113+
llm=function_llm,
114+
verbose=True,
115+
)
116+
117+
self.agents[agent_name] = agent
118+
119+
def _setup_query_engine(self):
120+
"""Setup the top-level query engine."""
121+
objects = []
122+
for agent_name in self.agent_names:
123+
data_summary = (
124+
f"This content contains specific data about {agent_name}. Use "
125+
f"this index if you need to lookup specific facts about {agent_name}.\n"
126+
f"Do not use this index if you want to analyze different topic "
127+
f"other than {agent_name}"
128+
)
129+
node = IndexNode(
130+
text=data_summary,
131+
index_id=agent_name,
132+
obj=self.agents[agent_name]
133+
)
134+
objects.append(node)
135+
136+
vector_index = VectorStoreIndex(objects=objects)
137+
self.query_engine = vector_index.as_query_engine(
138+
similarity_top_k=1,
139+
verbose=True
140+
)
141+
142+
def query(self, question: str) -> str:
143+
"""
144+
Query the agent system with a question.
145+
146+
Args:
147+
question (str): The question to ask
148+
149+
Returns:
150+
str: The response from the query engine
151+
"""
152+
if self.query_engine is None:
153+
raise RuntimeError("Query engine not initialized")
154+
return self.query_engine.query(question)
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
llamaindex
1+
llamaindex
2+
llama-index-llms-ollama
3+
llama-index-llms-openai
4+
llama-index-agent-openai
5+
llama-index-vector-stores-qdrant
6+
qdrant-client
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
DB_URL='http://localhost:6333'
2+
DB_API_KEY='th3s3cr3tk3y'
3+
COLLECTION_NAME='RECURSIVE_COLLECTION'
4+
5+
OPENAI_API_KEY='sk-proj-'
6+
OPENAI_EMBED_MODEL='gpt-4o'
7+
8+
# use this incase you are prefering to experiment with local models.
9+
OLLAMA_BASE_URL='http://localhost:11434'
10+
OLLAMA_LLM_MODEL='llama3.1'
11+
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'
12+
13+
CHUNK_SIZE=256
14+
CHUNK_OVERLAP=20
15+
16+
# Langfuse Observability Details
17+
LANGFUSE_PUBLIC_KEY='pk-lf-'
18+
LANGFUSE_SECRET_KEY='sk-lf-'
19+
LANGFUSE_HOST='http://localhost:3000'
20+
21+
# logger can be controlled usiing env
22+
CRITICAL = 50
23+
FATAL = 50
24+
ERROR = 40
25+
WARNING = 30
26+
WARN = 30
27+
INFO = 20
28+
DEBUG = 10
29+
NOTSET = 0
30+
31+
LIT_SERVER_PORT=8000
32+
LIT_SERVER_WORKERS_PER_DEVICE=4
33+
34+
IS_EVALUATION_NEEDED=true

bootstraprag/templates/llamaindex/rag_with_recursive_retriever_with_observability/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)