307 lines
11 KiB
Plaintext
307 lines
11 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Airline Customer Service Agent\n",
|
|
"\n",
|
|
"This is a simple chatbot designed to assist airline customers with common queries. Here the agents are also used as tools to help the bot answer questions more effectively.\n",
|
|
"\n",
|
|
"Using AgentOps we can track the flow of the conversation and the agents used. This is useful for debugging and understanding how the bot is performing."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Prerequisites\n",
|
|
"\n",
|
|
"Before running this notebook, you'll need:\n",
|
|
"\n",
|
|
"1. **AgentOps Account**: Create a free account at [app.agentops.ai](https://app.agentops.ai)\n",
|
|
"2. **AgentOps API Key**: Obtain your API key from your AgentOps dashboard\n",
|
|
"3. **OpenAI API Key**: Get your API key from [platform.openai.com](https://platform.openai.com)\n",
|
|
"\n",
|
|
"Make sure to set these as environment variables or create a `.env` file in your project root with:\n",
|
|
"\n",
|
|
"```\n",
|
|
"AGENTOPS_API_KEY=your_agentops_api_key_here\n",
|
|
"OPENAI_API_KEY=your_openai_api_key_here\n",
|
|
"```"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Install required packages\n",
|
|
"%pip install -q agentops\n",
|
|
"%pip install -q openai-agents\n",
|
|
"%pip install -q pydotenv"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Set the API keys for your AgentOps and OpenAI accounts.\n",
|
|
"import os\n",
|
|
"from dotenv import load_dotenv\n",
|
|
"\n",
|
|
"load_dotenv()\n",
|
|
"\n",
|
|
"os.environ[\"AGENTOPS_API_KEY\"] = os.getenv(\"AGENTOPS_API_KEY\", \"your_api_key_here\")\n",
|
|
"os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\", \"your_openai_api_key_here\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from __future__ import annotations as _annotations # noqa: F404\n",
|
|
"\n",
|
|
"import random\n",
|
|
"import uuid\n",
|
|
"\n",
|
|
"from pydantic import BaseModel\n",
|
|
"import agentops\n",
|
|
"\n",
|
|
"from agents import ( # noqa: E402\n",
|
|
" Agent,\n",
|
|
" HandoffOutputItem,\n",
|
|
" ItemHelpers,\n",
|
|
" MessageOutputItem,\n",
|
|
" RunContextWrapper,\n",
|
|
" Runner,\n",
|
|
" ToolCallItem,\n",
|
|
" ToolCallOutputItem,\n",
|
|
" TResponseInputItem,\n",
|
|
" function_tool,\n",
|
|
" handoff,\n",
|
|
" trace,\n",
|
|
")\n",
|
|
"from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX # noqa: E402"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"agentops.init(tags=[\"customer-service-agent\", \"openai-agents\", \"agentops-example\"])\n",
|
|
"tracer = agentops.start_trace(trace_name=\"Customer Service Agent\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Context model for the airline agent\n",
|
|
"class AirlineAgentContext(BaseModel):\n",
|
|
" passenger_name: str | None = None\n",
|
|
" confirmation_number: str | None = None\n",
|
|
" seat_number: str | None = None\n",
|
|
" flight_number: str | None = None"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Tools for the airline agent\n",
|
|
"@function_tool(name_override=\"faq_lookup_tool\", description_override=\"Lookup frequently asked questions.\")\n",
|
|
"async def faq_lookup_tool(question: str) -> str:\n",
|
|
" if \"bag\" in question or \"baggage\" in question:\n",
|
|
" return (\n",
|
|
" \"You are allowed to bring one bag on the plane. \"\n",
|
|
" \"It must be under 50 pounds and 22 inches x 14 inches x 9 inches.\"\n",
|
|
" )\n",
|
|
" elif \"seats\" in question or \"plane\" in question:\n",
|
|
" return (\n",
|
|
" \"There are 120 seats on the plane. \"\n",
|
|
" \"There are 22 business class seats and 98 economy seats. \"\n",
|
|
" \"Exit rows are rows 4 and 16. \"\n",
|
|
" \"Rows 5-8 are Economy Plus, with extra legroom. \"\n",
|
|
" )\n",
|
|
" elif \"wifi\" in question:\n",
|
|
" return \"We have free wifi on the plane, join Airline-Wifi\"\n",
|
|
" return \"I'm sorry, I don't know the answer to that question.\"\n",
|
|
"\n",
|
|
"\n",
|
|
"@function_tool\n",
|
|
"async def update_seat(context: RunContextWrapper[AirlineAgentContext], confirmation_number: str, new_seat: str) -> str:\n",
|
|
" \"\"\"\n",
|
|
" Update the seat for a given confirmation number.\n",
|
|
"\n",
|
|
" Args:\n",
|
|
" confirmation_number: The confirmation number for the flight.\n",
|
|
" new_seat: The new seat to update to.\n",
|
|
" \"\"\"\n",
|
|
" # Update the context based on the customer's input\n",
|
|
" context.context.confirmation_number = confirmation_number\n",
|
|
" context.context.seat_number = new_seat\n",
|
|
" # Ensure that the flight number has been set by the incoming handoff\n",
|
|
" assert context.context.flight_number is not None, \"Flight number is required\"\n",
|
|
" return f\"Updated seat to {new_seat} for confirmation number {confirmation_number}\"\n",
|
|
"\n",
|
|
"\n",
|
|
"### HOOKS\n",
|
|
"\n",
|
|
"\n",
|
|
"async def on_seat_booking_handoff(context: RunContextWrapper[AirlineAgentContext]) -> None:\n",
|
|
" flight_number = f\"FLT-{random.randint(100, 999)}\"\n",
|
|
" context.context.flight_number = flight_number\n",
|
|
"\n",
|
|
"\n",
|
|
"### AGENTS\n",
|
|
"\n",
|
|
"faq_agent = Agent[AirlineAgentContext](\n",
|
|
" name=\"FAQ Agent\",\n",
|
|
" handoff_description=\"A helpful agent that can answer questions about the airline.\",\n",
|
|
" instructions=f\"\"\"{RECOMMENDED_PROMPT_PREFIX}\n",
|
|
" You are an FAQ agent. If you are speaking to a customer, you probably were transferred to from the triage agent.\n",
|
|
" Use the following routine to support the customer.\n",
|
|
" # Routine\n",
|
|
" 1. Identify the last question asked by the customer.\n",
|
|
" 2. Use the faq lookup tool to answer the question. Do not rely on your own knowledge.\n",
|
|
" 3. If you cannot answer the question, transfer back to the triage agent.\"\"\",\n",
|
|
" tools=[faq_lookup_tool],\n",
|
|
")\n",
|
|
"\n",
|
|
"seat_booking_agent = Agent[AirlineAgentContext](\n",
|
|
" name=\"Seat Booking Agent\",\n",
|
|
" handoff_description=\"A helpful agent that can update a seat on a flight.\",\n",
|
|
" instructions=f\"\"\"{RECOMMENDED_PROMPT_PREFIX}\n",
|
|
" You are a seat booking agent. If you are speaking to a customer, you probably were transferred to from the triage agent.\n",
|
|
" Use the following routine to support the customer.\n",
|
|
" # Routine\n",
|
|
" 1. Ask for their confirmation number.\n",
|
|
" 2. Ask the customer what their desired seat number is.\n",
|
|
" 3. Use the update seat tool to update the seat on the flight.\n",
|
|
" If the customer asks a question that is not related to the routine, transfer back to the triage agent. \"\"\",\n",
|
|
" tools=[update_seat],\n",
|
|
")\n",
|
|
"\n",
|
|
"triage_agent = Agent[AirlineAgentContext](\n",
|
|
" name=\"Triage Agent\",\n",
|
|
" handoff_description=\"A triage agent that can delegate a customer's request to the appropriate agent.\",\n",
|
|
" instructions=(\n",
|
|
" f\"{RECOMMENDED_PROMPT_PREFIX} \"\n",
|
|
" \"You are a helpful triaging agent. You can use your tools to delegate questions to other appropriate agents.\"\n",
|
|
" ),\n",
|
|
" handoffs=[\n",
|
|
" faq_agent,\n",
|
|
" handoff(agent=seat_booking_agent, on_handoff=on_seat_booking_handoff),\n",
|
|
" ],\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"faq_agent.handoffs.append(triage_agent)\n",
|
|
"seat_booking_agent.handoffs.append(triage_agent)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"async def main():\n",
|
|
" current_agent: Agent[AirlineAgentContext] = triage_agent\n",
|
|
" input_items: list[TResponseInputItem] = []\n",
|
|
" context = AirlineAgentContext()\n",
|
|
"\n",
|
|
" # Normally, each input from the user would be an API request to your app, and you can wrap the request in a trace()\n",
|
|
" # Here, we'll just use a random UUID for the conversation ID\n",
|
|
" conversation_id = uuid.uuid4().hex[:16]\n",
|
|
"\n",
|
|
" while True:\n",
|
|
" user_input = input(\"Enter your message: \")\n",
|
|
" with trace(\"Customer service\", group_id=conversation_id):\n",
|
|
" input_items.append({\"content\": user_input, \"role\": \"user\"})\n",
|
|
" result = await Runner.run(current_agent, input_items, context=context)\n",
|
|
"\n",
|
|
" for new_item in result.new_items:\n",
|
|
" agent_name = new_item.agent.name\n",
|
|
" if isinstance(new_item, MessageOutputItem):\n",
|
|
" print(f\"{agent_name}: {ItemHelpers.text_message_output(new_item)}\")\n",
|
|
" elif isinstance(new_item, HandoffOutputItem):\n",
|
|
" print(f\"Handed off from {new_item.source_agent.name} to {new_item.target_agent.name}\")\n",
|
|
" elif isinstance(new_item, ToolCallItem):\n",
|
|
" print(f\"{agent_name}: Calling a tool\")\n",
|
|
" elif isinstance(new_item, ToolCallOutputItem):\n",
|
|
" print(f\"{agent_name}: Tool call output: {new_item.output}\")\n",
|
|
" else:\n",
|
|
" print(f\"{agent_name}: Skipping item: {new_item.__class__.__name__}\")\n",
|
|
" input_items = result.to_input_list()\n",
|
|
" current_agent = result.last_agent"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"await main()\n",
|
|
"agentops.end_trace(tracer, end_state=\"Success\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Conclusion\n",
|
|
"\n",
|
|
"**AgentOps makes observability effortless** - simply import the library and all your interactions are automatically tracked, visualized, and analyzed. This enables you to:\n",
|
|
"\n",
|
|
"- Monitor tool performance across different use cases\n",
|
|
"- Optimize costs by understanding tool usage patterns\n",
|
|
"- Debug tool integration issues quickly\n",
|
|
"- Scale your AI applications with confidence in tool reliability\n",
|
|
"\n",
|
|
"Visit [app.agentops.ai](https://app.agentops.ai) to explore your tool usage sessions and gain deeper insights into your AI application's tool interactions."
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "agentops (3.11.11)",
|
|
"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.11"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|