routing agent

This commit is contained in:
Xi Yan 2025-03-03 11:13:18 -08:00
parent b153d76c96
commit 28af6f9694

View file

@ -20,7 +20,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 36,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -31,8 +31,26 @@
"from rich.pretty import pprint\n", "from rich.pretty import pprint\n",
"import json\n", "import json\n",
"import uuid\n", "import uuid\n",
"from pydantic import BaseModel\n",
"import rich\n",
"\n", "\n",
"client = LlamaStackClient(base_url=\"http://localhost:8321\")" "client = LlamaStackClient(base_url=\"http://localhost:8321\")\n",
"\n",
"base_agent_config = AgentConfig(\n",
" model=MODEL_ID,\n",
" instructions=\"You are a helpful assistant.\",\n",
" sampling_params={\n",
" \"strategy\": {\"type\": \"top_p\", \"temperature\": 1.0, \"top_p\": 0.9},\n",
" },\n",
" toolgroups=[],\n",
" tool_config={\n",
" \"tool_choice\": \"auto\",\n",
" \"tool_prompt_format\": \"python_list\",\n",
" },\n",
" input_shields=[],\n",
" output_shields=[],\n",
" enable_session_persistence=False,\n",
")"
] ]
}, },
{ {
@ -43,9 +61,9 @@
"\n", "\n",
"1. **Prompt Chaining**: Decomposes a task into sequential subtasks, where each step builds on previous results. \n", "1. **Prompt Chaining**: Decomposes a task into sequential subtasks, where each step builds on previous results. \n",
"\n", "\n",
"2. **Parallelization**: Distributes independent subtasks acorss multiple LLMs for concurrent processing. \n", "2. **Routing**: Dynamically selects specialized LLM paths based on input characteristics. \n",
"\n", "\n",
"3. **Routing**: Dynamically selects specialized LLM paths based on input characteristics. " "3. **Parallelization**: Distributes independent subtasks acorss multiple LLMs for concurrent processing. "
] ]
}, },
{ {
@ -57,7 +75,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 22,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@ -65,6 +83,9 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"========= Turn: 0 =========\n", "========= Turn: 0 =========\n",
"Here are the extracted numerical values with their associated metrics:\n",
"\n",
"\n",
"92: customer satisfaction score\n", "92: customer satisfaction score\n",
"45%: revenue growth\n", "45%: revenue growth\n",
"23%: market share\n", "23%: market share\n",
@ -73,22 +94,28 @@
"78%: product adoption rate\n", "78%: product adoption rate\n",
"87: employee satisfaction\n", "87: employee satisfaction\n",
"34%: operating margin\n", "34%: operating margin\n",
"8%: customer churn (changed to reflect the original value for comparison)\n", "8%: customer churn (previous)\n",
"\n", "\n",
"\n", "\n",
"========= Turn: 1 =========\n", "========= Turn: 1 =========\n",
"Here are the numerical values converted to percentages or decimals:\n",
"\n",
"\n",
"92%: customer satisfaction\n", "92%: customer satisfaction\n",
"45%: revenue growth\n", "45%: revenue growth\n",
"23%: market share\n", "23%: market share\n",
"5%: customer churn\n", "5%: customer churn\n",
"0.043: new user acquisition cost\n", "8%: previous customer churn\n",
"78%: product adoption rate\n", "78%: product adoption rate\n",
"87%: employee satisfaction\n", "87%: employee satisfaction\n",
"34%: operating margin\n", "34%: operating margin\n",
"8%: previous customer churn\n", "0.043: new user acquisition cost (in millions, assuming the cost is $43 per user, but it can also be kept as is: 43: new user acquisition cost, depending on context)\n",
"\n", "\n",
"\n", "\n",
"========= Turn: 2 =========\n", "========= Turn: 2 =========\n",
"Here are the lines sorted in descending order by numerical value:\n",
"\n",
"\n",
"92%: customer satisfaction\n", "92%: customer satisfaction\n",
"87%: employee satisfaction\n", "87%: employee satisfaction\n",
"78%: product adoption rate\n", "78%: product adoption rate\n",
@ -101,6 +128,9 @@
"\n", "\n",
"\n", "\n",
"========= Turn: 3 =========\n", "========= Turn: 3 =========\n",
"Here are the sorted data formatted as a markdown table:\n",
"\n",
"\n",
"| Metric | Value |\n", "| Metric | Value |\n",
"|:--|--:|\n", "|:--|--:|\n",
"| Customer Satisfaction | 92% |\n", "| Customer Satisfaction | 92% |\n",
@ -118,9 +148,9 @@
} }
], ],
"source": [ "source": [
"vanilla_agent_config = AgentConfig(\n", "vanilla_agent_config = AgentConfig({\n",
" model=MODEL_ID,\n", " **base_agent_config,\n",
" instructions=\"\"\"\n", " \"instructions\": \"\"\"\n",
" You are a helpful assistant capable of structuring data extraction and formatting. \n", " You are a helpful assistant capable of structuring data extraction and formatting. \n",
"\n", "\n",
" You will be given tasks to extract and format data from a performance report. Here is the report:\n", " You will be given tasks to extract and format data from a performance report. Here is the report:\n",
@ -135,18 +165,7 @@
" Employee satisfaction is at 87 points.\n", " Employee satisfaction is at 87 points.\n",
" Operating margin improved to 34%.\n", " Operating margin improved to 34%.\n",
" \"\"\",\n", " \"\"\",\n",
" sampling_params={\n", "})\n",
" \"strategy\": {\"type\": \"top_p\", \"temperature\": 1.0, \"top_p\": 0.9},\n",
" },\n",
" toolgroups=[],\n",
" tool_config={\n",
" \"tool_choice\": \"auto\",\n",
" \"tool_prompt_format\": \"python_list\",\n",
" },\n",
" input_shields=[],\n",
" output_shields=[],\n",
" enable_session_persistence=False,\n",
")\n",
"\n", "\n",
"vanilla_agent = Agent(client, vanilla_agent_config)\n", "vanilla_agent = Agent(client, vanilla_agent_config)\n",
"\n", "\n",
@ -194,6 +213,369 @@
" print(\"\\n\")" " print(\"\\n\")"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1.2 Routing"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"========= Processing ticket 1: =========\n"
]
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing Result: The user is having trouble accessing their account due to an </span><span style=\"color: #008080; text-decoration-color: #008080\">'invalid password'</span><span style=\"color: #008080; text-decoration-color: #008080\"> error, despite </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">being certain they are using the correct password. This issue is related to account access and authentication, </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">which falls under the responsibility of the account support team. </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing Result: The user is having trouble accessing their account due to an \u001b[0m\u001b[36m'invalid password'\u001b[0m\u001b[36m error, despite \u001b[0m\n",
"\u001b[36mbeing certain they are using the correct password. This issue is related to account access and authentication, \u001b[0m\n",
"\u001b[36mwhich falls under the responsibility of the account support team. \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing to account... </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing to account\u001b[0m\u001b[36m...\u001b[0m\u001b[36m \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Account Support Response:\n",
"\n",
"Dear John,\n",
"\n",
"We take account security and accessibility very seriously. To ensure the integrity of your account, we must follow a thorough verification process. Before we can assist you with regaining access, we need to confirm your identity.\n",
"\n",
"To initiate the account recovery process, please follow these steps:\n",
"\n",
"1. **Verify your account information**: Please reply to this email with your full name, the email address associated with your account, and the last 4 digits of your phone number (if you have one listed on your account).\n",
"2. **Password reset**: We will send you a password reset link to the email address associated with your account. This link will allow you to create a new password. Please note that this link will only be valid for 24 hours.\n",
"3. **Security questions**: You may be prompted to answer security questions to further verify your identity.\n",
"\n",
"**Important Security Note**: If you are using a public computer or network, please be cautious when accessing your account. Public computers and networks may be vulnerable to malware and other security risks. We recommend using a secure, private device and network to access your account.\n",
"\n",
"**Resolution Timeframe**: Our goal is to resolve account access issues within 2-4 hours. However, this may vary depending on the complexity of the issue and the verification process.\n",
"\n",
"**Security Tips**:\n",
"\n",
"* Use a unique and complex password for your account.\n",
"* Avoid using public computers or networks to access sensitive information.\n",
"* Enable two-factor authentication (2FA) whenever possible.\n",
"* Regularly monitor your account activity and report any suspicious behavior to our support team.\n",
"\n",
"We appreciate your cooperation and understanding in this matter. If you have any further questions or concerns, please do not hesitate to reach out to us.\n",
"\n",
"Sincerely,\n",
"Account Support Team\n",
"\n",
"\n",
"========= Processing ticket 2: =========\n"
]
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing Result: The user is inquiring about an unexpected charge on their credit card, which suggests a </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">billing-related issue. They are also requesting an explanation and potential adjustment of the charge, which </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">further indicates that the issue is related to payment or billing. </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing Result: The user is inquiring about an unexpected charge on their credit card, which suggests a \u001b[0m\n",
"\u001b[36mbilling-related issue. They are also requesting an explanation and potential adjustment of the charge, which \u001b[0m\n",
"\u001b[36mfurther indicates that the issue is related to payment or billing. \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing to billing... </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing to billing\u001b[0m\u001b[36m...\u001b[0m\u001b[36m \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Billing Support Response:\n",
"\n",
"I apologize for the unexpected charge on your credit card, Sarah. I understand that you were expecting to be billed $29.99, but instead, you were charged $49.99. I'm here to help you resolve this issue.\n",
"\n",
"After reviewing your account, I found that the $49.99 charge is due to an upgrade to our premium plan, which was accidentally applied to your account during a recent system update. This upgrade includes additional features that are not part of the standard $29.99 plan.\n",
"\n",
"To correct this, I will immediately downgrade your account back to the $29.99 plan, and I will also process a refund of $20.00, which is the difference between the two plans. You can expect to see the refund credited back to your credit card within the next 3-5 business days.\n",
"\n",
"In the meantime, I will also send you a confirmation email with the updated account details and a receipt for the corrected charge. If you have any further questions or concerns, please don't hesitate to reach out to me directly.\n",
"\n",
"If you would like to make a payment for the corrected $29.99 charge, you can do so by visiting our website and logging into your account, or by calling our automated payment system at 1-800-XXX-XXXX. We accept all major credit cards, including Visa, Mastercard, and American Express.\n",
"\n",
"\n",
"========= Processing ticket 3: =========\n"
]
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing Result: The user is seeking assistance with a specific feature or functionality of the product, namely </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">exporting data to Excel. This type of inquiry is related to understanding and using the product's capabilities, </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">which falls under the scope of the product support team or technical support team. Since the issue is more about </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">how to use a feature rather than a technical fault, it leans more towards product support. However, given the </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">nature of the request, which involves understanding the technical capabilities of the product, it could also be </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">argued that it falls under technical support. Between the two, technical support is more appropriate because it </span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">often deals with the </span><span style=\"color: #008080; text-decoration-color: #008080\">'how-to'</span><span style=\"color: #008080; text-decoration-color: #008080\"> aspects of using the product's features. </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing Result: The user is seeking assistance with a specific feature or functionality of the product, namely \u001b[0m\n",
"\u001b[36mexporting data to Excel. This type of inquiry is related to understanding and using the product's capabilities, \u001b[0m\n",
"\u001b[36mwhich falls under the scope of the product support team or technical support team. Since the issue is more about \u001b[0m\n",
"\u001b[36mhow to use a feature rather than a technical fault, it leans more towards product support. However, given the \u001b[0m\n",
"\u001b[36mnature of the request, which involves understanding the technical capabilities of the product, it could also be \u001b[0m\n",
"\u001b[36margued that it falls under technical support. Between the two, technical support is more appropriate because it \u001b[0m\n",
"\u001b[36moften deals with the \u001b[0m\u001b[36m'how-to'\u001b[0m\u001b[36m aspects of using the product's features. \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">🔀 <span style=\"color: #008080; text-decoration-color: #008080\"> Routing to technical... </span>\n",
"</pre>\n"
],
"text/plain": [
"🔀 \u001b[36m Routing to technical\u001b[0m\u001b[36m...\u001b[0m\u001b[36m \u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Technical Support Response:\n",
"\n",
"Exporting data in bulk to Excel is a feature available in our system. To achieve this, follow these steps:\n",
"\n",
"1. **Login to the system**: Ensure you are logged in with the correct credentials and have the necessary permissions to access and export project data.\n",
"2. **Navigate to the Project Dashboard**: Click on the \"Projects\" tab and select the project for which you want to export data.\n",
"3. **Access the Data Export Tool**: In the project dashboard, click on the \"Tools\" menu and select \"Data Export\" from the dropdown list.\n",
"4. **Select Export Options**: In the Data Export tool, choose the data types you want to export (e.g., tasks, issues, users, etc.). You can select all data types or specific ones based on your requirements.\n",
"5. **Choose the Export Format**: Select \"Excel (.xlsx)\" as the export format from the available options.\n",
"6. **Configure Export Settings**: You can configure additional settings such as:\n",
"\t* Date range: Specify a date range for the data to be exported.\n",
"\t* Data filtering: Apply filters to export specific data based on conditions (e.g., status, priority, etc.).\n",
"7. **Initiate the Export**: Click the \"Export\" button to start the export process. Depending on the amount of data, this may take a few minutes.\n",
"8. **Download the Exported File**: Once the export is complete, you will receive a notification. Click on the \"Download\" button to save the exported Excel file to your local machine.\n",
"\n",
"System Requirements:\n",
"- Ensure you have the latest version of our software installed (v2.5 or later).\n",
"- Microsoft Excel 2013 or later is recommended for compatibility.\n",
"\n",
"Workarounds for Common Problems:\n",
"- If you encounter issues with large data exports, try breaking down the export into smaller chunks using the date range or data filtering options.\n",
"- If you experience errors during the export process, check the system logs for more information and contact support if needed.\n",
"\n",
"If you need further assistance or encounter any issues during the export process, please don't hesitate to reach out. You can escalate this issue by replying to this email or contacting our support team directly at [support@example.com](mailto:support@example.com) or by calling +1-800-EXAMPLE.\n",
"\n",
"\n"
]
}
],
"source": [
"# 1. Define a couple of specialized agents\n",
"billing_agent_config = AgentConfig({\n",
" **base_agent_config,\n",
" \"instructions\": \"\"\"You are a billing support specialist. Follow these guidelines:\n",
" 1. Always start with \"Billing Support Response:\"\n",
" 2. First acknowledge the specific billing issue\n",
" 3. Explain any charges or discrepancies clearly\n",
" 4. List concrete next steps with timeline\n",
" 5. End with payment options if relevant\n",
" \n",
" Keep responses professional but friendly.\n",
" \"\"\",\n",
"})\n",
"\n",
"technical_agent_config = AgentConfig({\n",
" **base_agent_config,\n",
" \"instructions\": \"\"\"You are a technical support engineer. Follow these guidelines:\n",
" 1. Always start with \"Technical Support Response:\"\n",
" 2. List exact steps to resolve the issue\n",
" 3. Include system requirements if relevant\n",
" 4. Provide workarounds for common problems\n",
" 5. End with escalation path if needed\n",
" \n",
" Use clear, numbered steps and technical details.\n",
" \"\"\",\n",
"})\n",
"\n",
"account_agent_config = AgentConfig({\n",
" **base_agent_config,\n",
" \"instructions\": \"\"\"You are an account security specialist. Follow these guidelines:\n",
" 1. Always start with \"Account Support Response:\"\n",
" 2. Prioritize account security and verification\n",
" 3. Provide clear steps for account recovery/changes\n",
" 4. Include security tips and warnings\n",
" 5. Set clear expectations for resolution time\n",
" \n",
" Maintain a serious, security-focused tone.\n",
" \"\"\",\n",
"})\n",
"\n",
"product_agent_config = AgentConfig({\n",
" **base_agent_config,\n",
" \"instructions\": \"\"\"You are a product specialist. Follow these guidelines:\n",
" 1. Always start with \"Product Support Response:\"\n",
" 2. Focus on feature education and best practices\n",
" 3. Include specific examples of usage\n",
" 4. Link to relevant documentation sections\n",
" 5. Suggest related features that might help\n",
" \n",
" Be educational and encouraging in tone.\n",
" \"\"\",\n",
"})\n",
"\n",
"specialized_agents = {\n",
" \"billing\": Agent(client, billing_agent_config),\n",
" \"technical\": Agent(client, technical_agent_config),\n",
" \"account\": Agent(client, account_agent_config),\n",
" \"product\": Agent(client, product_agent_config),\n",
"}\n",
"\n",
"# 2. Define a routing agent\n",
"class OutputSchema(BaseModel):\n",
" reasoning: str\n",
" support_team: str\n",
"\n",
"routing_agent_config = AgentConfig({\n",
" **base_agent_config,\n",
" \"instructions\": f\"\"\"You are a routing agent. Analyze the user's input and select the most appropriate support team from these options: \n",
"\n",
" {list(specialized_agents.keys())}\n",
"\n",
" Return the name of the support team in JSON format.\n",
"\n",
" First explain your reasoning, then provide your selection in this JSON format: \n",
" {{\n",
" \"reasoning\": \"<your explanation>\",\n",
" \"support_team\": \"<support team name>\"\n",
" }}\n",
"\n",
" Note the support team name can only be one of the following: {specialized_agents.keys()}\n",
" \"\"\",\n",
" \"response_format\": {\n",
" \"type\": \"json_schema\",\n",
" \"json_schema\": OutputSchema.model_json_schema()\n",
" }\n",
"})\n",
"\n",
"routing_agent = Agent(client, routing_agent_config)\n",
"\n",
"# 3. Create a session for all agents\n",
"routing_agent_session_id = routing_agent.create_session(session_name=f\"routing_agent_{uuid.uuid4()}\")\n",
"specialized_agents_session_ids = {\n",
" \"billing\": specialized_agents[\"billing\"].create_session(session_name=f\"billing_agent_{uuid.uuid4()}\"),\n",
" \"technical\": specialized_agents[\"technical\"].create_session(session_name=f\"technical_agent_{uuid.uuid4()}\"),\n",
" \"account\": specialized_agents[\"account\"].create_session(session_name=f\"account_agent_{uuid.uuid4()}\"),\n",
" \"product\": specialized_agents[\"product\"].create_session(session_name=f\"product_agent_{uuid.uuid4()}\"),\n",
"}\n",
"\n",
"# 4. Combine routing with specialized agents\n",
"def process_user_query(query):\n",
" # Step 1: Route to the appropriate support team\n",
" routing_response = routing_agent.create_turn(\n",
" messages=[\n",
" {\n",
" \"role\": \"user\",\n",
" \"content\": query,\n",
" }\n",
" ],\n",
" session_id=routing_agent_session_id,\n",
" stream=False,\n",
" )\n",
" try:\n",
" routing_result = json.loads(routing_response.output_message.content)\n",
" rich.print(f\"🔀 [cyan] Routing Result: {routing_result['reasoning']} [/cyan]\")\n",
" rich.print(f\"🔀 [cyan] Routing to {routing_result['support_team']}... [/cyan]\")\n",
"\n",
" # Route to the appropriate support team\n",
" return specialized_agents[routing_result[\"support_team\"]].create_turn(\n",
" messages=[\n",
" {\"role\": \"user\", \"content\": query}\n",
" ],\n",
" session_id=specialized_agents_session_ids[routing_result[\"support_team\"]],\n",
" stream=False,\n",
" )\n",
" except json.JSONDecodeError:\n",
" print(\"Error: Invalid JSON response from routing agent\")\n",
" return None\n",
"\n",
"\n",
"tickets = [\n",
" \"\"\"Subject: Can't access my account\n",
" Message: Hi, I've been trying to log in for the past hour but keep getting an 'invalid password' error. \n",
" I'm sure I'm using the right password. Can you help me regain access? This is urgent as I need to \n",
" submit a report by end of day.\n",
" - John\"\"\",\n",
" \n",
" \"\"\"Subject: Unexpected charge on my card\n",
" Message: Hello, I just noticed a charge of $49.99 on my credit card from your company, but I thought\n",
" I was on the $29.99 plan. Can you explain this charge and adjust it if it's a mistake?\n",
" Thanks,\n",
" Sarah\"\"\",\n",
" \n",
" \"\"\"Subject: How to export data?\n",
" Message: I need to export all my project data to Excel. I've looked through the docs but can't\n",
" figure out how to do a bulk export. Is this possible? If so, could you walk me through the steps?\n",
" Best regards,\n",
" Mike\"\"\"\n",
"]\n",
"\n",
"for i, ticket in enumerate(tickets):\n",
" print(f\"========= Processing ticket {i+1}: =========\")\n",
" response = process_user_query(ticket)\n",
" print(response.output_message.content)\n",
" print(\"\\n\")"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,