└── agno.txt /agno.txt: -------------------------------------------------------------------------------- 1 | Getting Started 2 | Introduction 3 | Build agents and workflows to automate intelligent work. 4 | 5 | Phidata is now Agno! We’ve moved! Check out our new home at Agno AGI 6 | ​ 7 | What is Phidata? 8 | Phidata is a framework for building multi-modal agents and workflows. 9 | Build agents with memory, knowledge, tools and reasoning. 10 | Build teams of agents that can work together to solve problems. 11 | Interact with your agents and workflows using a beautiful Agent UI. 12 | ​ 13 | Key Features 14 | Simple & Elegant 15 | Powerful & Flexible 16 | Multi-Modal by default 17 | Multi-Agent orchestration 18 | A beautiful Agent UI to chat with your agents 19 | Agentic RAG built-in 20 | Structured outputs 21 | Reasoning built-in 22 | Monitoring & Debugging built-in 23 | ​ 24 | Install 25 | 26 | Copy 27 | 28 | Ask AI 29 | pip install -U phidata 30 | ​ 31 | Simple & Elegant 32 | Phidata Agents are simple and elegant, resulting in minimal, beautiful code. 33 | For example, you can create a web search agent in 10 lines of code. 34 | web_search.py 35 | 36 | Copy 37 | 38 | Ask AI 39 | from phi.agent import Agent 40 | from phi.model.openai import OpenAIChat 41 | from phi.tools.duckduckgo import DuckDuckGo 42 | 43 | web_agent = Agent( 44 | name="Web Agent", 45 | model=OpenAIChat(id="gpt-4o"), 46 | tools=[DuckDuckGo()], 47 | instructions=["Always include sources"], 48 | show_tool_calls=True, 49 | markdown=True, 50 | ) 51 | web_agent.print_response("Tell me about OpenAI Sora?", stream=True) 52 | ​ 53 | Setup 54 | 1 55 | Setup your virtual environment 56 | 57 | 58 | Mac 59 | 60 | Windows 61 | 62 | Copy 63 | 64 | Ask AI 65 | python3 -m venv ~/.venvs/aienv 66 | source ~/.venvs/aienv/bin/activate 67 | 2 68 | Install libraries 69 | 70 | 71 | Mac 72 | 73 | Windows 74 | 75 | Copy 76 | 77 | Ask AI 78 | pip install -U phidata openai duckduckgo-search 79 | 3 80 | Export your OpenAI key 81 | 82 | Phidata works with most model providers but for these examples let’s use OpenAI. 83 | 84 | Mac 85 | 86 | Windows 87 | 88 | Copy 89 | 90 | Ask AI 91 | export OPENAI_API_KEY=sk-*** 92 | You can get an API key from here. 93 | 4 94 | Run the agent 95 | 96 | 97 | Copy 98 | 99 | Ask AI 100 | python web_search.py 101 | ​ 102 | Powerful & Flexible 103 | Phidata agents can use multiple tools and follow instructions to achieve complex tasks. 104 | For example, you can create a finance agent with tools to query financial data. 105 | 1 106 | Create a finance agent 107 | 108 | finance_agent.py 109 | 110 | Copy 111 | 112 | Ask AI 113 | from phi.agent import Agent 114 | from phi.model.openai import OpenAIChat 115 | from phi.tools.yfinance import YFinanceTools 116 | 117 | finance_agent = Agent( 118 | name="Finance Agent", 119 | model=OpenAIChat(id="gpt-4o"), 120 | tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)], 121 | instructions=["Use tables to display data"], 122 | show_tool_calls=True, 123 | markdown=True, 124 | ) 125 | finance_agent.print_response("Summarize analyst recommendations for NVDA", stream=True) 126 | 2 127 | Run the agent 128 | 129 | Install libraries 130 | 131 | Copy 132 | 133 | Ask AI 134 | pip install yfinance 135 | Run the agent 136 | 137 | Copy 138 | 139 | Ask AI 140 | python finance_agent.py 141 | ​ 142 | Multi-Modal by default 143 | Phidata agents support text, images, audio and video. 144 | For example, you can create an image agent that can understand images and make tool calls as needed 145 | 1 146 | Create an image agent 147 | 148 | image_agent.py 149 | 150 | Copy 151 | 152 | Ask AI 153 | from phi.agent import Agent 154 | from phi.model.openai import OpenAIChat 155 | from phi.tools.duckduckgo import DuckDuckGo 156 | 157 | agent = Agent( 158 | model=OpenAIChat(id="gpt-4o"), 159 | tools=[DuckDuckGo()], 160 | markdown=True, 161 | ) 162 | 163 | agent.print_response( 164 | "Tell me about this image and give me the latest news about it.", 165 | images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"], 166 | stream=True, 167 | ) 168 | 2 169 | Run the agent 170 | 171 | 172 | Copy 173 | 174 | Ask AI 175 | python image_agent.py 176 | ​ 177 | Multi-Agent orchestration 178 | Phidata agents can work together as a team to achieve complex tasks. 179 | 1 180 | Create an agent team 181 | 182 | agent_team.py 183 | 184 | Copy 185 | 186 | Ask AI 187 | from phi.agent import Agent 188 | from phi.model.openai import OpenAIChat 189 | from phi.tools.duckduckgo import DuckDuckGo 190 | from phi.tools.yfinance import YFinanceTools 191 | 192 | web_agent = Agent( 193 | name="Web Agent", 194 | role="Search the web for information", 195 | model=OpenAIChat(id="gpt-4o"), 196 | tools=[DuckDuckGo()], 197 | instructions=["Always include sources"], 198 | show_tool_calls=True, 199 | markdown=True, 200 | ) 201 | 202 | finance_agent = Agent( 203 | name="Finance Agent", 204 | role="Get financial data", 205 | model=OpenAIChat(id="gpt-4o"), 206 | tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True)], 207 | instructions=["Use tables to display data"], 208 | show_tool_calls=True, 209 | markdown=True, 210 | ) 211 | 212 | agent_team = Agent( 213 | team=[web_agent, finance_agent], 214 | instructions=["Always include sources", "Use tables to display data"], 215 | show_tool_calls=True, 216 | markdown=True, 217 | ) 218 | 219 | agent_team.print_response("Summarize analyst recommendations and share the latest news for NVDA", stream=True) 220 | 2 221 | Run the agent team 222 | 223 | Run the agent team 224 | 225 | Copy 226 | 227 | Ask AI 228 | python agent_team.py 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | Getting Started 237 | Agent UI 238 | Phidata provides a beautiful Agent UI for interacting with your agents. 239 | 240 | 241 | Agent Playground 242 | 243 | No data is sent to phidata, all agent sessions are stored locally in a sqlite database. 244 | Let’s take it for a spin, create a file playground.py 245 | playground.py 246 | 247 | Copy 248 | 249 | Ask AI 250 | from phi.agent import Agent 251 | from phi.model.openai import OpenAIChat 252 | from phi.storage.agent.sqlite import SqlAgentStorage 253 | from phi.tools.duckduckgo import DuckDuckGo 254 | from phi.tools.yfinance import YFinanceTools 255 | from phi.playground import Playground, serve_playground_app 256 | 257 | web_agent = Agent( 258 | name="Web Agent", 259 | model=OpenAIChat(id="gpt-4o"), 260 | tools=[DuckDuckGo()], 261 | instructions=["Always include sources"], 262 | storage=SqlAgentStorage(table_name="web_agent", db_file="agents.db"), 263 | add_history_to_messages=True, 264 | markdown=True, 265 | ) 266 | 267 | finance_agent = Agent( 268 | name="Finance Agent", 269 | model=OpenAIChat(id="gpt-4o"), 270 | tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)], 271 | instructions=["Use tables to display data"], 272 | storage=SqlAgentStorage(table_name="finance_agent", db_file="agents.db"), 273 | add_history_to_messages=True, 274 | markdown=True, 275 | ) 276 | 277 | app = Playground(agents=[finance_agent, web_agent]).get_app() 278 | 279 | if __name__ == "__main__": 280 | serve_playground_app("playground:app", reload=True) 281 | Make sure the serve_playground_app() points to the file that contains your Playground app. 282 | ​ 283 | Authenticate with phidata 284 | Authenticate with phidata by running the following command: 285 | 286 | Copy 287 | 288 | Ask AI 289 | phi auth 290 | or by exporting the PHI_API_KEY for your workspace from phidata.app 291 | 292 | Mac 293 | 294 | Windows 295 | 296 | Copy 297 | 298 | Ask AI 299 | export PHI_API_KEY=phi-*** 300 | ​ 301 | Run the playground 302 | Install dependencies and run the Agent Playground: 303 | 304 | Copy 305 | 306 | Ask AI 307 | pip install 'fastapi[standard]' sqlalchemy 308 | 309 | python playground.py 310 | ​ 311 | View the playground 312 | Open the link provided or navigate to http://phidata.app/playground (login required) 313 | Select the localhost:7777 endpoint and start chatting with your agents! 314 | 315 | 316 | 317 | Getting Started 318 | Examples 319 | ​ 320 | Research Agent 321 | Let’s build a research agent to generate a report using Exa. 322 | 1 323 | Create a research agent 324 | 325 | research_agent.py 326 | 327 | Copy 328 | 329 | Ask AI 330 | from textwrap import dedent 331 | from datetime import datetime 332 | 333 | from phi.agent import Agent 334 | from phi.model.openai import OpenAIChat 335 | from phi.tools.exa import ExaTools 336 | 337 | agent = Agent( 338 | model=OpenAIChat(id="gpt-4o"), 339 | tools=[ExaTools(start_published_date=datetime.now().strftime("%Y-%m-%d"), type="keyword")], 340 | description="You are an advanced AI researcher writing a report on a topic.", 341 | instructions=[ 342 | "For the provided topic, run 3 different searches.", 343 | "Read the results carefully and prepare a NYT worthy report.", 344 | "Focus on facts and make sure to provide references.", 345 | ], 346 | expected_output=dedent("""\ 347 | An engaging, informative, and well-structured report in markdown format: 348 | 349 | ## Engaging Report Title 350 | 351 | ### Overview 352 | {give a brief introduction of the report and why the user should read this report} 353 | {make this section engaging and create a hook for the reader} 354 | 355 | ### Section 1 356 | {break the report into sections} 357 | {provide details/facts/processes in this section} 358 | 359 | ... more sections as necessary... 360 | 361 | ### Takeaways 362 | {provide key takeaways from the article} 363 | 364 | ### References 365 | - [Reference 1](link) 366 | - [Reference 2](link) 367 | - [Reference 3](link) 368 | 369 | - published on {date} in dd/mm/yyyy 370 | """), 371 | markdown=True, 372 | show_tool_calls=True, 373 | add_datetime_to_instructions=True, 374 | save_response_to_file="tmp/{message}.md", 375 | ) 376 | agent.print_response("Simulation theory", stream=True) 377 | 2 378 | Run the agent 379 | 380 | Install libraries 381 | 382 | Copy 383 | 384 | Ask AI 385 | pip install openai exa-py phidata 386 | Run the agent 387 | 388 | Copy 389 | 390 | Ask AI 391 | python research_agent.py 392 | View the report 393 | 394 | Copy 395 | 396 | Ask AI 397 | cat tmp/Simulation theory.md 398 | ​ 399 | Agentic RAG 400 | We were the first to pioneer Agentic RAG using our Auto-RAG paradigm. With Agentic RAG (or auto-rag), the Agent can search its knowledge base (vector db) for the specific information it needs to achieve its task, instead of always inserting the “context” into the prompt. 401 | This saves tokens and improves response quality. 402 | 1 403 | Create a RAG agent 404 | 405 | rag_agent.py 406 | 407 | Copy 408 | 409 | Ask AI 410 | from phi.agent import Agent 411 | from phi.model.openai import OpenAIChat 412 | from phi.embedder.openai import OpenAIEmbedder 413 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 414 | from phi.vectordb.lancedb import LanceDb, SearchType 415 | 416 | # Create a knowledge base from a PDF 417 | knowledge_base = PDFUrlKnowledgeBase( 418 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 419 | # Use LanceDB as the vector database 420 | vector_db=LanceDb( 421 | table_name="recipes", 422 | uri="tmp/lancedb", 423 | search_type=SearchType.vector, 424 | embedder=OpenAIEmbedder(model="text-embedding-3-small"), 425 | ), 426 | ) 427 | # Comment out after first run as the knowledge base is loaded 428 | knowledge_base.load() 429 | 430 | agent = Agent( 431 | model=OpenAIChat(id="gpt-4o"), 432 | # Add the knowledge base to the agent 433 | knowledge=knowledge_base, 434 | show_tool_calls=True, 435 | markdown=True, 436 | ) 437 | agent.print_response("How do I make chicken and galangal in coconut milk soup", stream=True) 438 | 2 439 | Run the agent 440 | 441 | Install libraries 442 | 443 | Copy 444 | 445 | Ask AI 446 | pip install lancedb tantivy pypdf sqlalchemy 447 | Run the agent 448 | 449 | Copy 450 | 451 | Ask AI 452 | python rag_agent.py 453 | ​ 454 | Structured Outputs 455 | Agents can return their output in a structured format as a Pydantic model. 456 | Create a file structured_output.py 457 | 1 458 | Create a structured output agent 459 | 460 | structured_output.py 461 | 462 | Copy 463 | 464 | Ask AI 465 | from typing import List 466 | from pydantic import BaseModel, Field 467 | from phi.agent import Agent 468 | from phi.model.openai import OpenAIChat 469 | 470 | # Define a Pydantic model to enforce the structure of the output 471 | class MovieScript(BaseModel): 472 | setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.") 473 | ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.") 474 | genre: str = Field(..., description="Genre of the movie. If not available, select action, thriller or romantic comedy.") 475 | name: str = Field(..., description="Give a name to this movie") 476 | characters: List[str] = Field(..., description="Name of characters for this movie.") 477 | storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!") 478 | 479 | # Agent that uses JSON mode 480 | json_mode_agent = Agent( 481 | model=OpenAIChat(id="gpt-4o"), 482 | description="You write movie scripts.", 483 | response_model=MovieScript, 484 | ) 485 | # Agent that uses structured outputs 486 | structured_output_agent = Agent( 487 | model=OpenAIChat(id="gpt-4o"), 488 | description="You write movie scripts.", 489 | response_model=MovieScript, 490 | structured_outputs=True, 491 | ) 492 | 493 | json_mode_agent.print_response("New York") 494 | structured_output_agent.print_response("New York") 495 | 2 496 | Run the agent 497 | 498 | 499 | Copy 500 | 501 | Ask AI 502 | python structured_output.py 503 | ​ 504 | Reasoning Agent 505 | Reasoning is an experimental feature that helps agents work through a problem step-by-step, backtracking and correcting as needed. 506 | 1 507 | Create a reasoning agent 508 | 509 | reasoning_agent.py 510 | 511 | Copy 512 | 513 | Ask AI 514 | from phi.agent import Agent 515 | from phi.model.openai import OpenAIChat 516 | 517 | task = ( 518 | "Three missionaries and three cannibals need to cross a river. " 519 | "They have a boat that can carry up to two people at a time. " 520 | "If, at any time, the cannibals outnumber the missionaries on either side of the river, the cannibals will eat the missionaries. " 521 | "How can all six people get across the river safely? Provide a step-by-step solution and show the solutions as an ascii diagram" 522 | ) 523 | 524 | reasoning_agent = Agent(model=OpenAIChat(id="gpt-4o"), reasoning=True, markdown=True, structured_outputs=True) 525 | reasoning_agent.print_response(task, stream=True, show_full_reasoning=True) 526 | 2 527 | Run the reasoning agent 528 | 529 | 530 | Copy 531 | 532 | Ask AI 533 | python reasoning_agent.py 534 | 535 | 536 | 537 | Getting Started 538 | Monitoring 539 | Phidata comes with built-in monitoring and debugging. 540 | 541 | You can set monitoring=True on any agent to log that agent’s sessions or set PHI_MONITORING=true in your environment to log all agent sessions. 542 | Create a file monitoring.py with the following code: 543 | monitoring.py 544 | 545 | Copy 546 | 547 | Ask AI 548 | from phi.agent import Agent 549 | 550 | agent = Agent(markdown=True, monitoring=True) 551 | agent.print_response("Share a 2 sentence horror story") 552 | ​ 553 | Authenticate with phidata 554 | Authenticate with phidata by running the following command: 555 | 556 | Copy 557 | 558 | Ask AI 559 | phi auth 560 | or by exporting the PHI_API_KEY for your workspace from phidata.app 561 | 562 | Mac 563 | 564 | Windows 565 | 566 | Copy 567 | 568 | Ask AI 569 | export PHI_API_KEY=phi-*** 570 | ​ 571 | Run the agent 572 | Run the agent and view the session on phidata.app/sessions 573 | 574 | Copy 575 | 576 | Ask AI 577 | python monitoring.py 578 | 579 | ​ 580 | Debugging 581 | Phidata also includes a built-in debugger that will show debug logs in the terminal. You can set debug_mode=True on any agent to view debug logs or set PHI_DEBUG=true in your environment. 582 | debugging.py 583 | 584 | Copy 585 | 586 | Ask AI 587 | from phi.agent import Agent 588 | 589 | agent = Agent(markdown=True, debug_mode=True) 590 | agent.print_response("Share a 2 sentence horror story") 591 | Run the agent to view debug logs in the terminal: 592 | 593 | Copy 594 | 595 | Ask AI 596 | python debugging.py 597 | 598 | 599 | 600 | Getting Started 601 | Workflows 602 | Workflows are deterministic, stateful, multi-agent programs that are built for production applications. They’re incredibly powerful and offer the following benefits: 603 | Full control and flexibility: You have full control over the multi-agent process, how the input is processed, which agents are used and in what order. This is critical for reliability. 604 | Pure python: Control the agent process using standard python. Having built 100s of AI products, no framework will give you the flexibility of pure-python. 605 | Built-in state management and caching: Store state and cache intermediate results in a database, enabling your agents to re-use results from previous executions. 606 | How to build a workflow: 607 | Define your workflow as a class by inheriting from the Workflow class. 608 | Add one or more agents to the workflow. 609 | Implement your logic in the run() method. 610 | Cache results in the session_state as needed. 611 | Run the workflow using the .run() method. 612 | ​ 613 | Example: Blog Post Generator 614 | Let’s create a blog post generator that can search the web, read the top links and write a blog post for us. We’ll cache intermediate results in the database to improve performance. 615 | ​ 616 | Create the Workflow 617 | Create a file blog_post_generator.py 618 | blog_post_generator.py 619 | 620 | Copy 621 | 622 | Ask AI 623 | import json 624 | from typing import Optional, Iterator 625 | 626 | from pydantic import BaseModel, Field 627 | 628 | from phi.agent import Agent 629 | from phi.model.openai import OpenAIChat 630 | from phi.workflow import Workflow, RunResponse, RunEvent 631 | from phi.storage.workflow.sqlite import SqlWorkflowStorage 632 | from phi.tools.duckduckgo import DuckDuckGo 633 | from phi.utils.pprint import pprint_run_response 634 | from phi.utils.log import logger 635 | 636 | 637 | class NewsArticle(BaseModel): 638 | title: str = Field(..., description="Title of the article.") 639 | url: str = Field(..., description="Link to the article.") 640 | summary: Optional[str] = Field(..., description="Summary of the article if available.") 641 | 642 | 643 | class SearchResults(BaseModel): 644 | articles: list[NewsArticle] 645 | 646 | 647 | class BlogPostGenerator(Workflow): 648 | # Define an Agent that will search the web for a topic 649 | searcher: Agent = Agent( 650 | model=OpenAIChat(id="gpt-4o-mini"), 651 | tools=[DuckDuckGo()], 652 | instructions=["Given a topic, search for the top 5 articles."], 653 | response_model=SearchResults, 654 | structured_outputs=True, 655 | ) 656 | 657 | # Define an Agent that will write the blog post 658 | writer: Agent = Agent( 659 | model=OpenAIChat(id="gpt-4o"), 660 | instructions=[ 661 | "You will be provided with a topic and a list of top articles on that topic.", 662 | "Carefully read each article and generate a New York Times worthy blog post on that topic.", 663 | "Break the blog post into sections and provide key takeaways at the end.", 664 | "Make sure the title is catchy and engaging.", 665 | "Always provide sources, do not make up information or sources.", 666 | ], 667 | markdown=True, 668 | ) 669 | 670 | def run(self, topic: str, use_cache: bool = True) -> Iterator[RunResponse]: 671 | """This is where the main logic of the workflow is implemented.""" 672 | 673 | logger.info(f"Generating a blog post on: {topic}") 674 | 675 | # Step 1: Use the cached blog post if use_cache is True 676 | if use_cache: 677 | cached_blog_post = self.get_cached_blog_post(topic) 678 | if cached_blog_post: 679 | yield RunResponse(content=cached_blog_post, event=RunEvent.workflow_completed) 680 | return 681 | 682 | # Step 2: Search the web for articles on the topic 683 | search_results: Optional[SearchResults] = self.get_search_results(topic) 684 | # If no search_results are found for the topic, end the workflow 685 | if search_results is None or len(search_results.articles) == 0: 686 | yield RunResponse( 687 | event=RunEvent.workflow_completed, 688 | content=f"Sorry, could not find any articles on the topic: {topic}", 689 | ) 690 | return 691 | 692 | # Step 3: Write a blog post 693 | yield from self.write_blog_post(topic, search_results) 694 | 695 | def get_cached_blog_post(self, topic: str) -> Optional[str]: 696 | """Get the cached blog post for a topic.""" 697 | 698 | logger.info("Checking if cached blog post exists") 699 | return self.session_state.get("blog_posts", {}).get(topic) 700 | 701 | def add_blog_post_to_cache(self, topic: str, blog_post: Optional[str]): 702 | """Add a blog post to the cache.""" 703 | 704 | logger.info(f"Saving blog post for topic: {topic}") 705 | self.session_state.setdefault("blog_posts", {}) 706 | self.session_state["blog_posts"][topic] = blog_post 707 | 708 | def get_search_results(self, topic: str) -> Optional[SearchResults]: 709 | """Get the search results for a topic.""" 710 | 711 | MAX_ATTEMPTS = 3 712 | 713 | for attempt in range(MAX_ATTEMPTS): 714 | try: 715 | searcher_response: RunResponse = self.searcher.run(topic) 716 | 717 | # Check if we got a valid response 718 | if not searcher_response or not searcher_response.content: 719 | logger.warning(f"Attempt {attempt + 1}/{MAX_ATTEMPTS}: Empty searcher response") 720 | continue 721 | # Check if the response is of the expected SearchResults type 722 | if not isinstance(searcher_response.content, SearchResults): 723 | logger.warning(f"Attempt {attempt + 1}/{MAX_ATTEMPTS}: Invalid response type") 724 | continue 725 | 726 | article_count = len(searcher_response.content.articles) 727 | logger.info(f"Found {article_count} articles on attempt {attempt + 1}") 728 | return searcher_response.content 729 | 730 | except Exception as e: 731 | logger.warning(f"Attempt {attempt + 1}/{MAX_ATTEMPTS} failed: {str(e)}") 732 | 733 | logger.error(f"Failed to get search results after {MAX_ATTEMPTS} attempts") 734 | return None 735 | 736 | def write_blog_post(self, topic: str, search_results: SearchResults) -> Iterator[RunResponse]: 737 | """Write a blog post on a topic.""" 738 | 739 | logger.info("Writing blog post") 740 | # Prepare the input for the writer 741 | writer_input = {"topic": topic, "articles": [v.model_dump() for v in search_results.articles]} 742 | # Run the writer and yield the response 743 | yield from self.writer.run(json.dumps(writer_input, indent=4), stream=True) 744 | # Save the blog post in the cache 745 | self.add_blog_post_to_cache(topic, self.writer.run_response.content) 746 | 747 | 748 | # Run the workflow if the script is executed directly 749 | if __name__ == "__main__": 750 | from rich.prompt import Prompt 751 | 752 | # Get topic from user 753 | topic = Prompt.ask( 754 | "[bold]Enter a blog post topic[/bold]\n✨", 755 | default="Why Cats Secretly Run the Internet", 756 | ) 757 | 758 | # Convert the topic to a URL-safe string for use in session_id 759 | url_safe_topic = topic.lower().replace(" ", "-") 760 | 761 | # Initialize the blog post generator workflow 762 | # - Creates a unique session ID based on the topic 763 | # - Sets up SQLite storage for caching results 764 | generate_blog_post = BlogPostGenerator( 765 | session_id=f"generate-blog-post-on-{url_safe_topic}", 766 | storage=SqlWorkflowStorage( 767 | table_name="generate_blog_post_workflows", 768 | db_file="tmp/workflows.db", 769 | ), 770 | ) 771 | 772 | # Execute the workflow with caching enabled 773 | # Returns an iterator of RunResponse objects containing the generated content 774 | blog_post: Iterator[RunResponse] = generate_blog_post.run(topic=topic, use_cache=True) 775 | 776 | # Print the response 777 | pprint_run_response(blog_post, markdown=True) 778 | ​ 779 | Run the workflow 780 | Install libraries 781 | 782 | Copy 783 | 784 | Ask AI 785 | pip install phidata openai duckduckgo-search sqlalchemy 786 | Run the workflow 787 | 788 | Copy 789 | 790 | Ask AI 791 | python blog_post_generator.py 792 | Now the results are cached in the database and can be re-used for future runs. Run the workflow again to view the cached results. 793 | 794 | Copy 795 | 796 | Ask AI 797 | python blog_post_generator.py 798 | 799 | 800 | 801 | Agents 802 | Introduction 803 | Agents are autonomous programs that achieve tasks using language models. 804 | 805 | Engineers use phidata to build agents with memory, knowledge, tools and reasoning. 806 | 807 | ​ 808 | Example: Research Agent 809 | Let’s create a research agent that can search the web, read the top links and write a report for us. We “prompt” the agent using description and instructions. 810 | 1 811 | Create Research Agent 812 | 813 | Create a file research_agent.py 814 | research_agent.py 815 | 816 | Copy 817 | 818 | Ask AI 819 | from phi.agent import Agent 820 | from phi.model.openai import OpenAIChat 821 | from phi.tools.duckduckgo import DuckDuckGo 822 | from phi.tools.newspaper4k import Newspaper4k 823 | 824 | agent = Agent( 825 | model=OpenAIChat(id="gpt-4o"), 826 | tools=[DuckDuckGo(), Newspaper4k()], 827 | description="You are a senior NYT researcher writing an article on a topic.", 828 | instructions=[ 829 | "For a given topic, search for the top 5 links.", 830 | "Then read each URL and extract the article text, if a URL isn't available, ignore it.", 831 | "Analyse and prepare an NYT worthy article based on the information.", 832 | ], 833 | markdown=True, 834 | show_tool_calls=True, 835 | add_datetime_to_instructions=True, 836 | # debug_mode=True, 837 | ) 838 | agent.print_response("Simulation theory", stream=True) 839 | 2 840 | Run the agent 841 | 842 | Install libraries 843 | 844 | Copy 845 | 846 | Ask AI 847 | pip install phidata openai duckduckgo-search newspaper4k lxml_html_clean 848 | Run the agent 849 | 850 | Copy 851 | 852 | Ask AI 853 | python research_agent.py 854 | The description and instructions are converted to the system prompt and the input (e.g. Simulation theory) is passed as the user prompt. 855 | Use debug_mode=True to view the raw logs behind the scenes. 856 | ​ 857 | Capturing the Agent’s response in a variable 858 | While Agent.print_response() is useful for quick experiments, we typically want to capture the agent’s response in a variable to either pass to the frontend, another agent or use in our application. The Agent.run() function returns the response as a RunResponse object. 859 | 860 | Copy 861 | 862 | Ask AI 863 | from phi.agent import Agent, RunResponse 864 | from phi.utils.pprint import pprint_run_response 865 | 866 | agent = Agent(...) 867 | 868 | # Run agent and return the response as a variable 869 | response: RunResponse = agent.run("Simulation theory") 870 | # Print the response in markdown format 871 | pprint_run_response(response, markdown=True) 872 | By default stream=False, set stream=True to return a stream of RunResponse objects. 873 | 874 | Copy 875 | 876 | Ask AI 877 | from typing import Iterator 878 | 879 | # Run agent and return the response as a stream 880 | response_stream: Iterator[RunResponse] = agent.run("Simulation theory", stream=True) 881 | # Print the response stream in markdown format 882 | pprint_run_response(response_stream, markdown=True, show_time=True) 883 | ​ 884 | RunResponse 885 | The Agent.run() function returns either a RunResponse object or an Iterator[RunResponse] when stream=True. 886 | ​ 887 | RunResponse Attributes 888 | Attribute Type Default Description 889 | content Any None Content of the response. 890 | content_type str "str" Specifies the data type of the content. 891 | context List[MessageContext] None The context added to the response for RAG. 892 | event str RunEvent.run_response.value Event type of the response. 893 | event_data Dict[str, Any] None Data associated with the event. 894 | messages List[Message] None A list of messages included in the response. 895 | metrics Dict[str, Any] None Usage metrics of the run. 896 | model Model OpenAIChat OpenAI model is used to run by default. 897 | run_id str None Run Id. 898 | agent_id str None Agent Id for the run. 899 | session_id str None Session Id for the run. 900 | tools List[Dict[str, Any]] None List of tools provided to the model. 901 | created_at int - Unix timestamp of the response creation. 902 | 903 | 904 | 905 | 906 | Agents 907 | Prompts 908 | We prompt Agents using description and instructions and a number of other settings. These settings are used to build the system prompt that is sent to the language model. 909 | Understanding how these prompts are created will help you build better Agents. 910 | The 2 key parameters are: 911 | Description: A description that guides the overall behaviour of the agent. 912 | Instructions: A list of precise, task-specific instructions on how to achieve its goal. 913 | Description and instructions only provide a formatting benefit, we do not alter or abstract any information and you can always use system_prompt to provide your own system prompt. 914 | ​ 915 | System message 916 | The system message is created using description, instructions and a number of other settings. The description is added to the start of the system message and instructions are added as a list after ## Instructions. For example: 917 | instructions.py 918 | 919 | Copy 920 | 921 | Ask AI 922 | from phi.agent import Agent 923 | 924 | agent = Agent( 925 | description="You are a famous short story writer asked to write for a magazine", 926 | instructions=["You are a pilot on a plane flying from Hawaii to Japan."], 927 | markdown=True, 928 | debug_mode=True, 929 | ) 930 | agent.print_response("Tell me a 2 sentence horror story.", stream=True) 931 | Will translate to (set debug_mode=True to view the logs): 932 | 933 | Copy 934 | 935 | Ask AI 936 | DEBUG ============== system ============== 937 | DEBUG You are a famous short story writer asked to write for a magazine 938 | 939 | ## Instructions 940 | - You are a pilot on a plane flying from Hawaii to Japan. 941 | - Use markdown to format your answers. 942 | DEBUG ============== user ============== 943 | DEBUG Tell me a 2 sentence horror story. 944 | DEBUG ============== assistant ============== 945 | DEBUG As the autopilot disengaged inexplicably mid-flight over the Pacific, the pilot glanced at the copilot's seat 946 | only to find it empty despite his every recall of a full crew boarding. Hands trembling, he looked into the 947 | cockpit's rearview mirror and found his own reflection grinning back with blood-red eyes, whispering, 948 | "There's no escape, not at 30,000 feet." 949 | DEBUG **************** METRICS START **************** 950 | DEBUG * Time to first token: 0.4518s 951 | DEBUG * Time to generate response: 1.2594s 952 | DEBUG * Tokens per second: 63.5243 tokens/s 953 | DEBUG * Input tokens: 59 954 | DEBUG * Output tokens: 80 955 | DEBUG * Total tokens: 139 956 | DEBUG * Prompt tokens details: {'cached_tokens': 0} 957 | DEBUG * Completion tokens details: {'reasoning_tokens': 0} 958 | DEBUG **************** METRICS END ****************** 959 | ​ 960 | Set the system message directly 961 | You can manually set the system message using the system_prompt parameter. 962 | 963 | Copy 964 | 965 | Ask AI 966 | from phi.agent import Agent 967 | 968 | agent = Agent(system_prompt="Share a 2 sentence story about") 969 | agent.print_response("Love in the year 12000.") 970 | ​ 971 | User message 972 | The input message sent to the Agent.run() or Agent.print_response() functions is used as the user message. 973 | ​ 974 | User message when enable_rag=True 975 | If the Agent is provided knowledge, and the enable_rag=True, the user message is set to: 976 | 977 | Copy 978 | 979 | Ask AI 980 | user_prompt += f"""Use the following information from the knowledge base if it helps:" 981 | 982 | ## Context 983 | {context} 984 | """ 985 | ​ 986 | Default system message 987 | The Agent creates a default system message that can be customized using the following parameters: 988 | Parameter Type Default Description 989 | description str None A description of the Agent that is added to the start of the system message. 990 | task str None Describe the task the agent should achieve. 991 | instructions List[str] None List of instructions added to the system prompt in tags. Default instructions are also created depending on values for markdown, output_model etc. 992 | additional_context str None Additional context added to the end of the system message. 993 | expected_output str None Provide the expected output from the Agent. This is added to the end of the system message. 994 | extra_instructions List[str] None List of extra instructions added to the default system prompt. Use these when you want to add some extra instructions at the end of the default instructions. 995 | prevent_hallucinations bool False If True, add instructions to return “I don’t know” when the agent does not know the answer. 996 | prevent_prompt_injection bool False If True, add instructions to prevent prompt injection attacks. 997 | limit_tool_access bool False If True, add instructions for limiting tool access to the default system prompt if tools are provided 998 | markdown bool False Add an instruction to format the output using markdown. 999 | add_datetime_to_instructions bool False If True, add the current datetime to the prompt to give the agent a sense of time. This allows for relative times like “tomorrow” to be used in the prompt 1000 | system_prompt str None System prompt: provide the system prompt as a string 1001 | system_prompt_template PromptTemplate None Provide the system prompt as a PromptTemplate. 1002 | use_default_system_message bool True If True, build a default system message using agent settings and use that. 1003 | system_message_role str system Role for the system message. 1004 | Disable the default system message by setting use_default_system_message=False. 1005 | ​ 1006 | Default user message 1007 | The Agent creates a default user message, which is either the input message or a message with the context if enable_rag=True. The default user message can be customized using: 1008 | Parameter Type Default Description 1009 | enable_rag bool False Enable RAG by adding references from the knowledge base to the prompt. 1010 | add_rag_instructions bool False If True, adds instructions for using the RAG to the system prompt (if knowledge is also provided). For example: add an instruction to prefer information from the knowledge base over its training data. 1011 | add_history_to_messages bool False If true, adds the chat history to the messages sent to the Model. 1012 | num_history_responses int 3 Number of historical responses to add to the messages. 1013 | user_prompt Union[List, Dict, str] None Provide the user prompt as a string. Note: this will ignore the message sent to the run function. 1014 | user_prompt_template PromptTemplate None Provide the user prompt as a PromptTemplate. 1015 | use_default_user_message bool True If True, build a default user prompt using references and chat history. 1016 | user_message_role str user Role for the user message. 1017 | Disable the default user message by setting use_default_user_message=False. 1018 | 1019 | 1020 | 1021 | 1022 | Agents 1023 | Tools 1024 | Agents use tools to take actions and interact with external systems. 1025 | Tools are functions that an Agent can run to achieve tasks. For example: searching the web, running SQL, sending an email or calling APIs. You can use any python function as a tool or use a pre-built toolkit. The general syntax is: 1026 | 1027 | Copy 1028 | 1029 | Ask AI 1030 | from phi.agent import Agent 1031 | 1032 | agent = Agent( 1033 | # Add functions or Toolkits 1034 | tools=[...], 1035 | # Show tool calls in the Agent response 1036 | show_tool_calls=True 1037 | ) 1038 | ​ 1039 | Using a Toolkit 1040 | Phidata provides many pre-built toolkits that you can add to your Agents. For example, let’s use the DuckDuckGo toolkit to search the web. 1041 | You can find more toolkits in the Toolkits guide. 1042 | 1 1043 | Create Web Search Agent 1044 | 1045 | Create a file web_search.py 1046 | web_search.py 1047 | 1048 | Copy 1049 | 1050 | Ask AI 1051 | from phi.agent import Agent 1052 | from phi.tools.duckduckgo import DuckDuckGo 1053 | 1054 | agent = Agent(tools=[DuckDuckGo()], show_tool_calls=True, markdown=True) 1055 | agent.print_response("Whats happening in France?", stream=True) 1056 | 2 1057 | Run the agent 1058 | 1059 | Install libraries 1060 | 1061 | Copy 1062 | 1063 | Ask AI 1064 | pip install openai duckduckgo-search phidata 1065 | Run the agent 1066 | 1067 | Copy 1068 | 1069 | Ask AI 1070 | python web_search.py 1071 | ​ 1072 | Writing your own Tools 1073 | For more control, write your own python functions and add them as tools to an Agent. For example, here’s how to add a get_top_hackernews_stories tool to an Agent. 1074 | hn_agent.py 1075 | 1076 | Copy 1077 | 1078 | Ask AI 1079 | import json 1080 | import httpx 1081 | 1082 | from phi.agent import Agent 1083 | 1084 | 1085 | def get_top_hackernews_stories(num_stories: int = 10) -> str: 1086 | """Use this function to get top stories from Hacker News. 1087 | 1088 | Args: 1089 | num_stories (int): Number of stories to return. Defaults to 10. 1090 | 1091 | Returns: 1092 | str: JSON string of top stories. 1093 | """ 1094 | 1095 | # Fetch top story IDs 1096 | response = httpx.get('https://hacker-news.firebaseio.com/v0/topstories.json') 1097 | story_ids = response.json() 1098 | 1099 | # Fetch story details 1100 | stories = [] 1101 | for story_id in story_ids[:num_stories]: 1102 | story_response = httpx.get(f'https://hacker-news.firebaseio.com/v0/item/{story_id}.json') 1103 | story = story_response.json() 1104 | if "text" in story: 1105 | story.pop("text", None) 1106 | stories.append(story) 1107 | return json.dumps(stories) 1108 | 1109 | agent = Agent(tools=[get_top_hackernews_stories], show_tool_calls=True, markdown=True) 1110 | agent.print_response("Summarize the top 5 stories on hackernews?", stream=True) 1111 | Read more about: 1112 | Available toolkits 1113 | Using functions as tools 1114 | ​ 1115 | Attributes 1116 | The following attributes allow an Agent to use tools 1117 | Parameter Type Default Description 1118 | tools List[Union[Tool, Toolkit, Callable, Dict, Function]] - A list of tools provided to the Model. Tools are functions the model may generate JSON inputs for. 1119 | show_tool_calls bool False Print the signature of the tool calls in the Model response. 1120 | tool_call_limit int - Maximum number of tool calls allowed. 1121 | tool_choice Union[str, Dict[str, Any]] - Controls which (if any) tool is called by the model. “none” means the model will not call a tool and instead generates a message. “auto” means the model can pick between generating a message or calling a tool. Specifying a particular function via {"type": "function", "function": {"name": "my_function"}} forces the model to call that tool. “none” is the default when no tools are present. “auto” is the default if tools are present. 1122 | read_chat_history bool False Add a tool that allows the Model to read the chat history. 1123 | search_knowledge bool False Add a tool that allows the Model to search the knowledge base (aka Agentic RAG). 1124 | update_knowledge bool False Add a tool that allows the Model to update the knowledge base. 1125 | read_tool_call_history bool False Add a tool that allows the Model to get the tool call history. 1126 | 1127 | 1128 | 1129 | Agents 1130 | Knowledge 1131 | Agents use knowledge to supplement their training data with domain expertise. 1132 | Knowledge is stored in a vector database and provides agents with business context at query time, helping them respond in a context-aware manner. The general syntax is: 1133 | 1134 | Copy 1135 | 1136 | Ask AI 1137 | from phi.agent import Agent, AgentKnowledge 1138 | 1139 | # Create a knowledge base for the Agent 1140 | knowledge_base = AgentKnowledge(vector_db=...) 1141 | 1142 | # Add information to the knowledge base 1143 | knowledge_base.load_text("The sky is blue") 1144 | 1145 | # Add the knowledge base to the Agent and 1146 | # give it a tool to search the knowledge base as needed 1147 | agent = Agent(knowledge=knowledge_base, search_knowledge=True) 1148 | ​ 1149 | Vector Databases 1150 | While any type of storage can act as a knowledge base, vector databases offer the best solution for retrieving relevant results from dense information quickly. Here’s how vector databases are used with Agents: 1151 | 1 1152 | Chunk the information 1153 | 1154 | Break down the knowledge into smaller chunks to ensure our search query returns only relevant results. 1155 | 2 1156 | Load the knowledge base 1157 | 1158 | Convert the chunks into embedding vectors and store them in a vector database. 1159 | 3 1160 | Search the knowledge base 1161 | 1162 | When the user sends a message, we convert the input message into an embedding and “search” for nearest neighbors in the vector database. 1163 | ​ 1164 | Example: RAG Agent with a PDF Knowledge Base 1165 | Let’s build a RAG Agent that answers questions from a PDF. 1166 | ​ 1167 | Step 1: Run PgVector 1168 | Let’s use PgVector as our vector db as it can also provide storage for our Agents. 1169 | Install docker desktop and run PgVector on port 5532 using: 1170 | 1171 | Copy 1172 | 1173 | Ask AI 1174 | docker run -d \ 1175 | -e POSTGRES_DB=ai \ 1176 | -e POSTGRES_USER=ai \ 1177 | -e POSTGRES_PASSWORD=ai \ 1178 | -e PGDATA=/var/lib/postgresql/data/pgdata \ 1179 | -v pgvolume:/var/lib/postgresql/data \ 1180 | -p 5532:5432 \ 1181 | --name pgvector \ 1182 | phidata/pgvector:16 1183 | ​ 1184 | Step 2: Traditional RAG 1185 | Retrieval Augmented Generation (RAG) means “stuffing the prompt with relevant information” to improve the model’s response. This is a 2 step process: 1186 | Retrieve relevant information from the knowledge base. 1187 | Augment the prompt to provide context to the model. 1188 | Let’s build a traditional RAG Agent that answers questions from a PDF of recipes. 1189 | 1 1190 | Install libraries 1191 | 1192 | Install the required libraries using pip 1193 | 1194 | Mac 1195 | 1196 | Windows 1197 | 1198 | Copy 1199 | 1200 | Ask AI 1201 | pip install -U pgvector pypdf "psycopg[binary]" sqlalchemy 1202 | 2 1203 | Create a Traditional RAG Agent 1204 | 1205 | Create a file traditional_rag.py with the following contents 1206 | traditional_rag.py 1207 | 1208 | Copy 1209 | 1210 | Ask AI 1211 | from phi.agent import Agent 1212 | from phi.model.openai import OpenAIChat 1213 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 1214 | from phi.vectordb.pgvector import PgVector, SearchType 1215 | 1216 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 1217 | knowledge_base = PDFUrlKnowledgeBase( 1218 | # Read PDF from this URL 1219 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 1220 | # Store embeddings in the `ai.recipes` table 1221 | vector_db=PgVector(table_name="recipes", db_url=db_url, search_type=SearchType.hybrid), 1222 | ) 1223 | # Load the knowledge base: Comment after first run 1224 | knowledge_base.load(upsert=True) 1225 | 1226 | agent = Agent( 1227 | model=OpenAIChat(id="gpt-4o"), 1228 | knowledge=knowledge_base, 1229 | # Enable RAG by adding references from AgentKnowledge to the user prompt. 1230 | add_context=True, 1231 | # Set as False because Agents default to `search_knowledge=True` 1232 | search_knowledge=False, 1233 | markdown=True, 1234 | # debug_mode=True, 1235 | ) 1236 | agent.print_response("How do I make chicken and galangal in coconut milk soup") 1237 | 3 1238 | Run the agent 1239 | 1240 | Run the agent (it takes a few seconds to load the knowledge base). 1241 | 1242 | Mac 1243 | 1244 | Windows 1245 | 1246 | Copy 1247 | 1248 | Ask AI 1249 | python traditional_rag.py 1250 | 1251 | How to use local PDFs 1252 | 1253 | ​ 1254 | Step 3: Agentic RAG 1255 | With traditional RAG above, add_context=True always adds information from the knowledge base to the prompt, regardless of whether it is relevant to the question or helpful. 1256 | With Agentic RAG, we let the Agent decide if it needs to access the knowledge base and what search parameters it needs to query the knowledge base. 1257 | Set search_knowledge=True and read_chat_history=True, giving the Agent tools to search its knowledge and chat history on demand. 1258 | 1 1259 | Create an Agentic RAG Agent 1260 | 1261 | Create a file agentic_rag.py with the following contents 1262 | agentic_rag.py 1263 | 1264 | Copy 1265 | 1266 | Ask AI 1267 | from phi.agent import Agent 1268 | from phi.model.openai import OpenAIChat 1269 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 1270 | from phi.vectordb.pgvector import PgVector, SearchType 1271 | 1272 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 1273 | knowledge_base = PDFUrlKnowledgeBase( 1274 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 1275 | vector_db=PgVector(table_name="recipes", db_url=db_url, search_type=SearchType.hybrid), 1276 | ) 1277 | # Load the knowledge base: Comment out after first run 1278 | knowledge_base.load(upsert=True) 1279 | 1280 | agent = Agent( 1281 | model=OpenAIChat(id="gpt-4o"), 1282 | knowledge=knowledge_base, 1283 | # Add a tool to search the knowledge base which enables agentic RAG. 1284 | search_knowledge=True, 1285 | # Add a tool to read chat history. 1286 | read_chat_history=True, 1287 | show_tool_calls=True, 1288 | markdown=True, 1289 | # debug_mode=True, 1290 | ) 1291 | agent.print_response("How do I make chicken and galangal in coconut milk soup", stream=True) 1292 | agent.print_response("What was my last question?", markdown=True) 1293 | 2 1294 | Run the agent 1295 | 1296 | Run the agent 1297 | 1298 | Mac 1299 | 1300 | Windows 1301 | 1302 | Copy 1303 | 1304 | Ask AI 1305 | python agentic_rag.py 1306 | Notice how it searches the knowledge base and chat history when needed 1307 | ​ 1308 | Attributes 1309 | Parameter Type Default Description 1310 | knowledge AgentKnowledge None Provides the knowledge base used by the agent. 1311 | search_knowledge bool True Adds a tool that allows the Model to search the knowledge base (aka Agentic RAG). Enabled by default when knowledge is provided. 1312 | add_context bool False Enable RAG by adding references from AgentKnowledge to the user prompt. 1313 | retriever Callable[..., Optional[list[dict]]] None Function to get context to add to the user message. This function is called when add_context is True. 1314 | context_format Literal['json', 'yaml'] json Specifies the format for RAG, either “json” or “yaml”. 1315 | add_context_instructions bool False If True, add instructions for using the context to the system prompt (if knowledge is also provided). For example: add an instruction to prefer information from the knowledge base over its training data. 1316 | 1317 | 1318 | 1319 | 1320 | Agents 1321 | Memory 1322 | Phidata provides 3 types of memories for building a great Agent experience (AX): 1323 | Chat History: previous messages from the conversation, we recommend sending the last 3-5 messages to the model. 1324 | User Memories: notes and insights about the user, this helps the model personalize the response to the user. 1325 | Summaries: a summary of the conversation, which is added to the prompt when chat history gets too long. 1326 | Before we dive in, let’s understand the terminology: 1327 | Session: Each conversation with an Agent is called a session. Sessions are identified by a session_id. 1328 | Run: Every interaction (i.e. chat) within a session is called a run. Runs are identified by a run_id. 1329 | Messages: are the individual messages sent to and received from the model. They have a role (system, user or assistant) and content. 1330 | Sessions are equivalent to threads in the OpenAI Assistant API. 1331 | ​ 1332 | Built-in Memory 1333 | Every Agent comes with built-in memory that can be used to access the historical runs and messages. Access it using agent.memory 1334 | Show AgentMemory 1335 | 1336 | ​ 1337 | Example 1338 | agent_memory.py 1339 | 1340 | Copy 1341 | 1342 | Ask AI 1343 | from phi.agent import Agent 1344 | from phi.model.openai import OpenAIChat 1345 | from rich.pretty import pprint 1346 | 1347 | 1348 | agent = Agent( 1349 | model=OpenAIChat(id="gpt-4o"), 1350 | # Set add_history_to_messages=true to add the previous chat history to the messages sent to the Model. 1351 | add_history_to_messages=True, 1352 | # Number of historical responses to add to the messages. 1353 | num_history_responses=3, 1354 | description="You are a helpful assistant that always responds in a polite, upbeat and positive manner.", 1355 | ) 1356 | 1357 | # -*- Create a run 1358 | agent.print_response("Share a 2 sentence horror story", stream=True) 1359 | # -*- Print the messages in the memory 1360 | pprint([m.model_dump(include={"role", "content"}) for m in agent.memory.messages]) 1361 | 1362 | # -*- Ask a follow up question that continues the conversation 1363 | agent.print_response("What was my first message?", stream=True) 1364 | # -*- Print the messages in the memory 1365 | pprint([m.model_dump(include={"role", "content"}) for m in agent.memory.messages]) 1366 | ​ 1367 | Persistent Memory 1368 | The built-in memory only lasts while the session is active. To persist memory across sessions, we can store Agent sessions in a database using AgentStorage. 1369 | Storage is a necessary component when building user facing AI products as any production application will require users to be able to “continue” their conversation with the Agent. 1370 | Let’s test this out, create a file persistent_memory.py with the following code: 1371 | persistent_memory.py 1372 | 1373 | Copy 1374 | 1375 | Ask AI 1376 | import json 1377 | 1378 | from rich.console import Console 1379 | from rich.panel import Panel 1380 | from rich.json import JSON 1381 | 1382 | from phi.agent import Agent 1383 | from phi.model.openai import OpenAIChat 1384 | from phi.storage.agent.sqlite import SqlAgentStorage 1385 | 1386 | 1387 | agent = Agent( 1388 | model=OpenAIChat(id="gpt-4o"), 1389 | # Store agent sessions in a database 1390 | storage=SqlAgentStorage(table_name="agent_sessions", db_file="tmp/agent_storage.db"), 1391 | # Set add_history_to_messages=true to add the previous chat history to the messages sent to the Model. 1392 | add_history_to_messages=True, 1393 | # Number of historical responses to add to the messages. 1394 | num_history_responses=3, 1395 | # The session_id is used to identify the session in the database 1396 | # You can resume any session by providing a session_id 1397 | # session_id="xxxx-xxxx-xxxx-xxxx", 1398 | # Description creates a system prompt for the agent 1399 | description="You are a helpful assistant that always responds in a polite, upbeat and positive manner.", 1400 | ) 1401 | 1402 | console = Console() 1403 | 1404 | 1405 | def print_chat_history(agent): 1406 | # -*- Print history 1407 | console.print( 1408 | Panel( 1409 | JSON(json.dumps([m.model_dump(include={"role", "content"}) for m in agent.memory.messages]), indent=4), 1410 | title=f"Chat History for session_id: {agent.session_id}", 1411 | expand=True, 1412 | ) 1413 | ) 1414 | 1415 | 1416 | # -*- Create a run 1417 | agent.print_response("Share a 2 sentence horror story", stream=True) 1418 | # -*- Print the chat history 1419 | print_chat_history(agent) 1420 | 1421 | # -*- Ask a follow up question that continues the conversation 1422 | agent.print_response("What was my first message?", stream=True) 1423 | # -*- Print the chat history 1424 | print_chat_history(agent) 1425 | ​ 1426 | Run the agent 1427 | Install dependencies and run the agent: 1428 | 1429 | Copy 1430 | 1431 | Ask AI 1432 | pip install openai sqlalchemy phidata 1433 | 1434 | python persistent_memory.py 1435 | You can view the agent sessions in the sqlite database and continue any conversation by providing the same session_id. 1436 | Read more in the storage section. 1437 | ​ 1438 | User preferences and conversation summaries 1439 | Along with storing chat history and run messages, AgentMemory can be extended to automatically classify and store user preferences and conversation summaries. 1440 | To do this, add a db to AgentMemory and set create_user_memories=True and create_session_summary=True 1441 | User memories are stored in the AgentMemory whereas session summaries are stored in the AgentStorage table with the rest of the session information. 1442 | User preferences and conversation summaries are currently only compatible with OpenAI and OpenAILike models. While Persistent Memory is compatible with all model providers. 1443 | ​ 1444 | Example 1445 | personalized_memories_and_summaries.py 1446 | 1447 | Copy 1448 | 1449 | Ask AI 1450 | from rich.pretty import pprint 1451 | 1452 | from phi.agent import Agent, AgentMemory 1453 | from phi.model.openai import OpenAIChat 1454 | from phi.memory.db.postgres import PgMemoryDb 1455 | from phi.storage.agent.postgres import PgAgentStorage 1456 | 1457 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 1458 | agent = Agent( 1459 | model=OpenAIChat(id="gpt-4o"), 1460 | # Store the memories and summary in a database 1461 | memory=AgentMemory( 1462 | db=PgMemoryDb(table_name="agent_memory", db_url=db_url), create_user_memories=True, create_session_summary=True 1463 | ), 1464 | # Store agent sessions in a database 1465 | storage=PgAgentStorage(table_name="personalized_agent_sessions", db_url=db_url), 1466 | # Show debug logs so you can see the memory being created 1467 | # debug_mode=True, 1468 | ) 1469 | 1470 | # -*- Share personal information 1471 | agent.print_response("My name is john billings?", stream=True) 1472 | # -*- Print memories 1473 | pprint(agent.memory.memories) 1474 | # -*- Print summary 1475 | pprint(agent.memory.summary) 1476 | 1477 | # -*- Share personal information 1478 | agent.print_response("I live in nyc?", stream=True) 1479 | # -*- Print memories 1480 | pprint(agent.memory.memories) 1481 | # -*- Print summary 1482 | pprint(agent.memory.summary) 1483 | 1484 | # -*- Share personal information 1485 | agent.print_response("I'm going to a concert tomorrow?", stream=True) 1486 | # -*- Print memories 1487 | pprint(agent.memory.memories) 1488 | # -*- Print summary 1489 | pprint(agent.memory.summary) 1490 | 1491 | # Ask about the conversation 1492 | agent.print_response("What have we been talking about, do you know my name?", stream=True) 1493 | ​ 1494 | Attributes 1495 | Parameter Type Default Description 1496 | memory AgentMemory AgentMemory() Agent’s memory object used for storing and retrieving information. 1497 | add_history_to_messages bool False If true, adds the chat history to the messages sent to the Model. Also known as add_chat_history_to_messages. 1498 | num_history_responses int 3 Number of historical responses to add to the messages. 1499 | create_user_memories bool False If true, create and store personalized memories for the user. 1500 | update_user_memories_after_run bool True If true, update memories for the user after each run. 1501 | create_session_summary bool False If true, create and store session summaries. 1502 | update_session_summary_after_run bool True If true, update session summaries after each run. 1503 | 1504 | 1505 | 1506 | 1507 | 1508 | Agents 1509 | Storage 1510 | Agents use storage to persist sessions by storing them in a database. 1511 | Agents come with built-in memory, but it only lasts while the session is active. To continue conversations across sessions, we store agent sessions in a database like PostgreSQL. 1512 | The general syntax for adding storage to an Agent looks like: 1513 | 1514 | Copy 1515 | 1516 | Ask AI 1517 | from phi.agent import Agent 1518 | from phi.model.openai import OpenAIChat 1519 | from phi.tools.duckduckgo import DuckDuckGo 1520 | from phi.storage.agent.postgres import PgAgentStorage 1521 | 1522 | agent = Agent( 1523 | model=OpenAIChat(id="gpt-4o"), 1524 | storage=PgAgentStorage(table_name="agent_sessions", db_url="postgresql+psycopg://ai:ai@localhost:5532/ai"), 1525 | tools=[DuckDuckGo()], 1526 | show_tool_calls=True, 1527 | add_history_to_messages=True, 1528 | ) 1529 | agent.print_response("How many people live in Canada?") 1530 | agent.print_response("What is their national anthem called?") 1531 | agent.print_response("Which country are we speaking about?") 1532 | ​ 1533 | Example 1534 | 1 1535 | Run Postgres 1536 | 1537 | Install docker desktop and run Postgres on port 5532 using: 1538 | 1539 | Copy 1540 | 1541 | Ask AI 1542 | docker run -d \ 1543 | -e POSTGRES_DB=ai \ 1544 | -e POSTGRES_USER=ai \ 1545 | -e POSTGRES_PASSWORD=ai \ 1546 | -e PGDATA=/var/lib/postgresql/data/pgdata \ 1547 | -v pgvolume:/var/lib/postgresql/data \ 1548 | -p 5532:5432 \ 1549 | --name pgvector \ 1550 | phidata/pgvector:16 1551 | 2 1552 | Create an Agent with Storage 1553 | 1554 | Create a file agent_with_storage.py with the following contents 1555 | 1556 | Copy 1557 | 1558 | Ask AI 1559 | import typer 1560 | from typing import Optional, List 1561 | from phi.agent import Agent 1562 | from phi.storage.agent.postgres import PgAgentStorage 1563 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 1564 | from phi.vectordb.pgvector import PgVector, SearchType 1565 | 1566 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 1567 | knowledge_base = PDFUrlKnowledgeBase( 1568 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 1569 | vector_db=PgVector(table_name="recipes", db_url=db_url, search_type=SearchType.hybrid), 1570 | ) 1571 | # Load the knowledge base: Comment after first run 1572 | knowledge_base.load(upsert=True) 1573 | storage = PgAgentStorage(table_name="pdf_agent", db_url=db_url) 1574 | 1575 | def pdf_agent(new: bool = False, user: str = "user"): 1576 | session_id: Optional[str] = None 1577 | 1578 | if not new: 1579 | existing_sessions: List[str] = storage.get_all_session_ids(user) 1580 | if len(existing_sessions) > 0: 1581 | session_id = existing_sessions[0] 1582 | 1583 | agent = Agent( 1584 | session_id=session_id, 1585 | user_id=user, 1586 | knowledge=knowledge_base, 1587 | storage=storage, 1588 | # Show tool calls in the response 1589 | show_tool_calls=True, 1590 | # Enable the agent to read the chat history 1591 | read_chat_history=True, 1592 | # We can also automatically add the chat history to the messages sent to the model 1593 | # But giving the model the chat history is not always useful, so we give it a tool instead 1594 | # to only use when needed. 1595 | # add_history_to_messages=True, 1596 | # Number of historical responses to add to the messages. 1597 | # num_history_responses=3, 1598 | ) 1599 | if session_id is None: 1600 | session_id = agent.session_id 1601 | print(f"Started Session: {session_id}\n") 1602 | else: 1603 | print(f"Continuing Session: {session_id}\n") 1604 | 1605 | # Runs the agent as a cli app 1606 | agent.cli_app(markdown=True) 1607 | 1608 | 1609 | if __name__ == "__main__": 1610 | typer.run(pdf_agent) 1611 | 3 1612 | Run the agent 1613 | 1614 | Install libraries 1615 | 1616 | Mac 1617 | 1618 | Windows 1619 | 1620 | Copy 1621 | 1622 | Ask AI 1623 | pip install -U phidata openai pgvector pypdf "psycopg[binary]" sqlalchemy 1624 | Run the agent 1625 | 1626 | Copy 1627 | 1628 | Ask AI 1629 | python agent_with_storage.py 1630 | Now the agent continues across sessions. Ask a question: 1631 | 1632 | Copy 1633 | 1634 | Ask AI 1635 | How do I make pad thai? 1636 | Then message bye to exit, start the app again and ask: 1637 | 1638 | Copy 1639 | 1640 | Ask AI 1641 | What was my last message? 1642 | 4 1643 | Start a new run 1644 | 1645 | Run the agent_with_storage.py file with the --new flag to start a new run. 1646 | 1647 | Copy 1648 | 1649 | Ask AI 1650 | python agent_with_storage.py --new 1651 | ​ 1652 | Params 1653 | Parameter Type Default Description 1654 | storage Optional[AgentStorage] None Storage mechanism for the agent, if applicable. 1655 | 1656 | 1657 | 1658 | 1659 | Agents 1660 | Structured Output 1661 | One of our favorite features is using Agents to generate structured data (i.e. a pydantic model). Use this feature to extract features, classify data, produce fake data etc. The best part is that they work with function calls, knowledge bases and all other features. 1662 | ​ 1663 | Example 1664 | Let’s create an Movie Agent to write a MovieScript for us. 1665 | movie_agent.py 1666 | 1667 | Copy 1668 | 1669 | Ask AI 1670 | from typing import List 1671 | from rich.pretty import pprint 1672 | from pydantic import BaseModel, Field 1673 | from phi.agent import Agent, RunResponse 1674 | from phi.model.openai import OpenAIChat 1675 | 1676 | 1677 | class MovieScript(BaseModel): 1678 | setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.") 1679 | ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.") 1680 | genre: str = Field( 1681 | ..., description="Genre of the movie. If not available, select action, thriller or romantic comedy." 1682 | ) 1683 | name: str = Field(..., description="Give a name to this movie") 1684 | characters: List[str] = Field(..., description="Name of characters for this movie.") 1685 | storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!") 1686 | 1687 | 1688 | # Agent that uses JSON mode 1689 | json_mode_agent = Agent( 1690 | model=OpenAIChat(id="gpt-4o"), 1691 | description="You write movie scripts.", 1692 | response_model=MovieScript, 1693 | ) 1694 | # Agent that uses structured outputs 1695 | structured_output_agent = Agent( 1696 | model=OpenAIChat(id="gpt-4o-2024-08-06"), 1697 | description="You write movie scripts.", 1698 | response_model=MovieScript, 1699 | structured_outputs=True, 1700 | ) 1701 | 1702 | 1703 | # Get the response in a variable 1704 | # json_mode_response: RunResponse = json_mode_agent.run("New York") 1705 | # pprint(json_mode_response.content) 1706 | # structured_output_response: RunResponse = structured_output_agent.run("New York") 1707 | # pprint(structured_output_response.content) 1708 | 1709 | json_mode_agent.print_response("New York") 1710 | structured_output_agent.print_response("New York") 1711 | Run the script to see the output. 1712 | 1713 | Copy 1714 | 1715 | Ask AI 1716 | pip install -U phidata openai 1717 | 1718 | python movie_agent.py 1719 | The output is an object of the MovieScript class, here’s how it looks: 1720 | 1721 | Copy 1722 | 1723 | Ask AI 1724 | # Using JSON mode 1725 | MovieScript( 1726 | │ setting='The bustling streets of New York City, filled with skyscrapers, secret alleyways, and hidden underground passages.', 1727 | │ ending='The protagonist manages to thwart an international conspiracy, clearing his name and winning the love of his life back.', 1728 | │ genre='Thriller', 1729 | │ name='Shadows in the City', 1730 | │ characters=['Alex Monroe', 'Eva Parker', 'Detective Rodriguez', 'Mysterious Mr. Black'], 1731 | │ storyline="When Alex Monroe, an ex-CIA operative, is framed for a crime he didn't commit, he must navigate the dangerous streets of New York to clear his name. As he uncovers a labyrinth of deceit involving the city's most notorious crime syndicate, he enlists the help of an old flame, Eva Parker. Together, they race against time to expose the true villain before it's too late." 1732 | ) 1733 | 1734 | # Use the structured output 1735 | MovieScript( 1736 | │ setting='In the bustling streets and iconic skyline of New York City.', 1737 | │ ending='Isabella and Alex, having narrowly escaped the clutches of the Syndicate, find themselves standing at the top of the Empire State Building. As the glow of the setting sun bathes the city, they share a victorious kiss. Newly emboldened and as an unstoppable duo, they vow to keep NYC safe from any future threats.', 1738 | │ genre='Action Thriller', 1739 | │ name='The NYC Chronicles', 1740 | │ characters=['Isabella Grant', 'Alex Chen', 'Marcus Kane', 'Detective Ellie Monroe', 'Victor Sinclair'], 1741 | │ storyline='Isabella Grant, a fearless investigative journalist, uncovers a massive conspiracy involving a powerful syndicate plotting to control New York City. Teaming up with renegade cop Alex Chen, they must race against time to expose the culprits before the city descends into chaos. Dodging danger at every turn, they fight to protect the city they love from imminent destruction.' 1742 | ) 1743 | 1744 | 1745 | 1746 | 1747 | Agents 1748 | Teams 1749 | We can combine multiple Agents to form a team and tackle tasks as a cohesive unit. Here’s a simple example that uses a team of agents to write an article about the top stories on hackernews. 1750 | hn_team.py 1751 | 1752 | Copy 1753 | 1754 | Ask AI 1755 | from phi.agent import Agent 1756 | from phi.tools.hackernews import HackerNews 1757 | from phi.tools.duckduckgo import DuckDuckGo 1758 | from phi.tools.newspaper4k import Newspaper4k 1759 | 1760 | hn_researcher = Agent( 1761 | name="HackerNews Researcher", 1762 | role="Gets top stories from hackernews.", 1763 | tools=[HackerNews()], 1764 | ) 1765 | 1766 | web_searcher = Agent( 1767 | name="Web Searcher", 1768 | role="Searches the web for information on a topic", 1769 | tools=[DuckDuckGo()], 1770 | add_datetime_to_instructions=True, 1771 | ) 1772 | 1773 | article_reader = Agent( 1774 | name="Article Reader", 1775 | role="Reads articles from URLs.", 1776 | tools=[Newspaper4k()], 1777 | ) 1778 | 1779 | hn_team = Agent( 1780 | name="Hackernews Team", 1781 | team=[hn_researcher, web_searcher, article_reader], 1782 | instructions=[ 1783 | "First, search hackernews for what the user is asking about.", 1784 | "Then, ask the article reader to read the links for the stories to get more information.", 1785 | "Important: you must provide the article reader with the links to read.", 1786 | "Then, ask the web searcher to search for each story to get more information.", 1787 | "Finally, provide a thoughtful and engaging summary.", 1788 | ], 1789 | show_tool_calls=True, 1790 | markdown=True, 1791 | ) 1792 | hn_team.print_response("Write an article about the top 2 stories on hackernews", stream=True) 1793 | Run the script to see the output. 1794 | 1795 | Copy 1796 | 1797 | Ask AI 1798 | pip install -U openai duckduckgo-search newspaper4k lxml_html_clean phidata 1799 | 1800 | python hn_team.py 1801 | ​ 1802 | How to build Agent Teams 1803 | Add a name and role parameter to the member Agents. 1804 | Create a Team Leader that can delegate tasks to team-members. 1805 | Use your Agent team just like you would use a regular Agent. 1806 | Open-ended Agentic teams are great to play with, but are not reliable for real-world problems that require high reliability. 1807 | They need constant oversight and can get confused on very complex tasks. This drawback should improve as models get better (eagerly waiting for gpt-5o). 1808 | In our experience, Agent teams work best for simple tasks that require a small number of steps. We highly recommend using Workflows for production applications. 1809 | 1810 | 1811 | 1812 | Models 1813 | Introduction 1814 | Language Models are machine-learning programs that are trained to understand natural language and code. They provide reasoning and planning capabilities to Agents. 1815 | Use any model with an Agent like: 1816 | 1817 | Copy 1818 | 1819 | Ask AI 1820 | from phi.agent import Agent 1821 | from phi.model.openai import OpenAIChat 1822 | 1823 | agent = Agent( 1824 | model=OpenAIChat(id="gpt-4o"), 1825 | description="Share 15 minute healthy recipes.", 1826 | markdown=True, 1827 | ) 1828 | agent.print_response("Share a breakfast recipe.", stream=True) 1829 | Phidata supports the following model providers: 1830 | OpenAI 1831 | Anthropic 1832 | AWS Bedrock 1833 | Azure 1834 | Cohere 1835 | DeepSeek 1836 | Fireworks 1837 | Google 1838 | Groq 1839 | Mistral 1840 | Ollama 1841 | OpenAI Like 1842 | OpenRouter 1843 | Sambanova 1844 | Together 1845 | VertexAI 1846 | 1847 | 1848 | 1849 | 1850 | Models 1851 | Gemini - AI Studio 1852 | Use Google’s AI Studio to access the Gemini and Gemma models. 1853 | ​ 1854 | Authentication 1855 | Set your GOOGLE_API_KEY environment variable. You can get one from Google here. 1856 | 1857 | Mac 1858 | 1859 | Windows 1860 | 1861 | Copy 1862 | 1863 | Ask AI 1864 | export GOOGLE_API_KEY=*** 1865 | ​ 1866 | Example 1867 | Use Gemini with your Agent: 1868 | 1869 | agent.py 1870 | 1871 | Copy 1872 | 1873 | Ask AI 1874 | 1875 | from phi.agent import Agent, RunResponse 1876 | from phi.model.google import Gemini 1877 | 1878 | agent = Agent( 1879 | model=Gemini(id="gemini-1.5-flash"), 1880 | markdown=True, 1881 | ) 1882 | 1883 | # Get the response in a variable 1884 | # run: RunResponse = agent.run("Share a 2 sentence horror story.") 1885 | # print(run.content) 1886 | 1887 | # Print the response in the terminal 1888 | agent.print_response("Share a 2 sentence horror story.") 1889 | ​ 1890 | Params 1891 | Parameter Type Default Description 1892 | id str "gemini-1.5-flash" The specific Gemini model ID to use. 1893 | name str "Gemini" The name of this Gemini model instance. 1894 | provider str "Google" The provider of the model. 1895 | function_declarations Optional[List[FunctionDeclaration]] None List of function declarations for the model. 1896 | generation_config Optional[Any] None Configuration for text generation. 1897 | safety_settings Optional[Any] None Safety settings for the model. 1898 | generative_model_kwargs Optional[Dict[str, Any]] None Additional keyword arguments for the generative model. 1899 | api_key Optional[str] None API key for authentication. 1900 | client_params Optional[Dict[str, Any]] None Additional parameters for the client. 1901 | client Optional[GenerativeModel] None The underlying generative model client. 1902 | 1903 | 1904 | 1905 | Models 1906 | Groq 1907 | Groq offers blazing-fast API endpoints for large language models 1908 | ​ 1909 | Authentication 1910 | Set your GROQ_API_KEY environment variable. Get your key from here. 1911 | 1912 | Mac 1913 | 1914 | Windows 1915 | 1916 | Copy 1917 | 1918 | Ask AI 1919 | export GROQ_API_KEY=*** 1920 | ​ 1921 | Example 1922 | Use Groq with your Agent: 1923 | 1924 | agent.py 1925 | 1926 | Copy 1927 | 1928 | Ask AI 1929 | from phi.agent import Agent, RunResponse 1930 | from phi.model.groq import Groq 1931 | 1932 | agent = Agent( 1933 | model=Groq(id="llama-3.3-70b-versatile"), 1934 | markdown=True 1935 | ) 1936 | 1937 | # Get the response in a variable 1938 | # run: RunResponse = agent.run("Share a 2 sentence horror story.") 1939 | # print(run.content) 1940 | 1941 | # Print the response in the terminal 1942 | agent.print_response("Share a 2 sentence horror story.") 1943 | 1944 | ​ 1945 | Params 1946 | Parameter Type Default Description 1947 | id str "llama3-groq-70b-8192-tool-use-preview" The specific model ID used for generating responses. 1948 | name str "Groq" The name identifier for the agent. 1949 | provider str "Groq" The provider of the model. 1950 | frequency_penalty Optional[float] - A number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. 1951 | logit_bias Optional[Any] - A JSON object that modifies the likelihood of specified tokens appearing in the completion by mapping token IDs to bias values between -100 and 100. 1952 | logprobs Optional[bool] - Whether to return log probabilities of the output tokens. 1953 | max_tokens Optional[int] - The maximum number of tokens to generate in the chat completion. 1954 | presence_penalty Optional[float] - A number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. 1955 | response_format Optional[Dict[str, Any]] - Specifies the format that the model must output. Setting to { "type": "json_object" } enables JSON mode, ensuring the message generated is valid JSON. 1956 | seed Optional[int] - A seed value for deterministic sampling, ensuring repeated requests with the same seed and parameters return the same result. 1957 | stop Optional[Union[str, List[str]]] - Up to 4 sequences where the API will stop generating further tokens. 1958 | temperature Optional[float] - The sampling temperature to use, between 0 and 2. Higher values like 0.8 make the output more random, while lower values like 0.2 make it more focused and deterministic. 1959 | top_logprobs Optional[int] - The number of top log probabilities to return for each generated token. 1960 | top_p Optional[float] - Nucleus sampling parameter. The model considers the results of the tokens with top_p probability mass. 1961 | user Optional[str] - A unique identifier representing your end-user, helping to monitor and detect abuse. 1962 | request_params Optional[Dict[str, Any]] - Additional parameters to include in the request. 1963 | api_key Optional[str] - The API key for authenticating requests to the service. 1964 | base_url Optional[Union[str, httpx.URL]] - The base URL for making API requests to the service. 1965 | timeout Optional[int] - The timeout duration for requests, specified in seconds. 1966 | max_retries Optional[int] - The maximum number of retry attempts for failed requests. 1967 | client_params Optional[Dict[str, Any]] - Additional parameters for client configuration. 1968 | groq_client Optional[GroqClient] - An instance of GroqClient provided for making API requests. 1969 | 1970 | 1971 | 1972 | Models 1973 | Mistral 1974 | Mistral is a platform for providing endpoints for Large Language models. 1975 | ​ 1976 | Authentication 1977 | Set your MISTRAL_API_KEY environment variable. Get your key from here. 1978 | 1979 | Mac 1980 | 1981 | Windows 1982 | 1983 | Copy 1984 | 1985 | Ask AI 1986 | export MISTRAL_API_KEY=*** 1987 | ​ 1988 | Example 1989 | Use Mistral with your Agent: 1990 | 1991 | agent.py 1992 | 1993 | Copy 1994 | 1995 | Ask AI 1996 | import os 1997 | 1998 | from phi.agent import Agent, RunResponse 1999 | from phi.model.mistral import MistralChat 2000 | 2001 | mistral_api_key = os.getenv("MISTRAL_API_KEY") 2002 | 2003 | agent = Agent( 2004 | model=MistralChat( 2005 | id="mistral-large-latest", 2006 | api_key=mistral_api_key, 2007 | ), 2008 | markdown=True 2009 | ) 2010 | 2011 | # Get the response in a variable 2012 | # run: RunResponse = agent.run("Share a 2 sentence horror story.") 2013 | # print(run.content) 2014 | 2015 | # Print the response in the terminal 2016 | agent.print_response("Share a 2 sentence horror story.") 2017 | 2018 | ​ 2019 | Params 2020 | Parameter Type Default Description 2021 | id str "mistral-large-latest" The ID of the model. 2022 | name str "MistralChat" The name of the model. 2023 | provider str "Mistral" The provider of the model. 2024 | temperature Optional[float] None Controls randomness in output generation. 2025 | max_tokens Optional[int] None Maximum number of tokens to generate. 2026 | top_p Optional[float] None Controls diversity of output generation. 2027 | random_seed Optional[int] None Seed for random number generation. 2028 | safe_mode bool False Enables content filtering. 2029 | safe_prompt bool False Applies content filtering to prompts. 2030 | response_format Optional[Union[Dict[str, Any], ChatCompletionResponse]] None Specifies the desired response format. 2031 | request_params Optional[Dict[str, Any]] None Additional request parameters. 2032 | api_key Optional[str] None Your Mistral API key. 2033 | endpoint Optional[str] None Custom API endpoint URL. 2034 | max_retries Optional[int] None Maximum number of API call retries. 2035 | timeout Optional[int] None Timeout for API calls in seconds. 2036 | client_params Optional[Dict[str, Any]] None Additional client parameters. 2037 | mistral_client Optional[Mistral] None Custom Mistral client instance. 2038 | 2039 | 2040 | 2041 | 2042 | Models 2043 | Ollama 2044 | Run Large Language Models locally with Ollama 2045 | Ollama is a fantastic tool for running models locally. Install ollama and run a model using 2046 | 2047 | run model 2048 | 2049 | serve 2050 | 2051 | Copy 2052 | 2053 | Ask AI 2054 | ollama run llama3.1 2055 | After you have the local model running, use the Ollama model to access them 2056 | ​ 2057 | Example 2058 | 2059 | agent.py 2060 | 2061 | Copy 2062 | 2063 | Ask AI 2064 | from phi.agent import Agent, RunResponse 2065 | from phi.model.ollama import Ollama 2066 | 2067 | agent = Agent( 2068 | model=Ollama(id="llama3.1"), 2069 | markdown=True 2070 | ) 2071 | 2072 | # Get the response in a variable 2073 | # run: RunResponse = agent.run("Share a 2 sentence horror story.") 2074 | # print(run.content) 2075 | 2076 | # Print the response in the terminal 2077 | agent.print_response("Share a 2 sentence horror story.") 2078 | ​ 2079 | Params 2080 | Parameter Type Default Description 2081 | id str "llama3.2" The ID of the model to use. 2082 | name str "Ollama" The name of the model. 2083 | provider str "Ollama llama3.2" The provider of the model. 2084 | format Optional[str] None The format of the response. 2085 | options Optional[Any] None Additional options to pass to the model. 2086 | keep_alive Optional[Union[float, str]] None The keep alive time for the model. 2087 | request_params Optional[Dict[str, Any]] None Additional parameters to pass to the request. 2088 | host Optional[str] None The host to connect to. 2089 | timeout Optional[Any] None The timeout for the connection. 2090 | client_params Optional[Dict[str, Any]] None Additional parameters to pass to the client. 2091 | client Optional[OllamaClient] None A pre-configured instance of the Ollama client. 2092 | async_client Optional[AsyncOllamaClient] None A pre-configured instance of the asynchronous Ollama client. 2093 | 2094 | 2095 | 2096 | 2097 | 2098 | Tools 2099 | Introduction 2100 | Tools are functions that an Agent can run like searching the web, running SQL, sending an email or calling APIs. Use tools integrate Agents with external systems. You can use any python function as a tool or use a pre-built toolkit. The general syntax is: 2101 | 2102 | Copy 2103 | 2104 | Ask AI 2105 | from phi.agent import Agent 2106 | 2107 | agent = Agent( 2108 | # Add functions or Toolkits 2109 | tools=[...], 2110 | # Show tool calls in the Agent response 2111 | show_tool_calls=True 2112 | ) 2113 | 2114 | 2115 | 2116 | Tools 2117 | Functions 2118 | Any python function can be used as a tool by an Agent. We highly recommend creating functions specific to your workflow and adding them to your Agents. 2119 | For example, here’s how to use a get_top_hackernews_stories function as a tool: 2120 | hn_agent.py 2121 | 2122 | Copy 2123 | 2124 | Ask AI 2125 | import json 2126 | import httpx 2127 | 2128 | from phi.agent import Agent 2129 | 2130 | 2131 | def get_top_hackernews_stories(num_stories: int = 10) -> str: 2132 | """Use this function to get top stories from Hacker News. 2133 | 2134 | Args: 2135 | num_stories (int): Number of stories to return. Defaults to 10. 2136 | 2137 | Returns: 2138 | str: JSON string of top stories. 2139 | """ 2140 | 2141 | # Fetch top story IDs 2142 | response = httpx.get('https://hacker-news.firebaseio.com/v0/topstories.json') 2143 | story_ids = response.json() 2144 | 2145 | # Fetch story details 2146 | stories = [] 2147 | for story_id in story_ids[:num_stories]: 2148 | story_response = httpx.get(f'https://hacker-news.firebaseio.com/v0/item/{story_id}.json') 2149 | story = story_response.json() 2150 | if "text" in story: 2151 | story.pop("text", None) 2152 | stories.append(story) 2153 | return json.dumps(stories) 2154 | 2155 | agent = Agent(tools=[get_top_hackernews_stories], show_tool_calls=True, markdown=True) 2156 | agent.print_response("Summarize the top 5 stories on hackernews?", stream=True) 2157 | 2158 | 2159 | 2160 | 2161 | Tools 2162 | Toolkits 2163 | A Toolkit is a collection of functions that can be added to an Agent. The functions in a Toolkit are designed to work together, share internal state and provide a better development experience. 2164 | The following Toolkits are available to use 2165 | Apify 2166 | Tools to use Apify Actors. 2167 | Arxiv 2168 | Tools to read arXiv papers. 2169 | Calculator 2170 | Tools to perform calculations. 2171 | CalCom 2172 | Tools to interact with the Cal.com API. 2173 | Composio 2174 | Tools to compose complex workflows. 2175 | Crawl4AI 2176 | Tools to crawl web data. 2177 | CSV 2178 | Tools to work with CSV files. 2179 | DuckDb 2180 | Tools to run SQL using DuckDb. 2181 | DuckDuckGo 2182 | Tools to search the web using DuckDuckGo. 2183 | Dalle 2184 | Tools to interact with Dalle. 2185 | Email 2186 | Tools to send emails. 2187 | Exa 2188 | Tools to search the web using Exa. 2189 | File 2190 | Tools to read and write files. 2191 | Firecrawl 2192 | Tools to crawl the web using Firecrawl. 2193 | GitHub 2194 | Tools to interact with GitHub. 2195 | Google Search 2196 | Tools to search Google. 2197 | HackerNews 2198 | Tools to read Hacker News articles. 2199 | Jina Reader 2200 | Tools for neural search and AI services using Jina. 2201 | Jira 2202 | Tools to interact with Jira. 2203 | MLX Transcribe 2204 | Tools to transcribe audio using MLX. 2205 | ModelsLabs 2206 | Tools to generate videos using ModelsLabs. 2207 | Newspaper 2208 | Tools to read news articles. 2209 | Newspaper4k 2210 | Tools to read articles using Newspaper4k. 2211 | OpenBB 2212 | Tools to search for stock data using OpenBB. 2213 | Pandas 2214 | Tools to manipulate data using Pandas. 2215 | Postgres 2216 | Tools to interact with PostgreSQL databases. 2217 | Pubmed 2218 | Tools to search Pubmed. 2219 | Python 2220 | Tools to write and run Python code. 2221 | Resend 2222 | Tools to send emails using Resend. 2223 | SearxNG 2224 | Tools to search the web using SearxNG. 2225 | Serpapi 2226 | Tools to search Google, YouTube, and more using Serpapi. 2227 | Slack 2228 | Tools to interact with Slack. 2229 | Shell 2230 | Tools to run shell commands. 2231 | Sleep 2232 | Tools to pause execution for a given number of seconds. 2233 | Spider 2234 | Tools to crawl websites. 2235 | SQL 2236 | Tools to run SQL queries. 2237 | Twitter 2238 | Tools to interact with Twitter. 2239 | Tavily 2240 | Tools to search the web using Tavily. 2241 | Website 2242 | Tools to scrape websites. 2243 | Wikipedia 2244 | Tools to search Wikipedia. 2245 | YFinance 2246 | Tools to search Yahoo Finance. 2247 | YouTube 2248 | Tools to search YouTube. 2249 | Zendesk 2250 | Tools to search Zendesk. 2251 | 2252 | 2253 | 2254 | 2255 | Tools 2256 | Writing your own Toolkit 2257 | Many advanced use-cases will require writing custom Toolkits. Here’s the general flow: 2258 | Create a class inheriting the phi.tools.Toolkit class. 2259 | Add your functions to the class. 2260 | Important: Register the functions using self.register(function_name) 2261 | Now your Toolkit is ready to use with an Agent. For example: 2262 | shell_toolkit.py 2263 | 2264 | Copy 2265 | 2266 | Ask AI 2267 | from typing import List 2268 | 2269 | from phi.tools import Toolkit 2270 | from phi.utils.log import logger 2271 | 2272 | 2273 | class ShellTools(Toolkit): 2274 | def __init__(self): 2275 | super().__init__(name="shell_tools") 2276 | self.register(self.run_shell_command) 2277 | 2278 | def run_shell_command(self, args: List[str], tail: int = 100) -> str: 2279 | """Runs a shell command and returns the output or error. 2280 | 2281 | Args: 2282 | args (List[str]): The command to run as a list of strings. 2283 | tail (int): The number of lines to return from the output. 2284 | Returns: 2285 | str: The output of the command. 2286 | """ 2287 | import subprocess 2288 | 2289 | logger.info(f"Running shell command: {args}") 2290 | try: 2291 | logger.info(f"Running shell command: {args}") 2292 | result = subprocess.run(args, capture_output=True, text=True) 2293 | logger.debug(f"Result: {result}") 2294 | logger.debug(f"Return code: {result.returncode}") 2295 | if result.returncode != 0: 2296 | return f"Error: {result.stderr}" 2297 | # return only the last n lines of the output 2298 | return "\n".join(result.stdout.split("\n")[-tail:]) 2299 | except Exception as e: 2300 | logger.warning(f"Failed to run shell command: {e}") 2301 | return f"Error: {e}" 2302 | 2303 | 2304 | 2305 | Tools 2306 | Apify 2307 | ApifyTools enable an Agent to access the Apify API and run actors. 2308 | ​ 2309 | Prerequisites 2310 | The following example requires the apify-client library and an API token which can be obtained from Apify. 2311 | 2312 | Copy 2313 | 2314 | Ask AI 2315 | pip install -U apify-client 2316 | 2317 | Copy 2318 | 2319 | Ask AI 2320 | export MY_APIFY_TOKEN=*** 2321 | ​ 2322 | Example 2323 | The following agent will use Apify to crawl the webpage: https://docs.phidata.com/introduction and summarize it. 2324 | cookbook/tools/apify_tools.py 2325 | 2326 | Copy 2327 | 2328 | Ask AI 2329 | from phi.agent import Agent 2330 | from phi.tools.apify import ApifyTools 2331 | 2332 | agent = Agent(tools=[ApifyTools()], show_tool_calls=True) 2333 | agent.print_response("Tell me about https://docs.phidata.com/introduction", markdown=True) 2334 | ​ 2335 | Toolkit Params 2336 | Parameter Type Default Description 2337 | api_key str - API key for authentication purposes. 2338 | website_content_crawler bool True Enables the functionality to crawl a website using website-content-crawler actor. 2339 | web_scraper bool False Enables the functionality to crawl a website using web_scraper actor. 2340 | ​ 2341 | Toolkit Functions 2342 | Function Description 2343 | website_content_crawler Crawls a website using Apify’s website-content-crawler actor. 2344 | web_scrapper Scrapes a website using Apify’s web-scraper actor. 2345 | 2346 | 2347 | 2348 | Tools 2349 | Arxiv 2350 | ArxivTools enable an Agent to search for publications on Arxiv. 2351 | ​ 2352 | Prerequisites 2353 | The following example requires the arxiv and pypdf libraries. 2354 | 2355 | Copy 2356 | 2357 | Ask AI 2358 | pip install -U arxiv pypdf 2359 | ​ 2360 | Example 2361 | The following agent will run seach arXiv for “language models” and print the response. 2362 | cookbook/tools/arxiv_tools.py 2363 | 2364 | Copy 2365 | 2366 | Ask AI 2367 | from phi.agent import Agent 2368 | from phi.tools.arxiv_toolkit import ArxivToolkit 2369 | 2370 | agent = Agent(tools=[ArxivToolkit()], show_tool_calls=True) 2371 | agent.print_response("Search arxiv for 'language models'", markdown=True) 2372 | ​ 2373 | Toolkit Params 2374 | Parameter Type Default Description 2375 | search_arxiv bool True Enables the functionality to search the arXiv database. 2376 | read_arxiv_papers bool True Allows reading of arXiv papers directly. 2377 | download_dir Path - Specifies the directory path where downloaded files will be saved. 2378 | ​ 2379 | Toolkit Functions 2380 | Function Description 2381 | search_arxiv_and_update_knowledge_base This function searches arXiv for a topic, adds the results to the knowledge base and returns them. 2382 | search_arxiv Searches arXiv for a query. 2383 | 2384 | 2385 | 2386 | Tools 2387 | AWS Lambda 2388 | ​ 2389 | Prerequisites 2390 | The following example requires the boto3 library. 2391 | 2392 | Copy 2393 | 2394 | Ask AI 2395 | pip install openai boto3 2396 | ​ 2397 | Example 2398 | The following agent will use AWS Lambda to list all Lambda functions in our AWS account and invoke a specific Lambda function. 2399 | cookbook/tools/aws_lambda_tools.py 2400 | 2401 | Copy 2402 | 2403 | Ask AI 2404 | 2405 | from phi.agent import Agent 2406 | from phi.tools.aws_lambda import AWSLambdaTool 2407 | 2408 | 2409 | # Create an Agent with the AWSLambdaTool 2410 | agent = Agent( 2411 | tools=[AWSLambdaTool(region_name="us-east-1")], 2412 | name="AWS Lambda Agent", 2413 | show_tool_calls=True, 2414 | ) 2415 | 2416 | # Example 1: List all Lambda functions 2417 | agent.print_response("List all Lambda functions in our AWS account", markdown=True) 2418 | 2419 | # Example 2: Invoke a specific Lambda function 2420 | agent.print_response("Invoke the 'hello-world' Lambda function with an empty payload", markdown=True) 2421 | ​ 2422 | Toolkit Params 2423 | Parameter Type Default Description 2424 | region_name str "us-east-1" AWS region name where Lambda functions are located. 2425 | ​ 2426 | Toolkit Functions 2427 | Function Description 2428 | list_functions Lists all Lambda functions available in the AWS account. 2429 | invoke_function Invokes a specific Lambda function with an optional payload. Takes function_name and optional payload parameters. 2430 | 2431 | 2432 | 2433 | Calculator 2434 | Calculator enables an Agent to perform mathematical calculations. 2435 | ​ 2436 | Example 2437 | The following agent will calculate the result of 10*5 and then raise it to the power of 2: 2438 | cookbook/tools/calculator_tools.py 2439 | 2440 | Copy 2441 | 2442 | Ask AI 2443 | from phi.agent import Agent 2444 | from phi.tools.calculator import Calculator 2445 | 2446 | agent = Agent( 2447 | tools=[ 2448 | Calculator( 2449 | add=True, 2450 | subtract=True, 2451 | multiply=True, 2452 | divide=True, 2453 | exponentiate=True, 2454 | factorial=True, 2455 | is_prime=True, 2456 | square_root=True, 2457 | ) 2458 | ], 2459 | show_tool_calls=True, 2460 | markdown=True, 2461 | ) 2462 | agent.print_response("What is 10*5 then to the power of 2, do it step by step") 2463 | ​ 2464 | Toolkit Params 2465 | Parameter Type Default Description 2466 | add bool True Enables the functionality to perform addition. 2467 | subtract bool True Enables the functionality to perform subtraction. 2468 | multiply bool True Enables the functionality to perform multiplication. 2469 | divide bool True Enables the functionality to perform division. 2470 | exponentiate bool False Enables the functionality to perform exponentiation. 2471 | factorial bool False Enables the functionality to calculate the factorial of a number. 2472 | is_prime bool False Enables the functionality to check if a number is prime. 2473 | square_root bool False Enables the functionality to calculate the square root of a number. 2474 | ​ 2475 | Toolkit Functions 2476 | Function Description 2477 | add Adds two numbers and returns the result. 2478 | subtract Subtracts the second number from the first and returns the result. 2479 | multiply Multiplies two numbers and returns the result. 2480 | divide Divides the first number by the second and returns the result. Handles division by zero. 2481 | exponentiate Raises the first number to the power of the second number and returns the result. 2482 | factorial Calculates the factorial of a number and returns the result. Handles negative numbers. 2483 | is_prime Checks if a number is prime and returns the result. 2484 | square_root Calculates the square root of a number and returns the result. Handles negative numbers. 2485 | 2486 | 2487 | 2488 | 2489 | Tools 2490 | Cal.com 2491 | ​ 2492 | Prerequisites 2493 | The following example requires the pytz and requests libraries. 2494 | 2495 | Copy 2496 | 2497 | Ask AI 2498 | pip install requests pytz 2499 | 2500 | Copy 2501 | 2502 | Ask AI 2503 | export CALCOM_API_KEY="your_api_key" 2504 | export CALCOM_EVENT_TYPE_ID="your_event_type_id" 2505 | ​ 2506 | Example 2507 | The following agent will use Cal.com to list all events in your Cal.com account for tomorrow. 2508 | cookbook/tools/calcom_tools.py 2509 | 2510 | Copy 2511 | 2512 | Ask AI 2513 | 2514 | agent = Agent( 2515 | name="Calendar Assistant", 2516 | instructions=[ 2517 | f"You're scheduing assistant. Today is {datetime.now()}.", 2518 | "You can help users by:", 2519 | "- Finding available time slots", 2520 | "- Creating new bookings", 2521 | "- Managing existing bookings (view, reschedule, cancel) ", 2522 | "- Getting booking details", 2523 | "- IMPORTANT: In case of rescheduling or cancelling booking, call the get_upcoming_bookings function to get the booking uid. check available slots before making a booking for given time", 2524 | "Always confirm important details before making bookings or changes.", 2525 | ], 2526 | model=OpenAIChat(id="gpt-4"), 2527 | tools=[CalCom(user_timezone="America/New_York")], 2528 | show_tool_calls=True, 2529 | markdown=True, 2530 | ) 2531 | 2532 | agent.print_response("What are my bookings for tomorrow?") 2533 | ​ 2534 | Toolkit Params 2535 | Parameter Type Default Description 2536 | api_key str None Cal.com API key 2537 | event_type_id int None Event type ID for scheduling 2538 | user_timezone str None User’s timezone (e.g. “America/New_York”) 2539 | get_available_slots bool True Enable getting available time slots 2540 | create_booking bool True Enable creating new bookings 2541 | get_upcoming_bookings bool True Enable getting upcoming bookings 2542 | reschedule_booking bool True Enable rescheduling bookings 2543 | cancel_booking bool True Enable canceling bookings 2544 | ​ 2545 | Toolkit Functions 2546 | Function Description 2547 | get_available_slots Gets available time slots for a given date range 2548 | create_booking Creates a new booking with provided details 2549 | get_upcoming_bookings Gets list of upcoming bookings 2550 | get_booking_details Gets details for a specific booking 2551 | reschedule_booking Reschedules an existing booking 2552 | cancel_booking Cancels an existing booking 2553 | 2554 | 2555 | 2556 | 2557 | Tools 2558 | Crawl4AI 2559 | Crawl4aiTools enable an Agent to perform web crawling and scraping tasks using the Crawl4ai library. 2560 | ​ 2561 | Prerequisites 2562 | The following example requires the crawl4ai library. 2563 | 2564 | Copy 2565 | 2566 | Ask AI 2567 | pip install -U crawl4ai 2568 | ​ 2569 | Example 2570 | The following agent will scrape the content from the https://github.com/agno-agi/phidata webpage: 2571 | cookbook/tools/crawl4ai_tools.py 2572 | 2573 | Copy 2574 | 2575 | Ask AI 2576 | from phi.agent import Agent 2577 | from phi.tools.crawl4ai_tools import Crawl4aiTools 2578 | 2579 | agent = Agent(tools=[Crawl4aiTools(max_length=None)], show_tool_calls=True) 2580 | agent.print_response("Tell me about https://github.com/agno-agi/phidata.") 2581 | ​ 2582 | Toolkit Params 2583 | Parameter Type Default Description 2584 | max_length int 1000 Specifies the maximum length of the text from the webpage to be returned. 2585 | ​ 2586 | Toolkit Functions 2587 | Function Description 2588 | web_crawler Crawls a website using crawl4ai’s WebCrawler. Parameters include ‘url’ for the URL to crawl and an optional ‘max_length’ to limit the length of extracted content. The default value for ‘max_length’ is 1000. 2589 | 2590 | 2591 | 2592 | Tools 2593 | CSV 2594 | CsvTools enable an Agent to read and write CSV files. 2595 | ​ 2596 | Example 2597 | The following agent will download the IMDB csv file and allow the user to query it using a CLI app. 2598 | cookbook/tools/csv_tools.py 2599 | 2600 | Copy 2601 | 2602 | Ask AI 2603 | import httpx 2604 | from pathlib import Path 2605 | from phi.agent import Agent 2606 | from phi.tools.csv_tools import CsvTools 2607 | 2608 | url = "https://phidata-public.s3.amazonaws.com/demo_data/IMDB-Movie-Data.csv" 2609 | response = httpx.get(url) 2610 | 2611 | imdb_csv = Path(__file__).parent.joinpath("wip").joinpath("imdb.csv") 2612 | imdb_csv.parent.mkdir(parents=True, exist_ok=True) 2613 | imdb_csv.write_bytes(response.content) 2614 | 2615 | agent = Agent( 2616 | tools=[CsvTools(csvs=[imdb_csv])], 2617 | markdown=True, 2618 | show_tool_calls=True, 2619 | instructions=[ 2620 | "First always get the list of files", 2621 | "Then check the columns in the file", 2622 | "Then run the query to answer the question", 2623 | ], 2624 | ) 2625 | agent.cli_app(stream=False) 2626 | ​ 2627 | Toolkit Params 2628 | Parameter Type Default Description 2629 | csvs List[Union[str, Path]] - A list of CSV files or paths to be processed or read. 2630 | row_limit int - The maximum number of rows to process from each CSV file. 2631 | read_csvs bool True Enables the functionality to read data from specified CSV files. 2632 | list_csvs bool True Enables the functionality to list all available CSV files. 2633 | query_csvs bool True Enables the functionality to execute queries on data within CSV files. 2634 | read_column_names bool True Enables the functionality to read the column names from the CSV files. 2635 | duckdb_connection Any - Specifies a connection instance for DuckDB database operations. 2636 | duckdb_kwargs Dict[str, Any] - A dictionary of keyword arguments for configuring DuckDB operations. 2637 | ​ 2638 | Toolkit Functions 2639 | Function Description 2640 | list_csv_files Lists all available CSV files. 2641 | read_csv_file This function reads the contents of a csv file 2642 | get_columns This function returns the columns of a csv file 2643 | query_csv_file This function queries the contents of a csv file 2644 | 2645 | 2646 | 2647 | Tools 2648 | DuckDb 2649 | DuckDbTools enable an Agent to run SQL and analyze data using DuckDb. 2650 | ​ 2651 | Prerequisites 2652 | The following example requires DuckDB library. To install DuckDB, run the following command: 2653 | 2654 | Copy 2655 | 2656 | Ask AI 2657 | pip install duckdb 2658 | For more installation options, please refer to DuckDB documentation. 2659 | ​ 2660 | Example 2661 | The following agent will analyze the movies file using SQL and return the result. 2662 | cookbook/tools/duckdb_tools.py 2663 | 2664 | Copy 2665 | 2666 | Ask AI 2667 | from phi.agent import Agent 2668 | from phi.tools.duckdb import DuckDbTools 2669 | 2670 | agent = Agent( 2671 | tools=[DuckDbTools()], 2672 | show_tool_calls=True, 2673 | system_prompt="Use this file for Movies data: https://phidata-public.s3.amazonaws.com/demo_data/IMDB-Movie-Data.csv", 2674 | ) 2675 | agent.print_response("What is the average rating of movies?", markdown=True, stream=False) 2676 | ​ 2677 | Toolkit Params 2678 | Parameter Type Default Description 2679 | db_path str - Specifies the path to the database file. 2680 | connection DuckDBPyConnection - Provides an existing DuckDB connection object. 2681 | init_commands List - A list of initial SQL commands to run on database connection. 2682 | read_only bool False Configures the database connection to be read-only. 2683 | config dict - Configuration options for the database connection. 2684 | run_queries bool True Determines whether to run SQL queries during the operation. 2685 | inspect_queries bool False Enables inspection of SQL queries without executing them. 2686 | create_tables bool True Allows creation of tables in the database during the operation. 2687 | summarize_tables bool True Enables summarization of table data during the operation. 2688 | export_tables bool False Allows exporting tables to external formats during the operation. 2689 | ​ 2690 | Toolkit Functions 2691 | Function Description 2692 | show_tables Function to show tables in the database 2693 | describe_table Function to describe a table 2694 | inspect_query Function to inspect a query and return the query plan. Always inspect your query before running them. 2695 | run_query Function that runs a query and returns the result. 2696 | summarize_table Function to compute a number of aggregates over a table. The function launches a query that computes a number of aggregates over all columns, including min, max, avg, std and approx_unique. 2697 | get_table_name_from_path Get the table name from a path 2698 | create_table_from_path Creates a table from a path 2699 | export_table_to_path Save a table in a desired format (default: parquet). If the path is provided, the table will be saved under that path. Eg: If path is /tmp, the table will be saved as /tmp/table.parquet. Otherwise it will be saved in the current directory 2700 | load_local_path_to_table Load a local file into duckdb 2701 | load_local_csv_to_table Load a local CSV file into duckdb 2702 | load_s3_path_to_table Load a file from S3 into duckdb 2703 | load_s3_csv_to_table Load a CSV file from S3 into duckdb 2704 | create_fts_index Create a full text search index on a table 2705 | full_text_search Full text Search in a table column for a specific text/keyword 2706 | 2707 | 2708 | Tools 2709 | DuckDuckGo 2710 | DuckDuckGo enables an Agent to search the web for information. 2711 | ​ 2712 | Prerequisites 2713 | The following example requires the duckduckgo-search library. To install DuckDuckGo, run the following command: 2714 | 2715 | Copy 2716 | 2717 | Ask AI 2718 | pip install -U duckduckgo-search 2719 | ​ 2720 | Example 2721 | cookbook/tools/duckduckgo.py 2722 | 2723 | Copy 2724 | 2725 | Ask AI 2726 | from phi.agent import Agent 2727 | from phi.tools.duckduckgo import DuckDuckGo 2728 | 2729 | agent = Agent(tools=[DuckDuckGo()], show_tool_calls=True) 2730 | agent.print_response("Whats happening in France?", markdown=True) 2731 | ​ 2732 | Toolkit Params 2733 | Parameter Type Default Description 2734 | search bool True Enables the use of the duckduckgo_search function to search DuckDuckGo for a query. 2735 | news bool True Enables the use of the duckduckgo_news function to fetch the latest news via DuckDuckGo. 2736 | fixed_max_results int - Sets a fixed number of maximum results to return. No default is provided, must be specified if used. 2737 | headers Any - Accepts any type of header values to be sent with HTTP requests. 2738 | proxy str - Specifies a single proxy address as a string to be used for the HTTP requests. 2739 | proxies Any - Accepts a dictionary of proxies to be used for HTTP requests. 2740 | timeout int 10 Sets the timeout for HTTP requests, in seconds. 2741 | ​ 2742 | Toolkit Functions 2743 | Function Description 2744 | duckduckgo_search Use this function to search DuckDuckGo for a query. 2745 | duckduckgo_news Use this function to get the latest news from DuckDuckGo. 2746 | 2747 | 2748 | Tools 2749 | Email 2750 | EmailTools enable an Agent to send an email to a user. The Agent can send an email to a user with a specific subject and body. 2751 | ​ 2752 | Example 2753 | cookbook/tools/email_tools.py 2754 | 2755 | Copy 2756 | 2757 | Ask AI 2758 | from phi.agent import Agent 2759 | from phi.tools.email import EmailTools 2760 | 2761 | receiver_email = "" 2762 | sender_email = "" 2763 | sender_name = "" 2764 | sender_passkey = "" 2765 | 2766 | agent = Agent( 2767 | tools=[ 2768 | EmailTools( 2769 | receiver_email=receiver_email, 2770 | sender_email=sender_email, 2771 | sender_name=sender_name, 2772 | sender_passkey=sender_passkey, 2773 | ) 2774 | ] 2775 | ) 2776 | agent.print_response("send an email to ") 2777 | ​ 2778 | Toolkit Params 2779 | Parameter Type Default Description 2780 | receiver_email str - The email address of the receiver. 2781 | sender_name str - The name of the sender. 2782 | sender_email str - The email address of the sender. 2783 | sender_passkey str - The passkey for the sender’s email. 2784 | ​ 2785 | Toolkit Functions 2786 | Function Description 2787 | email_user Emails the user with the given subject and body. Currently works with Gmail. 2788 | 2789 | 2790 | 2791 | Tools 2792 | Exa 2793 | ExaTools enable an Agent to search the web using Exa. 2794 | ​ 2795 | Prerequisites 2796 | The following examples requires the exa-client library and an API key which can be obtained from Exa. 2797 | 2798 | Copy 2799 | 2800 | Ask AI 2801 | pip install -U exa-client 2802 | 2803 | Copy 2804 | 2805 | Ask AI 2806 | export EXA_API_KEY=*** 2807 | ​ 2808 | Example 2809 | The following agent will run seach exa for AAPL news and print the response. 2810 | cookbook/tools/exa_tools.py 2811 | 2812 | Copy 2813 | 2814 | Ask AI 2815 | from phi.agent import Agent 2816 | from phi.tools.exa import ExaTools 2817 | 2818 | agent = Agent(tools=[ExaTools(include_domains=["cnbc.com", "reuters.com", "bloomberg.com"])], show_tool_calls=True) 2819 | agent.print_response("Search for AAPL news", markdown=True) 2820 | ​ 2821 | Toolkit Params 2822 | Parameter Type Default Description 2823 | api_key str - API key for authentication purposes. 2824 | search bool False Determines whether to enable search functionality. 2825 | search_with_contents bool True Indicates whether to include contents in the search results. 2826 | show_results bool False Controls whether to display search results directly. 2827 | ​ 2828 | Toolkit Functions 2829 | Function Description 2830 | search_exa Searches Exa for a query. 2831 | search_exa_with_contents Searches Exa for a query and returns the contents from the search results. 2832 | 2833 | 2834 | 2835 | Tools 2836 | File 2837 | FileTools enable an Agent to read and write files on the local file system. 2838 | ​ 2839 | Example 2840 | The following agent will generate an answer and save it in a file. 2841 | cookbook/tools/file_tools.py 2842 | 2843 | Copy 2844 | 2845 | Ask AI 2846 | from phi.agent import Agent 2847 | from phi.tools.file import FileTools 2848 | 2849 | agent = Agent(tools=[FileTools()], show_tool_calls=True) 2850 | agent.print_response("What is the most advanced LLM currently? Save the answer to a file.", markdown=True) 2851 | ​ 2852 | Toolkit Params 2853 | Name Type Default Description 2854 | base_dir Path - Specifies the base directory path for file operations. 2855 | save_files bool True Determines whether files should be saved during the operation. 2856 | read_files bool True Allows reading from files during the operation. 2857 | list_files bool True Enables listing of files in the specified directory. 2858 | ​ 2859 | Toolkit Functions 2860 | Name Description 2861 | save_file Saves the contents to a file called file_name and returns the file name if successful. 2862 | read_file Reads the contents of the file file_name and returns the contents if successful. 2863 | list_files Returns a list of files in the base directory 2864 | 2865 | 2866 | 2867 | Tools 2868 | Giphy 2869 | GiphyTools enables an Agent to search for GIFs on GIPHY. 2870 | ​ 2871 | Prerequisites 2872 | 2873 | Copy 2874 | 2875 | Ask AI 2876 | export GIPHY_API_KEY=*** 2877 | ​ 2878 | Example 2879 | The following agent will search GIPHY for a GIF appropriate for a birthday message. 2880 | 2881 | Copy 2882 | 2883 | Ask AI 2884 | from phi.agent import Agent 2885 | from phi.model.openai import OpenAIChat 2886 | from phi.tools.giphy import GiphyTools 2887 | 2888 | 2889 | gif_agent = Agent( 2890 | name="Gif Generator Agent", 2891 | model=OpenAIChat(id="gpt-4o"), 2892 | tools=[GiphyTools()], 2893 | description="You are an AI agent that can generate gifs using Giphy.", 2894 | ) 2895 | 2896 | gif_agent.print_response("I want a gif to send to a friend for their birthday.") 2897 | ​ 2898 | Toolkit Params 2899 | Parameter Type Default Description 2900 | api_key str None If you want to manually supply the GIPHY API key. 2901 | limit int 1 The number of GIFs to return in a search. 2902 | ​ 2903 | Toolkit Functions 2904 | Function Description 2905 | search_gifs Searches GIPHY for a GIF based on the query string 2906 | 2907 | 2908 | 2909 | Tools 2910 | Google Search 2911 | GoogleSearch enables an Agent to perform web crawling and scraping tasks. 2912 | ​ 2913 | Prerequisites 2914 | The following examples requires the googlesearch and pycountry libraries. 2915 | 2916 | Copy 2917 | 2918 | Ask AI 2919 | pip install -U googlesearch-python pycountry 2920 | ​ 2921 | Example 2922 | The following agent will search Google for the latest news about “Mistral AI”: 2923 | cookbook/tools/googlesearch_tools.py 2924 | 2925 | Copy 2926 | 2927 | Ask AI 2928 | from phi.agent import Agent 2929 | from phi.tools.googlesearch import GoogleSearch 2930 | 2931 | agent = Agent( 2932 | tools=[GoogleSearch()], 2933 | description="You are a news agent that helps users find the latest news.", 2934 | instructions=[ 2935 | "Given a topic by the user, respond with 4 latest news items about that topic.", 2936 | "Search for 10 news items and select the top 4 unique items.", 2937 | "Search in English and in French.", 2938 | ], 2939 | show_tool_calls=True, 2940 | debug_mode=True, 2941 | ) 2942 | agent.print_response("Mistral AI", markdown=True) 2943 | ​ 2944 | Toolkit Params 2945 | Parameter Type Default Description 2946 | fixed_max_results int None Optional fixed maximum number of results to return. 2947 | fixed_language str None Optional fixed language for the requests. 2948 | headers Any None Optional headers to include in the requests. 2949 | proxy str None Optional proxy to be used for the requests. 2950 | timeout int None Optional timeout for the requests, in seconds. 2951 | ​ 2952 | Toolkit Functions 2953 | Function Description 2954 | google_search Searches Google for a specified query. Parameters include query for the search term, max_results for the maximum number of results (default is 5), and language for the language of the search results (default is “en”). Returns the search results as a JSON formatted string. 2955 | 2956 | 2957 | 2958 | Tools 2959 | Newspaper 2960 | NewspaperTools enable an Agent to read news articles using the Newspaper4k library. 2961 | ​ 2962 | Prerequisites 2963 | The following example requires the newspaper3k library. 2964 | 2965 | Copy 2966 | 2967 | Ask AI 2968 | pip install -U newspaper3k 2969 | ​ 2970 | Example 2971 | The following agent will summarize the wikipedia article on language models. 2972 | cookbook/tools/newspaper_tools.py 2973 | 2974 | Copy 2975 | 2976 | Ask AI 2977 | from phi.agent import Agent 2978 | from phi.tools.newspaper_tools import NewspaperTools 2979 | 2980 | agent = Agent(tools=[NewspaperTools()]) 2981 | agent.print_response("Please summarize https://en.wikipedia.org/wiki/Language_model") 2982 | ​ 2983 | Toolkit Params 2984 | Parameter Type Default Description 2985 | get_article_text bool True Enables the functionality to retrieve the text of an article. 2986 | ​ 2987 | Toolkit Functions 2988 | Function Description 2989 | get_article_text Retrieves the text of an article from a specified URL. Parameters include url for the URL of the article. Returns the text of the article or an error message if the retrieval fails. 2990 | 2991 | 2992 | 2993 | Tools 2994 | Newspaper4k 2995 | Newspaper4k enables an Agent to read news articles using the Newspaper4k library. 2996 | ​ 2997 | Prerequisites 2998 | The following example requires the newspaper4k and lxml_html_clean libraries. 2999 | 3000 | Copy 3001 | 3002 | Ask AI 3003 | pip install -U newspaper4k lxml_html_clean 3004 | ​ 3005 | Example 3006 | The following agent will summarize the article: https://www.rockymountaineer.com/blog/experience-icefields-parkway-scenic-drive-lifetime. 3007 | cookbook/tools/newspaper4k_tools.py 3008 | 3009 | Copy 3010 | 3011 | Ask AI 3012 | from phi.agent import Agent 3013 | from phi.tools.newspaper4k import Newspaper4k 3014 | 3015 | agent = Agent(tools=[Newspaper4k()], debug_mode=True, show_tool_calls=True) 3016 | agent.print_response("Please summarize https://www.rockymountaineer.com/blog/experience-icefields-parkway-scenic-drive-lifetime") 3017 | ​ 3018 | Toolkit Params 3019 | Parameter Type Default Description 3020 | read_article bool True Enables the functionality to read the full content of an article. 3021 | include_summary bool False Specifies whether to include a summary of the article along with the full content. 3022 | article_length int - The maximum length of the article or its summary to be processed or returned. 3023 | ​ 3024 | Toolkit Functions 3025 | Function Description 3026 | get_article_data This function reads the full content and data of an article. 3027 | read_article This function reads the full content of an article. 3028 | 3029 | 3030 | Tools 3031 | OpenBB 3032 | OpenBBTools enable an Agent to provide information about stocks and companies. 3033 | cookbook/tools/openbb_tools.py 3034 | 3035 | Copy 3036 | 3037 | Ask AI 3038 | from phi.agent import Agent 3039 | from phi.tools.openbb_tools import OpenBBTools 3040 | 3041 | 3042 | agent = Agent(tools=[OpenBBTools()], debug_mode=True, show_tool_calls=True) 3043 | 3044 | # Example usage showing stock analysis 3045 | agent.print_response( 3046 | "Get me the current stock price and key information for Apple (AAPL)" 3047 | ) 3048 | 3049 | # Example showing market analysis 3050 | agent.print_response( 3051 | "What are the top gainers in the market today?" 3052 | ) 3053 | 3054 | # Example showing economic indicators 3055 | agent.print_response( 3056 | "Show me the latest GDP growth rate and inflation numbers for the US" 3057 | ) 3058 | ​ 3059 | Toolkit Params 3060 | Parameter Type Default Description 3061 | read_article bool True Enables the functionality to read the full content of an article. 3062 | include_summary bool False Specifies whether to include a summary of the article along with the full content. 3063 | article_length int - The maximum length of the article or its summary to be processed or returned. 3064 | ​ 3065 | Toolkit Functions 3066 | Function Description 3067 | get_stock_price This function gets the current stock price for a stock symbol or list of symbols. 3068 | search_company_symbol This function searches for the stock symbol of a company. 3069 | get_price_targets This function gets the price targets for a stock symbol or list of symbols. 3070 | get_company_news This function gets the latest news for a stock symbol or list of symbols. 3071 | get_company_profile This function gets the company profile for a stock symbol or list of symbols. 3072 | 3073 | 3074 | 3075 | Tools 3076 | Pandas 3077 | PandasTools enable an Agent to perform data manipulation tasks using the Pandas library. 3078 | cookbook/tools/pandas_tool.py 3079 | 3080 | Copy 3081 | 3082 | Ask AI 3083 | from phi.agent import Agent 3084 | from phi.tools.pandas import PandasTools 3085 | 3086 | # Create an agent with PandasTools 3087 | agent = Agent(tools=[PandasTools()]) 3088 | 3089 | # Example: Create a dataframe with sample data and get the first 5 rows 3090 | agent.print_response(""" 3091 | Please perform these tasks: 3092 | 1. Create a pandas dataframe named 'sales_data' using DataFrame() with this sample data: 3093 | {'date': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05'], 3094 | 'product': ['Widget A', 'Widget B', 'Widget A', 'Widget C', 'Widget B'], 3095 | 'quantity': [10, 15, 8, 12, 20], 3096 | 'price': [9.99, 15.99, 9.99, 12.99, 15.99]} 3097 | 2. Show me the first 5 rows of the sales_data dataframe 3098 | """) 3099 | ​ 3100 | Toolkit Params 3101 | Parameter Type Default Description 3102 | dataframes Dict[str, pd.DataFrame] {} A dictionary to store Pandas DataFrames, keyed by their names. 3103 | create_pandas_dataframe function - Registers a function to create a Pandas DataFrame. 3104 | run_dataframe_operation function - Registers a function to run operations on a Pandas DataFrame. 3105 | ​ 3106 | Toolkit Functions 3107 | Function Description 3108 | create_pandas_dataframe Creates a Pandas DataFrame named dataframe_name by using the specified function create_using_function with parameters function_parameters. Parameters include ‘dataframe_name’ for the name of the DataFrame, ‘create_using_function’ for the function to create it (e.g., ‘read_csv’), and ‘function_parameters’ for the arguments required by the function. Returns the name of the created DataFrame if successful, otherwise returns an error message. 3109 | run_dataframe_operation Runs a specified operation operation on a DataFrame dataframe_name with the parameters operation_parameters. Parameters include ‘dataframe_name’ for the DataFrame to operate on, ‘operation’ for the operation to perform (e.g., ‘head’, ‘tail’), and ‘operation_parameters’ for the arguments required by the operation. Returns the result of the operation if successful, otherwise returns an error message. 3110 | 3111 | 3112 | 3113 | Tools 3114 | Python 3115 | PythonTools enable an Agent to write and run python code. 3116 | ​ 3117 | Example 3118 | The following agent will write a python script that creates the fibonacci series, save it to a file, run it and return the result. 3119 | cookbook/tools/python_tools.py 3120 | 3121 | Copy 3122 | 3123 | Ask AI 3124 | from phi.agent import Agent 3125 | from phi.tools.python import PythonTools 3126 | 3127 | agent = Agent(tools=[PythonTools()], show_tool_calls=True) 3128 | agent.print_response("Write a python script for fibonacci series and display the result till the 10th number") 3129 | ​ 3130 | Toolkit Params 3131 | Parameter Type Default Description 3132 | base_dir Path None Specifies the base directory for operations. Default is None, indicating the current working directory. 3133 | save_and_run bool True If True, saves and runs the code. Useful for execution of scripts after saving. 3134 | pip_install bool False Enables pip installation of required packages before running the code. 3135 | run_code bool False Determines whether the code should be executed. 3136 | list_files bool False If True, lists all files in the specified base directory. 3137 | run_files bool False If True, runs the Python files found in the specified directory. 3138 | read_files bool False If True, reads the contents of the files in the specified directory. 3139 | safe_globals dict - Specifies a dictionary of global variables that are considered safe to use during the execution. 3140 | safe_locals dict - Specifies a dictionary of local variables that are considered safe to use during the execution. 3141 | ​ 3142 | Toolkit Functions 3143 | Function Description 3144 | save_to_file_and_run This function saves Python code to a file called file_name and then runs it. If successful, returns the value of variable_to_return if provided otherwise returns a success message. If failed, returns an error message. Make sure the file_name ends with .py 3145 | run_python_file_return_variable This function runs code in a Python file. If successful, returns the value of variable_to_return if provided otherwise returns a success message. If failed, returns an error message. 3146 | read_file Reads the contents of the file file_name and returns the contents if successful. 3147 | list_files Returns a list of files in the base directory 3148 | run_python_code This function runs Python code in the current environment. If successful, returns the value of variable_to_return if provided otherwise returns a success message. If failed, returns an error message. 3149 | pip_install_package This function installs a package using pip in the current environment. If successful, returns a success message. If failed, returns an error message. 3150 | 3151 | 3152 | 3153 | 3154 | Tools 3155 | Sleep 3156 | ​ 3157 | Example 3158 | The following agent will use the sleep tool to pause execution for a given number of seconds. 3159 | cookbook/tools/sleep_tools.py 3160 | 3161 | Copy 3162 | 3163 | Ask AI 3164 | from phi.agent import Agent 3165 | from phi.tools.sleep import Sleep 3166 | 3167 | # Create an Agent with the Sleep tool 3168 | agent = Agent(tools=[Sleep()], name="Sleep Agent") 3169 | 3170 | # Example 1: Sleep for 2 seconds 3171 | agent.print_response("Sleep for 2 seconds") 3172 | 3173 | # Example 2: Sleep for a longer duration 3174 | agent.print_response("Sleep for 5 seconds") 3175 | ​ 3176 | Toolkit Params 3177 | Parameter Type Default Description 3178 | name str "sleep" The name of the tool 3179 | ​ 3180 | Toolkit Functions 3181 | Function Description 3182 | sleep Pauses execution for a specified number of seconds 3183 | 3184 | 3185 | Tools 3186 | Tavily 3187 | TavilyTools enable an Agent to search the web using the Tavily API. 3188 | ​ 3189 | Prerequisites 3190 | The following examples requires the tavily-python library and an API key from Tavily. 3191 | 3192 | Copy 3193 | 3194 | Ask AI 3195 | pip install -U tavily-python 3196 | 3197 | Copy 3198 | 3199 | Ask AI 3200 | export TAVILY_API_KEY=*** 3201 | ​ 3202 | Example 3203 | The following agent will run a search on Tavily for “language models” and print the response. 3204 | cookbook/tools/tavily_tools.py 3205 | 3206 | Copy 3207 | 3208 | Ask AI 3209 | from phi.agent import Agent 3210 | from phi.tools.tavily import TavilyTools 3211 | 3212 | agent = Agent(tools=[TavilyTools()], show_tool_calls=True) 3213 | agent.print_response("Search tavily for 'language models'", markdown=True) 3214 | ​ 3215 | Toolkit Params 3216 | Parameter Type Default Description 3217 | api_key str - API key for authentication. If not provided, will check TAVILY_API_KEY environment variable. 3218 | search bool True Enables search functionality. 3219 | max_tokens int 6000 Maximum number of tokens to use in search results. 3220 | include_answer bool True Whether to include an AI-generated answer summary in the response. 3221 | search_depth Literal['basic', 'advanced'] 'advanced' Depth of search - ‘basic’ for faster results or ‘advanced’ for more comprehensive search. 3222 | format Literal['json', 'markdown'] 'markdown' Output format - ‘json’ for raw data or ‘markdown’ for formatted text. 3223 | use_search_context bool False Whether to use Tavily’s search context API instead of regular search. 3224 | ​ 3225 | Toolkit Functions 3226 | Function Description 3227 | web_search_using_tavily Searches the web for a query using Tavily API. Takes a query string and optional max_results parameter (default 5). Returns results in specified format with titles, URLs, content and relevance scores. 3228 | web_search_with_tavily Alternative search function that uses Tavily’s search context API. Takes a query string and returns contextualized search results. Only available if use_search_context is True. 3229 | 3230 | 3231 | 3232 | Tools 3233 | Website 3234 | WebsiteTools enable an Agent to parse a website and add its contents to the knowledge base. 3235 | ​ 3236 | Prerequisites 3237 | The following example requires the beautifulsoup4 library. 3238 | 3239 | Copy 3240 | 3241 | Ask AI 3242 | pip install -U beautifulsoup4 3243 | ​ 3244 | Example 3245 | The following agent will read the contents of a website and add it to the knowledge base. 3246 | cookbook/tools/website_tools.py 3247 | 3248 | Copy 3249 | 3250 | Ask AI 3251 | from phi.agent import Agent 3252 | from phi.tools.website import WebsiteTools 3253 | 3254 | agent = Agent(tools=[WebsiteTools()], show_tool_calls=True) 3255 | agent.print_response("Search web page: 'https://docs.phidata.com/introduction'", markdown=True) 3256 | ​ 3257 | Toolkit Params 3258 | Parameter Type Default Description 3259 | knowledge_base WebsiteKnowledgeBase - The knowledge base associated with the website, containing various data and resources linked to the website’s content. 3260 | ​ 3261 | Toolkit Functions 3262 | Function Description 3263 | add_website_to_knowledge_base This function adds a website’s content to the knowledge base. NOTE: The website must start with https:// and should be a valid website. Use this function to get information about products from the internet. 3264 | read_url This function reads a URL and returns the contents. 3265 | 3266 | 3267 | 3268 | Tools 3269 | Youtube 3270 | YouTubeTools enable an Agent to access captions and metadata of YouTube videos, when provided with a video URL. 3271 | ​ 3272 | Prerequisites 3273 | The following example requires the youtube_transcript_api library. 3274 | 3275 | Copy 3276 | 3277 | Ask AI 3278 | pip install -U youtube_transcript_api 3279 | ​ 3280 | Example 3281 | The following agent will provide a summary of a YouTube video. 3282 | cookbook/tools/youtube_tools.py 3283 | 3284 | Copy 3285 | 3286 | Ask AI 3287 | from phi.agent import Agent 3288 | from phi.tools.youtube_tools import YouTubeTools 3289 | 3290 | agent = Agent( 3291 | tools=[YouTubeTools()], 3292 | show_tool_calls=True, 3293 | description="You are a YouTube agent. Obtain the captions of a YouTube video and answer questions.", 3294 | ) 3295 | 3296 | agent.print_response("Summarize this video https://www.youtube.com/watch?v=Iv9dewmcFbs&t", markdown=True) 3297 | ​ 3298 | Toolkit Params 3299 | Param Type Default Description 3300 | get_video_captions bool True Enables the functionality to retrieve video captions. 3301 | get_video_data bool True Enables the functionality to retrieve video metadata and other related data. 3302 | languages List[str] - Specifies the list of languages for which data should be retrieved, if applicable. 3303 | ​ 3304 | Toolkit Functions 3305 | Function Description 3306 | get_youtube_video_captions This function retrieves the captions of a YouTube video. 3307 | get_youtube_video_data This function retrieves the metadata of a YouTube video. 3308 | 3309 | 3310 | 3311 | Knowledge 3312 | Introduction 3313 | A knowledge base is a database of information that an agent can search to improve its responses. This information is stored in a vector database and provides agents with business context, helping them respond in a context-aware manner. The general syntax is: 3314 | 3315 | Copy 3316 | 3317 | Ask AI 3318 | from phi.agent import Agent, AgentKnowledge 3319 | 3320 | # Create a knowledge base for the Agent 3321 | knowledge_base = AgentKnowledge(vector_db=...) 3322 | 3323 | # Add information to the knowledge base 3324 | knowledge_base.load_text("The sky is blue") 3325 | 3326 | # Add the knowledge base to the Agent and 3327 | # give it a tool to search the knowledge base as needed 3328 | agent = Agent(knowledge=knowledge_base, search_knowledge=True) 3329 | ​ 3330 | Vector Databases 3331 | While any type of storage can act as a knowledge base, vector databases offer the best solution for retrieving relevant results from dense information quickly. Here’s how vector databases are used with Agents: 3332 | 1 3333 | Chunk the information 3334 | 3335 | Break down the knowledge into smaller chunks to ensure our search query returns only relevant results. 3336 | 2 3337 | Load the knowledge base 3338 | 3339 | Convert the chunks into embedding vectors and store them in a vector database. 3340 | 3 3341 | Search the knowledge base 3342 | 3343 | When the user sends a message, we convert the input message into an embedding and “search” for nearest neighbors in the vector database. 3344 | ​ 3345 | Loading the Knowledge Base 3346 | Before you can use a knowledge base, it needs to be loaded with embeddings that will be used for retrieval. Use one of the following knowledge bases to simplify the chunking, loading, searching and optimization process: 3347 | ArXiv knowledge base: Load ArXiv papers to a knowledge base 3348 | Combined knowledge base: Combine multiple knowledge bases into 1 3349 | CSV knowledge base: Load CSV files to a knowledge base 3350 | Document knowledge base: Load local docx files to a knowledge base 3351 | JSON knowledge base: Load JSON files to a knowledge base 3352 | LangChain knowledge base: Use a Langchain retriever as a knowledge base 3353 | PDF knowledge base: Load local PDF files to a knowledge base 3354 | PDF URL knowledge base: Load PDF files from a URL to a knowledge base 3355 | S3 PDF knowledge base: Load PDF files from S3 to a knowledge base 3356 | S3 Text knowledge base: Load text files from S3 to a knowledge base 3357 | Text knowledge base: Load text/docx files to a knowledge base 3358 | Website knowledge base: Load website data to a knowledge base 3359 | Wikipedia knowledge base: Load wikipedia articles to a knowledge base 3360 | 3361 | 3362 | Knowledge 3363 | ArXiv Knowledge Base 3364 | The ArxivKnowledgeBase reads Arxiv articles, converts them into vector embeddings and loads them to a vector databse. 3365 | ​ 3366 | Usage 3367 | We are using a local PgVector database for this example. Make sure it’s running 3368 | 3369 | Copy 3370 | 3371 | Ask AI 3372 | pip install arxiv 3373 | knowledge_base.py 3374 | 3375 | Copy 3376 | 3377 | Ask AI 3378 | from phi.knowledge.arxiv import ArxivKnowledgeBase 3379 | from phi.vectordb.pgvector import PgVector 3380 | 3381 | knowledge_base = ArxivKnowledgeBase( 3382 | queries=["Generative AI", "Machine Learning"], 3383 | # Table name: ai.arxiv_documents 3384 | vector_db=PgVector( 3385 | table_name="arxiv_documents", 3386 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3387 | ), 3388 | ) 3389 | Then use the knowledge_base with an Agent: 3390 | agent.py 3391 | 3392 | Copy 3393 | 3394 | Ask AI 3395 | from phi.agent import Agent 3396 | from knowledge_base import knowledge_base 3397 | 3398 | agent = Agent( 3399 | knowledge=knowledge_base, 3400 | search_knowledge=True, 3401 | ) 3402 | agent.knowledge.load(recreate=False) 3403 | 3404 | agent.print_response("Ask me about something from the knowledge base") 3405 | ​ 3406 | Params 3407 | Parameter Type Default Description 3408 | queries List[str] - Queries to search 3409 | reader ArxivReader ArxivReader() A ArxivReader that reads the articles and converts them into Documents for the vector database. 3410 | vector_db VectorDb - Vector Database for the Knowledge Base. 3411 | num_documents int 5 Number of documents to return on search. 3412 | optimize_on int - Number of documents to optimize the vector db on. 3413 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3414 | 3415 | 3416 | 3417 | Knowledge 3418 | Combined KnowledgeBase 3419 | The CombinedKnowledgeBase combines multiple knowledge bases into 1 and is used when your app needs information using multiple sources. 3420 | ​ 3421 | Usage 3422 | We are using a local PgVector database for this example. Make sure it’s running 3423 | 3424 | Copy 3425 | 3426 | Ask AI 3427 | pip install pypdf bs4 3428 | knowledge_base.py 3429 | 3430 | Copy 3431 | 3432 | Ask AI 3433 | from phi.knowledge.combined import CombinedKnowledgeBase 3434 | from phi.vectordb.pgvector import PgVector 3435 | 3436 | url_pdf_knowledge_base = PDFUrlKnowledgeBase( 3437 | urls=["pdf_url"], 3438 | # Table name: ai.pdf_documents 3439 | vector_db=PgVector( 3440 | table_name="pdf_documents", 3441 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3442 | ), 3443 | ) 3444 | 3445 | website_knowledge_base = WebsiteKnowledgeBase( 3446 | urls=["https://docs.phidata.com/introduction"], 3447 | # Number of links to follow from the seed URLs 3448 | max_links=10, 3449 | # Table name: ai.website_documents 3450 | vector_db=PgVector( 3451 | table_name="website_documents", 3452 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3453 | ), 3454 | ) 3455 | 3456 | local_pdf_knowledge_base = PDFKnowledgeBase( 3457 | path="data/pdfs", 3458 | # Table name: ai.pdf_documents 3459 | vector_db=PgVector( 3460 | table_name="pdf_documents", 3461 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3462 | ), 3463 | reader=PDFReader(chunk=True), 3464 | ) 3465 | 3466 | knowledge_base = CombinedKnowledgeBase( 3467 | sources=[ 3468 | url_pdf_knowledge_base, 3469 | website_knowledge_base, 3470 | local_pdf_knowledge_base, 3471 | ], 3472 | vector_db=PgVector( 3473 | # Table name: ai.combined_documents 3474 | table_name="combined_documents", 3475 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3476 | ), 3477 | ) 3478 | Then use the knowledge_base with an Agent: 3479 | agent.py 3480 | 3481 | Copy 3482 | 3483 | Ask AI 3484 | from phi.agent import Agent 3485 | from knowledge_base import knowledge_base 3486 | 3487 | agent = Agent( 3488 | knowledge=knowledge_base, 3489 | search_knowledge=True, 3490 | ) 3491 | agent.knowledge.load(recreate=False) 3492 | 3493 | agent.print_response("Ask me about something from the knowledge base") 3494 | ​ 3495 | Params 3496 | Parameter Type Default Description 3497 | sources List[AgentKnowledge] - List of Agent knowledge bases. 3498 | reader Reader - A Reader that converts the content of the documents into Documents for the vector database. 3499 | vector_db VectorDb - Vector Database for the Knowledge Base. 3500 | num_documents int 5 Number of documents to return on search. 3501 | optimize_on int - Number of documents to optimize the vector db on. 3502 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3503 | 3504 | 3505 | Knowledge 3506 | Docx Knowledge Base 3507 | The DocxKnowledgeBase reads local docx files, converts them into vector embeddings and loads them to a vector databse. 3508 | ​ 3509 | Usage 3510 | We are using a local PgVector database for this example. Make sure it’s running 3511 | 3512 | Copy 3513 | 3514 | Ask AI 3515 | pip install textract 3516 | 3517 | Copy 3518 | 3519 | Ask AI 3520 | from phi.knowledge.docx import DocxKnowledgeBase 3521 | from phi.vectordb.pgvector import PgVector 3522 | 3523 | knowledge_base = DocxKnowledgeBase( 3524 | path="data/docs", 3525 | # Table name: ai.docx_documents 3526 | vector_db=PgVector( 3527 | table_name="docx_documents", 3528 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3529 | ), 3530 | ) 3531 | Then use the knowledge_base with an Agent: 3532 | 3533 | Copy 3534 | 3535 | Ask AI 3536 | from phi.agent import Agent 3537 | from knowledge_base import knowledge_base 3538 | 3539 | agent = Agent( 3540 | knowledge=knowledge_base, 3541 | search_knowledge=True, 3542 | ) 3543 | agent.knowledge.load(recreate=False) 3544 | 3545 | agent.print_response("Ask me about something from the knowledge base") 3546 | ​ 3547 | Params 3548 | Parameter Type Default Description 3549 | path Union[str, Path] - Path to docx files. Can point to a single docx file or a directory of docx files. 3550 | formats List[str] [".doc", ".docx"] Formats accepted by this knowledge base. 3551 | reader DocxReader DocxReader() A DocxReader that converts the docx files into Documents for the vector database. 3552 | vector_db VectorDb - Vector Database for the Knowledge Base. 3553 | num_documents int 5 Number of documents to return on search. 3554 | optimize_on int - Number of documents to optimize the vector db on. 3555 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3556 | 3557 | 3558 | Knowledge 3559 | Document Knowledge Base 3560 | The DocumentKnowledgeBase reads local docs files, converts them into vector embeddings and loads them to a vector databse. 3561 | ​ 3562 | Usage 3563 | We are using a local PgVector database for this example. Make sure it’s running 3564 | 3565 | Copy 3566 | 3567 | Ask AI 3568 | pip install textract 3569 | 3570 | Copy 3571 | 3572 | Ask AI 3573 | from phi.knowledge.document import DocumentKnowledgeBase 3574 | from phi.vectordb.pgvector import PgVector 3575 | 3576 | knowledge_base = DocumentKnowledgeBase( 3577 | path="data/docs", 3578 | # Table name: ai.documents 3579 | vector_db=PgVector( 3580 | table_name="documents", 3581 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3582 | ), 3583 | ) 3584 | Then use the knowledge_base with an Agent: 3585 | 3586 | Copy 3587 | 3588 | Ask AI 3589 | from phi.agent import Agent 3590 | from knowledge_base import knowledge_base 3591 | 3592 | agent = Agent( 3593 | knowledge=knowledge_base, 3594 | search_knowledge=True, 3595 | ) 3596 | agent.knowledge.load(recreate=False) 3597 | 3598 | agent.print_response("Ask me about something from the knowledge base") 3599 | ​ 3600 | Params 3601 | Parameter Type Default Description 3602 | documents List[Document] - List of documents to load into the vector database. 3603 | vector_db VectorDb - Vector Database for the Knowledge Base. 3604 | reader Reader - A Reader that converts the content of the documents into Documents for the vector database. 3605 | num_documents int 5 Number of documents to return on search. 3606 | optimize_on int - Number of documents to optimize the vector db on. 3607 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3608 | 3609 | 3610 | Knowledge 3611 | JSON Knowledge Base 3612 | The JSONKnowledgeBase reads local JSON files, converts them into vector embeddings and loads them to a vector databse. 3613 | ​ 3614 | Usage 3615 | We are using a local PgVector database for this example. Make sure it’s running 3616 | knowledge_base.py 3617 | 3618 | Copy 3619 | 3620 | Ask AI 3621 | from phi.knowledge.json import JSONKnowledgeBase 3622 | from phi.vectordb.pgvector import PgVector 3623 | 3624 | knowledge_base = JSONKnowledgeBase( 3625 | path="data/json", 3626 | # Table name: ai.json_documents 3627 | vector_db=PgVector( 3628 | table_name="json_documents", 3629 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3630 | ), 3631 | ) 3632 | Then use the knowledge_base with an Agent: 3633 | agent.py 3634 | 3635 | Copy 3636 | 3637 | Ask AI 3638 | from phi.agent import Agent 3639 | from knowledge_base import knowledge_base 3640 | 3641 | agent = Agent( 3642 | knowledge=knowledge_base, 3643 | search_knowledge=True, 3644 | ) 3645 | agent.knowledge.load(recreate=False) 3646 | 3647 | agent.print_response("Ask me about something from the knowledge base") 3648 | ​ 3649 | Params 3650 | Parameter Type Default Description 3651 | path Union[str, Path] - Path to JSON files. Can point to a single JSON file or a directory of JSON files. 3652 | vector_db VectorDb - Vector Database for the Knowledge Base. 3653 | reader JSONReader JSONReader() A JSONReader that converts the JSON files into Documents for the vector database. 3654 | num_documents int 5 Number of documents to return on search. 3655 | optimize_on int - Number of documents to optimize the vector db on. 3656 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3657 | 3658 | 3659 | Knowledge 3660 | LlamaIndex Knowledge Base 3661 | The LlamaIndexKnowledgeBase allows us to use a LlamaIndex retriever or vector store as a knowledge base. 3662 | ​ 3663 | Usage 3664 | 3665 | Copy 3666 | 3667 | Ask AI 3668 | pip install llama-index-core llama-index-readers-file llama-index-embeddings-openai 3669 | llamaindex_kb.py 3670 | 3671 | Copy 3672 | 3673 | Ask AI 3674 | 3675 | from pathlib import Path 3676 | from shutil import rmtree 3677 | 3678 | import httpx 3679 | from phi.agent import Agent 3680 | from phi.knowledge.llamaindex import LlamaIndexKnowledgeBase 3681 | from llama_index.core import ( 3682 | SimpleDirectoryReader, 3683 | StorageContext, 3684 | VectorStoreIndex, 3685 | ) 3686 | from llama_index.core.retrievers import VectorIndexRetriever 3687 | from llama_index.core.node_parser import SentenceSplitter 3688 | 3689 | 3690 | data_dir = Path(__file__).parent.parent.parent.joinpath("wip", "data", "paul_graham") 3691 | if data_dir.is_dir(): 3692 | rmtree(path=data_dir, ignore_errors=True) 3693 | data_dir.mkdir(parents=True, exist_ok=True) 3694 | 3695 | url = "https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt" 3696 | file_path = data_dir.joinpath("paul_graham_essay.txt") 3697 | response = httpx.get(url) 3698 | if response.status_code == 200: 3699 | with open(file_path, "wb") as file: 3700 | file.write(response.content) 3701 | print(f"File downloaded and saved as {file_path}") 3702 | else: 3703 | print("Failed to download the file") 3704 | 3705 | 3706 | documents = SimpleDirectoryReader(str(data_dir)).load_data() 3707 | 3708 | splitter = SentenceSplitter(chunk_size=1024) 3709 | 3710 | nodes = splitter.get_nodes_from_documents(documents) 3711 | 3712 | storage_context = StorageContext.from_defaults() 3713 | 3714 | index = VectorStoreIndex(nodes=nodes, storage_context=storage_context) 3715 | 3716 | retriever = VectorIndexRetriever(index) 3717 | 3718 | # Create a knowledge base from the vector store 3719 | knowledge_base = LlamaIndexKnowledgeBase(retriever=retriever) 3720 | 3721 | # Create an agent with the knowledge base 3722 | agent = Agent(knowledge_base=knowledge_base, search_knowledge=True, debug_mode=True, show_tool_calls=True) 3723 | 3724 | # Use the agent to ask a question and print a response. 3725 | agent.print_response("Explain what this text means: low end eats the high end", markdown=True) 3726 | ​ 3727 | Params 3728 | Parameter Type Default Description 3729 | retriever BaseRetriever None LlamaIndex retriever used for querying the knowledge base. 3730 | loader Optional[Callable] None Optional callable function to load documents into the knowledge base. 3731 | 3732 | 3733 | Knowledge 3734 | PDF Knowledge Base 3735 | The PDFKnowledgeBase reads local PDF files, converts them into vector embeddings and loads them to a vector databse. 3736 | ​ 3737 | Usage 3738 | We are using a local PgVector database for this example. Make sure it’s running 3739 | 3740 | Copy 3741 | 3742 | Ask AI 3743 | pip install pypdf 3744 | knowledge_base.py 3745 | 3746 | Copy 3747 | 3748 | Ask AI 3749 | from phi.knowledge.pdf import PDFKnowledgeBase, PDFReader 3750 | from phi.vectordb.pgvector import PgVector 3751 | 3752 | pdf_knowledge_base = PDFKnowledgeBase( 3753 | path="data/pdfs", 3754 | # Table name: ai.pdf_documents 3755 | vector_db=PgVector( 3756 | table_name="pdf_documents", 3757 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3758 | ), 3759 | reader=PDFReader(chunk=True), 3760 | ) 3761 | Then use the knowledge_base with an Agent: 3762 | agent.py 3763 | 3764 | Copy 3765 | 3766 | Ask AI 3767 | from phi.agent import Agent 3768 | from knowledge_base import knowledge_base 3769 | 3770 | agent = Agent( 3771 | knowledge=knowledge_base, 3772 | search_knowledge=True, 3773 | ) 3774 | agent.knowledge.load(recreate=False) 3775 | 3776 | agent.print_response("Ask me about something from the knowledge base") 3777 | ​ 3778 | Params 3779 | Parameter Type Default Description 3780 | path Union[str, Path] - Path to PDF files. Can point to a single PDF file or a directory of PDF files. 3781 | vector_db VectorDb - Vector Database for the Knowledge Base. Example: PgVector 3782 | reader Union[PDFReader, PDFImageReader] PDFReader() A PDFReader that converts the PDFs into Documents for the vector database. 3783 | num_documents int 5 Number of documents to return on search. 3784 | optimize_on int - Number of documents to optimize the vector db on. For Example: Create an index for PgVector. 3785 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3786 | 3787 | 3788 | Knowledge 3789 | PDF URL Knowledge Base 3790 | The PDFUrlKnowledgeBase reads PDFs from urls, converts them into vector embeddings and loads them to a vector database. 3791 | ​ 3792 | Usage 3793 | We are using a local PgVector database for this example. Make sure it’s running 3794 | 3795 | Copy 3796 | 3797 | Ask AI 3798 | pip install pypdf 3799 | knowledge_base.py 3800 | 3801 | Copy 3802 | 3803 | Ask AI 3804 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 3805 | from phi.vectordb.pgvector import PgVector 3806 | 3807 | knowledge_base = PDFUrlKnowledgeBase( 3808 | urls=["pdf_url"], 3809 | # Table name: ai.pdf_documents 3810 | vector_db=PgVector( 3811 | table_name="pdf_documents", 3812 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3813 | ), 3814 | ) 3815 | Then use the knowledge_base with an Agent: 3816 | agent.py 3817 | 3818 | Copy 3819 | 3820 | Ask AI 3821 | from phi.agent import Agent 3822 | from knowledge_base import knowledge_base 3823 | 3824 | agent = Agent( 3825 | knowledge=knowledge_base, 3826 | search_knowledge=True, 3827 | ) 3828 | agent.knowledge.load(recreate=False) 3829 | 3830 | agent.print_response("Ask me about something from the knowledge base") 3831 | ​ 3832 | Params 3833 | Parameter Type Default Description 3834 | urls List[str] - URLs for PDF files. 3835 | reader Union[PDFUrlReader, PDFUrlImageReader] PDFUrlReader() A PDFUrlReader that converts the PDFs into Documents for the vector database. 3836 | vector_db VectorDb - Vector Database for the Knowledge Base. 3837 | num_documents int 5 Number of documents to return on search. 3838 | optimize_on int - Number of documents to optimize the vector db on. 3839 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3840 | 3841 | 3842 | 3843 | Knowledge 3844 | Text Knowledge Base 3845 | The TextKnowledgeBase reads local txt files, converts them into vector embeddings and loads them to a vector databse. 3846 | ​ 3847 | Usage 3848 | We are using a local PgVector database for this example. Make sure it’s running 3849 | knowledge_base.py 3850 | 3851 | Copy 3852 | 3853 | Ask AI 3854 | from phi.knowledge.text import TextKnowledgeBase 3855 | from phi.vectordb.pgvector import PgVector 3856 | 3857 | knowledge_base = TextKnowledgeBase( 3858 | path="data/txt_files", 3859 | # Table name: ai.text_documents 3860 | vector_db=PgVector( 3861 | table_name="text_documents", 3862 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3863 | ), 3864 | ) 3865 | Then use the knowledge_base with an Agent: 3866 | agent.py 3867 | 3868 | Copy 3869 | 3870 | Ask AI 3871 | from phi.agent import Agent 3872 | from knowledge_base import knowledge_base 3873 | 3874 | agent = Agent( 3875 | knowledge_base=knowledge_base, 3876 | search_knowledge=True, 3877 | ) 3878 | agent.knowledge.load(recreate=False) 3879 | 3880 | agent.print_response("Ask me about something from the knowledge base") 3881 | ​ 3882 | Params 3883 | Parameter Type Default Description 3884 | path Union[str, Path] - Path to text files. Can point to a single txt file or a directory of txt files. 3885 | formats List[str] [".txt"] Formats accepted by this knowledge base. 3886 | reader TextReader TextReader() A TextReader that converts the text files into Documents for the vector database. 3887 | vector_db VectorDb - Vector Database for the Knowledge Base. 3888 | num_documents int 5 Number of documents to return on search. 3889 | optimize_on int - Number of documents to optimize the vector db on. 3890 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3891 | 3892 | 3893 | Knowledge 3894 | Website Knowledge Base 3895 | The WebsiteKnowledgeBase reads websites, converts them into vector embeddings and loads them to a vector_db. 3896 | ​ 3897 | Usage 3898 | We are using a local PgVector database for this example. Make sure it’s running 3899 | 3900 | Copy 3901 | 3902 | Ask AI 3903 | pip install bs4 3904 | knowledge_base.py 3905 | 3906 | Copy 3907 | 3908 | Ask AI 3909 | from phi.knowledge.website import WebsiteKnowledgeBase 3910 | from phi.vectordb.pgvector import PgVector 3911 | 3912 | knowledge_base = WebsiteKnowledgeBase( 3913 | urls=["https://docs.phidata.com/introduction"], 3914 | # Number of links to follow from the seed URLs 3915 | max_links=10, 3916 | # Table name: ai.website_documents 3917 | vector_db=PgVector( 3918 | table_name="website_documents", 3919 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 3920 | ), 3921 | ) 3922 | Then use the knowledge_base with an Agent: 3923 | agent.py 3924 | 3925 | Copy 3926 | 3927 | Ask AI 3928 | from phi.agent import Agent 3929 | from knowledge_base import knowledge_base 3930 | 3931 | agent = Agent( 3932 | knowledge=knowledge_base, 3933 | search_knowledge=True, 3934 | ) 3935 | agent.knowledge.load(recreate=False) 3936 | 3937 | agent.print_response("Ask me about something from the knowledge base") 3938 | ​ 3939 | Params 3940 | Parameter Type Default Description 3941 | urls List[str] - URLs to read 3942 | reader WebsiteReader - A WebsiteReader that reads the urls and converts them into Documents for the vector database. 3943 | max_depth int 3 Maximum depth to crawl. 3944 | max_links int 10 Number of links to crawl. 3945 | vector_db VectorDb - Vector Database for the Knowledge Base. 3946 | num_documents int 5 Number of documents to return on search. 3947 | optimize_on int - Number of documents to optimize the vector db on. 3948 | chunking_strategy ChunkingStrategy FixedSizeChunking The chunking strategy to use. 3949 | 3950 | 3951 | 3952 | Chunking 3953 | Fixed Size Chunking 3954 | Fixed size chunking is a method of splitting documents into smaller chunks of a specified size, with optional overlap between chunks. This is useful when you want to process large documents in smaller, manageable pieces. 3955 | ​ 3956 | Usage 3957 | 3958 | Copy 3959 | 3960 | Ask AI 3961 | from phi.agent import Agent 3962 | from phi.document.chunking.fixed import FixedSizeChunking 3963 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 3964 | from phi.vectordb.pgvector import PgVector 3965 | 3966 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 3967 | 3968 | knowledge_base = PDFUrlKnowledgeBase( 3969 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 3970 | vector_db=PgVector(table_name="recipes_fixed_size_chunking", db_url=db_url), 3971 | chunking_strategy=FixedSizeChunking(), 3972 | ) 3973 | knowledge_base.load(recreate=False) # Comment out after first run 3974 | 3975 | agent = Agent( 3976 | knowledge_base=knowledge_base, 3977 | search_knowledge=True, 3978 | ) 3979 | 3980 | agent.print_response("How to make Thai curry?", markdown=True) 3981 | ​ 3982 | Params 3983 | Parameter Type Default Description 3984 | chunk_size int 5000 The maximum size of each chunk. 3985 | overlap int 0 The number of characters to overlap between chunks. 3986 | 3987 | 3988 | Chunking 3989 | Agentic Chunking 3990 | Agentic chunking is an intelligent method of splitting documents into smaller chunks by using an LLM to determine natural breakpoints in the text. Rather than splitting text at fixed character counts, it analyzes the content to find semantically meaningful boundaries like paragraph breaks and topic transitions. 3991 | ​ 3992 | Usage 3993 | 3994 | Copy 3995 | 3996 | Ask AI 3997 | from phi.agent import Agent 3998 | from phi.document.chunking.agentic import AgenticChunking 3999 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4000 | from phi.vectordb.pgvector import PgVector 4001 | 4002 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4003 | 4004 | knowledge_base = PDFUrlKnowledgeBase( 4005 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4006 | vector_db=PgVector(table_name="recipes_agentic_chunking", db_url=db_url), 4007 | chunking_strategy=AgenticChunking(), 4008 | ) 4009 | knowledge_base.load(recreate=False) # Comment out after first run 4010 | 4011 | agent = Agent( 4012 | knowledge_base=knowledge_base, 4013 | search_knowledge=True, 4014 | ) 4015 | 4016 | agent.print_response("How to make Thai curry?", markdown=True) 4017 | ​ 4018 | Params 4019 | Parameter Type Default Description 4020 | model Model OpenAIChat The model to use for chunking. 4021 | max_chunk_size int 5000 The maximum size of each chunk. 4022 | 4023 | 4024 | Chunking 4025 | Semantic Chunking 4026 | Semantic chunking is a method of splitting documents into smaller chunks by analyzing semantic similarity between text segments using embeddings. It uses the chonkie library to identify natural breakpoints where the semantic meaning changes significantly, based on a configurable similarity threshold. This helps preserve context and meaning better than fixed-size chunking by ensuring semantically related content stays together in the same chunk, while splitting occurs at meaningful topic transitions. 4027 | 4028 | Copy 4029 | 4030 | Ask AI 4031 | from phi.agent import Agent 4032 | from phi.document.chunking.semantic import SemanticChunking 4033 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4034 | from phi.vectordb.pgvector import PgVector 4035 | 4036 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4037 | 4038 | knowledge_base = PDFUrlKnowledgeBase( 4039 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4040 | vector_db=PgVector(table_name="recipes_semantic_chunking", db_url=db_url), 4041 | chunking_strategy=SemanticChunking(), 4042 | ) 4043 | knowledge_base.load(recreate=False) # Comment out after first run 4044 | 4045 | agent = Agent( 4046 | knowledge_base=knowledge_base, 4047 | search_knowledge=True, 4048 | ) 4049 | 4050 | agent.print_response("How to make Thai curry?", markdown=True) 4051 | 4052 | ​ 4053 | Params 4054 | Parameter Type Default Description 4055 | embedder Embedder OpenAIEmbedder The embedder to use for semantic chunking. 4056 | chunk_size int 5000 The maximum size of each chunk. 4057 | similarity_threshold float 0.5 The similarity threshold for determining chunk boundaries. 4058 | 4059 | 4060 | Chunking 4061 | Recursive Chunking 4062 | Recursive chunking is a method of splitting documents into smaller chunks by recursively applying a chunking strategy. This is useful when you want to process large documents in smaller, manageable pieces. 4063 | 4064 | Copy 4065 | 4066 | Ask AI 4067 | from phi.agent import Agent 4068 | from phi.document.chunking.recursive import RecursiveChunking 4069 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4070 | from phi.vectordb.pgvector import PgVector 4071 | 4072 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4073 | 4074 | knowledge_base = PDFUrlKnowledgeBase( 4075 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4076 | vector_db=PgVector(table_name="recipes_recursive_chunking", db_url=db_url), 4077 | chunking_strategy=RecursiveChunking(), 4078 | ) 4079 | knowledge_base.load(recreate=False) # Comment out after first run 4080 | 4081 | agent = Agent( 4082 | knowledge_base=knowledge_base, 4083 | search_knowledge=True, 4084 | ) 4085 | 4086 | agent.print_response("How to make Thai curry?", markdown=True) 4087 | 4088 | ​ 4089 | Params 4090 | Parameter Type Default Description 4091 | chunk_size int 5000 The maximum size of each chunk. 4092 | overlap int 0 The number of characters to overlap between chunks. 4093 | 4094 | 4095 | Chunking 4096 | Document Chunking 4097 | Document chunking is a method of splitting documents into smaller chunks based on document structure like paragraphs and sections. It analyzes natural document boundaries rather than splitting at fixed character counts. This is useful when you want to process large documents while preserving semantic meaning and context. 4098 | ​ 4099 | Usage 4100 | 4101 | Copy 4102 | 4103 | Ask AI 4104 | from phi.agent import Agent 4105 | from phi.document.chunking.document import DocumentChunking 4106 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4107 | from phi.vectordb.pgvector import PgVector 4108 | 4109 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4110 | 4111 | knowledge_base = PDFUrlKnowledgeBase( 4112 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4113 | vector_db=PgVector(table_name="recipes_document_chunking", db_url=db_url), 4114 | chunking_strategy=DocumentChunking(), 4115 | ) 4116 | knowledge_base.load(recreate=False) # Comment out after first run 4117 | 4118 | agent = Agent( 4119 | knowledge_base=knowledge_base, 4120 | search_knowledge=True, 4121 | ) 4122 | 4123 | agent.print_response("How to make Thai curry?", markdown=True) 4124 | 4125 | ​ 4126 | Params 4127 | Parameter Type Default Description 4128 | chunk_size int 5000 The maximum size of each chunk. 4129 | overlap int 0 The number of characters to overlap between chunks. 4130 | 4131 | 4132 | 4133 | Storage 4134 | Introduction 4135 | Agents come with built-in memory but it only lasts while the session is active. To continue conversations across sessions, we store Agent sessions in a database like PostgreSQL. 4136 | Storage is a necessary component when building user facing AI products as any production application will require users to be able to “continue” their conversation with the Agent. 4137 | The general syntax for adding storage to an Agent looks like: 4138 | storage.py 4139 | 4140 | Copy 4141 | 4142 | Ask AI 4143 | from phi.agent import Agent 4144 | from phi.model.openai import OpenAIChat 4145 | from phi.tools.duckduckgo import DuckDuckGo 4146 | from phi.storage.agent.postgres import PgAgentStorage 4147 | 4148 | agent = Agent( 4149 | model=OpenAIChat(id="gpt-4o"), 4150 | storage=PgAgentStorage(table_name="agent_sessions", db_url="postgresql+psycopg://ai:ai@localhost:5532/ai"), 4151 | tools=[DuckDuckGo()], 4152 | show_tool_calls=True, 4153 | add_history_to_messages=True, 4154 | ) 4155 | agent.print_response("How many people live in Canada?") 4156 | agent.print_response("What is their national anthem called?") 4157 | agent.print_response("Which country are we speaking about?") 4158 | The following databases are supported as a storage backend: 4159 | PostgreSQL 4160 | Sqlite 4161 | SingleStore 4162 | DynamoDB 4163 | MongoDB 4164 | 4165 | 4166 | 4167 | Storage 4168 | Postgres Agent Storage 4169 | Phidata supports using PostgreSQL as a storage backend for Agents using the PgAgentStorage class. 4170 | ​ 4171 | Usage 4172 | ​ 4173 | Run PgVector 4174 | Install docker desktop and run PgVector on port 5532 using: 4175 | 4176 | Copy 4177 | 4178 | Ask AI 4179 | docker run -d \ 4180 | -e POSTGRES_DB=ai \ 4181 | -e POSTGRES_USER=ai \ 4182 | -e POSTGRES_PASSWORD=ai \ 4183 | -e PGDATA=/var/lib/postgresql/data/pgdata \ 4184 | -v pgvolume:/var/lib/postgresql/data \ 4185 | -p 5532:5432 \ 4186 | --name pgvector \ 4187 | phidata/pgvector:16 4188 | storage.py 4189 | 4190 | Copy 4191 | 4192 | Ask AI 4193 | from phi.storage.agent.postgres import PgAgentStorage 4194 | 4195 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4196 | 4197 | # Create a storage backend using the Postgres database 4198 | storage = PgAgentStorage( 4199 | # store sessions in the ai.sessions table 4200 | table_name="agent_sessions", 4201 | # db_url: Postgres database URL 4202 | db_url=db_url, 4203 | ) 4204 | 4205 | # Add storage to the Agent 4206 | agent = Agent(storage=storage) 4207 | ​ 4208 | Params 4209 | Parameter Type Default Description 4210 | table_name str - Name of the table to be used. 4211 | schema Optional[str] "ai" Schema name, default is "ai". 4212 | db_url Optional[str] None Database URL, if provided. 4213 | db_engine Optional[Engine] None Database engine to be used. 4214 | schema_version int 1 Version of the schema, default is 1. 4215 | auto_upgrade_schema bool False If true, automatically upgrades the schema when necessary. 4216 | 4217 | 4218 | 4219 | Storage 4220 | Sqlite Agent Storage 4221 | Phidata supports using Sqlite as a storage backend for Agents using the SqlAgentStorage class. 4222 | ​ 4223 | Usage 4224 | You need to provide either db_url, db_file or db_engine. The following example uses db_file. 4225 | storage.py 4226 | 4227 | Copy 4228 | 4229 | Ask AI 4230 | from phi.storage.agent.sqlite import SqlAgentStorage 4231 | 4232 | # Create a storage backend using the Sqlite database 4233 | storage = SqlAgentStorage( 4234 | # store sessions in the ai.sessions table 4235 | table_name="agent_sessions", 4236 | # db_file: Sqlite database file 4237 | db_file="tmp/data.db", 4238 | ) 4239 | 4240 | # Add storage to the Agent 4241 | agent = Agent(storage=storage) 4242 | ​ 4243 | Params 4244 | Parameter Type Default Description 4245 | table_name str - Name of the table to be used. 4246 | schema Optional[str] "ai" Schema name, default is "ai". 4247 | db_url Optional[str] None Database URL, if provided. 4248 | db_engine Optional[Engine] None Database engine to be used. 4249 | schema_version int 1 Version of the schema, default is 1. 4250 | auto_upgrade_schema bool False If true, automatically upgrades the schema when necessary. 4251 | 4252 | 4253 | 4254 | Embeddings 4255 | Gemini Embedder 4256 | The GeminiEmbedder class is used to embed text data into vectors using the Gemini API. You can get one from here. 4257 | ​ 4258 | Usage 4259 | cookbook/embedders/gemini_embedder.py 4260 | 4261 | Copy 4262 | 4263 | Ask AI 4264 | from phi.agent import AgentKnowledge 4265 | from phi.vectordb.pgvector import PgVector 4266 | from phi.embedder.google import GeminiEmbedder 4267 | 4268 | embeddings = GeminiEmbedder().get_embedding("The quick brown fox jumps over the lazy dog.") 4269 | 4270 | # Print the embeddings and their dimensions 4271 | print(f"Embeddings: {embeddings[:5]}") 4272 | print(f"Dimensions: {len(embeddings)}") 4273 | 4274 | # Example usage: 4275 | knowledge_base = AgentKnowledge( 4276 | vector_db=PgVector( 4277 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 4278 | table_name="gemini_embeddings", 4279 | embedder=GeminiEmbedder(), 4280 | ), 4281 | num_documents=2, 4282 | ) 4283 | ​ 4284 | Params 4285 | Parameter Type Default Description 4286 | dimensions int 768 The dimensionality of the generated embeddings 4287 | model str models/text-embedding-004 The name of the Gemini model to use 4288 | task_type str - The type of task for which embeddings are being generated 4289 | title str - Optional title for the embedding task 4290 | api_key str - The API key used for authenticating requests. 4291 | request_params Optional[Dict[str, Any]] - Optional dictionary of parameters for the embedding request 4292 | client_params Optional[Dict[str, Any]] - Optional dictionary of parameters for the Gemini client 4293 | gemini_client Optional[Client] - Optional pre-configured Gemini client instance 4294 | 4295 | 4296 | 4297 | Embeddings 4298 | Mistral Embedder 4299 | The MistralEmbedder class is used to embed text data into vectors using the Mistral API. Get your key from here. 4300 | ​ 4301 | Usage 4302 | cookbook/embedders/mistral_embedder.py 4303 | 4304 | Copy 4305 | 4306 | Ask AI 4307 | from phi.agent import AgentKnowledge 4308 | from phi.vectordb.pgvector import PgVector 4309 | from phi.embedder.mistral import MistralEmbedder 4310 | 4311 | embeddings = MistralEmbedder().get_embedding("The quick brown fox jumps over the lazy dog.") 4312 | 4313 | # Print the embeddings and their dimensions 4314 | print(f"Embeddings: {embeddings[:5]}") 4315 | print(f"Dimensions: {len(embeddings)}") 4316 | 4317 | # Example usage: 4318 | knowledge_base = AgentKnowledge( 4319 | vector_db=PgVector( 4320 | db_url="postgresql+psycopg://ai:ai@localhost:5532/ai", 4321 | table_name="mistral_embeddings", 4322 | embedder=MistralEmbedder(), 4323 | ), 4324 | num_documents=2, 4325 | ) 4326 | ​ 4327 | Params 4328 | Parameter Type Default Description 4329 | model str "mistral-embed" The name of the model used for generating embeddings. 4330 | dimensions int 1024 The dimensionality of the embeddings generated by the model. 4331 | request_params Optional[Dict[str, Any]] - Additional parameters to include in the API request. Optional. 4332 | api_key str - The API key used for authenticating requests. 4333 | endpoint str - The endpoint URL for the API requests. 4334 | max_retries Optional[int] - The maximum number of retries for API requests. Optional. 4335 | timeout Optional[int] - The timeout duration for API requests. Optional. 4336 | client_params Optional[Dict[str, Any]] - Additional parameters for configuring the API client. Optional. 4337 | mistral_client Optional[MistralClient] - An instance of the MistralClient to use for making API requests. Optional. 4338 | 4339 | 4340 | 4341 | Workflows 4342 | Introduction 4343 | Workflows are deterministic, stateful, multi-agent pipelines that power many of our production use cases. They are incredibly powerful and offer the following benefits: 4344 | Control and Flexibility: You have full control over the multi-agent process, how the input is processed, which agents are used and in what order. 4345 | Built-in Memory: You can store state and cache results in a database at any time, meaning your agents can re-use results from previous steps. 4346 | Defined as a python class: You do not need to learn a new framework, its just python. 4347 | How to build a workflow: 4348 | Define your workflow as a class by inheriting from the Workflow class 4349 | Add one or more agents to the workflow 4350 | Implement your logic in the run() method 4351 | Cache results in the session_state as needed 4352 | Run the workflow using the .run() method 4353 | ​ 4354 | Example: Blog Post Generator 4355 | Let’s create a blog post generator that can search the web, read the top links and write a blog post for us. We’ll cache intermediate results in the database to improve performance. 4356 | ​ 4357 | Create the Workflow 4358 | Create a file blog_post_generator.py 4359 | blog_post_generator.py 4360 | 4361 | Copy 4362 | 4363 | Ask AI 4364 | import json 4365 | from typing import Optional, Iterator 4366 | 4367 | from pydantic import BaseModel, Field 4368 | 4369 | from phi.agent import Agent 4370 | from phi.workflow import Workflow, RunResponse, RunEvent 4371 | from phi.storage.workflow.sqlite import SqlWorkflowStorage 4372 | from phi.tools.duckduckgo import DuckDuckGo 4373 | from phi.utils.pprint import pprint_run_response 4374 | from phi.utils.log import logger 4375 | 4376 | 4377 | class NewsArticle(BaseModel): 4378 | title: str = Field(..., description="Title of the article.") 4379 | url: str = Field(..., description="Link to the article.") 4380 | summary: Optional[str] = Field(..., description="Summary of the article if available.") 4381 | 4382 | 4383 | class SearchResults(BaseModel): 4384 | articles: list[NewsArticle] 4385 | 4386 | 4387 | class BlogPostGenerator(Workflow): 4388 | searcher: Agent = Agent( 4389 | tools=[DuckDuckGo()], 4390 | instructions=["Given a topic, search for 20 articles and return the 5 most relevant articles."], 4391 | response_model=SearchResults, 4392 | ) 4393 | 4394 | writer: Agent = Agent( 4395 | instructions=[ 4396 | "You will be provided with a topic and a list of top articles on that topic.", 4397 | "Carefully read each article and generate a New York Times worthy blog post on that topic.", 4398 | "Break the blog post into sections and provide key takeaways at the end.", 4399 | "Make sure the title is catchy and engaging.", 4400 | "Always provide sources, do not make up information or sources.", 4401 | ], 4402 | ) 4403 | 4404 | def run(self, topic: str, use_cache: bool = True) -> Iterator[RunResponse]: 4405 | logger.info(f"Generating a blog post on: {topic}") 4406 | 4407 | # Use the cached blog post if use_cache is True 4408 | if use_cache and "blog_posts" in self.session_state: 4409 | logger.info("Checking if cached blog post exists") 4410 | for cached_blog_post in self.session_state["blog_posts"]: 4411 | if cached_blog_post["topic"] == topic: 4412 | logger.info("Found cached blog post") 4413 | yield RunResponse( 4414 | run_id=self.run_id, 4415 | event=RunEvent.workflow_completed, 4416 | content=cached_blog_post["blog_post"], 4417 | ) 4418 | return 4419 | 4420 | # Step 1: Search the web for articles on the topic 4421 | num_tries = 0 4422 | search_results: Optional[SearchResults] = None 4423 | # Run until we get a valid search results 4424 | while search_results is None and num_tries < 3: 4425 | try: 4426 | num_tries += 1 4427 | searcher_response: RunResponse = self.searcher.run(topic) 4428 | if ( 4429 | searcher_response 4430 | and searcher_response.content 4431 | and isinstance(searcher_response.content, SearchResults) 4432 | ): 4433 | logger.info(f"Searcher found {len(searcher_response.content.articles)} articles.") 4434 | search_results = searcher_response.content 4435 | else: 4436 | logger.warning("Searcher response invalid, trying again...") 4437 | except Exception as e: 4438 | logger.warning(f"Error running searcher: {e}") 4439 | 4440 | # If no search_results are found for the topic, end the workflow 4441 | if search_results is None or len(search_results.articles) == 0: 4442 | yield RunResponse( 4443 | run_id=self.run_id, 4444 | event=RunEvent.workflow_completed, 4445 | content=f"Sorry, could not find any articles on the topic: {topic}", 4446 | ) 4447 | return 4448 | 4449 | # Step 2: Write a blog post 4450 | logger.info("Writing blog post") 4451 | # Prepare the input for the writer 4452 | writer_input = { 4453 | "topic": topic, 4454 | "articles": [v.model_dump() for v in search_results.articles], 4455 | } 4456 | # Run the writer and yield the response 4457 | yield from self.writer.run(json.dumps(writer_input, indent=4), stream=True) 4458 | 4459 | # Save the blog post in the session state for future runs 4460 | if "blog_posts" not in self.session_state: 4461 | self.session_state["blog_posts"] = [] 4462 | self.session_state["blog_posts"].append({"topic": topic, "blog_post": self.writer.run_response.content}) 4463 | 4464 | 4465 | # The topic to generate a blog post on 4466 | topic = "US Elections 2024" 4467 | 4468 | # Create the workflow 4469 | generate_blog_post = BlogPostGenerator( 4470 | session_id=f"generate-blog-post-on-{topic}", 4471 | storage=SqlWorkflowStorage( 4472 | table_name="generate_blog_post_workflows", 4473 | db_file="tmp/workflows.db", 4474 | ), 4475 | ) 4476 | 4477 | # Run workflow 4478 | blog_post: Iterator[RunResponse] = generate_blog_post.run(topic=topic, use_cache=True) 4479 | 4480 | # Print the response 4481 | pprint_run_response(blog_post, markdown=True) 4482 | ​ 4483 | Run the workflow 4484 | Install libraries 4485 | 4486 | Copy 4487 | 4488 | Ask AI 4489 | pip install phidata openai duckduckgo-search sqlalchemy phidata 4490 | Run the workflow 4491 | 4492 | Copy 4493 | 4494 | Ask AI 4495 | python blog_post_generator.py 4496 | Now the results are cached in the database and can be re-used for future runs. Run the workflow again to view the cached results. 4497 | 4498 | Copy 4499 | 4500 | Ask AI 4501 | python blog_post_generator.py 4502 | 4503 | 4504 | 4505 | Workflows 4506 | Session State 4507 | Use the session_state to cache intermediate results in a database. 4508 | 4509 | All Workflows come with a session_state dictionary that you can use to cache intermediate results. Provide your workflows with storage and a session_id to enable caching. 4510 | For example, you can use the SqlWorkflowStorage to cache results in a Sqlite database. 4511 | 4512 | Copy 4513 | 4514 | Ask AI 4515 | # Create the workflow 4516 | generate_blog_post = BlogPostGenerator( 4517 | session_id="my-session-id", 4518 | storage=SqlWorkflowStorage( 4519 | table_name="generate_blog_post_workflows", 4520 | db_file="tmp/workflows.db", 4521 | ), 4522 | ) 4523 | Then in the run() method, you can read from and add to the session_state as needed. 4524 | 4525 | Copy 4526 | 4527 | Ask AI 4528 | 4529 | class BlogPostGenerator(Workflow): 4530 | # ... agents 4531 | def run(self, topic: str, use_cache: bool = True) -> Iterator[RunResponse]: 4532 | # Read from the session state cache 4533 | if use_cache and "blog_posts" in self.session_state: 4534 | logger.info("Checking if cached blog post exists") 4535 | for cached_blog_post in self.session_state["blog_posts"]: 4536 | if cached_blog_post["topic"] == topic: 4537 | logger.info("Found cached blog post") 4538 | yield RunResponse( 4539 | run_id=self.run_id, 4540 | event=RunEvent.workflow_completed, 4541 | content=cached_blog_post["blog_post"], 4542 | ) 4543 | return 4544 | 4545 | # ... generate the blog post 4546 | 4547 | # Save to session state for future runs 4548 | if "blog_posts" not in self.session_state: 4549 | self.session_state["blog_posts"] = [] 4550 | self.session_state["blog_posts"].append({"topic": topic, "blog_post": self.writer.run_response.content}) 4551 | When the workflow starts, the session_state for that particular session_id is read from the database and when the workflow ends, the session_state is stored in the database. 4552 | You can always call self.write_to_storage() to save the session_state to the database at any time. Incase you need to abort the workflow but want to store the intermediate results. 4553 | 4554 | 4555 | 4556 | Workflows 4557 | Streaming 4558 | Workflows are all about control and flexibility. You have full control over the multi-agent process, how the input is processed, which agents are used and in what order. 4559 | You also have full control over how the output is streamed. 4560 | ​ 4561 | Streaming 4562 | To stream the output, yield an Iterator[RunResponse] from the run() method of your workflow. 4563 | news_report_generator.py 4564 | 4565 | Copy 4566 | 4567 | Ask AI 4568 | # Define the workflow 4569 | class GenerateNewsReport(Workflow): 4570 | agent_1: Agent = ... 4571 | 4572 | agent_2: Agent = ... 4573 | 4574 | agent_3: Agent = ... 4575 | 4576 | def run(self, ...) -> Iterator[RunResponse]: 4577 | # Run agents and gather the response 4578 | # These can be batch responses, you can also stream intermediate results if you want 4579 | final_agent_input = ... 4580 | 4581 | # Generate the final response from the writer agent 4582 | agent_3_response_stream: Iterator[RunResponse] = self.agent_3.run(final_agent_input, stream=True) 4583 | 4584 | # Yield the response 4585 | yield agent_3_response_stream 4586 | 4587 | 4588 | # Instantiate the workflow 4589 | generate_news_report = GenerateNewsReport() 4590 | 4591 | # Run workflow and get the response as an iterator of RunResponse objects 4592 | report_stream: Iterator[RunResponse] = generate_news_report.run(...) 4593 | 4594 | # Print the response 4595 | pprint_run_response(report_stream, markdown=True) 4596 | ​ 4597 | Batch 4598 | Simply return a RunResponse object from the run() method of your workflow to return a single output. 4599 | news_report_generator.py 4600 | 4601 | Copy 4602 | 4603 | Ask AI 4604 | # Define the workflow 4605 | class GenerateNewsReport(Workflow): 4606 | agent_1: Agent = ... 4607 | 4608 | agent_2: Agent = ... 4609 | 4610 | agent_3: Agent = ... 4611 | 4612 | def run(self, ...) -> RunResponse: 4613 | # Run agents and gather the response 4614 | final_agent_input = ... 4615 | 4616 | # Generate the final response from the writer agent 4617 | agent_3_response: RunResponse = self.agent_3.run(final_agent_input) 4618 | 4619 | # Return the response 4620 | return agent_3_response 4621 | 4622 | 4623 | # Instantiate the workflow 4624 | generate_news_report = GenerateNewsReport() 4625 | 4626 | # Run workflow and get the response as a RunResponse object 4627 | report: RunResponse = generate_news_report.run(...) 4628 | 4629 | # Print the response 4630 | pprint_run_response(report, markdown=True) 4631 | 4632 | 4633 | 4634 | How To 4635 | Install & Upgrade 4636 | ​ 4637 | Install phidata 4638 | We recommend installing phidata using pip in a python virtual environment 4639 | 1 4640 | Create a virtual environment 4641 | 4642 | Open the Terminal and create a python virtual environment. 4643 | 4644 | Mac 4645 | 4646 | Windows 4647 | 4648 | Copy 4649 | 4650 | Ask AI 4651 | python3 -m venv ~/.venvs/aienv 4652 | source ~/.venvs/aienv/bin/activate 4653 | 2 4654 | Install phidata 4655 | 4656 | Install the latest version of phidata 4657 | 4658 | Mac 4659 | 4660 | Windows 4661 | 4662 | Copy 4663 | 4664 | Ask AI 4665 | pip install -U phidata 4666 | If you encounter errors, try updating pip using python -m pip install --upgrade pip 4667 | ​ 4668 | Upgrade phidata 4669 | To upgrade phidata, run this inside your virtual environment 4670 | 4671 | Copy 4672 | 4673 | Ask AI 4674 | pip install -U phidata --no-cache-dir 4675 | 4676 | 4677 | 4678 | Upgrade to v2.5.0 4679 | This guide will help you migrate your code to v2.5.0 4680 | ​ 4681 | Key Changes 4682 | Constructor: Assistant() -> Agent() 4683 | LLM/Model: llm -> model 4684 | Knowledge Base: knowledge_base -> knowledge 4685 | RunResponse: Pydantic model for string response 4686 | Structured Output: Changes in how structured output is handled 4687 | ​ 4688 | Detailed Migration Steps 4689 | ​ 4690 | 1. Update Import Statements 4691 | 4692 | Copy 4693 | 4694 | Ask AI 4695 | # Version < 2.5.0 4696 | from phi.assistant import Assistant 4697 | from phi.llm.openai import OpenAIChat 4698 | from phi.storage.assistant.postgres import PgAssistantStorage 4699 | 4700 | # Version >= 2.5.0 4701 | from phi.agent import Agent 4702 | from phi.model.openai import OpenAIChat 4703 | from phi.storage.agent.postgres import PgAgentStorage 4704 | ​ 4705 | 2. Update Arguments 4706 | Replace llm with model and model with id. 4707 | 4708 | Copy 4709 | 4710 | Ask AI 4711 | # Version < 2.5.0 4712 | from phi.assistant import Assistant 4713 | from phi.llm.openai import OpenAIChat 4714 | 4715 | assistant = Assistant( 4716 | llm=OpenAIChat(model="gpt-4o"), 4717 | ) 4718 | 4719 | # Version >= 2.5.0 4720 | from phi.agent import Agent 4721 | from phi.model.openai import OpenAIChat 4722 | 4723 | agent = Agent( 4724 | # Note: 'llm' is now 'model' and 'model' is now 'id' 4725 | model=OpenAIChat(id="gpt-4o"), 4726 | ) 4727 | ​ 4728 | 3. Update Knowledge Base 4729 | Replace knowledge_base with knowledge. 4730 | 4731 | Copy 4732 | 4733 | Ask AI 4734 | # Version < 2.5.0 4735 | from phi.assistant import Assistant 4736 | from phi.storage.assistant.postgres import PgAssistantStorage 4737 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4738 | from phi.vectordb.pgvector import PgVector2 4739 | from phi.llm.openai import OpenAIChat 4740 | 4741 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4742 | 4743 | knowledge_base = PDFUrlKnowledgeBase( 4744 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4745 | vector_db=PgVector2(collection="recipes", db_url=db_url), 4746 | ) 4747 | 4748 | # Comment out after first run 4749 | knowledge_base.load() 4750 | 4751 | storage = PgAssistantStorage(table_name="pdf_assistant", db_url=db_url) 4752 | 4753 | assistant = Assistant( 4754 | llm=OpenAIChat(model="gpt-4o"), 4755 | knowledge_base=knowledge_base, 4756 | search_knowledge=True, # enables agent to search knowledge base 4757 | storage=storage, 4758 | ) 4759 | 4760 | res = assistant.run("What is the recipe for chicken curry?") 4761 | 4762 | 4763 | # Version >= 2.5.0 4764 | from phi.agent import Agent, RunResponse 4765 | from phi.storage.agent.postgres import PgAgentStorage 4766 | from phi.knowledge.pdf import PDFUrlKnowledgeBase 4767 | from phi.vectordb.pgvector import PgVector, SearchType 4768 | from phi.model.openai import OpenAIChat 4769 | 4770 | db_url = "postgresql+psycopg://ai:ai@localhost:5532/ai" 4771 | 4772 | knowledge_base = PDFUrlKnowledgeBase( 4773 | urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], 4774 | vector_db=PgVector(table_name="recipes", db_url=db_url, search_type=SearchType.hybrid), 4775 | ) 4776 | 4777 | # Comment out after first run 4778 | knowledge_base.load() 4779 | 4780 | storage = PgAgentStorage(table_name="pdf_agent", db_url=db_url) 4781 | 4782 | agent = Agent( 4783 | model=OpenAIChat(id="gpt-4o"), 4784 | knowledge=knowledge_base, 4785 | storage=storage, 4786 | ) 4787 | 4788 | response: RunResponse = agent.run("What is the recipe for chicken curry?") 4789 | res = response.content 4790 | ​ 4791 | 4. Output model response as a string 4792 | 4793 | Copy 4794 | 4795 | Ask AI 4796 | # Version < 2.5.0 4797 | from phi.assistant import Assistant 4798 | from phi.llm.openai import OpenAIChat 4799 | 4800 | assistant = Assistant( 4801 | llm=OpenAIChat(model="gpt-4o"), 4802 | ) 4803 | 4804 | res = assistant.run("What is the recipe for chicken curry?") 4805 | 4806 | # Version >= 2.5.0 4807 | from phi.agent import Agent, RunResponse 4808 | from phi.model.openai import OpenAIChat 4809 | 4810 | agent = Agent( 4811 | model=OpenAIChat(id="gpt-4o"), 4812 | ) 4813 | 4814 | response: RunResponse = agent.run("What is the recipe for chicken curry?") 4815 | res = response.content 4816 | ​ 4817 | 5. Handle structured outputs 4818 | Replace output_model with response_model. 4819 | If you are using OpenAI models, you can set structured_outputs=True to get a structured output. 4820 | 4821 | Copy 4822 | 4823 | Ask AI 4824 | # Version < 2.5.0 4825 | from typing import List 4826 | from pydantic import BaseModel, Field 4827 | from rich.pretty import pprint 4828 | from phi.assistant import Assistant 4829 | from phi.llm.openai import OpenAIChat 4830 | 4831 | 4832 | class MovieScript(BaseModel): 4833 | setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.") 4834 | ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.") 4835 | genre: str = Field( 4836 | ..., description="Genre of the movie. If not available, select action, thriller or romantic comedy." 4837 | ) 4838 | name: str = Field(..., description="Give a name to this movie") 4839 | characters: List[str] = Field(..., description="Name of characters for this movie.") 4840 | storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!") 4841 | 4842 | 4843 | movie_assistant = Assistant( 4844 | llm=OpenAIChat(model="gpt-4-turbo-preview"), 4845 | description="You help people write movie ideas.", 4846 | output_model=MovieScript, 4847 | ) 4848 | 4849 | pprint(movie_assistant.run("New York")) 4850 | 4851 | # Version >= 2.5.0 4852 | from typing import List 4853 | from rich.pretty import pprint 4854 | from pydantic import BaseModel, Field 4855 | from phi.agent import Agent, RunResponse 4856 | from phi.model.openai import OpenAIChat 4857 | 4858 | 4859 | class MovieScript(BaseModel): 4860 | setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.") 4861 | ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.") 4862 | genre: str = Field( 4863 | ..., description="Genre of the movie. If not available, select action, thriller or romantic comedy." 4864 | ) 4865 | name: str = Field(..., description="Give a name to this movie") 4866 | characters: List[str] = Field(..., description="Name of characters for this movie.") 4867 | storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!") 4868 | 4869 | 4870 | # Agent that uses JSON mode 4871 | json_mode_agent = Agent( 4872 | model=OpenAIChat(id="gpt-4o"), 4873 | description="You write movie scripts.", 4874 | response_model=MovieScript, 4875 | ) 4876 | 4877 | # Print the response 4878 | json_mode_agent.print_response("New York") 4879 | 4880 | # Get the response in a variable 4881 | json_mode_response: RunResponse = json_mode_agent.run("New York") 4882 | pprint(json_mode_response.content) 4883 | 4884 | 4885 | # Agent that uses structured outputs 4886 | # Note: `structured_output` only works with OpenAI models 4887 | structured_output_agent = Agent( 4888 | model=OpenAIChat(id="gpt-4o-2024-08-06"), 4889 | description="You write movie scripts.", 4890 | response_model=MovieScript, 4891 | structured_outputs=True, 4892 | ) 4893 | 4894 | # Print the response 4895 | structured_output_agent.print_response("New York") 4896 | 4897 | # Get the response in a variable 4898 | structured_output_response: RunResponse = structured_output_agent.run("New York") 4899 | print(structured_output_response.content) 4900 | 4901 | --------------------------------------------------------------------------------