From 7717cd1b250e635bd83819c4a67c6958a14ae6d9 Mon Sep 17 00:00:00 2001 From: Pratyush Shukla Date: Fri, 3 Jan 2025 17:43:48 +0530 Subject: [PATCH] add examples and docs for smolagents --- docs/mint.json | 1 + docs/v1/examples/examples.mdx | 4 + docs/v1/integrations/smolagents.mdx | 82 ++++ .../multi_smolagents_system.ipynb | 282 ++++++++++++++ .../smolagents_examples/text_to_sql.ipynb | 366 ++++++++++++++++++ 5 files changed, 735 insertions(+) create mode 100644 docs/v1/integrations/smolagents.mdx create mode 100644 examples/smolagents_examples/multi_smolagents_system.ipynb create mode 100644 examples/smolagents_examples/text_to_sql.ipynb diff --git a/docs/mint.json b/docs/mint.json index 88959ae51..3fa8f6633 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -102,6 +102,7 @@ "v1/integrations/ollama", "v1/integrations/openai", "v1/integrations/rest", + "v1/integrations/smolagents", "v1/integrations/swarmzero", "v1/integrations/taskweaver", "v1/integrations/xai" diff --git a/docs/v1/examples/examples.mdx b/docs/v1/examples/examples.mdx index c67d1def4..120e9ec33 100644 --- a/docs/v1/examples/examples.mdx +++ b/docs/v1/examples/examples.mdx @@ -85,6 +85,10 @@ mode: "wide" Create a REST server that performs and observes agent tasks + } iconType="image" iconType="solid" href="/v1/examples/smolagents"> + Track HuggingFace's smolagents with AgentOps seamlessly + + } iconType="image" href="/v1/integrations/swarmzero"> SwarmZero multi-agent framework for AI Agents and AI Swarms with AgentOps support diff --git a/docs/v1/integrations/smolagents.mdx b/docs/v1/integrations/smolagents.mdx new file mode 100644 index 000000000..fed0ec8a3 --- /dev/null +++ b/docs/v1/integrations/smolagents.mdx @@ -0,0 +1,82 @@ +--- +title: smolagents +description: "Track HuggingFace's smolagents with AgentOps seamlessly" +--- + +import EnvTooltip from '/snippets/add-env-tooltip.mdx' + +[smolagents](https://github.com/huggingface/smolagents) is a framework for building and running AI agents from [HuggingFace](https://huggingface.co/). +Checkout their [docs](https://huggingface.co/docs/smolagents/index) to get started with creating your own agents. + +## Integrating AgentOps with smolagents + + + + + ```bash pip + pip install agentops + ``` + ```bash poetry + poetry add agentops + ``` + + + + + ```bash pip + pip install smolagents + ``` + ```bash poetry + poetry add smolagents + ``` + + + + + AgentOps tracks calls from smolagents via LiteLLM currently. + + + ```python python + import agentops + from smolagents import LiteLLMModel + + agentops.init() + model = LiteLLMModel() + + # Your code here... + + agentops.end_session('Success') + ``` + + + + ```python .env + AGENTOPS_API_KEY= + ``` + + Read more about environment variables in [Advanced Configuration](/v1/usage/advanced-configuration) + + + Execute your program and visit [app.agentops.ai/drilldown](https://app.agentops.ai/drilldown) to observe your Agent! 🕵️ + + After your run, AgentOps prints a clickable url to console linking directly to your session in the Dashboard + +
+ + + + + + +## Full Examples + +You can refer to the following examples - + +- [Text to SQL](https://github.com/AgentOps-AI/agentops/blob/main/examples/smolagents_examples/text_to_sql.ipynb) +- [Multi-Agent System](https://github.com/AgentOps-AI/agentops/blob/main/examples/smolagents_examples/multi_smolagents_system.ipynb) + + + + + + diff --git a/examples/smolagents_examples/multi_smolagents_system.ipynb b/examples/smolagents_examples/multi_smolagents_system.ipynb new file mode 100644 index 000000000..11aee7a7c --- /dev/null +++ b/examples/smolagents_examples/multi_smolagents_system.ipynb @@ -0,0 +1,282 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7d4c41ff", + "metadata": {}, + "source": [ + "# Orchestrate a Multi-Agent System\n", + "\n", + "In this notebook, we will make a multi-agent web browser: an agentic system with several agents collaborating to solve problems using the web!\n", + "\n", + "It will be a simple hierarchy, using a `ManagedAgent` object to wrap the managed web search agent:" + ] + }, + { + "cell_type": "markdown", + "id": "446d088d", + "metadata": {}, + "source": [ + "```\n", + "+----------------+\n", + "| Manager agent |\n", + "+----------------+\n", + " |\n", + "_________|______________\n", + "| |\n", + "Code interpreter +--------------------------------+\n", + " tool | Managed agent |\n", + " | +------------------+ |\n", + " | | Web Search agent | |\n", + " | +------------------+ |\n", + " | | | |\n", + " | Web Search tool | |\n", + " | Visit webpage tool |\n", + " +--------------------------------+\n", + "```\n", + "Let’s set up this system.\n", + "\n", + "Run the line below to install the required dependencies:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "015b0a87", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install markdownify\n", + "%pip install duckduckgo-search\n", + "%pip install smolagents\n", + "%pip install agentops" + ] + }, + { + "cell_type": "markdown", + "id": "00509499", + "metadata": {}, + "source": [ + "🖇️ Now we initialize the AgentOps client and load the environment variables to use the API keys." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "330770fd", + "metadata": {}, + "outputs": [], + "source": [ + "import agentops\n", + "from dotenv import load_dotenv\n", + "import os\n", + "\n", + "load_dotenv()\n", + "AGENTOPS_API_KEY = os.getenv(\"AGENTOPS_API_KEY\") or \"\"\n", + "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\") or \"\"" + ] + }, + { + "cell_type": "markdown", + "id": "9516d2a7", + "metadata": {}, + "source": [ + "⚡️ Our agent will be powered by `openai/gpt-4o-mini` using the `LiteLLMModel` class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f78927c", + "metadata": {}, + "outputs": [], + "source": [ + "from smolagents import LiteLLMModel\n", + "\n", + "agentops.init(api_key=AGENTOPS_API_KEY, default_tags=[\"smolagents\", \"example\", \"multi-agent\"])\n", + "model = LiteLLMModel(\"openai/gpt-4o-mini\")" + ] + }, + { + "cell_type": "markdown", + "id": "a08cc376", + "metadata": {}, + "source": [ + "## Create a Web Search Tool\n", + "\n", + "For web browsing, we can already use our pre-existing `DuckDuckGoSearchTool`. However, we will also create a `VisitWebpageTool` from scratch using `markdownify`. Here’s how:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "01689447", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "import requests\n", + "from markdownify import markdownify\n", + "from requests.exceptions import RequestException\n", + "from smolagents import tool\n", + "\n", + "@tool\n", + "def visit_webpage(url: str) -> str:\n", + " \"\"\"Visits a webpage at the given URL and returns its content as a markdown string.\n", + "\n", + " Args:\n", + " url: The URL of the webpage to visit.\n", + "\n", + " Returns:\n", + " The content of the webpage converted to Markdown, or an error message if the request fails.\n", + " \"\"\"\n", + " try:\n", + " # Send a GET request to the URL\n", + " response = requests.get(url)\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + "\n", + " # Convert the HTML content to Markdown\n", + " markdown_content = markdownify(response.text).strip()\n", + "\n", + " # Remove multiple line breaks\n", + " markdown_content = re.sub(r\"\\n{3,}\", \"\\n\\n\", markdown_content)\n", + "\n", + " return markdown_content\n", + "\n", + " except RequestException as e:\n", + " return f\"Error fetching the webpage: {str(e)}\"\n", + " except Exception as e:\n", + " return f\"An unexpected error occurred: {str(e)}\"" + ] + }, + { + "cell_type": "markdown", + "id": "3c45517b", + "metadata": {}, + "source": [ + "Let’s test our tool:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51cc54f1", + "metadata": {}, + "outputs": [], + "source": [ + "print(visit_webpage(\"https://en.wikipedia.org/wiki/Hugging_Face\")[:500])" + ] + }, + { + "cell_type": "markdown", + "id": "921df68d", + "metadata": {}, + "source": [ + "## Build Our Multi-Agent System\n", + "\n", + "We will now use the tools `search` and `visit_webpage` to create the web agent." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f274b34f", + "metadata": {}, + "outputs": [], + "source": [ + "from smolagents import (\n", + " CodeAgent,\n", + " ToolCallingAgent,\n", + " ManagedAgent,\n", + " DuckDuckGoSearchTool,\n", + ")\n", + "\n", + "web_agent = ToolCallingAgent(\n", + " tools=[DuckDuckGoSearchTool(), visit_webpage],\n", + " model=model,\n", + " max_iterations=10,\n", + ")\n", + "\n", + "managed_web_agent = ManagedAgent(\n", + " agent=web_agent,\n", + " name=\"search\",\n", + " description=\"Runs web searches for you. Give it your query as an argument.\",\n", + ")\n", + "\n", + "manager_agent = CodeAgent(\n", + " tools=[],\n", + " model=model,\n", + " managed_agents=[managed_web_agent],\n", + " additional_authorized_imports=[\"time\", \"numpy\", \"pandas\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d5977883", + "metadata": {}, + "source": [ + "Let’s run our system with the following query:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1e497c1", + "metadata": {}, + "outputs": [], + "source": [ + "answer = manager_agent.run(\"If LLM trainings continue to scale up at the current rhythm until 2030, what would be the electric power in GW required to power the biggest training runs by 2030? What does that correspond to, compared to some countries? Please provide a source for any number used.\")\n", + "\n", + "print(answer)" + ] + }, + { + "cell_type": "markdown", + "id": "169583c6", + "metadata": {}, + "source": [ + "Awesome! We've successfully run a multi-agent system. Let's end the agentops session with a \"Success\" state. You can also end the session with a \"Failure\" or \"Indeterminate\" state, which is set as default." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f82fafac", + "metadata": {}, + "outputs": [], + "source": [ + "agentops.end_session(\"Success\")" + ] + }, + { + "cell_type": "markdown", + "id": "d373e4ea", + "metadata": {}, + "source": [ + "You can view the session in the [AgentOps dashboard](https://app.agentops.ai/sessions) by clicking the link provided after ending the session." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "test", + "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.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/smolagents_examples/text_to_sql.ipynb b/examples/smolagents_examples/text_to_sql.ipynb new file mode 100644 index 000000000..1ad469de5 --- /dev/null +++ b/examples/smolagents_examples/text_to_sql.ipynb @@ -0,0 +1,366 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f190e59", + "metadata": {}, + "source": [ + "# Text-to-SQL\n", + "\n", + "In this tutorial, we’ll see how to implement an agent that leverages SQL using `smolagents`." + ] + }, + { + "cell_type": "markdown", + "id": "4baf4579", + "metadata": {}, + "source": [ + "> Let’s start with the golden question: why not keep it simple and use a standard text-to-SQL pipeline?\n", + "\n", + "A standard text-to-sql pipeline is brittle, since the generated SQL query can be incorrect. Even worse, the query could be incorrect, but not raise an error, instead giving some incorrect/useless outputs without raising an alarm.\n", + "\n", + "Instead, an agent system is able to critically inspect outputs and decide if the query needs to be changed or not, thus giving it a huge performance boost.\n", + "\n", + "Let’s build this agent!" + ] + }, + { + "cell_type": "markdown", + "id": "54de0fad", + "metadata": {}, + "source": [ + "## Installation\n", + "We will install the necessary packages for this example. We are going to use `sqlalchemy` to create a database and `smolagents` to build our agent. We will use `litellm` for LLM inference and `agentops` for observability." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb5670f7", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install smolagents\n", + "%pip install sqlalchemy\n", + "%pip install agentops" + ] + }, + { + "cell_type": "markdown", + "id": "94cd3def", + "metadata": {}, + "source": [ + "## Setting up the SQL Table" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b12ee7a2", + "metadata": {}, + "outputs": [], + "source": [ + "from sqlalchemy import (\n", + " create_engine,\n", + " MetaData,\n", + " Table,\n", + " Column,\n", + " String,\n", + " Integer,\n", + " Float,\n", + " insert,\n", + " inspect,\n", + " text,\n", + ")\n", + "\n", + "engine = create_engine(\"sqlite:///:memory:\")\n", + "metadata_obj = MetaData()\n", + "\n", + "# create city SQL table\n", + "table_name = \"receipts\"\n", + "receipts = Table(\n", + " table_name,\n", + " metadata_obj,\n", + " Column(\"receipt_id\", Integer, primary_key=True),\n", + " Column(\"customer_name\", String(16), primary_key=True),\n", + " Column(\"price\", Float),\n", + " Column(\"tip\", Float),\n", + ")\n", + "metadata_obj.create_all(engine)\n", + "\n", + "rows = [\n", + " {\"receipt_id\": 1, \"customer_name\": \"Alan Payne\", \"price\": 12.06, \"tip\": 1.20},\n", + " {\"receipt_id\": 2, \"customer_name\": \"Alex Mason\", \"price\": 23.86, \"tip\": 0.24},\n", + " {\"receipt_id\": 3, \"customer_name\": \"Woodrow Wilson\", \"price\": 53.43, \"tip\": 5.43},\n", + " {\"receipt_id\": 4, \"customer_name\": \"Margaret James\", \"price\": 21.11, \"tip\": 1.00},\n", + "]\n", + "for row in rows:\n", + " stmt = insert(receipts).values(**row)\n", + " with engine.begin() as connection:\n", + " cursor = connection.execute(stmt)" + ] + }, + { + "cell_type": "markdown", + "id": "7d8b4d1c", + "metadata": {}, + "source": [ + "## Build our Agent" + ] + }, + { + "cell_type": "markdown", + "id": "b861d52f", + "metadata": {}, + "source": [ + "We need to create the table description first because the agent will use it to generate the SQL query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61d5d41e", + "metadata": {}, + "outputs": [], + "source": [ + "inspector = inspect(engine)\n", + "columns_info = [(col[\"name\"], col[\"type\"]) for col in inspector.get_columns(\"receipts\")]\n", + "\n", + "table_description = \"Columns:\\n\" + \"\\n\".join([f\" - {name}: {col_type}\" for name, col_type in columns_info])\n", + "print(table_description)" + ] + }, + { + "cell_type": "markdown", + "id": "5272a433", + "metadata": {}, + "source": [ + "Now we can create the tool that will be used by the agent to perform the SQL query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84fd9b4d", + "metadata": {}, + "outputs": [], + "source": [ + "from smolagents import tool\n", + "\n", + "@tool\n", + "def sql_engine(query: str) -> str:\n", + " \"\"\"\n", + " Allows you to perform SQL queries on the table. Returns a string representation of the result.\n", + " The table is named 'receipts'. Its description is as follows:\n", + " Columns:\n", + " - receipt_id: INTEGER\n", + " - customer_name: VARCHAR(16)\n", + " - price: FLOAT\n", + " - tip: FLOAT\n", + "\n", + " Args:\n", + " query: The query to perform. This should be correct SQL.\n", + " \"\"\"\n", + " output = \"\"\n", + " with engine.connect() as con:\n", + " rows = con.execute(text(query))\n", + " for row in rows:\n", + " output += \"\\n\" + str(row)\n", + " return output" + ] + }, + { + "cell_type": "markdown", + "id": "84d7c4a7", + "metadata": {}, + "source": [ + "Everything is ready to create the agent. We will use the `CodeAgent` class from `smolagents` to create the agent. `litellm` is used to create the model and the agent will use the `sql_engine` tool to perform the SQL query.\n", + "\n", + "`agentops` is used to track the agents. We will initialize it with our API key, which can be found in the [AgentOps settings](https://app.agentops.ai/settings/projects)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0cc00a36", + "metadata": {}, + "outputs": [], + "source": [ + "import agentops\n", + "from dotenv import load_dotenv\n", + "import os\n", + "from smolagents import CodeAgent, LiteLLMModel\n", + "\n", + "load_dotenv()\n", + "\n", + "AGENTOPS_API_KEY = os.getenv(\"AGENTOPS_API_KEY\") or \"your_agentops_api_key\"\n", + "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\") or \"your_openai_api_key\"\n", + "\n", + "agentops.init(api_key=AGENTOPS_API_KEY, default_tags=[\"smolagents\", \"example\", \"text-to-sql\"])\n", + "model = LiteLLMModel(\"openai/gpt-4o-mini\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "208ef8d2", + "metadata": {}, + "outputs": [], + "source": [ + "agent = CodeAgent(\n", + " tools=[sql_engine],\n", + " model=model,\n", + ")\n", + "agent.run(\"Can you give me the name of the client who got the most expensive receipt?\")" + ] + }, + { + "cell_type": "markdown", + "id": "5cf2ac25", + "metadata": {}, + "source": [ + "## Level 2: Table Joins" + ] + }, + { + "cell_type": "markdown", + "id": "22fc9aed", + "metadata": {}, + "source": [ + "Now let’s make it more challenging! We want our agent to handle joins across multiple tables.\n", + "\n", + "So let’s make a second table recording the names of waiters for each receipt_id!" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2c893cec", + "metadata": {}, + "outputs": [], + "source": [ + "table_name = \"waiters\"\n", + "receipts = Table(\n", + " table_name,\n", + " metadata_obj,\n", + " Column(\"receipt_id\", Integer, primary_key=True),\n", + " Column(\"waiter_name\", String(16), primary_key=True),\n", + ")\n", + "metadata_obj.create_all(engine)\n", + "\n", + "rows = [\n", + " {\"receipt_id\": 1, \"waiter_name\": \"Corey Johnson\"},\n", + " {\"receipt_id\": 2, \"waiter_name\": \"Michael Watts\"},\n", + " {\"receipt_id\": 3, \"waiter_name\": \"Michael Watts\"},\n", + " {\"receipt_id\": 4, \"waiter_name\": \"Margaret James\"},\n", + "]\n", + "for row in rows:\n", + " stmt = insert(receipts).values(**row)\n", + " with engine.begin() as connection:\n", + " cursor = connection.execute(stmt)" + ] + }, + { + "cell_type": "markdown", + "id": "b5d486ca", + "metadata": {}, + "source": [ + "Since we changed the table, we update the `SQLExecutorTool` with this table’s description to let the LLM properly leverage information from this table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77c8e2a4", + "metadata": {}, + "outputs": [], + "source": [ + "updated_description = \"\"\"Allows you to perform SQL queries on the table. Beware that this tool's output is a string representation of the execution output.\n", + "It can use the following tables:\"\"\"\n", + "\n", + "inspector = inspect(engine)\n", + "for table in [\"receipts\", \"waiters\"]:\n", + " columns_info = [(col[\"name\"], col[\"type\"]) for col in inspector.get_columns(table)]\n", + "\n", + " table_description = f\"Table '{table}':\\n\"\n", + "\n", + " table_description += \"Columns:\\n\" + \"\\n\".join([f\" - {name}: {col_type}\" for name, col_type in columns_info])\n", + " updated_description += \"\\n\\n\" + table_description\n", + "\n", + "print(updated_description)" + ] + }, + { + "cell_type": "markdown", + "id": "ee51dad3", + "metadata": {}, + "source": [ + "Now let's update the `SQLExecutorTool` with the updated description and run the agent again." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6defa5b9", + "metadata": {}, + "outputs": [], + "source": [ + "sql_engine.description = updated_description\n", + "\n", + "agent = CodeAgent(\n", + " tools=[sql_engine],\n", + " model=model,\n", + ")\n", + "\n", + "agent.run(\"Which waiter got more total money from tips?\")" + ] + }, + { + "cell_type": "markdown", + "id": "739ffd3b", + "metadata": {}, + "source": [ + "All done! Now we can end the agentops session with a \"Success\" state. You can also end the session with a \"Failure\" or \"Indeterminate\" state, where the \"Indeterminate\" state is used by default." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9c7de64", + "metadata": {}, + "outputs": [], + "source": [ + "agentops.end_session(\"Success\")" + ] + }, + { + "cell_type": "markdown", + "id": "b272d348", + "metadata": {}, + "source": [ + "You can view the session in the [AgentOps dashboard](https://app.agentops.ai/sessions) by clicking the link provided after ending the session." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "test", + "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.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}