Skip to content

Instantly share code, notes, and snippets.

@jwill9999
Created August 30, 2025 23:23
Show Gist options
  • Save jwill9999/d946554fb305d8517f99d5c63445d64e to your computer and use it in GitHub Desktop.
Save jwill9999/d946554fb305d8517f99d5c63445d64e to your computer and use it in GitHub Desktop.
An example of deep research
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Deep Research\n",
"\n",
"One of the classic cross-business Agentic use cases! This is huge."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<table style=\"margin: 0; text-align: left; width:100%\">\n",
" <tr>\n",
" <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
" <img src=\"../assets/business.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
" </td>\n",
" <td>\n",
" <h2 style=\"color:#00bfff;\">Commercial implications</h2>\n",
" <span style=\"color:#00bfff;\">A Deep Research agent is broadly applicable to any business area, and to your own day-to-day activities. You can make use of this yourself!\n",
" </span>\n",
" </td>\n",
" </tr>\n",
"</table>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"\n",
"from agents import Agent, WebSearchTool, trace, Runner, function_tool\n",
"from agents.model_settings import ModelSettings\n",
"from pydantic import BaseModel\n",
"from dotenv import load_dotenv\n",
"import asyncio\n",
"import os\n",
"from IPython.display import display, Markdown\n",
"from pprint import pprint\n",
"import requests\n",
"load_dotenv(override=True)\n",
"\n",
"# Constants\n",
"\n",
"pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
"pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
"pushover_url = \"https://api.pushover.net/1/messages.json\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## OpenAI Hosted Tools\n",
"\n",
"OpenAI Agents SDK includes the following hosted tools:\n",
"\n",
"The `WebSearchTool` lets an agent search the web. \n",
"The `FileSearchTool` allows retrieving information from your OpenAI Vector Stores. \n",
"The `ComputerTool` allows automating computer use tasks like taking screenshots and clicking.\n",
"\n",
"### Important note - API charge of WebSearchTool\n",
"\n",
"This is costing me 2.5 cents per call for OpenAI WebSearchTool. That can add up to $2-$3 for the next 2 labs. We'll use low cost Search tools with other platforms, so feel free to skip running this if the cost is a concern.\n",
"\n",
"Costs are here: https://platform.openai.com/docs/pricing#web-search"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## We will be making 4 Agents:\n",
"\n",
"1. Search Agent - searches online given a search term using an OpenAI hosted tool\n",
"2. Planner Agent - given a query from the user, come up with searches\n",
"3. Report Agent - make a report on results\n",
"4. Push Agent - send a notification to the user's phone with a summary\n",
"\n",
"## Our First Agent: Search Agent\n",
"\n",
"Given a Search term, search for it on the internet and summarize results."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"INSTRUCTIONS = \"You are a research assistant. Given a search term, you search the web for that term and \\\n",
"produce a concise summary of the results. The summary must 2-3 paragraphs and less than 300 \\\n",
"words. Capture the main points. Write succintly, no need to have complete sentences or good \\\n",
"grammar. This will be consumed by someone synthesizing a report, so it's vital you capture the \\\n",
"essence and ignore any fluff. Do not include any additional commentary other than the summary itself.\"\n",
"\n",
"search_agent = Agent(\n",
" name=\"Search agent\",\n",
" instructions=INSTRUCTIONS,\n",
" tools=[WebSearchTool(search_context_size=\"low\")],\n",
" model=\"gpt-4.1-mini\",\n",
" model_settings=ModelSettings(tool_choice=\"required\"),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"message = \"What are the most popular and successful AI Agent frameworks in May 2025\"\n",
"\n",
"with trace(\"Search\"):\n",
" result = await Runner.run(search_agent, message)\n",
"\n",
"display(Markdown(result.final_output))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Take a look at the trace\n",
"\n",
"https://platform.openai.com/traces"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Our Second Agent: Planner Agent\n",
"\n",
"Given a query, come up with 5 ideas for web searches that could be run.\n",
"\n",
"Use Structured Outputs as our way to ensure the Agent provides what we need."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# See note above about cost of WebSearchTool\n",
"\n",
"HOW_MANY_SEARCHES = 5\n",
"\n",
"INSTRUCTIONS = f\"You are a helpful research assistant. Given a query, come up with a set of web searches \\\n",
"to perform to best answer the query. Output {HOW_MANY_SEARCHES} terms to query for.\"\n",
"\n",
"# We use Pydantic objects to describe the Schema of the output\n",
"\n",
"class WebSearchItem(BaseModel):\n",
" reason: str\n",
" \"Your reasoning for why this search is important to the query.\"\n",
"\n",
" query: str\n",
" \"The search term to use for the web search.\"\n",
"\n",
"\n",
"class WebSearchPlan(BaseModel):\n",
" searches: list[WebSearchItem]\n",
" \"\"\"A list of web searches to perform to best answer the query.\"\"\"\n",
"\n",
"# We pass in the Pydantic object to ensure the output follows the schema\n",
"\n",
"planner_agent = Agent(\n",
" name=\"PlannerAgent\",\n",
" instructions=INSTRUCTIONS,\n",
" model=\"gpt-4.1-mini\",\n",
" output_type=WebSearchPlan,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"message = \"What are the most popular and successful AI Agent frameworks in May 2025\"\n",
"\n",
"with trace(\"Search\"):\n",
" result = await Runner.run(planner_agent, message)\n",
" pprint(result.final_output)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Our Third Agent: Writer Agent\n",
"\n",
"Take the results of internet searches and make a report"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"INSTRUCTIONS = (\n",
" \"You are a senior researcher tasked with writing a cohesive report for a research query. \"\n",
" \"You will be provided with the original query, and some initial research done by a research assistant.\\n\"\n",
" \"You should first come up with an outline for the report that describes the structure and \"\n",
" \"flow of the report. Then, generate the report and return that as your final output.\\n\"\n",
" \"The final output should be in markdown format, and it should be lengthy and detailed. Aim \"\n",
" \"for 5-10 pages of content, at least 1000 words.\"\n",
")\n",
"\n",
"\n",
"class ReportData(BaseModel):\n",
" short_summary: str\n",
" \"\"\"A short 2-3 sentence summary of the findings.\"\"\"\n",
"\n",
" markdown_report: str\n",
" \"\"\"The final report\"\"\"\n",
"\n",
" follow_up_questions: list[str]\n",
" \"\"\"Suggested topics to research further\"\"\"\n",
"\n",
"\n",
"writer_agent = Agent(\n",
" name=\"WriterAgent\",\n",
" instructions=INSTRUCTIONS,\n",
" model=\"gpt-4o-mini\",\n",
" output_type=ReportData,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Our Fourth Agent: push notification\n",
"\n",
"Just to show how easy it is to make a tool!\n",
"\n",
"I'm using a nifty product called PushOver - to set this up yourself, visit https://pushover.net"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"@function_tool\n",
"def push(message: str):\n",
" \"\"\"Send a push notification with this brief message\"\"\"\n",
" payload = {\"user\": pushover_user, \"token\": pushover_token, \"message\": message}\n",
" requests.post(pushover_url, data=payload)\n",
" return {\"status\": \"success\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"push"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"INSTRUCTIONS = \"\"\"You are a member of a research team and will be provided with a short summary of a report.\n",
"When you receive the report summary, you send a push notification to the user using your tool, informing them that research is complete,\n",
"and including the report summary you receive\"\"\"\n",
"\n",
"\n",
"push_agent = Agent(\n",
" name=\"Push agent\",\n",
" instructions=INSTRUCTIONS,\n",
" tools=[push],\n",
" model=\"gpt-4.1-mini\",\n",
" model_settings=ModelSettings(tool_choice=\"required\")\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The next 3 functions will plan and execute the search, using planner_agent and search_agent"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"async def plan_searches(query: str):\n",
" \"\"\" Use the planner_agent to plan which searches to run for the query \"\"\"\n",
" print(\"Planning searches...\")\n",
" result = await Runner.run(planner_agent, f\"Query: {query}\")\n",
" print(f\"Will perform {len(result.final_output.searches)} searches\")\n",
" return result.final_output\n",
"\n",
"async def perform_searches(search_plan: WebSearchPlan):\n",
" \"\"\" Call search() for each item in the search plan \"\"\"\n",
" print(\"Searching...\")\n",
" tasks = [asyncio.create_task(search(item)) for item in search_plan.searches]\n",
" results = await asyncio.gather(*tasks)\n",
" print(\"Finished searching\")\n",
" return results\n",
"\n",
"async def search(item: WebSearchItem):\n",
" \"\"\" Use the search agent to run a web search for each item in the search plan \"\"\"\n",
" input = f\"Search term: {item.query}\\nReason for searching: {item.reason}\"\n",
" result = await Runner.run(search_agent, input)\n",
" return result.final_output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The next 2 functions write a report and send a push notification"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"async def write_report(query: str, search_results: list[str]):\n",
" \"\"\" Use the writer agent to write a report based on the search results\"\"\"\n",
" print(\"Thinking about report...\")\n",
" input = f\"Original query: {query}\\nSummarized search results: {search_results}\"\n",
" result = await Runner.run(writer_agent, input)\n",
" print(\"Finished writing report\")\n",
" return result.final_output\n",
"\n",
"async def send_push(report: ReportData):\n",
" \"\"\" Use the push agent to send a notification to the user \"\"\"\n",
" print(\"Pushing...\")\n",
" result = await Runner.run(push_agent, report.short_summary)\n",
" print(\"Push sent\")\n",
" return report"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Showtime!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"query =\"What are the most popular and successful AI Agent frameworks in May 2025\"\n",
"\n",
"with trace(\"Research trace\"):\n",
" print(\"Starting research...\")\n",
" search_plan = await plan_searches(query)\n",
" search_results = await perform_searches(search_plan)\n",
" report = await write_report(query, search_results)\n",
" await send_push(report) \n",
" print(\"Hooray!\")\n",
"display(Markdown(report.markdown_report))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### As always, take a look at the trace\n",
"\n",
"https://platform.openai.com/traces"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment