Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
DB_URL='http://localhost:6333'
DB_API_KEY='th3s3cr3tk3y'
COLLECTION_NAME='RECURSIVE_COLLECTION'

OPENAI_API_KEY='sk-proj-'
OPENAI_EMBED_MODEL='gpt-4o'

# use this incase you are prefering to experiment with local models.
OLLAMA_BASE_URL='http://localhost:11434'
OLLAMA_LLM_MODEL='llama3.1'
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'

CHUNK_SIZE=256
CHUNK_OVERLAP=20

# logger can be controlled usiing env
CRITICAL = 50
FATAL = 50
ERROR = 40
WARNING = 30
WARN = 30
INFO = 20
DEBUG = 10
NOTSET = 0

LIT_SERVER_PORT=8000
LIT_SERVER_WORKERS_PER_DEVICE=4

IS_EVALUATION_NEEDED=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from dotenv import load_dotenv, find_dotenv
from recursive_retriever_agents_core import RecursiveAgentManager
import litserve as lit
import os


class RecursiveAgentsAPI(lit.LitAPI):
def __init__(self):
load_dotenv(find_dotenv())
self.agent_names = ['mlops', 'attention', 'orthodontics']
self.agent_manager = None

def setup(self, device):
self.agent_manager = RecursiveAgentManager(self.agent_names)

def decode_request(self, request, **kwargs):
return request['query']

def predict(self, x, **kwargs):
return self.agent_manager.query(x)

def encode_response(self, output, **kwargs):
return {'Agent': output}


if __name__ == "__main__":
lit_api = RecursiveAgentsAPI()
server = lit.LitServer(lit_api=lit_api, api_path='/api/v1/chat-completion',
workers_per_device=int(os.environ.get('LIT_SERVER_WORKERS_PER_DEVICE')))
server.run(port=os.environ.get('LIT_SERVER_PORT'))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from recursive_retriever_agents_core import RecursiveAgentManager


agent_names = ['mlops', 'attention', 'orthodontics']
agent_manager = RecursiveAgentManager(agent_names)

# Usage example:
if __name__ == "__main__":
while True:
# Get user input
user_query = input("Enter your question (or 'quit' to exit): ")

# Check for quit command
if user_query.lower() == 'quit':
print("Exiting program...")
break

