diff --git a/cookbook/rag/03_agentic_rag_lancedb.py b/cookbook/rag/04_agentic_rag_lancedb.py similarity index 95% rename from cookbook/rag/03_agentic_rag_lancedb.py rename to cookbook/rag/04_agentic_rag_lancedb.py index d8bc37c9d..804756038 100644 --- a/cookbook/rag/03_agentic_rag_lancedb.py +++ b/cookbook/rag/04_agentic_rag_lancedb.py @@ -1,6 +1,6 @@ """ 1. Run: `pip install openai lancedb tantivy pypdf sqlalchemy phidata` to install the dependencies -2. Run: `python cookbook/rag/03_agentic_rag_lancedb.py` to run the agent +2. Run: `python cookbook/rag/04_agentic_rag_lancedb.py` to run the agent """ from phi.agent import Agent diff --git a/cookbook/rag/05_agentic_rag_playground.py b/cookbook/rag/05_agentic_rag_playground.py new file mode 100644 index 000000000..822b45e6b --- /dev/null +++ b/cookbook/rag/05_agentic_rag_playground.py @@ -0,0 +1,54 @@ +""" +1. Run: `./cookbook/run_pgvector.sh` to start a postgres container with pgvector +2. Run: `pip install openai sqlalchemy 'psycopg[binary]' pgvector 'fastapi[standard]'` to install the dependencies +3. Run: `python cookbook/rag/05_agentic_rag_playground.py` to run the agent +""" + +from phi.agent import Agent +from phi.model.openai import OpenAIChat +from phi.embedder.openai import OpenAIEmbedder +from phi.knowledge.pdf import PDFUrlKnowledgeBase +from phi.storage.agent.postgres import PgAgentStorage +from phi.vectordb.pgvector import PgVector, SearchType +from phi.playground import Playground, serve_playground_app + +db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" +# Create a knowledge base of PDFs from URLs +knowledge_base = PDFUrlKnowledgeBase( + urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], + # Use PgVector as the vector database and store embeddings in the `ai.recipes` table + vector_db=PgVector( + table_name="recipes", + db_url=db_url, + search_type=SearchType.hybrid, + embedder=OpenAIEmbedder(model="text-embedding-3-small"), + ), +) + +rag_agent = Agent( + name="RAG Agent", + agent_id="rag-agent", + model=OpenAIChat(id="gpt-4o"), + knowledge=knowledge_base, + # Add a tool to search the knowledge base which enables agentic RAG. + # This is enabled by default when `knowledge` is provided to the Agent. + search_knowledge=True, + # Add a tool to read chat history. + read_chat_history=True, + # Store the agent sessions in the `ai.rag_agent_sessions` table + storage=PgAgentStorage(table_name="rag_agent_sessions", db_url=db_url), + instructions=[ + "Always search your knowledge base first and use it if available.", + "Share the page number or source URL of the information you used in your response.", + "Important: Use tables where possible.", + "If health benefits are mentioned, include them in the response.", + ], + markdown=True, +) + +app = Playground(agents=[rag_agent]).get_app() + +if __name__ == "__main__": + # Load the knowledge base: Comment after first run as the knowledge base is already loaded + knowledge_base.load() + serve_playground_app("05_agentic_rag_playground:app", reload=True) diff --git a/phi/storage/agent/postgres.py b/phi/storage/agent/postgres.py index 39bcab1da..a05f262f7 100644 --- a/phi/storage/agent/postgres.py +++ b/phi/storage/agent/postgres.py @@ -351,7 +351,7 @@ def __deepcopy__(self, memo): # Deep copy attributes for k, v in self.__dict__.items(): - if k in {"metadata", "table"}: + if k in {"metadata", "table", "inspector"}: continue # Reuse db_engine and Session without copying elif k in {"db_engine", "Session"}: @@ -361,6 +361,7 @@ def __deepcopy__(self, memo): # Recreate metadata and table for the copied instance copied_obj.metadata = MetaData(schema=copied_obj.schema) + copied_obj.inspector = inspect(copied_obj.db_engine) copied_obj.table = copied_obj.get_table() return copied_obj diff --git a/phi/storage/agent/sqlite.py b/phi/storage/agent/sqlite.py index 8f1fa2981..2ee3c8d74 100644 --- a/phi/storage/agent/sqlite.py +++ b/phi/storage/agent/sqlite.py @@ -341,7 +341,7 @@ def __deepcopy__(self, memo): # Deep copy attributes for k, v in self.__dict__.items(): - if k in {"metadata", "table"}: + if k in {"metadata", "table", "inspector"}: continue # Reuse db_engine and Session without copying elif k in {"db_engine", "Session"}: @@ -351,6 +351,7 @@ def __deepcopy__(self, memo): # Recreate metadata and table for the copied instance copied_obj.metadata = MetaData() + copied_obj.inspector = inspect(copied_obj.db_engine) copied_obj.table = copied_obj.get_table() return copied_obj diff --git a/phi/storage/workflow/postgres.py b/phi/storage/workflow/postgres.py index 2dd613653..fe55e99be 100644 --- a/phi/storage/workflow/postgres.py +++ b/phi/storage/workflow/postgres.py @@ -354,7 +354,7 @@ def __deepcopy__(self, memo): # Deep copy attributes for k, v in self.__dict__.items(): - if k in {"metadata", "table"}: + if k in {"metadata", "table", "inspector"}: continue # Reuse db_engine and Session without copying elif k in {"db_engine", "Session"}: @@ -364,6 +364,7 @@ def __deepcopy__(self, memo): # Recreate metadata and table for the copied instance copied_obj.metadata = MetaData(schema=copied_obj.schema) + copied_obj.inspector = inspect(copied_obj.db_engine) copied_obj.table = copied_obj.get_table() return copied_obj diff --git a/phi/storage/workflow/sqlite.py b/phi/storage/workflow/sqlite.py index 990a08222..4c2a2de74 100644 --- a/phi/storage/workflow/sqlite.py +++ b/phi/storage/workflow/sqlite.py @@ -347,7 +347,7 @@ def __deepcopy__(self, memo): # Deep copy attributes for k, v in self.__dict__.items(): - if k in {"metadata", "table"}: + if k in {"metadata", "table", "inspector"}: continue # Reuse db_engine and Session without copying elif k in {"db_engine", "Session"}: @@ -357,6 +357,7 @@ def __deepcopy__(self, memo): # Recreate metadata and table for the copied instance copied_obj.metadata = MetaData() + copied_obj.inspector = inspect(copied_obj.db_engine) copied_obj.table = copied_obj.get_table() return copied_obj diff --git a/pyproject.toml b/pyproject.toml index 5ff4089e4..9b07a908f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "phidata" -version = "2.5.23" +version = "2.5.24" description = "Build AI Agents with memory, knowledge and tools." requires-python = ">=3.7" readme = "README.md"