From adcb7b623a9dc795b5f5186a5a5e4c6f858e5d08 Mon Sep 17 00:00:00 2001 From: Sandi Besen Date: Wed, 26 Nov 2025 13:18:16 -0800 Subject: [PATCH 1/2] adding notebook and readme for kitchen-aide Signed-off-by: Sandi Besen --- docs/kitchen-aide/README.md | 69 +++ kitchen-aide/beeai_kitchen_aide.ipynb | 826 ++++++++++++++++++++++++++ 2 files changed, 895 insertions(+) create mode 100644 kitchen-aide/beeai_kitchen_aide.ipynb diff --git a/docs/kitchen-aide/README.md b/docs/kitchen-aide/README.md index e69de29..48ac8fb 100644 --- a/docs/kitchen-aide/README.md +++ b/docs/kitchen-aide/README.md @@ -0,0 +1,69 @@ +--- +title: Kitchen-Aide Agent Showcasing Conditional Requirements +description: Exploring Conditional Requirements with a fun kitchen + example +logo: images/BeeAI-Logo-White.png +--- + +# Kitchen-Aide Agent: Conditional Requirements 🍳🐝 + +In this notebook, you'll learn how **Conditional Requirements** shape +what tools an agent *can see and use* on each turn. Using a playful +**Kitchen-Aide Agent**, you'll explore how developer-defined rules can +restrict, allow, or sequence tool access. + +
+ +## 🥘 Workshop Scenario + +Your Kitchen-Aide Agent helps you make cooking decisions using: + +- Your **fridge**, **freezer**, and **pantry** inventory tools\ +- Your **personal recipe search**\ +- An optional **internet recipe tool** + +You'll ask questions like: + +- *"What can I make with what I already have?"*\ +- *"What ingredients am I missing for this recipe?"*\ +- *"Is there a web recipe that fits my ingredients?"* + +The key lesson: **conditional requirements decide which of these tools +the LLM is even allowed to call on each turn.** + +
+ +## 📚 What You'll Learn + +### ⭐ Conditional Requirements + +You'll implement rules such as: + +- A tool can be used only once (e.g., `get_fridge`)\ +- Certain tools are hidden until another tool has been used\ +- A tool may require a specific argument before the LLM can call it\ +- A tool may be temporarily unavailable depending on state + +These rules can either force a workflow or simply **expose or hide +tools** based on developer-defined conditions. + +
+ +## 🚀 Getting Started + +**Quick Setup** + - Google Account – Required for accessing Google Colab + - Workshop Notebook – Open the notebook Open In Colab + - Personal Copy – If you'd like to save your changes, please copy this notebook and create your own version + +Then: +- Configure your agent and tools +- Add Conditional Requirements +- Test how the agent's accessible tools change as you interact + +
+ +## Learn More About BeeAI + +- 📚 **Framework Documentation**: [https://framework.beeai.dev/introduction/welcome](https://framework.beeai.dev/introduction/welcome) +- 🧠 **GitHub Repository**: [https://github.com/i-am-bee/beeai-framework](https://github.com/i-am-bee/beeai-framework) \ No newline at end of file diff --git a/kitchen-aide/beeai_kitchen_aide.ipynb b/kitchen-aide/beeai_kitchen_aide.ipynb new file mode 100644 index 0000000..cbc0906 --- /dev/null +++ b/kitchen-aide/beeai_kitchen_aide.ipynb @@ -0,0 +1,826 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "RDMNr1S86fWn" + }, + "source": [ + "# Welcome to the Kitchen Aide Agent 🐝\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bv4UxF3f3_-c" + }, + "source": [ + "🎯 Scenario: You need some help figuring out what to make with the food in your fridge and what you might need to buy during your next grocery shop.\n", + "\n", + "Your Kitchen-Aide Agent can assist you by checking to see what foods are in your pantry, regrigerator, and freezer. It also has access to all your personal recipes as well as new ones online.\n", + "\n", + "You can ask Kitchen-Aide questions like:\n", + "- Which ingedients am I missing to create X recipe?\n", + "- What can I make with my ingredients on hand?\n", + "- What food do I have on hand?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Jk5sBse_66_H" + }, + "source": [ + "## 🔧 Setup\n", + "First, let's install the BeeAI Framework and set up our environment.\n", + "\n", + "- setting up the observability so we can capture and log the actions our agent takes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ivhQKPrL652y" + }, + "outputs": [], + "source": [ + "%pip install -Uqq arize-phoenix s3fs unstructured \"requests==2.32.4\"\\\n", + " \"openinference-instrumentation-beeai==0.1.13\" \\\n", + " \"beeai-framework[duckduckgo,rag]\" \"fsspec==2025.3.0\" jedi \\\n", + " \"opentelemetry-api==1.37.0\" \"opentelemetry-sdk==1.37.0\" \"langgraph<=0.5.0\"\n", + "\n", + "# The following wraps Notebook output\n", + "from IPython.display import HTML, display\n", + "def set_css(*_, **__):\n", + " display(HTML(\"\\n\\n\"))\n", + "get_ipython().events.register(\"pre_run_cell\", set_css)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dF_sHdJY7LnK" + }, + "source": [ + "Now let's import the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DN1XO5lj7MoB" + }, + "outputs": [], + "source": [ + "import os\n", + "import asyncio\n", + "import time\n", + "import phoenix as px\n", + "import ipywidgets\n", + "from typing import Any, Optional\n", + "from datetime import date\n", + "from pydantic import BaseModel, Field\n", + "from dotenv import load_dotenv\n", + "from beeai_framework.agents.requirement import RequirementAgent\n", + "from beeai_framework.agents.requirement.types import RequirementAgentOutput\n", + "from beeai_framework.agents.requirement.requirements import Requirement, Rule\n", + "from beeai_framework.agents.requirement.requirements.conditional import ConditionalRequirement\n", + "from beeai_framework.backend import ChatModel, ChatModelParameters\n", + "from beeai_framework.backend.document_loader import DocumentLoader\n", + "from beeai_framework.backend.embedding import EmbeddingModel\n", + "from beeai_framework.backend.text_splitter import TextSplitter\n", + "from beeai_framework.backend.vector_store import VectorStore\n", + "from beeai_framework.context import RunContext\n", + "from beeai_framework.emitter.emitter import Emitter, EventMeta\n", + "from beeai_framework.emitter.types import EmitterOptions\n", + "from beeai_framework.memory import UnconstrainedMemory\n", + "from beeai_framework.middleware.trajectory import GlobalTrajectoryMiddleware\n", + "from beeai_framework.tools import Tool, ToolRunOptions, tool, StringToolOutput\n", + "from beeai_framework.tools.search.duckduckgo import DuckDuckGoSearchTool\n", + "from beeai_framework.tools.search.retrieval import VectorStoreSearchTool\n", + "from beeai_framework.tools.think import ThinkTool\n", + "from beeai_framework.tools.weather import OpenMeteoTool\n", + "from beeai_framework.tools.types import ToolRunOptions\n", + "from openinference.instrumentation.beeai import BeeAIInstrumentor\n", + "from opentelemetry import trace as trace_api\n", + "from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\n", + "from opentelemetry.sdk import trace as trace_sdk\n", + "from opentelemetry.sdk.resources import Resource\n", + "from opentelemetry.sdk.trace.export import SimpleSpanProcessor\n", + "from langchain_text_splitters import MarkdownHeaderTextSplitter\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lweJWWT0BJI1" + }, + "source": [ + " ## 1️⃣ LLM Providers: Choose Your AI Engine" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y9YkgZafBnFO" + }, + "source": [ + "BeeAI Framework supports 10+ LLM providers including Ollama, Groq, OpenAI, Watsonx.ai, and more, giving you flexibility to choose local or hosted models based on your needs. You can find the documentation on how to connect to other providers [here](https://framework.beeai.dev/modules/backend).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8ug4p_c8ktOp" + }, + "source": [ + "### *❗* Exercise: Select your Language Model Provider\n", + "\n", + "Change the `provider` and `model` variables to your desired provider and model.\n", + "\n", + "If you select a provider that requires an API key URL or Project_ID, select the key icon on the left menu and set the variables to match those in the userdata.get() function.\n", + "\n", + "Try several models to see how your agent performs. Note that you may need to modify the system prompt for each model, as they all have their own system prompt best practice." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BBNZGq4Gvhyc" + }, + "outputs": [], + "source": [ + "#Use widgets to show provider choices\n", + "providers=ipywidgets.ToggleButtons(options=['ollama','openai'])\n", + "display(providers)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9mmEwaxPxrJA" + }, + "source": [ + "In Colab, install and start Ollama for providing the Embedding Model used during RAG operations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xYKHEd3ZxhOz" + }, + "outputs": [], + "source": [ + "!curl -fsSL https://ollama.com/install.sh | sh > /dev/null\n", + "!nohup ollama serve >/dev/null 2>&1 &" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YdDRJpoPhvrz" + }, + "outputs": [], + "source": [ + "provider=providers.value\n", + "from google.colab import userdata\n", + "# Ollama - No parameters required\n", + "if provider==\"ollama\":\n", + " model=\"granite4:tiny-h\"\n", + " #model=\"granite3.3\"\n", + " provider_model=provider+\":\"+model\n", + " !ollama pull $model\n", + " llm=ChatModel.from_name(provider_model, ChatModelParameters(temperature=0))\n", + "# OpenAI - Place OpenAI API Key in Colab Secrets (key icon) as OPENAI_KEY\n", + "elif provider==\"openai\":\n", + " model=\"gpt-5-mini\"\n", + " provider_model=provider+\":\"+model\n", + " api_key = userdata.get('OPENAI_KEY') #Set secret value using key in left menu\n", + " llm=ChatModel.from_name(provider_model, ChatModelParameters(temperature=1), api_key=api_key)\n", + "else:\n", + " print(\"Provider \" + provider + \" undefined\")" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Pull Recipe and Food Inventory Data from your Fridge, Freezer, and Pantry into Colab" + ], + "metadata": { + "id": "LHRYD41j8LZw" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "if os.getcwd() == \"/\":\n", + " os.chdir('/content/')\n", + "\n", + "if os.path.exists(\"beeai-workshop\"):\n", + " !rm -rf beeai-workshop\n", + "\n", + "# Sparse checkout only kitchen-contents directory\n", + "!git clone --filter=blob:none --no-checkout https://github.com/IBM/beeai-workshop.git\n", + "os.chdir(\"beeai-workshop\")\n", + "!git sparse-checkout init --cone\n", + "!git sparse-checkout set kitchen-aide/kitchen-contents\n", + "!git checkout\n", + "\n", + "os.chdir(\"kitchen-aide/kitchen-contents\")\n", + "\n", + "print(\"Now inside:\", os.getcwd())\n" + ], + "metadata": { + "id": "7ASlzPf0bbUG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "see a sneak peak of each file in your kitchen inentory and your recipes" + ], + "metadata": { + "id": "m2QS4BST3KQq" + } + }, + { + "cell_type": "code", + "source": [ + "folder = \"/content/beeai-workshop/kitchen-aide/kitchen-contents\"\n", + "num_lines_to_show = 20\n", + "\n", + "for fname in sorted(os.listdir(folder)):\n", + " fpath = os.path.join(folder, fname)\n", + "\n", + " if os.path.isfile(fpath):\n", + " print(\"\\n\" + \"=\"*80)\n", + " print(f\"📄 {fname} — showing first {num_lines_to_show} lines\")\n", + " print(\"=\"*80)\n", + "\n", + " with open(fpath, \"r\") as f:\n", + " for i in range(num_lines_to_show):\n", + " line = f.readline()\n", + " if not line:\n", + " break\n", + " print(line.rstrip())\n" + ], + "metadata": { + "id": "ipsvebaycA0E" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NarMFy4272JG" + }, + "source": [ + "## 2️⃣ Provide System Prompt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oFXat-h6Nh1V" + }, + "source": [ + "### *❗* Exercise: Customize Your System Prompt\n", + "Try modifying the system prompt. Customize the \"basic rules\" section to add your own. Note that changes to the system prompt will affect the performance of the model. Creating a great `System Prompt` is an art, not a science." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_FOCLkIn73sk" + }, + "outputs": [], + "source": [ + "instruct_prompt = f\"\"\"You help the user understand the inventory of their kitchen and what recipes they can make or what they are lacking.\n", + "\n", + "Basic Rules:\n", + "- Favor my recipes over recipes on the internet\n", + "- If we cant' prepare a recipe, make a shopping list of the items needed for a recipe\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7Ad__zpmDqjR" + }, + "source": [ + "## 3️⃣ Memory Systems: Maintaining Context across iterations or sessions" + ] + }, + { + "cell_type": "markdown", + "source": [ + "BeeAI has several built in memory startegies to chose from such as sliding window, token optimized, summarized, and more. Read about them [here](https://framework.beeai.dev/modules/memory." + ], + "metadata": { + "id": "hUMr2hcZ33d8" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "U4q3OUmRC5xI" + }, + "outputs": [], + "source": [ + "from beeai_framework.memory import UnconstrainedMemory\n", + "\n", + "memory = UnconstrainedMemory()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "t3KvR8_nr28N" + }, + "source": [ + "## 4️⃣ Tools: Enabling LLMs to Take Action\n", + "\n", + "The BeeAI framework provides [built in tools](https://framework.beeai.dev/modules/tools#built-in-tools) for common tool types, but also provides the ability to create [custom tools](https://framework.beeai.dev/modules/tools#creating-custom-tools)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ou-4PH6dtlSD" + }, + "source": [ + "### Adding Framework Provided Tools\n", + "The **Think tool** encourages a Re-Act or planning pattern (depending on how it is implemented in the conditional requirements) where the agent reasons and plans before calling a tool.\n", + "\n", + "The DuckDuckGoSearchTool is a Web Search tool that provides relevant data from the internet to the LLM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9hA0-Yo8r17M" + }, + "outputs": [], + "source": [ + "think_tool = ThinkTool()\n", + "internet_search_tool = DuckDuckGoSearchTool()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-hagkWZpGOGb" + }, + "source": [ + "### Add A Custom Tool to Read Kitchen Inventory\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Nz0IdEMzGWN6" + }, + "source": [ + "There are 2 ways to provide custom tools to your agent. For simple tools you can use the `@tool` decorator above the function. For more complex tools, you can extend the `Tool Class` and customize things such as the run time and tool execution. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wGFtLc9EQ8Kk" + }, + "source": [ + "We will extend the tool class in this example, because we want to midify the _run method. To learn more about advanced tool customization, take a look at this section in the [documentation](https://framework.beeai.dev/modules/tools#advanced-custom-tool)." + ] + }, + { + "cell_type": "code", + "source": [ + "class InventoryToolInput(BaseModel):\n", + " pass\n", + "\n", + "\n", + "class InventoryTool(Tool[InventoryToolInput, ToolRunOptions, StringToolOutput]):\n", + " \"\"\"\n", + " Base inventory tool. Subclasses define the location and tool name.\n", + " \"\"\"\n", + "\n", + " name = \"InventoryBase\"\n", + " description = \"Base inventory tool – do not register directly.\"\n", + " input_schema = InventoryToolInput\n", + "\n", + " def __init__(\n", + " self,\n", + " location: str,\n", + " options: dict[str, Any] | None = None,\n", + " ) -> None:\n", + " self.location = location\n", + " super().__init__(options)\n", + "\n", + " def _create_emitter(self) -> Emitter:\n", + " return Emitter.root().child(\n", + " namespace=[\"tool\", \"example\", \"result\"],\n", + " creator=self,\n", + " )\n", + "\n", + " async def _run(\n", + " self, input: InventoryToolInput, options: ToolRunOptions | None, context: RunContext\n", + " ) -> StringToolOutput:\n", + " location = self.location\n", + " file_path = f\"{location}_contents.md\"\n", + "\n", + " try:\n", + " with open(file_path, \"r\") as file:\n", + " result = file.read()\n", + " except Exception as e:\n", + " result = f\"Error reading file {file_path}: {e}\"\n", + "\n", + " print(location, \"inventory:\", result)\n", + " return StringToolOutput(result=result)\n", + "\n", + "\n", + "class PantryInventoryTool(InventoryTool):\n", + " name = \"get_pantry_inventory\"\n", + " description = \"Search the pantry inventory for ingredients.\"\n", + "\n", + " def __init__(self, options: dict[str, Any] | None = None):\n", + " super().__init__(location=\"pantry\", options=options)\n", + "\n", + "\n", + "class FreezerInventoryTool(InventoryTool):\n", + " name = \"get_freezer_inventory\"\n", + " description = \"Search the freezer inventory for ingredients.\"\n", + "\n", + " def __init__(self, options: dict[str, Any] | None = None):\n", + " super().__init__(location=\"freezer\", options=options)\n", + "\n", + "\n", + "class FridgeInventoryTool(InventoryTool):\n", + " name = \"get_fridge_inventory\"\n", + " description = \"Search the fridge inventory for ingredients.\"\n", + "\n", + " def __init__(self, options: dict[str, Any] | None = None):\n", + " super().__init__(location=\"fridge\", options=options)\n", + "\n", + "\n", + "#Three distinct tools from the base InventoryTool Class\n", + "get_pantry_tool = PantryInventoryTool()\n", + "get_freezer_tool = FreezerInventoryTool()\n", + "get_fridge_tool = FridgeInventoryTool()\n" + ], + "metadata": { + "id": "XiKIVPAdJ1Q0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7zwInfQoGhNc" + }, + "source": [ + "## 5️⃣ Creating a RAG (Retrieval Augmented Generation) Tool to Search My Recipes" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JwgXCM1QU-nP" + }, + "source": [ + "The BeeAI Framework has built in abstractions to make RAG simple to implement. Read more about it [here](https://framework.beeai.dev/modules/rag)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8YZs3LUoVOgL" + }, + "source": [ + "First, we must pull an embedding model which converts text into numerical vectors so we can compare meanings and retrieve the most relevant snippets. The original document is:\n", + "1. preprocessed (cleaned + broken into chunks)\n", + "2. ran through the embedding algorithm\n", + "3. stored in the vector database (in system RAM for this example)\n" + ] + }, + { + "cell_type": "code", + "source": [ + "!ollama pull nomic-embed-text:latest" + ], + "metadata": { + "id": "dl4vy_D-dYYG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GwbUILLBtRKO" + }, + "outputs": [], + "source": [ + "embedding_model = EmbeddingModel.from_name(\"ollama:nomic-embed-text\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LiC9dmdPWEkK" + }, + "source": [ + "Take a look at the internal documents so you know what type of questions to ask your agent\n" + ] + }, + { + "cell_type": "code", + "source": [ + "file_path=\"my_recipes.md\"\n", + "with open(file_path, 'r') as file:\n", + " content = file.read()\n", + "\n", + "#Print first 50 lines\n", + "lines = content.splitlines()\n", + "for i in range(min(50, len(lines))):\n", + " print(lines[i])" + ], + "metadata": { + "id": "kdmbG-AG3ptI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Split the documents into chunks based on Markdown formatting and add the documents to the System RAM BeeAI vector store" + ], + "metadata": { + "id": "SjOvHIyO5Nk7" + } + }, + { + "cell_type": "code", + "source": [ + "from beeai_framework.backend.types import Document\n", + "from langchain.schema import Document as LangchainDocument\n", + "from langchain_text_splitters import MarkdownHeaderTextSplitter\n", + "\n", + "headers_to_split_on=[(\"#\", \"Header 1\"), (\"##\", \"Header 2\")]\n", + "\n", + "# Directly use Langchain's MarkdownHeaderTextSplitter\n", + "langchain_text_splitter = MarkdownHeaderTextSplitter(\n", + " headers_to_split_on=headers_to_split_on, strip_headers = False\n", + " )\n", + "\n", + "# Split the content to get Langchain Document objects\n", + "langchain_doc_splits = langchain_text_splitter.split_text(content)\n", + "\n", + "\n", + "# Convert each Langchain Document to a BeeAI Framework Document\n", + "documents = [\n", + " Document(content=split.page_content, metadata=split.metadata)\n", + " for split in langchain_doc_splits\n", + "]\n", + "\n", + "# Create vector store and add documents\n", + "vector_store = VectorStore.from_name(name=\"beeai:TemporalVectorStore\", embedding_model=embedding_model)\n", + "await vector_store.add_documents(documents=documents)\n", + "print(f\"Vector store populated with {len(documents)} documents\")\n" + ], + "metadata": { + "id": "qPdARPGT3piV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Create the vector store search tool\n", + "my_recipe_search = VectorStoreSearchTool(vector_store=vector_store)" + ], + "metadata": { + "id": "5LixFFnz3pdA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zw1lca6av6q_" + }, + "source": [ + "## Explore Observability: See what is happening under the hood" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a9Eq5KKCv6rB" + }, + "source": [ + "Create the function that sets up observability using `OpenTelemetry` and [Arize's Phoenix Platform](https://arize.com/docs/phoenix/inferences/how-to-inferences/manage-the-app). There a several ways to view what is happening under the hood of your agent. View the observability documentation [here](https://framework.beeai.dev/modules/observability)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-0keGvLvv6rC" + }, + "outputs": [], + "source": [ + "def setup_observability(endpoint: str = \"http://localhost:6006/v1/traces\") -> None:\n", + " \"\"\"\n", + " Sets up OpenTelemetry with OTLP HTTP exporter and instruments the beeai framework.\n", + " \"\"\"\n", + " resource = Resource(attributes={})\n", + " tracer_provider = trace_sdk.TracerProvider(resource=resource)\n", + " tracer_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter(endpoint)))\n", + " trace_api.set_tracer_provider(tracer_provider)\n", + "\n", + " BeeAIInstrumentor().instrument()" + ] + }, + { + "cell_type": "code", + "source": [ + "load_dotenv()\n", + "# Enable OpenTelemetry integration\n", + "setup_observability(\"http://localhost:6006/v1/traces\")\n", + "px_session = px.launch_app()" + ], + "metadata": { + "id": "y5xBf50MwGDS" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VkI0FLQfyrqv" + }, + "source": [ + "## 6️⃣ Conditional Requirements: Guiding Agent Behavior\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rUVF44hCzDIE" + }, + "source": [ + "What Are Conditional Requirements?\n", + "[Conditional requirements](https://framework.beeai.dev/experimental/requirement-agent#conditional-requirement) ensure your agents are reliable by controlling when and how tools are used. They're like business rules for agent behavior. You can make them as strict (esentially writing a static workflow) or flexible (no rules! LLM decides) as you'd like.\n", + "\n", + "The rules that you enforce may seem simple in the BeeAI framework, but in other frameworks they require ~5X the amount of code. Check out this [blog](https://beeai.dev/blog/reliable-ai-agents) where we built the same agent in BeeAI and other agent framework LangGraph." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "v67JBs7C1oUs" + }, + "source": [ + "These conditional requirements enforce the following in only 6 lines of code:\n", + "1. The agent must call the think tool as the first tool call and then after every other tool enforcing a re-act pattern. It is not allowed to call the think tool consecutive times in a row.\n", + "3. The internet_search_tool can also only be called after the my_recipe_search tool and think tool, it is allowed to be called up to 3 times, and it has a relative priority of 15. Consecutive calls are allowed.\n", + "4. The get_fridge_tool tool can only be called once.\n", + "5. The get_freezer_tool can be called only after the get_fridge_tool and only can be invoked once.\n", + "6. The get_pantry_tool can only be called after the get_fridge_tool and only invoked once.\n", + "7. The my_recipe_search is allowed to be invoked up to 6 tiems and allwed to be called consecutively.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xbktgviaGY-A" + }, + "source": [ + "## 7️⃣ Assemble Your Reliable BeeAI Agent" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Q01Efmh0fuCv" + }, + "source": [ + "This is the part we've been working towards! Let's assemble the agent with all the parts we created." + ] + }, + { + "cell_type": "markdown", + "source": [ + "NEED TO ADD BACK IN MY_RECIPE SEARCH ONCE RAG IS FIXED. AND NEED TO ADD BACK IN THE ONLY AFTER CONDITION FOR DUCK DUCK GO" + ], + "metadata": { + "id": "GQvu2cUb_Pn5" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_8e74HSg_omm" + }, + "outputs": [], + "source": [ + "agent = RequirementAgent(\n", + " llm=llm,\n", + " instructions= instruct_prompt,\n", + " memory = memory,\n", + " tools=[think_tool, internet_search_tool, get_pantry_tool, get_freezer_tool, get_fridge_tool, my_recipe_search],\n", + " requirements=[\n", + " ConditionalRequirement(think_tool, consecutive_allowed=False, force_at_step=1 ),\n", + " ConditionalRequirement(get_pantry_tool, only_after=[get_fridge_tool,think_tool], min_invocations=1, max_invocations=1, priority=10),\n", + " ConditionalRequirement(get_freezer_tool, only_after=[get_fridge_tool,think_tool], min_invocations=1, max_invocations=1, priority=5 ),\n", + " ConditionalRequirement(get_fridge_tool, min_invocations=1, priority=15, max_invocations=1 ),\n", + " ConditionalRequirement(my_recipe_search, only_after=think_tool, max_invocations=6, consecutive_allowed=True),\n", + " ConditionalRequirement(internet_search_tool, max_invocations=3, only_after= [think_tool, my_recipe_search], consecutive_allowed=True),\n", + " ],\n", + " # Log intermediate steps to the console\n", + " middlewares=[GlobalTrajectoryMiddleware(included=[Tool])],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tOsjZFrhkymC" + }, + "source": [ + "### *❗* Exercise: Test Your Agent\n", + "Change the execution settings and see what happens. Does your agent run out of iterations? Every task is different and its important to balance flexibility with control.\n", + "\n", + "Example Questions:\n", + "- Which of my recipes can I prepare with the items I have on hand?\n", + "- What do I need to buy to make blueberry scones?\n", + "- What breakfast recipes can I make with the items I have on hand?\n", + "- What internet recipe can I prepare with the items I have on hand?\n", + "- What items do I need to buy to prepare my pizza recipe?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "M05oeIY-_rRe" + }, + "outputs": [], + "source": [ + "while (question := input(\"How can Kitchen-Aide Help you? (Enter q to end): \")) !=\"q\":\n", + " response = await agent.run(question, max_retries_per_step=3, total_max_retries=25)\n", + " print(response.last_message.text)" + ] + }, + { + "cell_type": "code", + "source": [ + "px_session.view()" + ], + "metadata": { + "id": "nbUVLcPgA6oH" + }, + "execution_count": null, + "outputs": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file From e95681e6abe66d801d3f4c1a892eeb6005ad421e Mon Sep 17 00:00:00 2001 From: Sandi Besen Date: Wed, 26 Nov 2025 13:23:05 -0800 Subject: [PATCH 2/2] fixing lint Signed-off-by: Sandi Besen --- docs/kitchen-aide/README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/kitchen-aide/README.md b/docs/kitchen-aide/README.md index 48ac8fb..ed4bb6b 100644 --- a/docs/kitchen-aide/README.md +++ b/docs/kitchen-aide/README.md @@ -18,15 +18,15 @@ restrict, allow, or sequence tool access. Your Kitchen-Aide Agent helps you make cooking decisions using: -- Your **fridge**, **freezer**, and **pantry** inventory tools\ -- Your **personal recipe search**\ -- An optional **internet recipe tool** +- Your **fridge**, **freezer**, and **pantry** inventory tools +- Your **personal recipe search** +- An optional **internet recipe tool** You'll ask questions like: -- *"What can I make with what I already have?"*\ -- *"What ingredients am I missing for this recipe?"*\ -- *"Is there a web recipe that fits my ingredients?"* +- "What can I make with what I already have?" +- "What ingredients am I missing for this recipe?" +- "Is there a web recipe that fits my ingredients?" The key lesson: **conditional requirements decide which of these tools the LLM is even allowed to call on each turn.** @@ -39,10 +39,10 @@ the LLM is even allowed to call on each turn.** You'll implement rules such as: -- A tool can be used only once (e.g., `get_fridge`)\ -- Certain tools are hidden until another tool has been used\ -- A tool may require a specific argument before the LLM can call it\ -- A tool may be temporarily unavailable depending on state +- A tool can be used only once (e.g., `get_fridge`)\ +- Certain tools are hidden until another tool has been used\ +- A tool may require a specific argument before the LLM can call it\ +- A tool may be temporarily unavailable depending on state These rules can either force a workflow or simply **expose or hide tools** based on developer-defined conditions. @@ -57,9 +57,10 @@ tools** based on developer-defined conditions. - Personal Copy – If you'd like to save your changes, please copy this notebook and create your own version Then: -- Configure your agent and tools -- Add Conditional Requirements -- Test how the agent's accessible tools change as you interact + +- Configure your agent and tools +- Add Conditional Requirements +- Test how the agent's accessible tools change as you interact