# Process query and print response
try:
response = agent_manager.query(user_query)
print("\nResponse:")
print(response)
print("\n" + "-"*50 + "\n") # Separator for readability
except Exception as e:
print(f"Error processing query: {str(e)}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import os
from typing import Dict, List

from llama_index.agent.openai import OpenAIAgent
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings, StorageContext
from llama_index.core import SummaryIndex
from llama_index.core.schema import IndexNode
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from dotenv import load_dotenv, find_dotenv
import qdrant_client
from llama_index.vector_stores.qdrant import QdrantVectorStore


class RecursiveAgentManager:
def __init__(self, agent_names: List[str], data_dir: str = 'data'):
"""
Initialize the AgentManager with a list of agent names and optional data directory path.

Args:
agent_names (List[str]): List of agent names to initialize
data_dir (str): Directory containing the PDF files (default: 'data')
"""
self.agent_names = agent_names
self.data_dir = data_dir
self.document_data = {}
self.agents = {}
self.query_engine = None

# Load environment variables
load_dotenv(find_dotenv())

# Initialize settings
self._initialize_settings()

# Setup components
self._load_documents()
self._setup_vector_store()
self._build_agents()
self._setup_query_engine()

def _initialize_settings(self):
"""Initialize LlamaIndex settings."""
Settings.llm = OpenAI(model=os.environ.get("OPENAI_EMBED_MODEL"), temperature=0.0)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.chunk_size = int(os.environ.get("CHUNK_SIZE"))
Settings.chunk_overlap = int(os.environ.get("CHUNK_OVERLAP"))

def _load_documents(self):
"""Load PDF documents for each agent."""
for agent_name in self.agent_names:
self.document_data[agent_name] = SimpleDirectoryReader(
input_files=[f'{self.data_dir}/{agent_name}.pdf']
).load_data()

def _setup_vector_store(self):
"""Setup Qdrant vector store and storage context."""
client = qdrant_client.QdrantClient(
url=os.environ['DB_URL'],
api_key=os.environ['DB_API_KEY']
)
self.vector_store = QdrantVectorStore(
client=client,
collection_name=os.environ['COLLECTION_NAME']
)
self.storage_context = StorageContext.from_defaults(
vector_store=self.vector_store
)

def _create_query_engine_tools(self, agent_name: str, vector_index: VectorStoreIndex,
summary_index: SummaryIndex) -> List[QueryEngineTool]:
"""Create query engine tools for an agent."""
return [
QueryEngineTool(
query_engine=vector_index.as_query_engine(),
metadata=ToolMetadata(
name="vector_tool",
description=f"Useful for retrieving specific context from {agent_name}"
),
),
QueryEngineTool(
query_engine=summary_index.as_query_engine(),
metadata=ToolMetadata(
name="summary_tool",
description=f"Useful for summarization questions related to {agent_name}"
),
),
]

def _build_agents(self):
"""Build agents with their respective tools."""
for agent_name in self.agent_names:
# Build indices
vector_index = VectorStoreIndex.from_documents(
self.document_data[agent_name],
storage_context=self.storage_context
)
summary_index = SummaryIndex.from_documents(
self.document_data[agent_name],
storage_context=self.storage_context
)

# Create tools
query_engine_tools = self._create_query_engine_tools(
agent_name, vector_index, summary_index
)

# Build agent
function_llm = OpenAI(model=os.environ.get("OPENAI_EMBED_MODEL"))
agent = OpenAIAgent.from_tools(
query_engine_tools,
llm=function_llm,
verbose=True,
)

self.agents[agent_name] = agent

def _setup_query_engine(self):
"""Setup the top-level query engine."""
objects = []
for agent_name in self.agent_names:
data_summary = (
f"This content contains specific data about {agent_name}. Use "
f"this index if you need to lookup specific facts about {agent_name}.\n"
f"Do not use this index if you want to analyze different topic "
f"other than {agent_name}"
)
node = IndexNode(
text=data_summary,
index_id=agent_name,
obj=self.agents[agent_name]
)
objects.append(node)

vector_index = VectorStoreIndex(objects=objects)
self.query_engine = vector_index.as_query_engine(
similarity_top_k=1,
verbose=True
)

def query(self, question: str) -> str:
"""
Query the agent system with a question.

Args:
question (str): The question to ask

Returns:
str: The response from the query engine
"""
if self.query_engine is None:
raise RuntimeError("Query engine not initialized")
return self.query_engine.query(question)
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
llamaindex
llamaindex
llama-index-llms-ollama
llama-index-llms-openai
llama-index-agent-openai
llama-index-vector-stores-qdrant
qdrant-client
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
DB_URL='http://localhost:6333'
DB_API_KEY='th3s3cr3tk3y'
COLLECTION_NAME='RECURSIVE_COLLECTION'

OPENAI_API_KEY='sk-proj-'
OPENAI_EMBED_MODEL='gpt-4o'

# use this incase you are prefering to experiment with local models.
OLLAMA_BASE_URL='http://localhost:11434'
OLLAMA_LLM_MODEL='llama3.1'
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'

CHUNK_SIZE=256
CHUNK_OVERLAP=20

# Langfuse Observability Details
LANGFUSE_PUBLIC_KEY='pk-lf-'
LANGFUSE_SECRET_KEY='sk-lf-'
LANGFUSE_HOST='http://localhost:3000'

# logger can be controlled usiing env
CRITICAL = 50
FATAL = 50
ERROR = 40
WARNING = 30
WARN = 30
INFO = 20
DEBUG = 10
NOTSET = 0

LIT_SERVER_PORT=8000
LIT_SERVER_WORKERS_PER_DEVICE=4

IS_EVALUATION_NEEDED=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from dotenv import load_dotenv, find_dotenv
from recursive_retriever_agents_core import RecursiveAgentManager
import litserve as lit
import os


class RecursiveAgentsAPI(lit.LitAPI):
def __init__(self):
load_dotenv(find_dotenv())
self.agent_names = ['mlops', 'attention', 'orthodontics']
self.agent_manager = None

def setup(self, device):
self.agent_manager = RecursiveAgentManager(self.agent_names)

def decode_request(self, request, **kwargs):
return request['query']

def predict(self, x, **kwargs):
return self.agent_manager.query(x)

def encode_response(self, output, **kwargs):
return {'Agent': output}


if __name__ == "__main__":
lit_api = RecursiveAgentsAPI()
server = lit.LitServer(lit_api=lit_api, api_path='/api/v1/chat-completion',
workers_per_device=int(os.environ.get('LIT_SERVER_WORKERS_PER_DEVICE')))
server.run(port=os.environ.get('LIT_SERVER_PORT'))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
version: '3.8'

services:
postgres:
image: postgres:latest
container_name: postgres
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: langfuse
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- langfuse-network

langfuse:
image: langfuse/langfuse:latest
container_name: langfuse
environment:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/langfuse
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: mysecret
SALT: mysalt
ENCRYPTION_KEY: 98637d42c277ef10b8a324e25d492daa8eee8f769574124ba25132f71481f183
ports:
- "3000:3000"
depends_on:
- postgres
networks:
- langfuse-network

volumes:
postgres_data:

networks:
langfuse-network:
driver: bridge
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from recursive_retriever_agents_core import RecursiveAgentManager


agent_names = ['mlops', 'attention', 'orthodontics']
agent_manager = RecursiveAgentManager(agent_names)

# Usage example:
if __name__ == "__main__":
while True:
# Get user input
user_query = input("Enter your question (or 'quit' to exit): ")

# Check for quit command
if user_query.lower() == 'quit':
print("Exiting program...")
break

# Process query and print response
try:
response = agent_manager.query(user_query)
print("\nResponse:")
print(response)
print("\n" + "-"*50 + "\n") # Separator for readability
except Exception as e:
print(f"Error processing query: {str(e)}")
Loading