openai-cookbook/examples/Structured_outputs_multi_agent.ipynb
2024-08-06 10:13:08 -07:00

785 lines
72 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "xs8_Q1nPwxlK"
},
"source": [
"# Structured Outputs for Multi-Agent Systems\n",
"\n",
"In this cookbook, we will explore how to use Structured Outputs to build multi-agent systems.\n",
"\n",
"Structured Outputs is a new capability that builds upon JSON mode and function calling to enforce a strict schema in a model output.\n",
"\n",
"By using the new parameter `strict: true`, we are able to guarantee the response abides by a provided schema.\n",
"\n",
"To demonstrate the power of this feature, we will use it to build a multi-agent system.\n",
"\n",
"### Why build a Multi-Agent System?\n",
"\n",
"When using function calling, if the number of functions (or tools) increases, the performance may suffer.\n",
"\n",
"To mitigate this, we can logically group the tools together and have specialized \"agents\" that are able to solve specific tasks or sub-tasks, which will increase the overall system performance."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7SLTnfLRKVnP"
},
"source": [
"## Environment set up"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"id": "UCySx7jT6T7Y"
},
"outputs": [],
"source": [
"from openai import OpenAI\n",
"from IPython.display import Image\n",
"import json\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"from io import StringIO\n",
"import numpy as np\n",
"client = OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [],
"source": [
"MODEL = \"gpt-4o-2024-08-06\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "X34-4ZYyK6-S"
},
"source": [
"## Agents set up\n",
"\n",
"The use case we will tackle is a data analysis task.\n",
"\n",
"Let's first set up our 4-agents system:\n",
"\n",
"1. **Triaging agent:** Decides which agent(s) to call\n",
"2. **Data pre-processing Agent:** Prepares data for analysis - for example by cleaning it up\n",
"3. **Data Analysis Agent:** Performs analysis on the data\n",
"4. **Data Visualization Agent:** Visualizes the output of the analysis to extract insights\n",
"\n",
"We will start by defining the system prompts for each of these agents."
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {
"id": "CewlAQuhKUIe"
},
"outputs": [],
"source": [
"triaging_system_prompt = \"\"\"You are a Triaging Agent. Your role is to assess the user's query and route it to the relevant agents. The agents available are:\n",
"- Data Processing Agent: Cleans, transforms, and aggregates data.\n",
"- Analysis Agent: Performs statistical, correlation, and regression analysis.\n",
"- Visualization Agent: Creates bar charts, line charts, and pie charts.\n",
"\n",
"Use the send_query_to_agents tool to forward the user's query to the relevant agents. Also, use the speak_to_user tool to get more information from the user if needed.\"\"\"\n",
"\n",
"processing_system_prompt = \"\"\"You are a Data Processing Agent. Your role is to clean, transform, and aggregate data using the following tools:\n",
"- clean_data\n",
"- transform_data\n",
"- aggregate_data\"\"\"\n",
"\n",
"analysis_system_prompt = \"\"\"You are an Analysis Agent. Your role is to perform statistical, correlation, and regression analysis using the following tools:\n",
"- stat_analysis\n",
"- correlation_analysis\n",
"- regression_analysis\"\"\"\n",
"\n",
"visualization_system_prompt = \"\"\"You are a Visualization Agent. Your role is to create bar charts, line charts, and pie charts using the following tools:\n",
"- create_bar_chart\n",
"- create_line_chart\n",
"- create_pie_chart\"\"\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vkpZ409POhiS"
},
"source": [
"We will then define the tools for each agent.\n",
"\n",
"Apart from the triaging agent, each agent will be equipped with tools specific to their role:\n",
"\n",
"#### Data pre-processing agent\n",
"\n",
"\n",
"1. Clean data\n",
"2. Transform data\n",
"3. Aggregate data\n",
"\n",
"#### Data analysis agent\n",
"\n",
"1. Statistical analysis\n",
"2. Correlation analysis\n",
"3. Regression Analysis\n",
"\n",
"#### Data visualization agent\n",
"\n",
"1. Create bar chart\n",
"2. Create line chart\n",
"3. Create pie chart"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"id": "MzBvgBliOc9Y"
},
"outputs": [],
"source": [
"triage_tools = [\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"send_query_to_agents\",\n",
" \"description\": \"Sends the user query to relevant agents based on their capabilities.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"agents\": {\n",
" \"type\": \"array\",\n",
" \"items\": {\"type\": \"string\"},\n",
" \"description\": \"An array of agent names to send the query to.\"\n",
" },\n",
" \"query\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The user query to send.\"\n",
" }\n",
" },\n",
" \"required\": [\"agents\", \"query\"]\n",
" }\n",
" },\n",
" \"strict\": True\n",
" }\n",
"]\n",
"\n",
"preprocess_tools = [\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"clean_data\",\n",
" \"description\": \"Cleans the provided data by removing duplicates and handling missing values.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The dataset to clean. Should be in a suitable format such as JSON or CSV.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"transform_data\",\n",
" \"description\": \"Transforms data based on specified rules.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The data to transform. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"rules\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Transformation rules to apply, specified in a structured format.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"rules\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
"\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"aggregate_data\",\n",
" \"description\": \"Aggregates data by specified columns and operations.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The data to aggregate. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"group_by\": {\n",
" \"type\": \"array\",\n",
" \"items\": {\"type\": \"string\"},\n",
" \"description\": \"Columns to group by.\"\n",
" },\n",
" \"operations\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Aggregation operations to perform, specified in a structured format.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"group_by\", \"operations\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" }\n",
"]\n",
"\n",
"\n",
"analysis_tools = [\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"stat_analysis\",\n",
" \"description\": \"Performs statistical analysis on the given dataset.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The dataset to analyze. Should be in a suitable format such as JSON or CSV.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"correlation_analysis\",\n",
" \"description\": \"Calculates correlation coefficients between variables in the dataset.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The dataset to analyze. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"variables\": {\n",
" \"type\": \"array\",\n",
" \"items\": {\"type\": \"string\"},\n",
" \"description\": \"List of variables to calculate correlations for.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"variables\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"regression_analysis\",\n",
" \"description\": \"Performs regression analysis on the dataset.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The dataset to analyze. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"dependent_var\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The dependent variable for regression.\"\n",
" },\n",
" \"independent_vars\": {\n",
" \"type\": \"array\",\n",
" \"items\": {\"type\": \"string\"},\n",
" \"description\": \"List of independent variables.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"dependent_var\", \"independent_vars\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" }\n",
"]\n",
"\n",
"visualization_tools = [\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"create_bar_chart\",\n",
" \"description\": \"Creates a bar chart from the provided data.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The data for the bar chart. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"x\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the x-axis.\"\n",
" },\n",
" \"y\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the y-axis.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"x\", \"y\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"create_line_chart\",\n",
" \"description\": \"Creates a line chart from the provided data.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The data for the line chart. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"x\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the x-axis.\"\n",
" },\n",
" \"y\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the y-axis.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"x\", \"y\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" },\n",
" {\n",
" \"type\": \"function\",\n",
" \"function\": {\n",
" \"name\": \"create_pie_chart\",\n",
" \"description\": \"Creates a pie chart from the provided data.\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"data\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The data for the pie chart. Should be in a suitable format such as JSON or CSV.\"\n",
" },\n",
" \"labels\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the labels.\"\n",
" },\n",
" \"values\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"Column for the values.\"\n",
" }\n",
" },\n",
" \"required\": [\"data\", \"labels\", \"values\"],\n",
" \"additionalProperties\": False\n",
" }\n",
" },\n",
" \"strict\": True\n",
" }\n",
"]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "yh8tRZHkQJVv"
},
"source": [
"## Tool execution\n",
"\n",
"We need to write the code logic to:\n",
"- handle passing the user query to the multi-agent system\n",
"- handle the internal workings of the multi-agent system\n",
"- execute the tool calls\n",
"\n",
"For the sake of brevity, we will only define the logic for tools that are relevant to the user query."
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"id": "dwM_0mHZ5pXx"
},
"outputs": [],
"source": [
"# Example query\n",
"\n",
"user_query = \"\"\"\n",
"Below is some data. I want you to first remove the duplicates then analyze the statistics of the data as well as plot a line chart.\n",
"\n",
"house_size (m3), house_price ($)\n",
"90, 100\n",
"80, 90\n",
"100, 120\n",
"90, 100\n",
"\"\"\"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"From the user query, we can infer that the tools we would need to call are `clean_data`, `start_analysis` and `use_line_chart`.\n",
"\n",
"We will first define the execution function which runs tool calls.\n",
"\n",
"This maps a tool call to the corresponding function. It then appends the output of the function to the conversation history."
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {
"id": "XH6wgrATUA_l"
},
"outputs": [],
"source": [
"def clean_data(data):\n",
" data_io = StringIO(data)\n",
" df = pd.read_csv(data_io, sep=\",\")\n",
" df_deduplicated = df.drop_duplicates()\n",
" return df_deduplicated\n",
"\n",
"def stat_analysis(data):\n",
" data_io = StringIO(data)\n",
" df = pd.read_csv(data_io, sep=\",\")\n",
" return df.describe()\n",
"\n",
"def plot_line_chart(data):\n",
" data_io = StringIO(data)\n",
" df = pd.read_csv(data_io, sep=\",\")\n",
" \n",
" x = df.iloc[:, 0]\n",
" y = df.iloc[:, 1]\n",
" \n",
" coefficients = np.polyfit(x, y, 1)\n",
" polynomial = np.poly1d(coefficients)\n",
" y_fit = polynomial(x)\n",
" \n",
" plt.figure(figsize=(10, 6))\n",
" plt.plot(x, y, 'o', label='Data Points')\n",
" plt.plot(x, y_fit, '-', label='Best Fit Line')\n",
" plt.title('Line Chart with Best Fit Line')\n",
" plt.xlabel(df.columns[0])\n",
" plt.ylabel(df.columns[1])\n",
" plt.legend()\n",
" plt.grid(True)\n",
" plt.show()\n",
"\n",
"# Define the function to execute the tools\n",
"def execute_tool(tool_calls, messages):\n",
" for tool_call in tool_calls:\n",
" tool_name = tool_call.function.name\n",
" tool_arguments = json.loads(tool_call.function.arguments)\n",
"\n",
" if tool_name == 'clean_data':\n",
" # Simulate data cleaning\n",
" cleaned_df = clean_data(tool_arguments['data'])\n",
" cleaned_data = {\"cleaned_data\": cleaned_df.to_dict()}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(cleaned_data)})\n",
" print('Cleaned data: ', cleaned_df)\n",
" elif tool_name == 'transform_data':\n",
" # Simulate data transformation\n",
" transformed_data = {\"transformed_data\": \"sample_transformed_data\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(transformed_data)})\n",
" elif tool_name == 'aggregate_data':\n",
" # Simulate data aggregation\n",
" aggregated_data = {\"aggregated_data\": \"sample_aggregated_data\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(aggregated_data)})\n",
" elif tool_name == 'stat_analysis':\n",
" # Simulate statistical analysis\n",
" stats_df = stat_analysis(tool_arguments['data'])\n",
" stats = {\"stats\": stats_df.to_dict()}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(stats)})\n",
" print('Statistical Analysis: ', stats_df)\n",
" elif tool_name == 'correlation_analysis':\n",
" # Simulate correlation analysis\n",
" correlations = {\"correlations\": \"sample_correlations\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(correlations)})\n",
" elif tool_name == 'regression_analysis':\n",
" # Simulate regression analysis\n",
" regression_results = {\"regression_results\": \"sample_regression_results\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(regression_results)})\n",
" elif tool_name == 'create_bar_chart':\n",
" # Simulate bar chart creation\n",
" bar_chart = {\"bar_chart\": \"sample_bar_chart\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(bar_chart)})\n",
" elif tool_name == 'create_line_chart':\n",
" # Simulate line chart creation\n",
" line_chart = {\"line_chart\": \"sample_line_chart\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(line_chart)})\n",
" plot_line_chart(tool_arguments['data'])\n",
" elif tool_name == 'create_pie_chart':\n",
" # Simulate pie chart creation\n",
" pie_chart = {\"pie_chart\": \"sample_pie_chart\"}\n",
" messages.append({\"role\": \"tool\", \"name\": tool_name, \"content\": json.dumps(pie_chart)})\n",
" return messages"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we will create the tool handlers for each of the sub-agents.\n",
"\n",
"These have a unique prompt and tool set passed to the model. \n",
"\n",
"The output is then passed to an execution function which runs the tool calls.\n",
"\n",
"We will also append the messages to the conversation history."
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"id": "EcOGJ0AZTmkp"
},
"outputs": [],
"source": [
"# Define the functions to handle each agent's processing\n",
"def handle_data_processing_agent(query, conversation_messages):\n",
" messages = [{\"role\": \"system\", \"content\": processing_system_prompt}]\n",
" messages.append({\"role\": \"user\", \"content\": query})\n",
"\n",
" response = client.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" temperature=0,\n",
" tools=preprocess_tools,\n",
" )\n",
"\n",
" conversation_messages.append([tool_call.function for tool_call in response.choices[0].message.tool_calls])\n",
" execute_tool(response.choices[0].message.tool_calls, conversation_messages)\n",
"\n",
"def handle_analysis_agent(query, conversation_messages):\n",
" messages = [{\"role\": \"system\", \"content\": analysis_system_prompt}]\n",
" messages.append({\"role\": \"user\", \"content\": query})\n",
"\n",
" response = client.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" temperature=0,\n",
" tools=analysis_tools,\n",
" )\n",
"\n",
" conversation_messages.append([tool_call.function for tool_call in response.choices[0].message.tool_calls])\n",
" execute_tool(response.choices[0].message.tool_calls, conversation_messages)\n",
"\n",
"def handle_visualization_agent(query, conversation_messages):\n",
" messages = [{\"role\": \"system\", \"content\": visualization_system_prompt}]\n",
" messages.append({\"role\": \"user\", \"content\": query})\n",
"\n",
" response = client.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" temperature=0,\n",
" tools=visualization_tools,\n",
" )\n",
"\n",
" conversation_messages.append([tool_call.function for tool_call in response.choices[0].message.tool_calls])\n",
" execute_tool(response.choices[0].message.tool_calls, conversation_messages)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we create the overarching tool to handle processing the user query.\n",
"\n",
"This function takes the user query, gets a response from the model and handles passing it to the other agents to execute. In addition to this, we will keep the state of the ongoing conversation."
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"id": "4skE5-KYI9Tw"
},
"outputs": [],
"source": [
"# Function to handle user input and triaging\n",
"def handle_user_message(user_query, conversation_messages=[]):\n",
" user_message = {\"role\": \"user\", \"content\": user_query}\n",
" conversation_messages.append(user_message)\n",
"\n",
"\n",
" messages = [{\"role\": \"system\", \"content\": triaging_system_prompt}]\n",
" messages.extend(conversation_messages)\n",
"\n",
" response = client.chat.completions.create(\n",
" model=MODEL,\n",
" messages=messages,\n",
" temperature=0,\n",
" tools=triage_tools,\n",
" )\n",
"\n",
" conversation_messages.append([tool_call.function for tool_call in response.choices[0].message.tool_calls])\n",
"\n",
" for tool_call in response.choices[0].message.tool_calls:\n",
" if tool_call.function.name == 'send_query_to_agents':\n",
" agents = json.loads(tool_call.function.arguments)['agents']\n",
" query = json.loads(tool_call.function.arguments)['query']\n",
" for agent in agents:\n",
" if agent == \"Data Processing Agent\":\n",
" handle_data_processing_agent(query, conversation_messages)\n",
" elif agent == \"Analysis Agent\":\n",
" handle_analysis_agent(query, conversation_messages)\n",
" elif agent == \"Visualization Agent\":\n",
" handle_visualization_agent(query, conversation_messages)\n",
"\n",
" return conversation_messages"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "jzQAwIW_WL3k"
},
"source": [
"## Multi-agent system execution\n",
"\n",
"Finally, we run the overarching `handle_user_message` function on the user query and view the output."
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "a0h10s_W49ct",
"outputId": "7e340af9-dc3d-44ba-aa0c-e613fbdcc153"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cleaned data: house_size (m3) house_price ($)\n",
"0 90 100\n",
"1 80 90\n",
"2 100 120\n",
"Statistical Analysis: house_size house_price\n",
"count 4.000000 4.000000\n",
"mean 90.000000 102.500000\n",
"std 8.164966 12.583057\n",
"min 80.000000 90.000000\n",
"25% 87.500000 97.500000\n",
"50% 90.000000 100.000000\n",
"75% 92.500000 105.000000\n",
"max 100.000000 120.000000\n"
]
},
{
"data": {
"image/png": "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+vDDDxUcHKy1a9eqYcOGOn/+vO666y5VrlxZklS9enXb+osXL27b05Sd3bt323qRpBo1amjLli12ywQFBcnHx0cBAQE5WmduTZ06Va1atVJCQoLGjh2rLl26KDk5WX5+fpo4caKefvppDRgwQJJUqVIlTZ48WWPHjiVIAQAAwAFBKre8A67sGXKS9PR0JVy4oMASJWyBx27budCmTRvNmTNHknT27Fm9+eab6tSpk7Zs2aIKFSpo165dOnjwoEqUKGH3uOTkZB06dEgdOnTQwIED1bFjR7Vv315RUVHq1auXwsLCcv28br31Vn399de2276+vrlex42qXbu27e8Zz+HkyZMqX768du3apY0bN2rq1Km2ZdLS0pScnKykpCQFBORu9gAAACjcCFK5ZbHk+fC6HElPl7zTrmzj2iCVS8WKFVOVKlVst9977z0FBQXp3Xff1ZQpU5SYmKgGDRpo4cKFDo/NOKTuww8/1MiRI7V8+XJ98skneu655xQbG6s77rgjV734+PjY9WIGb29v298z9sClp6dLunLo48SJE9WjRw+Hx/n5+bmmQQAAABQYBKkixGKxyMPDQ5cuXZIk1a9fX5988onKlCmjwMDALB9Xr1491atXT88884yaNGmiRYsW6Y477pCPj4/S0tLytUdnrDMn6tevr/3795se9gAAAFAwEKQKsZSUFB0/flzSlUP73njjDSUmJqpLly6SpH79+unll19Wt27dNGnSJN188836448/9OWXX2rs2LGyWq1655131LVrV4WHh2v//v06cOCAHnjgAUlSxYoVFRcXp507d+rmm29WiRIlbviQvYoVK2rz5s06cuSIihcvrpCQEMdDHP/fqVOnHD50Ny+HHUrS888/r7vuukvly5fXPffcIw8PD+3atUt79uzRlClT8rROAAAAFF5c/rwQW758ucLCwhQWFqbGjRtr69at+uyzz9S6dWtJUkBAgNavX6/y5curR48eql69uh588EElJycrMDBQAQEB+u2339SzZ0/dcsstGjp0qIYPH66HH35YktSzZ09FR0erTZs2Kl26tBYvXnzDPT/xxBPy9PRUjRo1VLp0aR09ejTLZRctWmTbW5bx9e677+Zpux07dtS3336rFStW6Pbbb9cdd9yh1157TRUqVMjrUwEAAEAhxh6pQmru3LnX/VynDKGhoZo3b16m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OswqOjo623Xz+s3ZfK+dbcbXyy+/nOV6ef3+68KFCxo1apQqVKggf39/NW3aVFu3brXdz/vvjbnefHn/vXHZvX55/70x2c2X99/cWb9+vbp06aLw8HBZLBYtWbLE7v6cvN+eOXNG/fr1U2BgoIKDg/Xggw8qMTHxuttNTk7W8OHDVapUKRUvXlw9e/bUiRMn8vvpZc2A00ydOtUoVaqU8e233xpxcXHGZ599ZhQvXtx4/fXXbcv897//NYKCgowlS5YYu3btMrp27WpERkYaly5dynK9H3/8seHj42N88MEHxq+//moMGTLECA4ONk6cOOGKp+U2spvvuXPnjKioKOOTTz4xfvvtN2PTpk1Go0aNjAYNGlx3vRMmTDBq1qxpxMfH275OnTrliqfkVnLy+h0wYIARHR1tN6szZ85cd728fq/IyXyvnmt8fLzxwQcfGBaLxTh06FCW6+X1+69evXoZNWrUMNatW2ccOHDAmDBhghEYGGj8+eefhmHw/nujrjdf3n9vXHavX95/b0x28+X9N3eWLVtmPPvss8aXX35pSDK++uoru/tz8n4bHR1t1KlTx/jpp5+MDRs2GFWqVDH69Olz3e0OGzbMiIiIMFatWmVs27bNuOOOO4ymTZs64ylmiiDlRHfeeacxePBgu1qPHj2Mfv36GYZhGOnp6UZoaKjx8ssv2+4/d+6c4evrayxevDjL9TZq1MgYPny47XZaWpoRHh5uTJs2LZ+fgXvLbr6Z2bJliyHJ+OOPP7JcZsKECUadOnXyq80CKyfzHTBggNGtW7dcrZfX7xV5ef1269bNaNu27XXXy+v3iqSkJMPT09P49ttv7er169c3nn32Wd5/b1B2880M7785l5P58v6bd3l5/fL+m3PXBqmcvN/u3bvXkGRs3brVtsx3331nWCwW46+//sp0O+fOnTO8vb2Nzz77zFbbt2+fIcnYtGlTPj+rzHFonxM1bdpUq1at0u+//y5J2rVrl3744Qd16tRJkhQXF6fjx48rKirK9pigoCA1btxYmzZtynSdly9f1vbt2+0e4+HhoaioqCwfU1hlN9/MnD9/XhaLRcHBwddd94EDBxQeHq5KlSqpX79+Onr0aH62XiDkdL5r165VmTJldOutt+qRRx7R6dOns1wnr99/5fb1e+LECf3vf//Tgw8+mO26ef1KqampSktLk5+f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AACchCAFAIAThIaGmt0CAMCJOLQPAGCq9PR0jR07ViEhIQoNDVVMTIztvqNHj6pbt24qXry4AgMD1atXL504ccJ2/8CBA9W9e3e79Y0aNUqtW7e23f78889Vq1Yt+fv7q1SpUoqKitLFixdt97/33nuqXr26/Pz8VK1aNb355ps56vvy5csaMWKEwsLC5OfnpwoVKmjatGm2+68+tC8mJkYWi8Xha+7cubYZTJs2TZGRkfL391edOnX0+eef52yAAABTEKQAAKaaN2+eihUrps2bN+ull17SpEmTFBsbq/T0dHXr1k1nzpzRunXrFBsbq8OHD+u+++7L8brj4+PVp08fDR48WPv27dPatWvVo0cPGYYhSVq4cKGef/55TZ06Vfv27dMLL7yg8ePHa968edmue+bMmfr666/16aefav/+/Vq4cKEqVqyY6bJPPPGE4uPjbV+vvPKKAgIC1LBhQ0nStGnTNH/+fL311lv69ddfNXr0aPXv31/r1q3L8XMFALgWh/YBAExVu3ZtTZgwQZJUtWpVvfHGG1q1apUkaffu3YqLi1NERIQkaf78+apZs6a2bt2q22+/Pdt1x8fHKzU1VT169FCFChUkSbVq1bLdP2HCBL366qvq0aOHJCkyMlJ79+7V22+/rQEDBlx33UePHlXVqlXVvHlzWSwW2/ozU7x4cRUvXlyS9NNPP+m5557TvHnzdNtttyklJUUvvPCCVq5cqSZNmkiSKlWqpB9++EFvv/22WrVqle3zBAC4HkEKAGCq2rVr290OCwvTyZMntW/fPkVERNhClCTVqFFDwcHB2rdvX46CVJ06ddSuXTvVqlVLHTt2VIcOHXTPPfeoZMmSunjxog4dOqQHH3xQQ4YMsT0mNTVVQUFB2a574MCBat++vW699VZFR0frrrvuUocOHa77mKNHj6p79+564okn1KtXL0nSwYMHlZSUpPbt29ste/nyZdWrVy/bPgAA5iBIAQBM5e3tbXfbYrEoPT09R4/18PCwHaaXwWq12v7u6emp2NhY/fjjj1qxYoVmzZqlZ599Vps3b1ZAQIAk6d1331Xjxo3t1uHp6ZnttuvXr6+4uDh99913WrlypXr16qWoqKgsz226ePGiunbtqiZNmmjSpEm2emJioiTpf//7n8qVK2f3GF9f32z7AACYgyAFAHBL1atX17Fjx3Ts2DHbXqm9e/fq3LlzqlGjhiSpdOnS2rNnj93jdu7caRfOLBaLmjVrpmbNmun5559XhQoV9NVXX2nMmDEKDw/X4cOH1a9fvzz1GBgYqPvuu0/33Xef7rnnHkVHR+vMmTMKCQmxW84wDPXv31/p6elasGCBLBaL7b4aNWrI19dXR48e5TA+AChACFIAALcUFRWlWrVqqV+/fpoxY4ZSU1P16KOPqlWrVraLNLRt21Yvv/yy5s+fryZNmuijjz7Snj17bIfEbd68WatWrVKHDh1UpkwZbd68WadOnVL16tUlSRMnTtTIkSMVFBSk6OhopaSkaNu2bTp79qzGjBlz3f6mT5+usLAw1atXTx4eHvrss88UGhqq4OBgh2VjYmK0cuVKrVixQomJiba9UEFBQSpRooSeeOIJjR49Wunp6WrevLnOnz+vjRs3KjAwMNtztQAA5iBIAQDcksVi0dKlS/XYY4+pZcuW8vDwUHR0tGbNmmVbpmPHjho/frzGjh2r5ORkDR48WA888IB2794t6coeo/Xr12vGjBlKSEhQhQoV9Oqrr6pTp06SpIceekgBAQF6+eWX9eSTT6pYsWKqVauWRo0alW1/JUqU0EsvvaQDBw7I09NTt99+u5YtWyYPD8cL4q5bt06JiYlq2rSpXf3DDz/UwIEDNXnyZJUuXVrTpk3T4cOHFRwcrPr162vcuHE3MEEAgDNZjGsPLgcAAAAAXBefIwUAAAAAuUSQAgAgEy+88ILt85+u/co4NBAAUHRxaB8AAJk4c+aMzpw5k+l9/v7+DpcqBwAULQQpAAAAAMglDu0DAAAAgFwiSAEAAABALhGkAAAAACCXCFIAAAAAkEsEKQAAAADIJYIUAAAAAOQSQQoAAAAAcun/AFbB4P/79gI3AAAAAElFTkSuQmCC",
"text/plain": [
"<Figure size 1000x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"[{'role': 'user',\n",
" 'content': '\\nBelow is some data. I want you to first remove the duplicates then analyze the statistics of the data as well as plot a line chart.\\n\\nhouse_size (m3), house_price ($)\\n90, 100\\n80, 90\\n100, 120\\n90, 100\\n'},\n",
" [Function(arguments='{\"agents\": [\"Data Processing Agent\"], \"query\": \"Remove duplicates from the data: house_size (m3), house_price ($)\\\\n90, 100\\\\n80, 90\\\\n100, 120\\\\n90, 100\"}', name='send_query_to_agents'),\n",
" Function(arguments='{\"agents\": [\"Analysis Agent\"], \"query\": \"Analyze the statistics of the data: house_size (m3), house_price ($)\\\\n90, 100\\\\n80, 90\\\\n100, 120\\\\n90, 100\"}', name='send_query_to_agents'),\n",
" Function(arguments='{\"agents\": [\"Visualization Agent\"], \"query\": \"Plot a line chart for the data: house_size (m3), house_price ($)\\\\n90, 100\\\\n80, 90\\\\n100, 120\\\\n90, 100\"}', name='send_query_to_agents')],\n",
" [Function(arguments='{\"data\":\"house_size (m3), house_price ($)\\\\n90, 100\\\\n80, 90\\\\n100, 120\\\\n90, 100\"}', name='clean_data')],\n",
" {'role': 'tool',\n",
" 'name': 'clean_data',\n",
" 'content': '{\"cleaned_data\": {\"house_size (m3)\": {\"0\": 90, \"1\": 80, \"2\": 100}, \" house_price ($)\": {\"0\": 100, \"1\": 90, \"2\": 120}}}'},\n",
" [Function(arguments='{\"data\":\"house_size,house_price\\\\n90,100\\\\n80,90\\\\n100,120\\\\n90,100\"}', name='stat_analysis')],\n",
" {'role': 'tool',\n",
" 'name': 'stat_analysis',\n",
" 'content': '{\"stats\": {\"house_size\": {\"count\": 4.0, \"mean\": 90.0, \"std\": 8.16496580927726, \"min\": 80.0, \"25%\": 87.5, \"50%\": 90.0, \"75%\": 92.5, \"max\": 100.0}, \"house_price\": {\"count\": 4.0, \"mean\": 102.5, \"std\": 12.583057392117917, \"min\": 90.0, \"25%\": 97.5, \"50%\": 100.0, \"75%\": 105.0, \"max\": 120.0}}}'},\n",
" [Function(arguments='{\"data\":\"house_size,house_price\\\\n90,100\\\\n80,90\\\\n100,120\\\\n90,100\",\"x\":\"house_size\",\"y\":\"house_price\"}', name='create_line_chart')],\n",
" {'role': 'tool',\n",
" 'name': 'create_line_chart',\n",
" 'content': '{\"line_chart\": \"sample_line_chart\"}'}]"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"handle_user_message(user_query)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"In this cookbook, we've explored how to leverage Structured Outputs to build more robust multi-agent systems.\n",
"\n",
"Using this new feature allows to make sure that tool calls follow the specified schema and avoids having to handle edge cases or validate arguments on your side.\n",
"\n",
"This can be applied to many more use cases, and we hope you can take inspiration from this to build your own use case!"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
}