From 7d9c047033bd59539fe0fbe11260379e54624d16 Mon Sep 17 00:00:00 2001 From: Blair Hudson Date: Fri, 17 Jan 2025 21:25:11 +1100 Subject: [PATCH] add walkthrough --- examples/FastAPI Agents Step-by-Step.ipynb | 226 +++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 examples/FastAPI Agents Step-by-Step.ipynb diff --git a/examples/FastAPI Agents Step-by-Step.ipynb b/examples/FastAPI Agents Step-by-Step.ipynb new file mode 100644 index 0000000..75b33f4 --- /dev/null +++ b/examples/FastAPI Agents Step-by-Step.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using FastAPI Agents\n", + "\n", + "This notebook walks you through the process of setting up a basic agent with Pydantic AI and FastAPI Agents for the first time step-by-step.\n", + "\n", + "To run this notebook, make sure you have `fastapi`, `fastapi-agents` and `pydantic-ai` installed (e.g. `pip install fastapi fastapi-agents pydantic-ai`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create your Pydantic AI Agent\n", + "\n", + "We're going to build a very simple agent to demo the combined power of these tools, a todo list manager!\n", + "\n", + "Before running this, make sure `OPENAI_API_KEY` is set in your environment variables. If you need it, also set `OPENAI_BASE_URL` (e.g. if you are using models from GitHub Models).\n", + "\n", + "To go to production we probably need to persist our todo lists somewhere like a database, but this is fine for a demo." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import List\n", + "from pydantic_ai import Agent\n", + "\n", + "todo_agent = Agent(\n", + " \"openai:gpt-4o-mini\",\n", + " system_prompt=\"You are managing the user's todo list.\"\n", + ")\n", + "\n", + "todos: List[str] = []\n", + "\n", + "@todo_agent.tool\n", + "def list_todos(context):\n", + " return f\"{len(todos)} todos: {\"\".join(todos) if len(todos) > 0 else \"empty\"}\"\n", + "\n", + "@todo_agent.tool\n", + "def add_todo(context, description: str):\n", + " todos.append(description)\n", + " return f\"added {description} to todos\"\n", + "\n", + "@todo_agent.tool\n", + "def delete_todo(context, description: str):\n", + " todos.remove(description)\n", + " return f\"removed {description} from todos\"\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test your agent\n", + "\n", + "Let's make sure it works!\n", + "\n", + "Since we are using Jupyter which uses asyncio for execution, we need to tell asyncio to nest the execution loop so we execute our Pydantic AI, which also uses asyncio. (You won't need this outside of Jupyter.)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"I've added the following todos for you:\\n\\n1. Buy groceries\\n2. Complete the project report\\n3. Go for a 30-minute walk\\n\\nYou need to complete these tasks!\"" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import nest_asyncio\n", + "nest_asyncio.apply()\n", + "\n", + "result = todo_agent.run_sync(\"make up 3 todos and add them then tell me what do i need to do\")\n", + "result.data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup FastAPI \n", + "\n", + "Start by creating your FastAPI instance. This gives us an app we can add our routes to and ultimately run." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from fastapi import FastAPI\n", + "app = FastAPI()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup FastAPI Agents\n", + "\n", + "We need to configure our FastAPIAgents router. A router is just a place in FastAPI where routes can be defined.\n", + "\n", + "Under the hood, FastAPIAgents is just a special kind of FastAPI APIRouter." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "from fastapi_agents import FastAPIAgents\n", + "\n", + "agents = FastAPIAgents(path_prefix=\"/agents\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can register our todo agent. FastAPI Agents comes with a set of agent adapters for various frameworks. These adapters wrap the agent and convert it to FastAPI Agents standard interface.\n", + "\n", + "We can then add the router to our FastAPI app. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from fastapi_agents.pydantic_ai import PydanticAIAgent\n", + "\n", + "agents.register(\"todo\", PydanticAIAgent(todo_agent))\n", + "app.include_router(agents)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Serve our agent with FastAPI Agents!\n", + "\n", + "Now we can start our app, serving our API with uvicorn.\n", + "\n", + "Uvicorn will find an available port and start our API.\n", + "\n", + "You can reach the docs at the endpoint `/docs` to interact with your agent through the API in your browser." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO: Started server process [80740]\n", + "INFO: Waiting for application startup.\n", + "INFO: Application startup complete.\n", + "INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO: 127.0.0.1:65520 - \"GET /docs HTTP/1.1\" 200 OK\n", + "INFO: 127.0.0.1:65520 - \"GET /openapi.json HTTP/1.1\" 200 OK\n", + "INFO: 127.0.0.1:65521 - \"POST /agents/todo HTTP/1.1\" 422 Unprocessable Entity\n", + "INFO: 127.0.0.1:65523 - \"POST /agents/todo HTTP/1.1\" 200 OK\n", + "INFO: 127.0.0.1:65525 - \"POST /agents/todo HTTP/1.1\" 200 OK\n", + "INFO: 127.0.0.1:65528 - \"POST /agents/todo HTTP/1.1\" 200 OK\n" + ] + } + ], + "source": [ + "import uvicorn\n", + "\n", + "uvicorn.run(app)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}