Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
243 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "aslamkhan-github/lab", "files": {"AI/projects/agents/1_foundations/community_contributions/2_lab2_async.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745480.5559027, "n": 14252, "h": "08c3405382f7c27b", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"import asyncio\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI, AsyncOpenAI\\n\",\n \"from anthropic import AsyncAnthropic\\n\",\n \"from pydantic import BaseModel\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')\\n\",\n \"ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')\\n\",\n \"DEEPSEEK_API_KEY = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"GROQ_API_KEY = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if OPENAI_API_KEY:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {OPENAI_API_KEY[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if ANTHROPIC_API_KEY:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {ANTHROPIC_API_KEY[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if GOOGLE_API_KEY:\\n\",\n \" print(f\\\"Google API Key exists and begins {GOOGLE_API_KEY[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if DEEPSEEK_API_KEY:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {DEEPSEEK_API_KEY[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if GROQ_API_KEY:\\n\",\n \" print(f\\\"Groq API Key exists and begins {GROQ_API_KEY[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(messages)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = AsyncOpenAI()\\n\",\n \"response = await openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-4o-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Define Pydantic model for storing LLM results\\n\",\n \"class LLMResult(BaseModel):\\n\",\n \" model: str\\n\",\n \" answer: str\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"results: list[LLMResult] = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 9,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"async def openai_answer() -> None:\\n\",\n \"\\n\",\n \" if OPENAI_API_KEY is None:\\n\",\n \" return None\\n\",\n \" \\n\",\n \" print(\\\"OpenAI starting!\\\")\\n\",\n \" model_name = \\\"gpt-4o-mini\\\"\\n\",\n \"\\n\",\n \" try:\\n\",\n \" response = await openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with OpenAI: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"OpenAI done!\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 10,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"\\n\",\n \"async def anthropic_answer() -> None:\\n\",\n \"\\n\",\n \" if ANTHROPIC_API_KEY is None:\\n\",\n \" return None\\n\",\n \" \\n\",\n \" print(\\\"Anthropic starting!\\\")\\n\",\n \" model_name = \\\"claude-3-7-sonnet-latest\\\"\\n\",\n \"\\n\",\n \" claude = AsyncAnthropic()\\n\",\n \" try:\\n\",\n \" response = await claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \" answer = response.content[0].text\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with Anthropic: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"Anthropic done!\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 11,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def google_answer() -> None:\\n\",\n \"\\n\",\n \" if GOOGLE_API_KEY is None:\\n\",\n \" return None\\n\",\n \" \\n\",\n \" print(\\\"Google starting!\\\")\\n\",\n \" model_name = \\\"gemini-2.0-flash\\\"\\n\",\n \"\\n\",\n \" gemini = AsyncOpenAI(api_key=GOOGLE_API_KEY, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \" try:\\n\",\n \" response = await gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with Google: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"Google done!\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def deepseek_answer() -> None:\\n\",\n \"\\n\",\n \" if DEEPSEEK_API_KEY is None:\\n\",\n \" return None\\n\",\n \" \\n\",\n \" print(\\\"DeepSeek starting!\\\")\\n\",\n \" model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \" deepseek = AsyncOpenAI(api_key=DEEPSEEK_API_KEY, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \" try:\\n\",\n \" response = await deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with DeepSeek: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"DeepSeek done!\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def groq_answer() -> None:\\n\",\n \"\\n\",\n \" if GROQ_API_KEY is None:\\n\",\n \" return None\\n\",\n \" \\n\",\n \" print(\\\"Groq starting!\\\")\\n\",\n \" model_name = \\\"llama-3.3-70b-versatile\\\"\\n\",\n \"\\n\",\n \" groq = AsyncOpenAI(api_key=GROQ_API_KEY, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \" try:\\n\",\n \" response = await groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with Groq: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"Groq done!\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 15,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def ollama_answer() -> None:\\n\",\n \" model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \" print(\\\"Ollama starting!\\\")\\n\",\n \" ollama = AsyncOpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \" try:\\n\",\n \" response = await ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" results.append(LLMResult(model=model_name, answer=answer))\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error with Ollama: {e}\\\")\\n\",\n \" return None\\n\",\n \"\\n\",\n \" print(\\\"Ollama done!\\\") \"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def gather_answers():\\n\",\n \" tasks = [\\n\",\n \" openai_answer(),\\n\",\n \" anthropic_answer(),\\n\",\n \" google_answer(),\\n\",\n \" deepseek_answer(),\\n\",\n \" groq_answer(),\\n\",\n \" ollama_answer()\\n\",\n \" ]\\n\",\n \" await asyncio.gather(*tasks)\\n\",\n \"\\n\",\n \"await gather_answers()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"together = \\\"\\\"\\n\",\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"\\n\",\n \"for res in results:\\n\",\n \" competitor = res.model\\n\",\n \" answer = res.answer\\n\",\n \" competitors.append(competitor)\\n\",\n \" answers.append(answer)\\n\",\n \" together += f\\\"# Response from competitor {competitor}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Number of competitors: {len(results)}\\\")\\n\",\n \"print(together)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 18,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(results)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 20,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"o3-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"judgement = response.choices[0].message.content\\n\",\n \"print(judgement)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(judgement)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, comp in enumerate(ranks):\\n\",\n \" print(f\\\"Rank {index+1}: {comp}\\\")\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.11\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/1_lab2_Routing_Workflow.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745482.6962347, "n": 16261, "h": "e319ec7e127a7e63", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Judging and Routing — Optimizing Resource Usage by Evaluating Problem Complexity\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"In the original Lab 2, we explored the **Orchestrator–Worker pattern**, where a planner sent the same question to multiple agents, and a judge assessed their responses to evaluate agent intelligence.\\n\",\n \"\\n\",\n \"In this notebook, we extend that design by adding multiple judges and a routing component to optimize model usage based on task complexity. \"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Imports and Environment Setup\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"load_dotenv(override=True)\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"if openai_api_key and google_api_key and deepseek_api_key:\\n\",\n \" print(\\\"All keys were loaded successfully\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\\n\",\n \"!ollama pull mistral\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Creating Models\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"The notebook uses instances of GPT, Gemini and DeepSeek APIs, along with two local models served via Ollama: ```llama3.2``` and ```mistral```.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"model_specs = {\\n\",\n \" \\\"gpt-4o-mini\\\" : None,\\n\",\n \" \\\"gemini-2.0-flash\\\": {\\n\",\n \" \\\"api_key\\\" : google_api_key,\\n\",\n \" \\\"url\\\" : \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \" },\\n\",\n \" \\\"deepseek-chat\\\" : {\\n\",\n \" \\\"api_key\\\" : deepseek_api_key,\\n\",\n \" \\\"url\\\" : \\\"https://api.deepseek.com/v1\\\"\\n\",\n \" },\\n\",\n \" \\\"llama3.2\\\" : {\\n\",\n \" \\\"api_key\\\" : \\\"ollama\\\",\\n\",\n \" \\\"url\\\" : \\\"http://localhost:11434/v1\\\"\\n\",\n \" },\\n\",\n \" \\\"mistral\\\" : {\\n\",\n \" \\\"api_key\\\" : \\\"ollama\\\",\\n\",\n \" \\\"url\\\" : \\\"http://localhost:11434/v1\\\"\\n\",\n \" }\\n\",\n \"}\\n\",\n \"\\n\",\n \"def create_model(model_name):\\n\",\n \" spec = model_specs[model_name]\\n\",\n \" if spec is None:\\n\",\n \" return OpenAI()\\n\",\n \" \\n\",\n \" return OpenAI(api_key=spec[\\\"api_key\\\"], base_url=spec[\\\"url\\\"])\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"orchestrator_model = \\\"gemini-2.0-flash\\\"\\n\",\n \"generator = create_model(orchestrator_model)\\n\",\n \"router = create_model(orchestrator_model)\\n\",\n \"\\n\",\n \"qa_models = {\\n\",\n \" model_name : create_model(model_name) \\n\",\n \" for model_name in model_specs.keys()\\n\",\n \"}\\n\",\n \"\\n\",\n \"judges = {\\n\",\n \" model_name : create_model(model_name) \\n\",\n \" for model_name, specs in model_specs.items() \\n\",\n \" if not(specs) or specs[\\\"api_key\\\"] != \\\"ollama\\\"\\n\",\n \"}\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Orchestrator-Worker Workflow\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"First, we generate a question to evaluate the intelligence of each LLM.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs \\\"\\n\",\n \"request += \\\"to evaluate and rank them based on their intelligence. \\\" \\n\",\n \"request += \\\"Answer **only** with the question, no explanation or preamble.\\\"\\n\",\n \"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\\n\",\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"response = generator.chat.completions.create(\\n\",\n \" model=orchestrator_model,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"eval_question = response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"display(Markdown(eval_question))\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Task Parallelization\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"Now, having the question and all the models instantiated it's time to see what each model has to say about the complex task it was given.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"question = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": eval_question}]\\n\",\n \"answers = []\\n\",\n \"competitors = []\\n\",\n \"\\n\",\n \"for name, model in qa_models.items():\\n\",\n \" response = model.chat.completions.create(model=name, messages=question)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" competitors.append(name)\\n\",\n \" answers.append(answer)\\n\",\n \"\\n\",\n \"answers\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"report = \\\"# Answer report for each of the 5 models\\\\n\\\\n\\\"\\n\",\n \"report += \\\"\\\\n\\\\n\\\".join([f\\\"## **Model: {model}**\\\\n\\\\n{answer}\\\" for model, answer in zip(competitors, answers)])\\n\",\n \"display(Markdown(report))\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Synthetizer/Judge\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"The Judge Agents ranks the LLM responses based on coherence and relevance to the evaluation prompt. Judges vote and the final LLM ranking is based on the aggregated ranking of all three judges.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\\n\",\n \"\\n\",\n \"together\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_prompt = f\\\"\\\"\\\"\\n\",\n \" You are judging a competition between {len(competitors)} LLM competitors.\\n\",\n \" Each model has been given this nuanced question to evaluate their intelligence:\\n\",\n \"\\n\",\n \" {eval_question}\\n\",\n \"\\n\",\n \" Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \" Respond with JSON, and only JSON, with the following format:\\n\",\n \" {{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \" With 'best competitor number being ONLY the number', for instance:\\n\",\n \" {{\\\"results\\\": [\\\"5\\\", \\\"2\\\", \\\"4\\\", ...]}}\\n\",\n \" Here are the responses from each competitor:\\n\",\n \"\\n\",\n \" {together}\\n\",\n \"\\n\",\n \" Now respond with the JSON with the ranked order of the competitors, nothing else. Do NOT include MARKDOWN FORMATTING or CODE BLOCKS. ONLY the JSON\\n\",\n \" \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge_prompt}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"from collections import defaultdict\\n\",\n \"import re\\n\",\n \"\\n\",\n \"N = len(competitors)\\n\",\n \"scores = defaultdict(int)\\n\",\n \"for judge_name, judge in judges.items():\\n\",\n \" response = judge.chat.completions.create(\\n\",\n \" model=judge_name,\\n\",\n \" messages=judge_messages,\\n\",\n \" )\\n\",\n \" response = response.choices[0].message.content\\n\",\n \" response_json = re.findall(r'\\\\{.*?\\\\}', response)[0]\\n\",\n \" results = json.loads(response_json)[\\\"results\\\"]\\n\",\n \" ranks = [int(result) for result in results]\\n\",\n \" print(f\\\"Judge {judge_name} ranking:\\\")\\n\",\n \" for i, c in enumerate(ranks):\\n\",\n \" model_name = competitors[c - 1]\\n\",\n \" print(f\\\"#{i+1} : {model_name}\\\")\\n\",\n \" scores[c - 1] += (N - i)\\n\",\n \" print()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"sorted_indices = sorted(scores, key=scores.get)\\n\",\n \"\\n\",\n \"# Convert to model names\\n\",\n \"ranked_model_names = [competitors[i] for i in sorted_indices]\\n\",\n \"\\n\",\n \"print(\\\"Final ranking from best to worst:\\\")\\n\",\n \"for i, name in enumerate(ranked_model_names[::-1], 1):\\n\",\n \" print(f\\\"#{i}: {name}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Routing Workflow\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"We now define a routing agent responsible for classifying task complexity and delegating the prompt to the most appropriate model.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 15,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def classify_question_complexity(question: str, routing_agent, routing_model) -> int:\\n\",\n \" \\\"\\\"\\\"\\n\",\n \" Ask an LLM to classify the question complexity from 1 (easy) to 5 (very hard).\\n\",\n \" \\\"\\\"\\\"\\n\",\n \" prompt = f\\\"\\\"\\\"\\n\",\n \" You are a classifier responsible for assigning a complexity level to user questions, based on how difficult they would be for a language model to answer.\\n\",\n \"\\n\",\n \" Please read the question below and assign a complexity score from 1 to 5:\\n\",\n \"\\n\",\n \" - Level 1: Very simple factual or definitional question (e.g., “What is the capital of France?”)\\n\",\n \" - Level 2: Slightly more involved, requiring basic reasoning or comparison\\n\",\n \" - Level 3: Moderate complexity, requiring synthesis, context understanding, or multi-part answers\\n\",\n \" - Level 4: High complexity, requiring abstract thinking, ethical judgment, or creative generation\\n\",\n \" - Level 5: Extremely challenging, requiring deep reasoning, philosophical reflection, or long-term multi-step inference\\n\",\n \"\\n\",\n \" Respond ONLY with a single integer between 1 and 5 that best reflects the complexity of the question.\\n\",\n \"\\n\",\n \" Question:\\n\",\n \" {question}\\n\",\n \" \\\"\\\"\\\"\\n\",\n \"\\n\",\n \" response = routing_agent.chat.completions.create(\\n\",\n \" model=routing_model,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": prompt}]\\n\",\n \" )\\n\",\n \" try:\\n\",\n \" return int(response.choices[0].message.content.strip())\\n\",\n \" except Exception:\\n\",\n \" return 3 # default to medium complexity on error\\n\",\n \" \\n\",\n \"def route_question_to_model(question: str, models_by_rank, classifier_model=router, model_name=orchestrator_model):\\n\",\n \" level = classify_question_complexity(question, classifier_model, model_name)\\n\",\n \" selected_model_name = models_by_rank[level - 1]\\n\",\n \" return selected_model_name\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"difficulty_prompts = [\\n\",\n \" \\\"Generate a very basic, factual question that a small or entry-level language model could answer easily. It should require no reasoning, just direct knowledge lookup.\\\",\\n\",\n \" \\\"Generate a slightly involved question that requires basic reasoning, comparison, or combining two known facts. Still within the grasp of small models but not purely factual.\\\",\\n\",\n \" \\\"Generate a moderately challenging question that requires some synthesis of ideas, multi-step reasoning, or contextual understanding. A mid-tier model should be able to answer it with effort.\\\",\\n\",\n \" \\\"Generate a difficult question involving abstract thinking, open-ended reasoning, or ethical tradeoffs. The question should challenge large models to produce thoughtful and coherent responses.\\\",\\n\",\n \" \\\"Generate an extremely complex and nuanced question that tests the limits of current language models. It should require deep reasoning, long-term planning, philosophy, or advanced multi-domain knowledge.\\\"\\n\",\n \"]\\n\",\n \"def generate_question(level, generator=generator, generator_model=orchestrator_model):\\n\",\n \" prompt = (\\n\",\n \" f\\\"{difficulty_prompts[level - 1]}\\\\n\\\"\\n\",\n \" \\\"Answer only with the question, no explanation.\\\"\\n\",\n \" )\\n\",\n \" messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": prompt}]\\n\",\n \" response = generator.chat.completions.create(\\n\",\n \" model=generator_model, # or your planner model\\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \" \\n\",\n \" return response.choices[0].message.content\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Testing Routing Workflow\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"Finally, to test the routing workflow, we create a function that accepts a task complexity level and triggers the full routing process.\\n\",\n \"\\n\",\n \"*Note: A level-N prompt isn't always assigned to the Nth-most capable model due to the classifier's subjective decisions.*\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 17,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def test_generation_routing(level):\\n\",\n \" question = generate_question(level=level)\\n\",\n \" answer_model = route_question_to_model(question, ranked_model_names)\\n\",\n \" messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\\n\",\n \"\\n\",\n \" response =qa_models[answer_model].chat.completions.create(\\n\",\n \" model=answer_model, # or your planner model\\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \" print(f\\\"Question : {question}\\\")\\n\",\n \" print(f\\\"Routed to {answer_model}\\\")\\n\",\n \" display(Markdown(response.choices[0].message.content))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"test_generation_routing(level=1)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"test_generation_routing(level=2)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"test_generation_routing(level=3)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"test_generation_routing(level=4)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"test_generation_routing(level=5)\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.11\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/2_openai/community_contributions/2_lab2_product_recommendation.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745484.4399438, "n": 31348, "h": "b3b213bb8f4dbf8e", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"6cab655c\",\n \"metadata\": {},\n \"source\": [\n \"# Creating a Product Recommendation Solution to help people with analysis paralysis\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"81dcbaa2\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Import necessary libraries\\n\",\n \"import os\\n\",\n \"import litellm\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from duckduckgo_search import DDGS\\n\",\n \"from agents import Agent, Runner, trace\\n\",\n \"from datetime import datetime\\n\",\n \"from agents.extensions.models.litellm_model import LitellmModel\\n\",\n \"import ipywidgets as widgets\\n\",\n \"from IPython.display import display, Markdown\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c401bea7\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Load environment variables\\n\",\n \"load_dotenv(override=True)\\n\",\n \"#litellm._turn_on_debug()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"70fa4952\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Test your API keys - add this as a new cell\\n\",\n \"async def test_api_keys():\\n\",\n \" print(\\\"Testing API connections...\\\")\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Test OpenAI\\n\",\n \" test_openai = LitellmModel(model=\\\"gpt-4o-mini\\\", api_key=os.getenv(\\\"OPENAI_API_KEY\\\"))\\n\",\n \" print(\\\"✅ OpenAI API key working\\\")\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"❌ OpenAI API issue: {e}\\\")\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Test Gemini\\n\",\n \" test_gemini = LitellmModel(model=\\\"gemini-pro\\\", api_key=os.getenv(\\\"GEMINI_API_KEY\\\"))\\n\",\n \" print(\\\"✅ Gemini API key working\\\")\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"❌ Gemini API issue: {e}\\\")\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Test DeepSeek\\n\",\n \" test_deepseek = LitellmModel(model=\\\"deepseek/deepseek-chat\\\", api_key=os.getenv(\\\"DEEPSEEK_API_KEY\\\"))\\n\",\n \" print(\\\"✅ DeepSeek API key working\\\")\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"❌ DeepSeek API issue: {e}\\\")\\n\",\n \"\\n\",\n \"await test_api_keys()\\n\",\n \"\\n\",\n \"# System Status Check\\n\",\n \"def check_system_status():\\n\",\n \" print(\\\"🔍 System Status Check\\\")\\n\",\n \" print(\\\"=\\\" * 30)\\n\",\n \" \\n\",\n \" # Check APIs\\n\",\n \" apis_working = []\\n\",\n \" if os.getenv(\\\"OPENAI_API_KEY\\\"):\\n\",\n \" apis_working.append(\\\"OpenAI ✅\\\")\\n\",\n \" if os.getenv(\\\"GEMINI_API_KEY\\\"):\\n\",\n \" apis_working.append(\\\"Gemini ✅\\\")\\n\",\n \" if os.getenv(\\\"DEEPSEEK_API_KEY\\\"):\\n\",\n \" apis_working.append(\\\"DeepSeek ✅\\\")\\n\",\n \" \\n\",\n \" print(f\\\"APIs: {', '.join(apis_working)}\\\")\\n\",\n \" print(f\\\"Language: {session.user_preferences['language']}\\\")\\n\",\n \" print(f\\\"Session messages: {len(session.conversation_history)}\\\")\\n\",\n \" print(f\\\"Available tools: {len([electronics_smarttech_tool, lifestyle_wellness_tool, entertainment_tool, home_garden_pets_tool, fashion_lifestyle_tool, sports_auto_industry_tool])}\\\")\\n\",\n \" \\n\",\n \" if len(apis_working) > 0:\\n\",\n \" print(\\\"🟢 System ready\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"🔴 System not ready - check API keys\\\")\\n\",\n \"\\n\",\n \"# Uncomment to check status\\n\",\n \" #check_system_status()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"e2effdba\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Define language selection\\n\",\n \"language_selector = widgets.Dropdown(\\n\",\n \" options=['English', 'Spanish', 'Portuguese', 'French', 'Italian', 'German', 'Dutch', 'Chinese'],\\n\",\n \" value='English',\\n\",\n \" description='Language:',\\n\",\n \")\\n\",\n \"\\n\",\n \"display(language_selector)\\n\",\n \"\\n\",\n \"# Simplified Session Manager - let the agent handle region naturally\\n\",\n \"class SessionManager:\\n\",\n \" def __init__(self):\\n\",\n \" self.conversation_history = []\\n\",\n \" self.user_preferences = {\\n\",\n \" \\\"language\\\": \\\"English\\\",\\n\",\n \" \\\"region\\\": \\\"\\\", # Agent will manage this\\n\",\n \" \\\"current_request\\\": \\\"\\\"\\n\",\n \" }\\n\",\n \" \\n\",\n \" def add_message(self, role, content):\\n\",\n \" self.conversation_history.append({\\n\",\n \" \\\"role\\\": role,\\n\",\n \" \\\"content\\\": content,\\n\",\n \" \\\"timestamp\\\": datetime.now()\\n\",\n \" })\\n\",\n \" \\n\",\n \" def get_context(self):\\n\",\n \" return self.conversation_history[-5:] if len(self.conversation_history) > 5 else self.conversation_history\\n\",\n \" \\n\",\n \" def get_context_string(self):\\n\",\n \" \\\"\\\"\\\"Get conversation context as a string for the agent\\\"\\\"\\\"\\n\",\n \" if not self.conversation_history:\\n\",\n \" return \\\"\\\"\\n\",\n \" \\n\",\n \" context = \\\"Previous conversation:\\\\n\\\"\\n\",\n \" for msg in self.get_context():\\n\",\n \" role = msg[\\\"role\\\"].title()\\n\",\n \" context += f\\\"{role}: {msg['content']}\\\\n\\\"\\n\",\n \" \\n\",\n \" return context\\n\",\n \"\\n\",\n \"# Initialize session\\n\",\n \"session = SessionManager()\\n\",\n \"\\n\",\n \"# Connect language widget to session (keep this part)\\n\",\n \"def on_language_change(change):\\n\",\n \" session.user_preferences[\\\"language\\\"] = change['new']\\n\",\n \" print(f\\\"Language changed to: {change['new']}\\\")\\n\",\n \"\\n\",\n \"language_selector.observe(on_language_change, names='value')\\n\",\n \"selected_language = language_selector.value\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"58c1d1cf\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# === REGION AGENT ===\\n\",\n \"region_search_instructions = f\\\"\\\"\\\"\\n\",\n \"You are a region-specific online shop research agent.\\n\",\n \"\\n\",\n \"Your goal is to help users discover the most relevant, trustworthy, and accessible online shops based on their geographical location or specified region. Your response should include both major global e-commerce platforms and regionally popular, well-known options when possible.\\n\",\n \"\\n\",\n \"Instructions:\\n\",\n \"1. Prioritize well-reviewed and popular shops in the specified region.\\n\",\n \"2. Ensure the online shops cater to the user's expected product categories.\\n\",\n \"3. Consider delivery availability and language support in the region.\\n\",\n \"4. Only access or recommend world-known, verified links of reputable websites such as Amazon, Mercado Livre, Coolblue, Decathlon, and other trusted platforms.\\n\",\n \"5. When performing searches, prefer Google Shopping results but avoid entering or scraping unknown or suspicious websites to minimize risks of viruses or compromised content.\\n\",\n \"6. If a website is not widely recognized or trusted, do NOT access or recommend it.\\n\",\n \"7. Present your findings in a clear, well-structured list.\\n\",\n \"\\n\",\n \"Always respond in English\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"region_search_agent = Agent(\\n\",\n \" name=\\\"Region Search Agent\\\",\\n\",\n \" instructions=region_search_instructions,\\n\",\n \" model=LitellmModel(model=\\\"deepseek/deepseek-chat\\\", api_key=os.getenv(\\\"DEEPSEEK_API_KEY\\\"))\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"4a4b62b0\",\n \"metadata\": {},\n \"source\": [\n \"## Let's start defining our specialist agents\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c8ee9c08\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Shared Gemini configuration for all specialist agents\\n\",\n \"gemini_model_config = LitellmModel(model=\\\"gemini-2.0-flash-exp\\\", api_key=os.getenv(\\\"GEMINI_API_KEY\\\"))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"adf2bb9b\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Electronics & Smart Tech\\n\",\n \"electronics_smarttech_instructions = f\\\"\\\"\\\"\\n\",\n \"You are an Electronics and Smart Tech Specialist Agent.\\n\",\n \"\\n\",\n \"You guide users in choosing modern technology products, including:\\n\",\n \"- Laptops, PCs, phones, tablets\\n\",\n \"- Smart home devices (e.g., Alexa, Google Nest)\\n\",\n \"- Audio & Video gear (e.g., soundbars)\\n\",\n \"- Computer accessories\\n\",\n \"- TVs, wearables, and home security\\n\",\n \"\\n\",\n \"You understand requirements such as HDMI ARC, Bluetooth, price limits, and system configurations.\\n\",\n \"\\n\",\n \"Tags include:\\n\",\n \"- Smart speakers\\n\",\n \"- Home theater\\n\",\n \"- Budget tech\\n\",\n \"- ARC compatible sound systems\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"electronics_smarttech_agent = Agent(\\n\",\n \" name=\\\"Electronics & Smart Tech Specialist\\\",\\n\",\n \" instructions=electronics_smarttech_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\\n\",\n \"\\n\",\n \"# Lifestyle & Wellness\\n\",\n \"lifestyle_wellness_instructions = f\\\"\\\"\\\"\\n\",\n \"You are a Lifestyle and Wellness Specialist Agent.\\n\",\n \"\\n\",\n \"You help users find high-quality products related to health, nutrition, wellness, food, and parenting. Your expertise includes categories like:\\n\",\n \"- Health & Beauty\\n\",\n \"- Dietary Supplements\\n\",\n \"- Sports Nutrition (e.g., protein powder)\\n\",\n \"- Baby & Children’s Products\\n\",\n \"- Food and Beverages\\n\",\n \"\\n\",\n \"You understand Amazon-style product tags such as:\\n\",\n \"- Diet & food\\n\",\n \"- Protein supplements\\n\",\n \"- Sports supplements\\n\",\n \"- Vitamins\\n\",\n \"- Skincare\\n\",\n \"- Baby food\\n\",\n \"- Snacks\\n\",\n \"\\n\",\n \"Ask clarifying questions if needed and make relevant, safe, and trusted recommendations.\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"lifestyle_wellness_agent = Agent(\\n\",\n \" name=\\\"Lifestyle & Wellness Specialist\\\",\\n\",\n \" instructions=lifestyle_wellness_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\\n\",\n \"\\n\",\n \"# Entertainment & Media\\n\",\n \"entertainment_instructions = f\\\"\\\"\\\"\\n\",\n \"You are an Entertainment and Media Specialist Agent.\\n\",\n \"\\n\",\n \"You help users explore content across books, games, music, and video. Your categories include:\\n\",\n \"- Books (fiction, non-fiction, eBooks)\\n\",\n \"- Video Games (consoles, PC, accessories)\\n\",\n \"- Music (vinyl, CDs, digital)\\n\",\n \"- Movies & TV (DVDs, streaming options)\\n\",\n \"\\n\",\n \"Recognize user interests and recommend products that are relevant and popular.\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"entertainment_agent = Agent(\\n\",\n \" name=\\\"Entertainment & Media Specialist\\\",\\n\",\n \" instructions=entertainment_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\\n\",\n \"\\n\",\n \"# Home, Garden & Pets\\n\",\n \"home_garden_pets_instructions = f\\\"\\\"\\\"\\n\",\n \"You are a Home, Garden & Pets Specialist Agent.\\n\",\n \"\\n\",\n \"You assist users in selecting products that enhance home comfort, outdoor living, and pet care. You specialize in:\\n\",\n \"- Furniture & Lighting\\n\",\n \"- Gardening tools & equipment\\n\",\n \"- Pet supplies (food, toys, accessories)\\n\",\n \"- Decor & DIY\\n\",\n \"\\n\",\n \"Amazon tags include:\\n\",\n \"- Home improvement\\n\",\n \"- Garden furniture\\n\",\n \"- Pet grooming\\n\",\n \"- Home organization\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"home_garden_pets_agent = Agent(\\n\",\n \" name=\\\"Home, Garden & Pets Specialist\\\",\\n\",\n \" instructions=home_garden_pets_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\\n\",\n \"\\n\",\n \"# Fashion & Lifestyle Accessories\\n\",\n \"fashion_lifestyle_instructions = f\\\"\\\"\\\"\\n\",\n \"You are a Fashion & Lifestyle Accessories Specialist Agent.\\n\",\n \"\\n\",\n \"You help users find clothing, shoes, jewelry, and stylish accessories tailored to their tastes, needs, and occasions. You cover:\\n\",\n \"- Men’s and Women’s Fashion\\n\",\n \"- Shoes, Bags, Watches\\n\",\n \"- Jewelry and Accessories\\n\",\n \"\\n\",\n \"Use tags like:\\n\",\n \"- Casual wear\\n\",\n \"- Formal wear\\n\",\n \"- Accessories\\n\",\n \"- Seasonal collections\\n\",\n \"\\n\",\n \"Provide outfit ideas or coordinate suggestions when possible.\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"fashion_lifestyle_agent = Agent(\\n\",\n \" name=\\\"Fashion & Lifestyle Specialist\\\",\\n\",\n \" instructions=fashion_lifestyle_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\\n\",\n \"\\n\",\n \"# Sports, Automotive & Industry\\n\",\n \"sports_auto_industry_instructions = f\\\"\\\"\\\"\\n\",\n \"You are a Sports, Automotive & Industry Specialist Agent.\\n\",\n \"\\n\",\n \"You specialize in products related to:\\n\",\n \"- Sports and Outdoor Gear\\n\",\n \"- Car parts, tools, and accessories\\n\",\n \"- Industrial and Scientific Equipment\\n\",\n \"\\n\",\n \"You help users find:\\n\",\n \"- Fitness equipment\\n\",\n \"- Auto electronics\\n\",\n \"- Professional tools\\n\",\n \"- Lab and industry gear\\n\",\n \"\\n\",\n \"Tags include:\\n\",\n \"- Outdoor adventure\\n\",\n \"- Automotive accessories\\n\",\n \"- Power tools\\n\",\n \"- Camping & fitness gear\\n\",\n \"\\n\",\n \"Always respond in English.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"sports_auto_industry_agent = Agent(\\n\",\n \" name=\\\"Sports, Automotive & Industry Specialist\\\",\\n\",\n \" instructions=sports_auto_industry_instructions,\\n\",\n \" model=gemini_model_config\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"eb3e9065\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Convert specialist agents to tools\\n\",\n \"electronics_smarttech_tool = electronics_smarttech_agent.as_tool(\\n\",\n \" tool_name=\\\"electronics_smarttech_specialist\\\",\\n\",\n \" tool_description=\\\"Get electronics and smart tech product recommendations\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"lifestyle_wellness_tool = lifestyle_wellness_agent.as_tool(\\n\",\n \" tool_name=\\\"lifestyle_wellness_specialist\\\",\\n\",\n \" tool_description=\\\"Get lifestyle and wellness product recommendations\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"entertainment_tool = entertainment_agent.as_tool(\\n\",\n \" tool_name=\\\"entertainment_specialist\\\",\\n\",\n \" tool_description=\\\"Get entertainment product recommendations\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"home_garden_pets_tool = home_garden_pets_agent.as_tool(\\n\",\n \" tool_name=\\\"home_garden_pets_specialist\\\", \\n\",\n \" tool_description=\\\"Get home, garden, and pet product recommendations\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"fashion_lifestyle_tool = fashion_lifestyle_agent.as_tool(\\n\",\n \" tool_name=\\\"fashion_lifestyle_specialist\\\",\\n\",\n \" tool_description=\\\"Get fashion and lifestyle product recommendations\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"sports_auto_industry_tool = sports_auto_industry_agent.as_tool(\\n\",\n \" tool_name=\\\"sports_auto_industry_specialist\\\",\\n\",\n \" tool_description=\\\"Get sports, automotive, and industry product recommendations\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"b4b7ac87\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Optional: Add web search capability\\n\",\n \"# First install: pip install duckduckgo-search\\n\",\n \"\\n\",\n \"def web_search_tool(query: str) -> str:\\n\",\n \" \\\"\\\"\\\"Search the web for current information\\\"\\\"\\\"\\n\",\n \" try:\\n\",\n \" print(f\\\"🔍 Web search activated: {query}\\\")\\n\",\n \" with DDGS() as ddgs:\\n\",\n \" results = list(ddgs.text(query, max_results=3))\\n\",\n \" formatted_results = []\\n\",\n \" for result in results:\\n\",\n \" formatted_results.append(f\\\"**{result['title']}**\\\\n{result['body']}\\\\nSource: {result['href']}\\\")\\n\",\n \" print(f\\\"✅ Found {len(results)} search results\\\")\\n\",\n \" return \\\"\\\\n\\\\n\\\".join(formatted_results)\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"❌ Search error: {e}\\\")\\n\",\n \" return f\\\"Search error: {e}\\\"\\n\",\n \"\\n\",\n \"# Convert to tool for the agents framework\\n\",\n \"def create_search_tool():\\n\",\n \" \\\"\\\"\\\"Create a search tool compatible with the agents framework\\\"\\\"\\\"\\n\",\n \" def search_function(input: str) -> str:\\n\",\n \" return web_search_tool(input)\\n\",\n \" \\n\",\n \" # Create a mock agent for the tool conversion\\n\",\n \" search_agent = Agent(\\n\",\n \" name=\\\"Web Search Agent\\\",\\n\",\n \" instructions=\\\"You search the web for current information and return relevant results.\\\",\\n\",\n \" model=LitellmModel(model=\\\"gpt-4o-mini\\\", api_key=os.getenv(\\\"OPENAI_API_KEY\\\"))\\n\",\n \" )\\n\",\n \" \\n\",\n \" # Override the agent's run method to use our search function\\n\",\n \" async def custom_run(self, user_input):\\n\",\n \" return web_search_tool(user_input)\\n\",\n \" \\n\",\n \" search_agent.run = custom_run.__get__(search_agent, Agent)\\n\",\n \" \\n\",\n \" return search_agent.as_tool(\\n\",\n \" tool_name=\\\"web_search\\\",\\n\",\n \" tool_description=\\\"Search the web for current product information, prices, and availability\\\"\\n\",\n \" )\\n\",\n \"\\n\",\n \"# Create the search tool\\n\",\n \"web_search_tool_agent = create_search_tool()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"735e093b\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def create_manager_instructions():\\n\",\n \" current_language = session.user_preferences[\\\"language\\\"]\\n\",\n \" context = session.get_context_string()\\n\",\n \" \\n\",\n \" instructions = f\\\"\\\"\\\"\\n\",\n \"You are the Manager Agent responsible for interacting with the user and coordinating the work of specialist agents.\\n\",\n \"\\n\",\n \"{context}\\n\",\n \"\\n\",\n \"Workflow:\\n\",\n \"1. From the conversation context, identify if you know the user's region/country. Look for mentions like:\\n\",\n \" - \\\"I'm in Netherlands\\\", \\\"I live in Germany\\\", \\\"I'm from the US\\\"\\n\",\n \" - \\\"Dutch\\\", \\\"German\\\", \\\"American\\\" (referring to nationality)\\n\",\n \" - Any country or region references\\n\",\n \" \\n\",\n \"2. If you don't know their region yet, ask for it politely.\\n\",\n \"\\n\",\n \"3. Once you have both region and product requirements:\\n\",\n \" - FIRST use web_search to find current prices and availability\\n\",\n \" - THEN use the Electronics & Smart Tech Specialist to get recommendations\\n\",\n \" - Combine both sources for comprehensive recommendations\\n\",\n \"\\n\",\n \"4. Present specific product recommendations with:\\n\",\n \" - Product name and brand\\n\",\n \" - Key features matching their requirements \\n\",\n \" - Current price range (from web search)\\n\",\n \" - Regional availability/where to buy\\n\",\n \" \\n\",\n \"Key Intelligence:\\n\",\n \"- Remember region information from earlier in the conversation\\n\",\n \"- \\\"Dutch\\\" = Netherlands, \\\"German\\\" = Germany, \\\"American/US/USA\\\" = United States, etc.\\n\",\n \"- Use your knowledge to provide region-appropriate recommendations\\n\",\n \"\\n\",\n \"Always respond in {current_language}.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \" \\n\",\n \" return instructions\\n\",\n \"\\n\",\n \"# Manager Agent Creation\\n\",\n \"def get_manager_agent():\\n\",\n \" return Agent(\\n\",\n \" name=\\\"Manager Agent\\\",\\n\",\n \" instructions=create_manager_instructions(),\\n\",\n \" tools=[electronics_smarttech_tool, lifestyle_wellness_tool, entertainment_tool, \\n\",\n \" home_garden_pets_tool, fashion_lifestyle_tool, sports_auto_industry_tool,\\n\",\n \" web_search_tool_agent], # Add search tool here\\n\",\n \" model=LitellmModel(model=\\\"gemini-2.5-flash\\\", api_key=os.getenv(\\\"GEMINI_API_KEY\\\"))\\n\",\n \" )\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"f5a91d6a\",\n \"metadata\": {},\n \"source\": [\n \"## Display Menu Options for User\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"ea3b782c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Smart translation function using LLM\\n\",\n \"async def translate_text(text, target_language):\\n\",\n \" \\\"\\\"\\\"Use LLM to translate text to target language\\\"\\\"\\\"\\n\",\n \" if target_language.lower() == \\\"english\\\":\\n\",\n \" return text\\n\",\n \" \\n\",\n \" try:\\n\",\n \" translation_prompt = f\\\"\\\"\\\"\\n\",\n \" Translate this text to {target_language}, keeping the same structure and formatting:\\n\",\n \" \\n\",\n \" \\\"{text}\\\"\\n\",\n \" \\n\",\n \" Return only the translated text, nothing else.\\n\",\n \" \\\"\\\"\\\"\\n\",\n \" \\n\",\n \" response = await litellm.acompletion(\\n\",\n \" model=\\\"gpt-4o-mini\\\",\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": translation_prompt}],\\n\",\n \" api_key=os.getenv(\\\"OPENAI_API_KEY\\\"),\\n\",\n \" max_tokens=200\\n\",\n \" )\\n\",\n \" \\n\",\n \" return response.choices[0].message.content.strip()\\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Translation error: {e}\\\")\\n\",\n \" return text # Fallback to original text\\n\",\n \"\\n\",\n \"# Dynamic menu system\\n\",\n \"async def display_menu():\\n\",\n \" \\\"\\\"\\\"Display menu in selected language\\\"\\\"\\\"\\n\",\n \" # Update session language from widget\\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" target_language = session.user_preferences[\\\"language\\\"]\\n\",\n \" \\n\",\n \" # Base menu in English\\n\",\n \" base_title = \\\"Sound System Recommendation Agent\\\"\\n\",\n \" base_options = [\\n\",\n \" \\\"Choose an option:\\\",\\n\",\n \" \\\"1. Quick test with sample query\\\",\\n\",\n \" \\\"2. Test intelligent region handling\\\",\\n\",\n \" \\\"3. Debug test (fresh session)\\\",\\n\",\n \" \\\"4. Launch interactive chat interface\\\",\\n\",\n \" \\\"5. Debug instructions\\\"\\n\",\n \" ]\\n\",\n \" \\n\",\n \" # Translate if needed\\n\",\n \" if target_language.lower() != \\\"english\\\":\\n\",\n \" title = await translate_text(base_title, target_language)\\n\",\n \" options = []\\n\",\n \" for option in base_options:\\n\",\n \" translated_option = await translate_text(option, target_language)\\n\",\n \" options.append(translated_option)\\n\",\n \" else:\\n\",\n \" title = base_title\\n\",\n \" options = base_options\\n\",\n \" \\n\",\n \" # Display menu\\n\",\n \" print(title)\\n\",\n \" print(\\\"=\\\" * 40)\\n\",\n \" for option in options:\\n\",\n \" print(option)\\n\",\n \" print()\\n\",\n \"\\n\",\n \"# Quick test - run this cell for a simple test\\n\",\n \"async def quick_test():\\n\",\n \" try:\\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" \\n\",\n \" test_query = \\\"I'm looking for a sound system for my living room under $1000\\\"\\n\",\n \" print(f\\\"🧪 Testing: {test_query}\\\")\\n\",\n \" \\n\",\n \" manager_agent = get_manager_agent()\\n\",\n \" session.add_message(\\\"user\\\", test_query)\\n\",\n \" result = await Runner.run(manager_agent, test_query)\\n\",\n \" session.add_message(\\\"assistant\\\", result.final_output)\\n\",\n \" \\n\",\n \" print(\\\"✅ Test completed successfully\\\")\\n\",\n \" print(f\\\"📊 Session has {len(session.conversation_history)} messages\\\")\\n\",\n \" print(result.final_output)\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"❌ Test failed: {str(e)}\\\")\\n\",\n \" session.add_message(\\\"error\\\", str(e))\\n\",\n \"\\n\",\n \"# Add this new test function\\n\",\n \"async def test_intelligent_region():\\n\",\n \" try:\\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" \\n\",\n \" print(\\\"=== TESTING INTELLIGENT REGION HANDLING ===\\\")\\n\",\n \" \\n\",\n \" # Test 1: Mention region indirectly\\n\",\n \" test_1 = \\\"I'm Dutch and need a sound system under 500 euros\\\"\\n\",\n \" print(f\\\"\\\\n1. Testing: {test_1}\\\")\\n\",\n \" \\n\",\n \" manager_agent = get_manager_agent()\\n\",\n \" session.add_message(\\\"user\\\", test_1)\\n\",\n \" result = await Runner.run(manager_agent, test_1)\\n\",\n \" session.add_message(\\\"assistant\\\", result.final_output)\\n\",\n \" \\n\",\n \" print(\\\"Response:\\\", result.final_output)\\n\",\n \" \\n\",\n \" # Test 2: Follow up\\n\",\n \" test_2 = \\\"I need HDMI ARC and Bluetooth support\\\"\\n\",\n \" print(f\\\"\\\\n2. Testing: {test_2}\\\")\\n\",\n \" \\n\",\n \" manager_agent = get_manager_agent() # Refresh with context\\n\",\n \" session.add_message(\\\"user\\\", test_2)\\n\",\n \" result = await Runner.run(manager_agent, test_2)\\n\",\n \" session.add_message(\\\"assistant\\\", result.final_output)\\n\",\n \" \\n\",\n \" print(\\\"Response:\\\", result.final_output)\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n=== FINAL SESSION STATE ===\\\")\\n\",\n \" print(f\\\"Total messages: {len(session.conversation_history)}\\\")\\n\",\n \" print(f\\\"Language: {session.user_preferences['language']}\\\")\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" print(f\\\"Error: {e}\\\")\\n\",\n \"\\n\",\n \"# Debug test function\\n\",\n \"async def debug_test():\\n\",\n \" # Clear session and start fresh\\n\",\n \" global session\\n\",\n \" session = SessionManager()\\n\",\n \" print(\\\"Session cleared. Starting fresh...\\\")\\n\",\n \" \\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" \\n\",\n \" # First message\\n\",\n \" test_1 = \\\"I'm in Berlin and need 5kg ankle weights under 50 euros\\\"\\n\",\n \" print(f\\\"Testing: {test_1}\\\")\\n\",\n \" \\n\",\n \" session.add_message(\\\"user\\\", test_1)\\n\",\n \" print(f\\\"Context after first message: {session.get_context_string()}\\\")\\n\",\n \" \\n\",\n \" manager_agent = get_manager_agent()\\n\",\n \" result = await Runner.run(manager_agent, test_1)\\n\",\n \" session.add_message(\\\"assistant\\\", result.final_output)\\n\",\n \" \\n\",\n \" print(\\\"Response:\\\", result.final_output)\\n\",\n \"\\n\",\n \"# DEBUG: Check what instructions are being generated\\n\",\n \"def debug_instructions():\\n\",\n \" print(\\\"=== DEBUG MANAGER INSTRUCTIONS ===\\\")\\n\",\n \" print(\\\"Session context:\\\")\\n\",\n \" print(session.get_context_string())\\n\",\n \" print(\\\"\\\\nGenerated instructions:\\\")\\n\",\n \" print(create_manager_instructions())\\n\",\n \" print(\\\"=\\\" * 50)\\n\",\n \"\\n\",\n \"# Call this to display menu in selected language\\n\",\n \"await display_menu()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"d2613eba\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"import gradio as gr\\n\",\n \"\\n\",\n \"def chat_interface(message, history):\\n\",\n \" try:\\n\",\n \" # Update session language from current widget value\\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" session.add_message(\\\"user\\\", message)\\n\",\n \" session.user_preferences[\\\"current_request\\\"] = message\\n\",\n \" \\n\",\n \" # Simple status log instead of verbose context\\n\",\n \" print(f\\\"💬 Processing: {message[:50]}...\\\" if len(message) > 50 else f\\\"💬 Processing: {message}\\\")\\n\",\n \" \\n\",\n \" # Create fresh manager agent with current context\\n\",\n \" manager_agent = get_manager_agent()\\n\",\n \" \\n\",\n \" # Get response from manager agent\\n\",\n \" import asyncio\\n\",\n \" \\n\",\n \" try:\\n\",\n \" loop = asyncio.get_event_loop()\\n\",\n \" except RuntimeError:\\n\",\n \" loop = asyncio.new_event_loop()\\n\",\n \" asyncio.set_event_loop(loop)\\n\",\n \" \\n\",\n \" result = loop.run_until_complete(Runner.run(manager_agent, message))\\n\",\n \" \\n\",\n \" # Update session with assistant response\\n\",\n \" session.add_message(\\\"assistant\\\", result.final_output)\\n\",\n \" \\n\",\n \" # Clean the response to avoid syntax errors\\n\",\n \" clean_response = str(result.final_output).strip()\\n\",\n \" \\n\",\n \" return clean_response\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" error_msg = f\\\"I encountered an error: {str(e)}. Please try again.\\\"\\n\",\n \" session.add_message(\\\"error\\\", error_msg)\\n\",\n \" return error_msg\\n\",\n \"\\n\",\n \"async def launch_chat():\\n\",\n \" \\\"\\\"\\\"Launch chat interface with dynamic translation\\\"\\\"\\\"\\n\",\n \" # Update language\\n\",\n \" session.user_preferences[\\\"language\\\"] = language_selector.value\\n\",\n \" target_language = session.user_preferences[\\\"language\\\"]\\n\",\n \" \\n\",\n \" # Base text in English\\n\",\n \" base_title = \\\"Product Recommendation Assistant\\\"\\n\",\n \" base_description = f\\\"Ask me for product recommendations! I'll help you find the perfect products for your region. Current language: {target_language}\\\"\\n\",\n \" base_examples = [\\n\",\n \" \\\"I need a sound system under 500 euros\\\",\\n\",\n \" \\\"I'm in Netherlands and looking for Bluetooth speakers\\\",\\n\",\n \" \\\"Recommend a laptop for programming under $1000 in USA\\\",\\n\",\n \" \\\"I'm in Germany and need fitness equipment for home use\\\"\\n\",\n \" ]\\n\",\n \" \\n\",\n \" # Translate if needed\\n\",\n \" if target_language.lower() != \\\"english\\\":\\n\",\n \" title = await translate_text(base_title, target_language)\\n\",\n \" description = await translate_text(base_description, target_language)\\n\",\n \" examples = []\\n\",\n \" for example in base_examples:\\n\",\n \" translated_example = await translate_text(example, target_language)\\n\",\n \" examples.append(translated_example)\\n\",\n \" else:\\n\",\n \" title = base_title\\n\",\n \" description = base_description\\n\",\n \" examples = base_examples\\n\",\n \" \\n\",\n \" demo = gr.ChatInterface(\\n\",\n \" fn=chat_interface,\\n\",\n \" title=title,\\n\",\n \" description=description,\\n\",\n \" examples=examples\\n\",\n \" )\\n\",\n \" \\n\",\n \" print(f\\\"Launching chat interface in {target_language}...\\\")\\n\",\n \" print(f\\\"Session initialized with {len(session.conversation_history)} messages\\\")\\n\",\n \" demo.launch(share=True, debug=True)\\n\",\n \"\\n\",\n \"# Uncomment to launch\\n\",\n \"await launch_chat()\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.10\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/diptiman_lab2_solution.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745484.55959, "n": 17385, "h": "066d1ae3e83812ce", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Important point - please read</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"perplexity_api_key = os.getenv('PPLX_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if perplexity_api_key:\\n\",\n \" print(f\\\"Perplexity API Key exists and begins {perplexity_api_key[:6]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Perplexity API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Note - update since the videos\\n\",\n \"\\n\",\n \"I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"# I've updated this with the latest model, but it can take some time because it likes to think!\\n\",\n \"# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\\n\",\n \"\\n\",\n \"model_name = \\\"gpt-5-nano\\\"\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\n\",\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"model_name = \\\"claude-sonnet-4-5\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \"answer = response.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"import os\\n\",\n \"import httpx\\n\",\n \"import urllib3\\n\",\n \"from openai import OpenAI\\n\",\n \"from IPython.display import display, Markdown\\n\",\n \"\\n\",\n \"# Disable SSL warnings\\n\",\n \"urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\\n\",\n \"\\n\",\n \"# Create httpx client with SSL verification disabled\\n\",\n \"httpx_client = httpx.Client(verify=False)\\n\",\n \"\\n\",\n \"# Perplexity via OpenAI-compatible client\\n\",\n \"model_name = \\\"sonar-pro\\\"\\n\",\n \"perplexity_client = OpenAI(\\n\",\n \" api_key=os.getenv(\\\"PPLX_API_KEY\\\"),\\n\",\n \" base_url=\\\"https://api.perplexity.ai\\\",\\n\",\n \" http_client=httpx_client,\\n\",\n \")\\n\",\n \"\\n\",\n \"response = perplexity_client.chat.completions.create(\\n\",\n \" model=model_name,\\n\",\n \" messages=messages,\\n\",\n \" max_tokens=500,\\n\",\n \")\\n\",\n \"\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \"model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \"response = deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Updated with the latest Open Source model from OpenAI\\n\",\n \"\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"openai/gpt-oss-120b\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# So where are we?\\n\",\n \"\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(together)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": []\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(competitors)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"results = response.choices[0].message.content\\n\",\n \"print(results)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(results)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/business.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">Commercial implications</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">These kinds of patterns - to send a task to multiple models, and evaluate results,\\n\",\n \" are common where you need to improve the quality of your LLM response. This approach can be universally applied\\n\",\n \" to business projects where accuracy is critical.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \"agents\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.11\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/paresh_lab-assignments/2_lab2_assignment.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745486.1533494, "n": 15937, "h": "90619b8095c65eb1", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Important point - please read</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Note - update since the videos\\n\",\n \"\\n\",\n \"I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"# I've updated this with the latest model, but it can take some time because it likes to think!\\n\",\n \"# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\\n\",\n \"\\n\",\n \"model_name = \\\"gpt-5-nano\\\"\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"\\n\",\n \"model_name = \\\"claude-sonnet-4-5\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \"answer = response.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \"model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \"response = deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Updated with the latest Open Source model from OpenAI\\n\",\n \"\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"openai/gpt-oss-120b\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# So where are we?\\n\",\n \"\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 15,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(together)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": []\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 19,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(competitors)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 21,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"results = response.choices[0].message.content\\n\",\n \"print(results)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(results)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/business.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">Commercial implications</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">These kinds of patterns - to send a task to multiple models, and evaluate results,\\n\",\n \" are common where you need to improve the quality of your LLM response. This approach can be universally applied\\n\",\n \" to business projects where accuracy is critical.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.12\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/akash_lab2_orchestrator_worker.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745491.1218708, "n": 21754, "h": "48e5321c0ef961dc", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Important point - please read</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Note - update since the videos\\n\",\n \"\\n\",\n \"I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"# I've updated this with the latest model, but it can take some time because it likes to think!\\n\",\n \"# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\\n\",\n \"\\n\",\n \"model_name = \\\"gpt-5-nano\\\"\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"\\n\",\n \"model_name = \\\"claude-sonnet-4-5\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \"answer = response.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \"model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \"response = deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Updated with the latest Open Source model from OpenAI\\n\",\n \"\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"openai/gpt-oss-120b\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# So where are we?\\n\",\n \"\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(together)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": []\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(competitors)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"results = response.choices[0].message.content\\n\",\n \"print(results)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(results)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/business.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">Commercial implications</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">These kinds of patterns - to send a task to multiple models, and evaluate results,\\n\",\n \" are common where you need to improve the quality of your LLM response. This approach can be universally applied\\n\",\n \" to business projects where accuracy is critical.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"Orchestrator–Worker Pattern\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"metadata\": {},\n \"outputs\": [\n {\n \"data\": {\n \"text/plain\": [\n \"True\"\n ]\n },\n \"execution_count\": 2,\n \"metadata\": {},\n \"output_type\": \"execute_result\"\n }\n ],\n \"source\": [\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 3,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"GOOGLE_API_KEY = os.getenv(\\\"GOOGLE_API_KEY\\\")\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Create Gemini client\\n\",\n \"gemini = OpenAI(\\n\",\n \" base_url=GEMINI_BASE_URL,\\n\",\n \" api_key=GOOGLE_API_KEY\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def gemini_safe_request(messages):\\n\",\n \" retries = 5\\n\",\n \" for i in range(retries):\\n\",\n \" try:\\n\",\n \" return gemini.chat.completions.create(\\n\",\n \" model=\\\"gemini-2.0-flash\\\",\\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \" except Exception as e:\\n\",\n \" if \\\"429\\\" in str(e):\\n\",\n \" wait = (2 ** i)\\n\",\n \" print(f\\\"Rate limit hit. Retrying in {wait} seconds...\\\")\\n\",\n \" time.sleep(wait)\\n\",\n \" else:\\n\",\n \" raise e\\n\",\n \" raise Exception(\\\" Max retries reached. Try again later.\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"ORCHESTRATOR–WORKER START\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 6,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def orchestrator(user_question):\\n\",\n \" \\\"\\\"\\\"\\n\",\n \" The orchestrator controls everything:\\n\",\n \" 1 - sends question to Worker A\\n\",\n \" 2 - sends Worker A's answer to Worker B for critique\\n\",\n \" 3 - sends both to Worker C for improvement\\n\",\n \" 4 - returns final improved answer\\n\",\n \" \\\"\\\"\\\"\\n\",\n \"\\n\",\n \" print(\\\"\\\\n Orchestrator: Sending question to Worker A...\\\")\\n\",\n \" workerA_output = worker_A_generate(user_question)\\n\",\n \"\\n\",\n \" print(\\\"\\\\n Orchestrator: Sending Worker A output to Worker B...\\\")\\n\",\n \" workerB_output = worker_B_critic(workerA_output)\\n\",\n \"\\n\",\n \" print(\\\"\\\\n Orchestrator: Sending both outputs to Worker C...\\\")\\n\",\n \" final_output = worker_C_improver(workerA_output, workerB_output)\\n\",\n \"\\n\",\n \" print(\\\"\\\\n Final Improved Answer:\\\\n\\\")\\n\",\n \" print(final_output)\\n\",\n \" return final_output\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"WORKER A: Generate answer\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def worker_A_generate(question):\\n\",\n \" messages = [\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are Worker A. Provide a direct answer.\\\"},\\n\",\n \" {\\\"role\\\": \\\"user\\\", \\\"content\\\": question}\\n\",\n \" ]\\n\",\n \" response = gemini_safe_request(messages)\\n\",\n \" answer = response.choices[0].message.content\\n\",\n \" print(\\\"Worker A Answer:\\\", answer)\\n\",\n \" return answer\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"WORKER B: Critic\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def worker_B_critic(answer):\\n\",\n \" messages = [\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are Worker B. Criticize the answer clearly with flaws, missing points, wrong assumptions.\\\"},\\n\",\n \" {\\\"role\\\": \\\"user\\\", \\\"content\\\": f\\\"Critique this answer:\\\\n\\\\n{answer}\\\"}\\n\",\n \" ]\\n\",\n \" response = gemini_safe_request(messages)\\n\",\n \" critique = response.choices[0].message.content\\n\",\n \" print(\\\"Worker B Critique:\\\", critique)\\n\",\n \" return critique\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"WORKER C: Improve final output\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"def worker_C_improver(answer, critique):\\n\",\n \" messages = [\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are Worker C. Improve the answer using the critique. Provide a clean final response.\\\"},\\n\",\n \" {\\\"role\\\": \\\"user\\\", \\\"content\\\": f\\\"Original Answer:\\\\n{answer}\\\\n\\\\nCritique:\\\\n{critique}\\\\n\\\\nImprove it.\\\"}\\n\",\n \" ]\\n\",\n \" response = gemini_safe_request(messages)\\n\",\n \" improved = response.choices[0].message.content\\n\",\n \" print(\\\"Worker C Improved Answer:\\\", improved)\\n\",\n \" return improved\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"Run the orchestrator\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"user_question = \\\"Explain how quantum computers differ from classical computers in simple terms.\\\"\\n\",\n \"orchestrator(user_question)\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.3\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/2_lab2_task-optimized-solver_JPM.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745497.1936233, "n": 16765, "h": "f2c5703be1f94d5b", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"e3ce93ad\",\n \"metadata\": {},\n \"source\": [\n \"# Designing a workflow agent pattern\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"749cc73c\",\n \"metadata\": {},\n \"source\": [\n \"## Objective\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"4aa188cb\",\n \"metadata\": {},\n \"source\": [\n \"To build a robust \\\"Task-Optimized Solver\\\" that maximizes answer quality by combining three Agentic Patterns: Parallelization, Evaluation, and Routing. The goal is to first generate the highest-quality problem possible through competition, and then dynamically assign that problem to the specific AI model best suited to solve it.\\n\",\n \"\\n\",\n \"**Workflow Steps**\\n\",\n \"\\n\",\n \"Phase 1: Generation (Parallelization)\\n\",\n \"\\n\",\n \"- Fan-Out: Simultaneously prompt three different models to generate a challenging problem (math, reasoning, or coding).\\n\",\n \"\\n\",\n \"- Aggregator: Collect the three candidate problems into a single list.\\n\",\n \"\\n\",\n \"- Judge: Use a model (e.g., GPT-4o) to evaluate the candidates and output only the single best problem.\\n\",\n \"\\n\",\n \"Phase 2: Classification (Evaluator). \\n\",\n \"\\n\",\n \"- Analysis: Classify the question into a topic.\\n\",\n \"\\n\",\n \"- Decision: The evaluator classifies the problem into one of three domains: MATH, REASONING, or CODE.\\n\",\n \"\\n\",\n \"Phase 3: Specialized Execution (Router).\\n\",\n \"\\n\",\n \"- Routing: Automatically direct the problem to the domain specialist: * Math: Send to specific model. * Reasoning: Send to another. * Code: Send to another.\\n\",\n \"\\n\",\n \"- Final Output: Display the specialized solution.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"d25c98d7\",\n \"metadata\": {},\n \"source\": [\n \"## Set up the enviroment\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"d6199e71\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f2e6e0cd\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4ad8a352\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Set up the API key variables\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"5b494e22\",\n \"metadata\": {},\n \"source\": [\n \"## Phase 1: Generation (Parallelization)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"78fe8102\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Define the request\\n\",\n \"\\n\",\n \"request = \\\"Please design a single, difficult question to evaluate the specifyc intelligence of an LLM.\\\"\\n\",\n \"request += \\\"You must independently choose to make it one of these three types:\\\"\\n\",\n \"request += \\\"1) A Mathematical Problem, 2) A logical Reasoning Puzzle, or 3) A coding Challenge.\\\"\\n\",\n \"request += \\\"Do not tell me wich category you chose. Just output the question itself\\\"\\n\",\n \"\\n\",\n \"# Create the messages object the we will send to all competitors\\n\",\n \"messages = [{\\n\",\n \" \\\"role\\\": \\\"user\\\",\\n\",\n \" \\\"content\\\": request\\n\",\n \"}]\\n\",\n \"\\n\",\n \"print(messages)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"5ad266f4\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Initialize lists\\n\",\n \"competitors = []\\n\",\n \"questions = []\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"1da961ec\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Gemini call\\n\",\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash-preview-09-2025\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"questions.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"7fe3be6d\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Groq call\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"openai/gpt-oss-120b\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(\\n\",\n \" model=model_name, \\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"questions.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c7def008\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Ollama call\\n\",\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(\\n\",\n \" model=model_name, \\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"questions.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"398ad5f6\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(competitors)\\n\",\n \"print(questions)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"946d6e14\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# prepare the data for the judge \\n\",\n \"# we zip the lists together\\n\",\n \"\\n\",\n \"for competitor, question in zip(competitors, questions):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{question}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"5839d1fb\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Aggregation building\\n\",\n \"\\n\",\n \"# We define a string variable to hold all the options\\n\",\n \"candidates_questions = \\\"\\\"\\n\",\n \"\\n\",\n \"# We use enumerate to assign IDs automatically\\n\",\n \"for index, question in enumerate(questions):\\n\",\n \" # index is 0, then 1, then 2 ...\\n\",\n \" # answer is the actual text\\n\",\n \" # we use {index+a} because humans count from 1, but Python counts from 0\\n\",\n \" candidates_questions += f\\\"# Question proposed from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" candidates_questions += question + \\\"\\\\n\\\\n\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"d685ed0f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(candidates_questions)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"997d4d9f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# We define the judge´s system prompt\\n\",\n \"judge = f\\\"\\\"\\\"\\n\",\n \"You are an expert in IQ detection level.\\n\",\n \"Here are 3 candidates question generated by AI models to evaluate their intelligence:\\n\",\n \"\\n\",\n \"{candidates_questions}\\n\",\n \"\\n\",\n \"Task: Analyze these questions. Select the SINGLE most accurate question to measure the intelligence level of an LLM.\\n\",\n \"\\n\",\n \"Return your decision in this exact JSON format, response ONLY in JSON:\\n\",\n \"{{\\n\",\n \" \\\"winner_id\\\": <number 1, 2 or 3>,\\n\",\n \" \\\"reason\\\": \\\"<short explanation in PLAIN ENGLISH ONLY. Do not use LaTeX, backslashes, or markdown>\\\"\\n\",\n \"}}\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"a714ec92\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judge messages\\n\",\n \"judge_messages = [{\\n\",\n \" \\\"role\\\":\\\"user\\\",\\n\",\n \" \\\"content\\\": judge\\n\",\n \" }]\\n\",\n \"\\n\",\n \"print(judge_messages)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"5d36b829\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Call the judge\\n\",\n \"\\n\",\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash-preview-09-2025\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=judge_messages)\\n\",\n \"winner_text = response.choices[0].message.content\\n\",\n \"\\n\",\n \"print(winner_text)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"709eaa9f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Clean the output\\n\",\n \"winner_text = winner_text.replace(\\\"```json\\\", \\\"\\\").replace(\\\"```\\\", \\\"\\\").strip()\\n\",\n \"\\n\",\n \"try:\\n\",\n \" # Parse the JSON \\n\",\n \" winner_dict = json.loads(winner_text)\\n\",\n \" \\n\",\n \" # Get the ID\\n\",\n \" winning_id = int(winner_dict[\\\"winner_id\\\"])\\n\",\n \" \\n\",\n \" # RETRIEVE THE QUESTION FROM YOUR LIST\\n\",\n \" selected_question = questions[winning_id - 1]\\n\",\n \" \\n\",\n \" print(f\\\"Winner ID: {winning_id}\\\")\\n\",\n \" print(f\\\"Reason: {winner_dict['reason']}\\\")\\n\",\n \" print(\\\"-\\\" * 50)\\n\",\n \" print(f\\\"Selected Question (Safe Retrieve):\\\\n{selected_question[:200]}...\\\")\\n\",\n \"\\n\",\n \"except json.JSONDecodeError as e:\\n\",\n \" print(f\\\"JSON Error: {e}\\\")\\n\",\n \" print(f\\\"Raw Output: {winner_text}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"1acf4190\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"selected_question\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"d58505a6\",\n \"metadata\": {},\n \"source\": [\n \"## Phase 2: Classification (Evaluator)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c91b1227\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(selected_question)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"6ad92a1b\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Define the Router Prompt\\n\",\n \"\\n\",\n \"router_prompt = f\\\"\\\"\\\"\\n\",\n \"You are an intelligent classifier agent.\\n\",\n \"Classify the following question into exactly one of these three categories:\\n\",\n \"- MATH\\n\",\n \"- CODE\\n\",\n \"- Reasoning\\n\",\n \"\\n\",\n \"Question:\\n\",\n \"\\\"{selected_question}\\\"\\n\",\n \"\\n\",\n \"Output ONLY the category name. Do not explain.\\n\",\n \"\\\"\\\"\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"39d1e657\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Call the Router (using Gemini for free)\\n\",\n \"\\n\",\n \"# Router messages\\n\",\n \"router_messages = [{\\n\",\n \" \\\"role\\\":\\\"user\\\",\\n\",\n \" \\\"content\\\": router_prompt\\n\",\n \" }]\\n\",\n \"\\n\",\n \"print(router_messages)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"dfb2299e\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Call the router\\n\",\n \"\\n\",\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash-preview-09-2025\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(\\n\",\n \" model=model_name, \\n\",\n \" messages=router_messages\\n\",\n \" )\\n\",\n \"\\n\",\n \"topic = response.choices[0].message.content\\n\",\n \"\\n\",\n \"print(f\\\"Router decision: {topic}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"11a94151\",\n \"metadata\": {},\n \"source\": [\n \"## Phase 3: Specialized Execution (Router)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"06a98872\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# We use an IF/ELSE block to direct traffic base on the \\\"topic\\\" variables\\n\",\n \"\\n\",\n \"if \\\"MATH\\\" in topic:\\n\",\n \" print(\\\"Routing to math expert LLM ...\\\")\\n\",\n \"\\n\",\n \" # Create a specific prompt for the Math Expert\\n\",\n \" math_prompt = f\\\"You are a mathematician. Solve this problem step-by-step, showing all work:\\\\n\\\\n{selected_question}\\\"\\n\",\n \"\\n\",\n \" math_messages = [{\\n\",\n \" \\\"role\\\":\\\"user\\\",\\n\",\n \" \\\"content\\\": math_prompt\\n\",\n \" }]\\n\",\n \"\\n\",\n \" gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \" model_name = \\\"gemini-2.5-flash-lite\\\"\\n\",\n \"\\n\",\n \" response = gemini.chat.completions.create(\\n\",\n \" model= model_name, \\n\",\n \" messages= math_messages\\n\",\n \" )\\n\",\n \"\\n\",\n \" math_response = response.choices[0].message.content\\n\",\n \"\\n\",\n \" display(Markdown(selected_question))\\n\",\n \" display(Markdown(math_response))\\n\",\n \"\\n\",\n \"elif \\\"CODE\\\" in topic:\\n\",\n \" print(\\\"Routing to code expert LLM ...\\\")\\n\",\n \"\\n\",\n \" # Create a specific prompt for the CodeExpert\\n\",\n \" code_prompt = f\\\"You are a Senior Python Developer. Write efficient code to solve this:\\\\n\\\\n{selected_question}\\\"\\n\",\n \"\\n\",\n \" code_messages = [{\\n\",\n \" \\\"role\\\":\\\"user\\\",\\n\",\n \" \\\"content\\\": code_prompt\\n\",\n \" }]\\n\",\n \"\\n\",\n \" ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \" model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \" response = ollama.chat.completions.create(\\n\",\n \" model= model_name, \\n\",\n \" messages= code_messages\\n\",\n \" )\\n\",\n \"\\n\",\n \" code_response = response.choices[0].message.content\\n\",\n \"\\n\",\n \" display(Markdown(selected_question))\\n\",\n \" display(Markdown(code_response))\\n\",\n \"\\n\",\n \"elif \\\"REASONING\\\" in topic:\\n\",\n \" print(\\\"Routing to reasoning expert LLM ...\\\")\\n\",\n \"\\n\",\n \" # Create a specific prompt for the Reasoning Expert\\n\",\n \" reasoning_prompt = f\\\"Solve this logic puzzle clearly:\\\\n\\\\n{selected_question}\\\"\\n\",\n \"\\n\",\n \" reasoning_messages = [{\\n\",\n \" \\\"role\\\":\\\"user\\\",\\n\",\n \" \\\"content\\\": reasoning_prompt\\n\",\n \" }]\\n\",\n \"\\n\",\n \" ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \" model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \" response = ollama.chat.completions.create(\\n\",\n \" model= model_name, \\n\",\n \" messages= reasoning_messages\\n\",\n \" )\\n\",\n \"\\n\",\n \" reasoning_response = response.choices[0].message.content\\n\",\n \"\\n\",\n \" display(Markdown(selected_question))\\n\",\n \" display(Markdown(reasoning_response))\\n\",\n \"\\n\",\n \"else:\\n\",\n \" print(f\\\"Error: Router returned unknow topic '{topic}'\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4ade9a19\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": []\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.12\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/christopher_contribution_orchestrator_worker.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745502.1039984, "n": 12462, "h": "d7fe972162110cfe", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"10485b79\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"import os\\n\",\n \"import json\\n\",\n \"import asyncio\\n\",\n \"import nest_asyncio\\n\",\n \"from dataclasses import dataclass\\n\",\n \"from typing import Literal\\n\",\n \"\\n\",\n \"import anthropic\\n\",\n \"from openai import AsyncOpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"\\n\",\n \"load_dotenv()\\n\",\n \"nest_asyncio.apply() # lets asyncio.run work inside Jupyter\\n\",\n \"\\n\",\n \"# Anthropic — kept native (orchestrator uses advanced features)\\n\",\n \"anthropic_client = anthropic.AsyncAnthropic(api_key=os.getenv(\\\"ANTHROPIC_API_KEY\\\"))\\n\",\n \"\\n\",\n \"# Everything else via OpenAI-compatible endpoints\\n\",\n \"openai_client = AsyncOpenAI(\\n\",\n \" api_key=os.getenv(\\\"OPENAI_API_KEY\\\"),\\n\",\n \")\\n\",\n \"deepseek_client = AsyncOpenAI(\\n\",\n \" api_key=os.getenv(\\\"DEEPSEEK_API_KEY\\\"),\\n\",\n \" base_url=\\\"https://api.deepseek.com/v1\\\",\\n\",\n \")\\n\",\n \"groq_client = AsyncOpenAI(\\n\",\n \" api_key=os.getenv(\\\"GROQ_API_KEY\\\"),\\n\",\n \" base_url=\\\"https://api.groq.com/openai/v1\\\",\\n\",\n \")\\n\",\n \"gemini_client = AsyncOpenAI(\\n\",\n \" api_key=os.getenv(\\\"GEMINI_API_KEY\\\"),\\n\",\n \" base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\",\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c56a383f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"@dataclass\\n\",\n \"class Worker:\\n\",\n \" name: str\\n\",\n \" provider: Literal[\\\"openai\\\", \\\"gemini\\\", \\\"groq\\\", \\\"deepseek\\\"]\\n\",\n \" model: str\\n\",\n \" system_prompt: str\\n\",\n \"\\n\",\n \"WORKERS: dict[str, Worker] = {\\n\",\n \" \\\"market_positioning\\\": Worker(\\n\",\n \" name=\\\"Market Positioning Analyst\\\",\\n\",\n \" provider=\\\"openai\\\",\\n\",\n \" model=\\\"gpt-4o\\\",\\n\",\n \" system_prompt=(\\n\",\n \" \\\"You are a market research analyst. Given a company and context, \\\"\\n\",\n \" \\\"produce a concise analysis of: market position, target customers, \\\"\\n\",\n \" \\\"primary competitors, and recent strategic moves. Be specific and factual. \\\"\\n\",\n \" \\\"If you're uncertain about a fact, say so rather than guessing. \\\"\\n\",\n \" \\\"Respond in under 250 words.\\\"\\n\",\n \" ),\\n\",\n \" ),\\n\",\n \" \\\"product_features\\\": Worker(\\n\",\n \" name=\\\"Product Features Analyst\\\",\\n\",\n \" provider=\\\"gemini\\\",\\n\",\n \" model=\\\"gemini-2.5-flash\\\",\\n\",\n \" system_prompt=(\\n\",\n \" \\\"You are a product analyst. Given a company, extract its core product \\\"\\n\",\n \" \\\"capabilities and notable features. Structure output as: Core Product, \\\"\\n\",\n \" \\\"Key Features (bulleted), Notable Integrations, Recent Product Updates. \\\"\\n\",\n \" \\\"Be concrete. Respond in under 250 words.\\\"\\n\",\n \" ),\\n\",\n \" ),\\n\",\n \" \\\"pricing_model\\\": Worker(\\n\",\n \" name=\\\"Pricing & Business Model Analyst\\\",\\n\",\n \" provider=\\\"groq\\\",\\n\",\n \" model=\\\"llama-3.3-70b-versatile\\\",\\n\",\n \" system_prompt=(\\n\",\n \" \\\"You are a pricing analyst. Given a company, summarize: pricing tiers, \\\"\\n\",\n \" \\\"pricing model type (subscription, usage-based, freemium, etc.), \\\"\\n\",\n \" \\\"typical customer spend, and unusual pricing decisions. If exact prices \\\"\\n\",\n \" \\\"are unknown, describe the model qualitatively. Under 200 words.\\\"\\n\",\n \" ),\\n\",\n \" ),\\n\",\n \" \\\"technical_architecture\\\": Worker(\\n\",\n \" name=\\\"Technical Architecture Analyst\\\",\\n\",\n \" provider=\\\"deepseek\\\",\\n\",\n \" model=\\\"deepseek-chat\\\",\\n\",\n \" system_prompt=(\\n\",\n \" \\\"You are a technical analyst. Given a company, describe: underlying \\\"\\n\",\n \" \\\"technology stack, architectural differentiators, performance/scale \\\"\\n\",\n \" \\\"characteristics, and any technical moat. Only include what's publicly \\\"\\n\",\n \" \\\"knowable. Under 250 words.\\\"\\n\",\n \" ),\\n\",\n \" ),\\n\",\n \"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"0e526856\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"PROVIDER_CLIENTS = {\\n\",\n \" \\\"openai\\\": openai_client,\\n\",\n \" \\\"deepseek\\\": deepseek_client,\\n\",\n \" \\\"groq\\\": groq_client,\\n\",\n \" \\\"gemini\\\": gemini_client,\\n\",\n \"}\\n\",\n \"\\n\",\n \"async def call_worker(worker: Worker, task: str) -> str:\\n\",\n \" \\\"\\\"\\\"Dispatch a task to the appropriate provider via OpenAI-compatible API.\\\"\\\"\\\"\\n\",\n \" try:\\n\",\n \" client = PROVIDER_CLIENTS[worker.provider]\\n\",\n \" resp = await client.chat.completions.create(\\n\",\n \" model=worker.model,\\n\",\n \" messages=[\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": worker.system_prompt},\\n\",\n \" {\\\"role\\\": \\\"user\\\", \\\"content\\\": task},\\n\",\n \" ],\\n\",\n \" )\\n\",\n \" return resp.choices[0].message.content\\n\",\n \" except Exception as e:\\n\",\n \" return f\\\"[Worker {worker.name} failed: {type(e).__name__}: {e}]\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"1dcc6fb1\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ORCHESTRATOR_SYSTEM = \\\"\\\"\\\"You are an orchestrator for a competitive analysis system.\\n\",\n \"\\n\",\n \"Given a user's analysis request, you must:\\n\",\n \"1. Identify the companies to analyze (2-5 companies).\\n\",\n \"2. Select which analysis dimensions are most relevant from this fixed set:\\n\",\n \" - market_positioning\\n\",\n \" - product_features\\n\",\n \" - pricing_model\\n\",\n \" - technical_architecture\\n\",\n \"\\n\",\n \"Choose 3-4 dimensions based on what matters most for this specific query.\\n\",\n \"For example, a query about enterprise software focuses on pricing and features;\\n\",\n \"a query about infrastructure focuses on technical architecture.\\n\",\n \"\\n\",\n \"Respond ONLY with valid JSON in this exact shape:\\n\",\n \"{\\n\",\n \" \\\"companies\\\": [\\\"Company A\\\", \\\"Company B\\\", ...],\\n\",\n \" \\\"dimensions\\\": [\\\"dimension_key_1\\\", \\\"dimension_key_2\\\", ...],\\n\",\n \" \\\"rationale\\\": \\\"one-sentence explanation of your choices\\\"\\n\",\n \"}\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"async def orchestrate(user_query: str) -> dict:\\n\",\n \" resp = await anthropic_client.messages.create(\\n\",\n \" model=\\\"claude-opus-4-5\\\",\\n\",\n \" max_tokens=1024,\\n\",\n \" system=ORCHESTRATOR_SYSTEM,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": user_query}],\\n\",\n \" )\\n\",\n \" text = resp.content[0].text\\n\",\n \" # Strip markdown fences if the model added them\\n\",\n \" text = text.strip().removeprefix(\\\"```json\\\").removeprefix(\\\"```\\\").removesuffix(\\\"```\\\").strip()\\n\",\n \" return json.loads(text)\\n\",\n \"\\n\",\n \" \\\"\\\"\\\"The orchestrator constrains output to valid JSON — this is how you turn freeform reasoning into structured data you can iterate over. The removeprefix/removesuffix dance handles the case where Claude wraps JSON in markdown fences despite being told not to. Small defensive move that saves debugging time.\\n\",\n \"Dimensions are a fixed set because workers are predefined. But notice the orchestrator chooses which to use per query — that's the dynamic decomposition.\\\"\\\"\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f6378206\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"async def analyze(user_query: str) -> dict:\\n\",\n \" # Step 1: Plan\\n\",\n \" print(\\\"🧭 Orchestrator planning...\\\")\\n\",\n \" plan = await orchestrate(user_query)\\n\",\n \" print(f\\\" Companies: {plan['companies']}\\\")\\n\",\n \" print(f\\\" Dimensions: {plan['dimensions']}\\\")\\n\",\n \" print(f\\\" Rationale: {plan['rationale']}\\\\n\\\")\\n\",\n \"\\n\",\n \" # Step 2: Dispatch all (company × dimension) tasks in parallel\\n\",\n \" tasks = []\\n\",\n \" task_meta = [] # parallel list to track what each task is\\n\",\n \" for company in plan[\\\"companies\\\"]:\\n\",\n \" for dim in plan[\\\"dimensions\\\"]:\\n\",\n \" worker = WORKERS[dim]\\n\",\n \" prompt = f\\\"Analyze: {company}\\\\n\\\\nContext: {user_query}\\\"\\n\",\n \" tasks.append(call_worker(worker, prompt))\\n\",\n \" task_meta.append((company, dim, worker.name))\\n\",\n \"\\n\",\n \" print(f\\\"🔨 Dispatching {len(tasks)} worker calls across providers...\\\\n\\\")\\n\",\n \" results = await asyncio.gather(*tasks)\\n\",\n \"\\n\",\n \" # Step 3: Organize results\\n\",\n \" findings: dict[str, dict[str, str]] = {c: {} for c in plan[\\\"companies\\\"]}\\n\",\n \" for (company, dim, _), result in zip(task_meta, results):\\n\",\n \" findings[company][dim] = result\\n\",\n \"\\n\",\n \" # Step 4: Synthesize — back to orchestrator for the final report\\n\",\n \" print(\\\"🧩 Synthesizing final report...\\\\n\\\")\\n\",\n \" synthesis_prompt = f\\\"\\\"\\\"Original query: {user_query}\\n\",\n \"\\n\",\n \"Worker findings (JSON):\\n\",\n \"{json.dumps(findings, indent=2)}\\n\",\n \"\\n\",\n \"Write a competitive analysis report. Start with a 2-3 sentence executive summary,\\n\",\n \"then a comparison organized by dimension (not by company), then end with\\n\",\n \"'Key Takeaways' — 3-5 bullets. Call out where companies meaningfully differ.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \" resp = await anthropic_client.messages.create(\\n\",\n \" model=\\\"claude-opus-4-5\\\",\\n\",\n \" max_tokens=4096,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": synthesis_prompt}],\\n\",\n \" )\\n\",\n \" report = resp.content[0].text\\n\",\n \"\\n\",\n \" return {\\\"plan\\\": plan, \\\"findings\\\": findings, \\\"report\\\": report}\\n\",\n \"\\n\",\n \" \\\"\\\"\\\"The synthesis step is the other half of the pattern people sometimes forget: you need the orchestrator (or another synthesizer) to stitch the worker outputs back together. \\n\",\n \" Raw worker outputs are ingredients, not a deliverable.\\\"\\\"\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"b1cf88bf\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"from IPython.display import Markdown, display\\n\",\n \"\\n\",\n \"query = \\\"Compare the leading enterprise data warehouse providers for a mid-sized SaaS company\\\"\\n\",\n \"\\n\",\n \"result = await analyze(query)\\n\",\n \"\\n\",\n \"display(Markdown(\\\"## 📊 Final Report\\\\n\\\\n\\\" + result[\\\"report\\\"]))\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"66ef2f9b\",\n \"metadata\": {},\n \"source\": [\n \"Experiments to try once it's working\\n\",\n \"Once you've got a baseline run, these will cement the pattern:\\n\",\n \"\\n\",\n \"Try a query that names specific companies (\\\"Compare Snowflake, Databricks, and BigQuery\\\") vs. one that doesn't (\\\"Who are the leaders in vector databases?\\\"). Watch how the orchestrator handles each — the second requires it to infer the competitor set, which is a much harder planning task.\\n\",\n \"\\n\",\n \"Time the full run, then try making the worker calls sequential (swap asyncio.gather for a loop). On a 4-company × 4-dimension query that's 16 calls — sequential will be painfully slow, and you'll feel why parallelism matters.\\n\",\n \"\\n\",\n \"Add a fifth worker using a different model on a provider you're already using, and teach the orchestrator about it by editing ORCHESTRATOR_SYSTEM. This shows how extensible the pattern is: workers are just plug-in specialists.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"443b4a65\",\n \"metadata\": {},\n \"source\": [\n \"Model-name sanity check before you run\\n\",\n \"Model IDs change more often than anything else in these setups. If Cell 6 fails with a \\\"model not found\\\" error, check these two first:\\n\",\n \"\\n\",\n \"Gemini: if gemini-2.5-flash errors on the compat endpoint, try gemini-2.0-flash.\\n\",\n \"Groq: if llama-3.3-70b-versatile has been deprecated, their current models page will list the replacement — Groq rotates model availability more than other providers.\\n\",\n \"\\n\",\n \"Everything else should be stable.\"\n ]\n }\n ],\n \"metadata\": {\n \"language_info\": {\n \"name\": \"python\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/claude_based_chatbot_tc/docs/Multi-modal-tailored-faq.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785745509.1472294, "n": 10267, "h": "f124f4cde08f21ad", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Multi-model Evaluation LinkedIn Summary and FAQ\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [\n {\n \"data\": {\n \"text/plain\": [\n \"True\"\n ]\n },\n \"execution_count\": 1,\n \"metadata\": {},\n \"output_type\": \"execute_result\"\n }\n ],\n \"source\": [\n \"import os\\n\",\n \"import gradio as gr\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from pypdf import PdfReader\\n\",\n \"from pathlib import Path\\n\",\n \"from IPython.display import Markdown, display\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from openai import OpenAI # Used here to call Ollama-compatible API and Google Gemini\\n\",\n \"\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"OpenAI API Key not set\\n\",\n \"Anthropic API Key exists and begins sk-ant-\\n\",\n \"Google API Key exists and begins AI\\n\",\n \"DeepSeek API Key not set (and this is optional)\\n\",\n \"Groq API Key exists and begins gsk_\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 6,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"anthropic = Anthropic()\\n\",\n \"\\n\",\n \"# === Load PDF and extract resume text ===\\n\",\n \"\\n\",\n \"reader = PdfReader(\\\"../claude_based_chatbot_tc/me/linkedin.pdf\\\")\\n\",\n \"linkedin = \\\"\\\"\\n\",\n \"for page in reader.pages:\\n\",\n \" text = page.extract_text()\\n\",\n \" if text:\\n\",\n \" linkedin += text\\n\",\n \"\\n\",\n \"# === Create the shared FAQ generation prompt ===\\n\",\n \"faq_prompt = (\\n\",\n \" \\\"Please read the following professional background and resume content carefully. \\\"\\n\",\n \" \\\"Based on this information, generate a well-structured FAQ (Frequently Asked Questions) document that reflects the subject’s professional background.\\\\n\\\\n\\\"\\n\",\n \" \\\"== RESUME TEXT START ==\\\\n\\\"\\n\",\n \" f\\\"{linkedin}\\\\n\\\"\\n\",\n \" \\\"== RESUME TEXT END ==\\\\n\\\\n\\\"\\n\",\n \"\\n\",\n \" \\\"**Instructions:**\\\\n\\\"\\n\",\n \" \\\"- Write at least 15 FAQs.\\\\n\\\"\\n\",\n \" \\\"- Each entry should be in the format:\\\\n\\\"\\n\",\n \" \\\" - Q: [Question here]\\\\n\\\"\\n\",\n \" \\\" - A: [Answer here]\\\\n\\\"\\n\",\n \" \\\"- Focus on real-world questions that recruiters, collaborators, or website visitors would ask.\\\\n\\\"\\n\",\n \" \\\"- Be concise, accurate, and use only the information in the resume. Do not speculate or invent details.\\\\n\\\"\\n\",\n \" \\\"- Use a professional tone suitable for publishing on a personal website.\\\\n\\\\n\\\"\\n\",\n \"\\n\",\n \" \\\"Output only the FAQ content. Do not include commentary, headers, or formatting outside of the Q/A list.\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": faq_prompt}]\\n\",\n \"evaluators = []\\n\",\n \"answers = []\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic API Call\\n\",\n \"\\n\",\n \"model_name = \\\"claude-3-7-sonnet-latest\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"faq_prompt = claude.messages.create(\\n\",\n \" model=model_name, \\n\",\n \" messages=messages, \\n\",\n \" max_tokens=1000\\n\",\n \")\\n\",\n \"\\n\",\n \"faq_answer = faq_prompt.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(faq_answer))\\n\",\n \"evaluators.append(model_name)\\n\",\n \"answers.append(faq_answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# === 2. Google Gemini Call ===\\n\",\n \"\\n\",\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash\\\"\\n\",\n \"\\n\",\n \"faq_prompt = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"faq_answer = faq_prompt.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(faq_answer))\\n\",\n \"evaluators.append(model_name)\\n\",\n \"answers.append(faq_answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# === 2. Ollama Groq Call ===\\n\",\n \"\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"llama-3.3-70b-versatile\\\"\\n\",\n \"\\n\",\n \"faq_prompt = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"faq_answer = faq_prompt.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(faq_answer))\\n\",\n \"evaluators.append(model_name)\\n\",\n \"answers.append(faq_answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"\\n\",\n \"for evaluator, answer in zip(evaluators, answers):\\n\",\n \" print(f\\\"Evaluator: {evaluator}\\\\n\\\\n{answer}\\\")\\n\",\n \"\\n\",\n \"\\n\",\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from evaluator {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 15,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"formatter = f\\\"\\\"\\\"You are a meticulous AI evaluator tasked with synthesizing multiple assistant-generated career FAQs and summaries into one high-quality file. You have received {len(evaluators)} drafts based on the same resume, each containing a 2-line summary and a set of FAQ questions with answers.\\n\",\n \"\\n\",\n \"---\\n\",\n \"**Original Request:**\\n\",\n \"\\\"{faq_prompt}\\\"\\n\",\n \"---\\n\",\n \"\\n\",\n \"Your goal is to combine the strongest parts of each submission into a single, polished output. This will be the final `faq.txt` that lives in a public-facing portfolio folder.\\n\",\n \"\\n\",\n \"**Evaluation & Synthesis Instructions:**\\n\",\n \"\\n\",\n \"1. **Prioritize Accuracy:** Only include information clearly supported by the resume. Do not invent or speculate.\\n\",\n \"2. **Best Questions Only:** Select the most relevant and insightful FAQ questions. Discard weak, redundant, or generic ones.\\n\",\n \"3. **Edit for Quality:** Improve the clarity and fluency of answers. Fix grammar, wording, or formatting inconsistencies.\\n\",\n \"4. **Merge Strengths:** If two assistants answer the same question differently, combine the best phrasing and facts from each.\\n\",\n \"5. **Consistency in Voice:** Ensure a single professional tone throughout the summary and FAQ.\\n\",\n \"\\n\",\n \"**Required Output Structure:**\\n\",\n \"\\n\",\n \"1. **2-Line Summary:** Start with the best or synthesized version of the summary, capturing key career strengths.\\n\",\n \"2. **FAQ Entries:** Follow with at least 8–12 strong FAQ entries in this format:\\n\",\n \"\\n\",\n \"Q: [Question] \\n\",\n \"A: [Answer]\\n\",\n \"\\n\",\n \"---\\n\",\n \"**Examples of Strong FAQ Topics:**\\n\",\n \"- Key technical skills or languages\\n\",\n \"- Past projects or employers\\n\",\n \"- Teamwork or communication style\\n\",\n \"- Remote work or leadership experience\\n\",\n \"- Career goals or current availability\\n\",\n \"\\n\",\n \"This will be saved as a plain text file (`faq.txt`). Ensure the tone is accurate, clean, and helpful. Do not add unnecessary commentary or meta-analysis. The final version should look like it was written by a professional assistant who knows the subject well.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"formatter_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": formatter}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# === 1. Final (Claude) API Call ===\\n\",\n \"anthropic = Anthropic(api_key=anthropic_api_key)\\n\",\n \"faq_prompt = anthropic.messages.create(\\n\",\n \" model=\\\"claude-3-7-sonnet-latest\\\",\\n\",\n \" messages=formatter_messages,\\n\",\n \" max_tokens=1000,\\n\",\n \")\\n\",\n \"results = faq_prompt.content[0].text\\n\",\n \"display(Markdown(results))\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gr.ChatInterface(results, type=\\\"messages\\\").launch()\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.10\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/6_mcp/community_contributions/trading_with_short/traders.py": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1785746640.6017148, "n": 5082, "h": "c8956a1558420b94", "c": "from contextlib import AsyncExitStack\nfrom accounts_client import read_accounts_resource, read_strategy_resource\nfrom tracers import make_trace_id\nfrom agents import Agent, Tool, Runner, OpenAIChatCompletionsModel, trace\nfrom openai import AsyncOpenAI\nfrom dotenv import load_dotenv\nimport os\nimport json\nfrom agents.mcp import MCPServerStdio\nfrom templates import (\n researcher_instructions,\n trader_instructions,\n trade_message,\n rebalance_message,\n research_tool,\n)\nfrom mcp_params import trader_mcp_server_params, researcher_mcp_server_params\n\nload_dotenv(override=True)\n\ndeepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\")\ngoogle_api_key = os.getenv(\"GOOGLE_API_KEY\")\ngrok_api_key = os.getenv(\"GROK_API_KEY\")\nopenrouter_api_key = os.getenv(\"OPENROUTER_API_KEY\")\n\nDEEPSEEK_BASE_URL = \"https://api.deepseek.com/v1\"\nGROK_BASE_URL = \"https://api.x.ai/v1\"\nGEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\nOPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\"\n\nMAX_TURNS = 20\n\nopenrouter_client = AsyncOpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\ndeepseek_client = AsyncOpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\ngrok_client = AsyncOpenAI(base_url=GROK_BASE_URL, api_key=grok_api_key)\ngemini_client = AsyncOpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\n\n\ndef get_model(model_name: str):\n if \"/\" in model_name:\n return OpenAIChatCompletionsModel(model=model_name, openai_client=openrouter_client)\n elif \"deepseek\" in model_name:\n return OpenAIChatCompletionsModel(model=model_name, openai_client=deepseek_client)\n elif \"grok\" in model_name:\n return OpenAIChatCompletionsModel(model=model_name, openai_client=grok_client)\n elif \"gemini\" in model_name:\n return OpenAIChatCompletionsModel(model=model_name, openai_client=gemini_client)\n else:\n return model_name\n\n\nasync def get_researcher(mcp_servers, model_name) -> Agent:\n researcher = Agent(\n name=\"Researcher\",\n instructions=researcher_instructions(),\n model=get_model(model_name),\n mcp_servers=mcp_servers,\n )\n return researcher\n\n\nasync def get_researcher_tool(mcp_servers, model_name) -> Tool:\n researcher = await get_researcher(mcp_servers, model_name)\n return researcher.as_tool(tool_name=\"Researcher\", tool_description=research_tool())\n\n\nclass Trader:\n def __init__(self, name: str, lastname=\"Trader\", model_name=\"gpt-4o-mini\"):\n self.name = name\n self.lastname = lastname\n self.agent = None\n self.model_name = model_name\n self.do_trade = True\n\n async def create_agent(self, trader_mcp_servers, researcher_mcp_servers) -> Agent:\n tool = await get_researcher_tool(researcher_mcp_servers, self.model_name)\n self.agent = Agent(\n name=self.name,\n instructions=trader_instructions(self.name),\n model=get_model(self.model_name),\n tools=[tool],\n mcp_servers=trader_mcp_servers,\n )\n return self.agent\n\n async def get_account_report(self) -> str:\n account = await read_accounts_resource(self.name)\n account_json = json.loads(account)\n account_json.pop(\"portfolio_value_time_series\", None)\n return json.dumps(account_json)\n\n async def run_agent(self, trader_mcp_servers, researcher_mcp_servers):\n self.agent = await self.create_agent(trader_mcp_servers, researcher_mcp_servers)\n account = await self.get_account_report()\n strategy = await read_strategy_resource(self.name)\n message = (\n trade_message(self.name, strategy, account)\n if self.do_trade\n else rebalance_message(self.name, strategy, account)\n )\n await Runner.run(self.agent, message, max_turns=MAX_TURNS)\n\n async def run_with_mcp_servers(self):\n async with AsyncExitStack() as stack:\n trader_mcp_servers = [\n await stack.enter_async_context(\n MCPServerStdio(params, client_session_timeout_seconds=120)\n )\n for params in trader_mcp_server_params\n ]\n async with AsyncExitStack() as stack:\n researcher_mcp_servers = [\n await stack.enter_async_context(\n MCPServerStdio(params, client_session_timeout_seconds=120)\n )\n for params in researcher_mcp_server_params(self.name)\n ]\n await self.run_agent(trader_mcp_servers, researcher_mcp_servers)\n\n async def run_with_trace(self):\n trace_name = f\"{self.name}-trading\" if self.do_trade else f\"{self.name}-rebalancing\"\n trace_id = make_trace_id(f\"{self.name.lower()}\")\n with trace(trace_name, trace_id=trace_id):\n await self.run_with_mcp_servers()\n\n async def run(self):\n try:\n await self.run_with_trace()\n except Exception as e:\n print(f\"Error running trader {self.name}: {e}\")\n self.do_trade = not self.do_trade\n"}}, "AI/projects/agents/2_openai/community_contributions/3_lab3_with_pushover_notifications.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1786067392.297245, "n": 14755, "h": "7f45fef067ec4a47", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Week 2 Day 3\\n\",\n \"\\n\",\n \"Now we get to more detail:\\n\",\n \"\\n\",\n \"1. Different models\\n\",\n \"\\n\",\n \"2. Structured Outputs\\n\",\n \"\\n\",\n \"3. Guardrails\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"from dotenv import load_dotenv\\n\",\n \"from openai import AsyncOpenAI\\n\",\n \"from agents import Agent, Runner, trace, function_tool, OpenAIChatCompletionsModel, input_guardrail, GuardrailFunctionOutput\\n\",\n \"from typing import Dict\\n\",\n \"import requests\\n\",\n \"import os\\n\",\n \"from pydantic import BaseModel\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"instructions1 = \\\"You are a sales agent working for ComplAI, \\\\\\n\",\n \"a company that provides a SaaS tool for ensuring SOC2 compliance and preparing for audits, powered by AI. \\\\\\n\",\n \"You write professional, serious cold emails.\\\"\\n\",\n \"\\n\",\n \"instructions2 = \\\"You are a humorous, engaging sales agent working for ComplAI, \\\\\\n\",\n \"a company that provides a SaaS tool for ensuring SOC2 compliance and preparing for audits, powered by AI. \\\\\\n\",\n \"You write witty, engaging cold emails that are likely to get a response.\\\"\\n\",\n \"\\n\",\n \"instructions3 = \\\"You are a busy sales agent working for ComplAI, \\\\\\n\",\n \"a company that provides a SaaS tool for ensuring SOC2 compliance and preparing for audits, powered by AI. \\\\\\n\",\n \"You write concise, to the point cold emails.\\\"\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### It's easy to use any models with OpenAI compatible endpoints\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"GROQ_BASE_URL = \\\"https://api.groq.com/openai/v1\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\n\",\n \"deepseek_client = AsyncOpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\\n\",\n \"gemini_client = AsyncOpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\\n\",\n \"groq_client = AsyncOpenAI(base_url=GROQ_BASE_URL, api_key=groq_api_key)\\n\",\n \"\\n\",\n \"deepseek_model = OpenAIChatCompletionsModel(model=\\\"deepseek-chat\\\", openai_client=deepseek_client)\\n\",\n \"gemini_model = OpenAIChatCompletionsModel(model=\\\"gemini-2.0-flash\\\", openai_client=gemini_client)\\n\",\n \"llama3_3_model = OpenAIChatCompletionsModel(model=\\\"llama-3.3-70b-versatile\\\", openai_client=groq_client)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Use different models, falling back to OpenAI if others don't work\\n\",\n \"sales_agent1 = Agent(name=\\\"OpenAI Sales Agent\\\", instructions=instructions1, model=\\\"gpt-4o-mini\\\")\\n\",\n \"sales_agent2 = Agent(name=\\\"OpenAI Sales Agent 2\\\", instructions=instructions2, model=\\\"gpt-4o\\\") \\n\",\n \"sales_agent3 = Agent(name=\\\"OpenAI Sales Agent 3\\\", instructions=instructions3, model=\\\"gpt-3.5-turbo\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"description = \\\"Write a cold sales email\\\"\\n\",\n \"\\n\",\n \"tool1 = sales_agent1.as_tool(tool_name=\\\"sales_agent1\\\", tool_description=description)\\n\",\n \"tool2 = sales_agent2.as_tool(tool_name=\\\"sales_agent2\\\", tool_description=description)\\n\",\n \"tool3 = sales_agent3.as_tool(tool_name=\\\"sales_agent3\\\", tool_description=description)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"@function_tool\\n\",\n \"def send_simple_notification(message: str) -> Dict[str, str]:\\n\",\n \" \\\"\\\"\\\" Send a simple notification with the given message to all sales prospects \\\"\\\"\\\"\\n\",\n \" url = \\\"https://api.pushover.net/1/messages.json\\\"\\n\",\n \" \\n\",\n \" data = {\\n\",\n \" \\\"token\\\": os.environ.get('PUSHOVER_TOKEN'),\\n\",\n \" \\\"user\\\": os.environ.get('PUSHOVER_USER'),\\n\",\n \" \\\"message\\\": message,\\n\",\n \" \\\"title\\\": \\\"Sales Email\\\"\\n\",\n \" }\\n\",\n \" \\n\",\n \" response = requests.post(url, data=data)\\n\",\n \" if response.status_code == 200:\\n\",\n \" return {\\\"status\\\": \\\"success\\\", \\\"message\\\": \\\"Notification sent successfully\\\"}\\n\",\n \" else:\\n\",\n \" return {\\\"status\\\": \\\"error\\\", \\\"message\\\": f\\\"Error {response.status_code}: {response.text}\\\"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"subject_instructions = \\\"You can write a subject for a cold sales email. \\\\\\n\",\n \"You are given a message and you need to write a subject for an email that is likely to get a response.\\\"\\n\",\n \"\\n\",\n \"html_instructions = \\\"You can convert a text email body to an HTML email body. \\\\\\n\",\n \"You are given a text email body which might have some markdown \\\\\\n\",\n \"and you need to convert it to an HTML email body with simple, clear, compelling layout and design.\\\"\\n\",\n \"\\n\",\n \"subject_writer = Agent(name=\\\"Email subject writer\\\", instructions=subject_instructions, model=\\\"gpt-4o-mini\\\")\\n\",\n \"subject_tool = subject_writer.as_tool(tool_name=\\\"subject_writer\\\", tool_description=\\\"Write a subject for a cold sales email\\\")\\n\",\n \"\\n\",\n \"html_converter = Agent(name=\\\"HTML email body converter\\\", instructions=html_instructions, model=\\\"gpt-4o-mini\\\")\\n\",\n \"html_tool = html_converter.as_tool(tool_name=\\\"html_converter\\\",tool_description=\\\"Convert a text email body to an HTML email body\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"notification_tools = [send_simple_notification]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"instructions = \\\"You are a notification sender. You receive the body of an email to be sent. \\\\\\n\",\n \"You use the send_simple_notification tool to send the email content as a clean, readable notification. \\\\\\n\",\n \"Do not add any formatting or subjects - just send the email content directly.\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"notification_agent = Agent(\\n\",\n \" name=\\\"Notification Sender\\\",\\n\",\n \" instructions=instructions,\\n\",\n \" tools=[send_simple_notification],\\n\",\n \" model=\\\"gpt-4o-mini\\\",\\n\",\n \" handoff_description=\\\"Send the email content as a simple notification\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"tools = [tool1, tool2, tool3]\\n\",\n \"handoffs = [notification_agent]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"sales_manager_instructions = \\\"\\\"\\\"\\n\",\n \"You are a Sales Manager at ComplAI. Your goal is to find the single best cold sales email using the sales_agent tools.\\n\",\n \"\\n\",\n \"CRITICAL: You must complete ALL steps before making ANY handoff. You can only make ONE handoff total.\\n\",\n \"\\n\",\n \"Follow these steps carefully:\\n\",\n \"1. Generate Drafts: Use all three sales_agent tools to generate three different email drafts. Do not proceed until all three drafts are ready.\\n\",\n \"\\n\",\n \"2. Evaluate and Select: Review ALL three drafts and choose the single best email using your judgment of which one is most effective. DO NOT hand off during this step.\\n\",\n \"\\n\",\n \"3. Single Handoff: Hand off ONLY the winning email draft text to the 'Notification Sender' agent. \\n\",\n \"\\n\",\n \"FORBIDDEN ACTIONS:\\n\",\n \"- DO NOT hand off each email as you generate it\\n\",\n \"- DO NOT make multiple handoffs\\n\",\n \"- DO NOT hand off all three emails\\n\",\n \"- You can make ONLY ONE handoff with ONLY the best email text\\n\",\n \"\\n\",\n \"Crucial Rules:\\n\",\n \"- You must use the sales agent tools to generate the drafts — do not write them yourself.\\n\",\n \"- You must hand off exactly ONE email to the Notification Sender — never more than one.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"sales_manager = Agent(\\n\",\n \" name=\\\"Sales Manager\\\",\\n\",\n \" instructions=sales_manager_instructions,\\n\",\n \" tools=tools,\\n\",\n \" handoffs=[notification_agent],\\n\",\n \" model=\\\"gpt-4o-mini\\\")\\n\",\n \"\\n\",\n \"message = \\\"Send out a cold sales email addressed to Dear CEO from Alice\\\"\\n\",\n \"\\n\",\n \"with trace(\\\"Automated SDR\\\"):\\n\",\n \" result = await Runner.run(sales_manager, message, max_turns=20)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Check out the trace:\\n\",\n \"\\n\",\n \"https://platform.openai.com/traces\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"class NameCheckOutput(BaseModel):\\n\",\n \" is_name_in_message: bool\\n\",\n \" name: str\\n\",\n \"\\n\",\n \"guardrail_agent = Agent( \\n\",\n \" name=\\\"Name check\\\",\\n\",\n \" instructions=\\\"Check if the user is including someone's personal name in what they want you to do.\\\",\\n\",\n \" output_type=NameCheckOutput,\\n\",\n \" model=\\\"gpt-4o-mini\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"@input_guardrail\\n\",\n \"async def guardrail_against_name(ctx, agent, message):\\n\",\n \" result = await Runner.run(guardrail_agent, message, context=ctx.context)\\n\",\n \" is_name_in_message = result.final_output.is_name_in_message\\n\",\n \" return GuardrailFunctionOutput(output_info={\\\"found_name\\\": result.final_output},tripwire_triggered=is_name_in_message)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"careful_sales_manager = Agent(\\n\",\n \" name=\\\"Careful Sales Manager\\\",\\n\",\n \" instructions=sales_manager_instructions,\\n\",\n \" tools=tools,\\n\",\n \" handoffs=[notification_agent],\\n\",\n \" model=\\\"gpt-4o-mini\\\",\\n\",\n \" input_guardrails=[guardrail_against_name]\\n\",\n \" )\\n\",\n \"\\n\",\n \"# Test Guardrail Behavior - Choose one message:\\n\",\n \"\\n\",\n \"# Option 1: Message WITHOUT personal name - Guardrail will allow execution\\n\",\n \"# message = \\\"Send out a cold sales email addressed to Dear CEO from Sales Team\\\"\\n\",\n \"\\n\",\n \"# Option 2: Message WITH personal name - Guardrail will BLOCK with InputGuardrailTripwireTriggered\\n\",\n \"message = \\\"Send out a cold sales email addressed to Dear CEO from Alice\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Testing with message: {message}\\\")\\n\",\n \"if \\\"Alice\\\" in message or \\\"from \\\" in message.split(\\\"from \\\")[-1] and len(message.split(\\\"from \\\")[-1].split()) == 1:\\n\",\n \" print(\\\"Expected: Guardrail will BLOCK execution (personal name detected)\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Expected: Guardrail allows execution (no personal name detected)\\\")\\n\",\n \"\\n\",\n \"with trace(\\\"Protected Automated SDR\\\"):\\n\",\n \" result = await Runner.run(careful_sales_manager, message, max_turns=20)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Check out the trace:\\n\",\n \"\\n\",\n \"https://platform.openai.com/traces\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\n\",\n \"# This message should pass the guardrail (no personal name)\\n\",\n \"message = \\\"Send out a cold sales email addressed to Dear CEO from Head of Business Development\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Testing with message: {message}\\\")\\n\",\n \"print(\\\"Expected: Guardrail allows execution (no personal name detected)\\\")\\n\",\n \"\\n\",\n \"with trace(\\\"Protected Automated SDR\\\"):\\n\",\n \" result = await Runner.run(careful_sales_manager, message, max_turns=20)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">• Try different models<br/>• Add more input and output guardrails<br/>• Use structured outputs for the email generation\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": []\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.11\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/2_openai/community_contributions/kisali/1_lab1_strands_sdk_intro.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1786068253.9694128, "n": 7399, "h": "f239aaf96ddceebd", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Strands Agents with DeepSeek and Amazon Bedrock\\n\",\n \"\\n\",\n \"I'll be using AWS Strands Agents SDK instead of Open AI Agents SDK, in addition to Deepseek API directly. This will enable me use different models available on Amazon Bedrock.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../../../assets/tools.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">The Strands Agents SDK Docs</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">The documentation on Amazon Strands Agents SDK is really clear and simple: <a href=\\\"https://strandsagents.com/latest/documentation/docs/\\\">https://strandsagents.com/latest/documentation/docs/</a> and it's well worth a look.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Strands Agents with DeepSeek and Amazon Bedrock\\n\",\n \"This notebook demonstrates how to create basic Strands agents using models from DeepSeek API and Amazon Bedrock.\\n\",\n \"\\n\",\n \" **Prerequisites:**\\n\",\n \" - Python virtual environment set up.\\n\",\n \" - `strands-agents`, `strands-agents-tools`, `litellm`, `boto3`, `python-dotenv` installed.\\n\",\n \" - DeepSeek API Key configured as `DEEPSEEK_API_KEY` environment variable (e.g., in a `.env` file).\\n\",\n \" - Bedrock API Key configured as `AMAZON_BEDROCK_API_KEY` environment variable (e.g., in a `.env` file).\\n\",\n \" - AWS CLI configured with credentials that have access to Amazon Bedrock and desired models.\\n\",\n \" - Desired models enabled in Amazon Bedrock console.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing necessary components\\n\",\n \"from strands.models import BedrockModel\\n\",\n \"from strands_tools import calculator\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from strands import Agent\\n\",\n \"import os \\n\",\n \"#import boto3\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Loading environment variables from .env file\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### 1. Strands Agent with Amazon Bedrock\\n\",\n \"\\n\",\n \" Strands SDK has native integration with Amazon Bedrock using the `BedrockModel` class.\\n\",\n \"\\n\",\n \" Initialize the Bedrock model\\n\",\n \" - Ensure your AWS credentials are configured (e.g., via `aws configure`) and you have access to the specified model in the correct region.\\n\",\n \" - Example model_id for Claude 3.5 Sonnet in us-east-1: \\\"anthropic.claude-3-sonnet-20240229-v1:0\\\"\\n\",\n \" - Example model_id for Amazon's own model: \\\"amazon.titan-text-express-v1\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"bedrock_model = BedrockModel(\\n\",\n \" model_id=\\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\",\\n\",\n \" region_name=\\\"us-east-1\\\", \\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"- Create a Strands Agent for Bedrock\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Create an agent with the configured model\\n\",\n \"joke_agent = Agent(name=\\\"Jokester\\\", \\n\",\n \" system_prompt=\\\"You are a joke teller\\\", \\n\",\n \" model=bedrock_model)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"- Running Bedrock agent with a query\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Use the agent\\n\",\n \"response = joke_agent(\\\"Tell me a joke about Agentic AI.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"bedrock_model = BedrockModel(\\n\",\n \" model_id=\\\"amazon.nova-pro-v1:0\\\",\\n\",\n \" region_name=\\\"us-east-1\\\", \\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"- Creating a strands agent using amazon nova pro using calculator tool available as one of strands tools\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"math_agent = Agent(name=\\\"Math Agent\\\", \\n\",\n \" system_prompt=\\\"You are a helpful math assistant\\\", \\n\",\n \" model=bedrock_model, \\n\",\n \" tools=[calculator])\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"response = math_agent(\\\"What is the area of a triangle whose height is 16 ad base is 20?\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### 1. Strands Agent with DeepSeek API (via LiteLLM)\\n\",\n \"\\n\",\n \"- DeepSeek's API is OpenAI-compatible, so we can leverage LiteLLM to connect to it seamlessly.\\n\",\n \"\\n\",\n \"- Initialize the LiteLLM model for DeepSeek\\n\",\n \"- We specify the model name which LiteLLM maps to DeepSeek's service.\\n\",\n \"- You can choose 'deepseek/deepseek-chat' (V3) or 'deepseek/deepseek-reasoner' (R1)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek_api_key = os.getenv(\\\"DEEPSEEK_API_KEY\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"from strands.models.litellm import LiteLLMModel\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"model = LiteLLMModel(\\n\",\n \" client_args={\\n\",\n \" \\\"api_key\\\": deepseek_api_key,\\n\",\n \" },\\n\",\n \" model_id=\\\"deepseek/deepseek-chat\\\",\\n\",\n \" params={\\n\",\n \" \\\"max_tokens\\\": 1000,\\n\",\n \" \\\"temperature\\\": 0.7,\\n\",\n \" }\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"- Create a Strands Agent for DeepSeek\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"agent = Agent(model=model)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"response_1 = agent(\\\"What is an ai agent\\\")\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/Shmacked/2_lab2.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1786068256.962523, "n": 18604, "h": "88206d527930d579", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Important point - please read</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-4o-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"\\n\",\n \"model_name = \\\"gpt-4o-mini\\\"\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"\\n\",\n \"# model_name = \\\"claude-3-7-sonnet-latest\\\"\\n\",\n \"model_name = \\\"claude-3-5-haiku-20241022\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \"answer = response.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.0-flash\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \"model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \"response = deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"llama-3.3-70b-versatile\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# So where are we?\\n\",\n \"\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(together)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(competitors)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, nothing else. Do not include markdown formatting or code blocks.\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"o3-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"results = response.choices[0].message.content\\n\",\n \"print(results)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(results)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/business.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">Commercial implications</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">These kinds of patterns - to send a task to multiple models, and evaluate results,\\n\",\n \" are common where you need to improve the quality of your LLM response. This approach can be universally applied\\n\",\n \" to business projects where accuracy is critical.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\n\",\n \"\\n\",\n \"def send_receive(model, message, base_url=None, api_key=None):\\n\",\n \" messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" # print(model, base_url, api_key, message)\\n\",\n \" # print(model, base_url, api_key)\\n\",\n \" if base_url == \\\"anthropic\\\":\\n\",\n \" claude = Anthropic()\\n\",\n \" response = claude.messages.create(model=model, messages=messages, max_tokens=1000)\\n\",\n \" return response.content[0].text\\n\",\n \" elif base_url is not None and api_key is not None:\\n\",\n \" openai = OpenAI(base_url=base_url, api_key=api_key)\\n\",\n \" else:\\n\",\n \" openai = OpenAI()\\n\",\n \" response = openai.chat.completions.create(\\n\",\n \" model=model,\\n\",\n \" messages=messages,\\n\",\n \" )\\n\",\n \" return response.choices[0].message.content\\n\",\n \"\\n\",\n \"\\n\",\n \"def print_results(response):\\n\",\n \" results_dict = json.loads(response[\\\"response\\\"])\\n\",\n \" ranks = results_dict[\\\"results\\\"]\\n\",\n \" print(f\\\"Results from {response[\\\"model\\\"]}...\\\")\\n\",\n \" for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor}\\\")\\n\",\n \" print()\\n\",\n \"\\n\",\n \"\\n\",\n \"model_routing = {\\n\",\n \" \\\"gpt-4o-mini\\\": {\\n\",\n \" \\\"base_url\\\": None,\\n\",\n \" \\\"api_key\\\": None\\n\",\n \" },\\n\",\n \" \\\"llama-3.3-70b-versatile\\\": {\\n\",\n \" \\\"base_url\\\": \\\"https://api.groq.com/openai/v1\\\",\\n\",\n \" \\\"api_key\\\": groq_api_key\\n\",\n \" },\\n\",\n \" # \\\"llama3.2\\\": {\\n\",\n \" # \\\"base_url\\\": \\\"http://localhost:11434/v1\\\",\\n\",\n \" # \\\"api_key\\\": \\\"ollama\\\"\\n\",\n \" # },\\n\",\n \" \\\"claude-3-5-haiku-20241022\\\": {\\n\",\n \" \\\"base_url\\\": \\\"anthropic\\\",\\n\",\n \" \\\"api_key\\\": anthropic_api_key\\n\",\n \" },\\n\",\n \" \\\"deepseek-chat\\\": {\\n\",\n \" \\\"base_url\\\": \\\"https://api.deepseek.com/v1\\\",\\n\",\n \" \\\"api_key\\\": deepseek_api_key,\\n\",\n \" },\\n\",\n \"}\\n\",\n \"\\n\",\n \"results = []\\n\",\n \"\\n\",\n \"for model_name, details in model_routing.items():\\n\",\n \" if details[\\\"base_url\\\"] is None and details[\\\"api_key\\\"] is None:\\n\",\n \" results.append({\\\"model\\\": model_name, \\\"response\\\": send_receive(model_name, judge_messages[0][\\\"content\\\"])})\\n\",\n \" else:\\n\",\n \" results.append({\\\"model\\\": model_name, \\\"response\\\": send_receive(model_name, judge_messages[0][\\\"content\\\"], base_url=details[\\\"base_url\\\"], api_key=details[\\\"api_key\\\"])})\\n\",\n \"\\n\",\n \"for result in results:\\n\",\n \" print_results(result)\\n\",\n \"\\n\",\n \"\\n\",\n \"# display(\\n\",\n \"# Markdown(\\n\",\n \"# send_receive(\\n\",\n \"# \\\"gpt-4o-mini\\\", \\n\",\n \"# \\\"If I am querying multiple AI models the same question, then passing the responses back to another model to rank them, what type of Agentic design pattern am I using?\\\"\\n\",\n \"# )\\n\",\n \"# )\\n\",\n \"# )\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": []\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.11\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "AI/projects/agents/1_foundations/community_contributions/kevj/2_lab2.ipynb": {"975e1c27234c97e8f004d52d39ab732b40b8f33c": {"t": 1786068259.8374746, "n": 16159, "h": "35331951faff2161", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Welcome to the Second Lab - Week 1, Day 3\\n\",\n \"\\n\",\n \"Today we will work with lots of models! This is a way to get comfortable with APIs.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Important point - please read</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The way I collaborate with you may be different to other courses you've taken. I prefer not to type code while you watch. Rather, I execute Jupyter Labs, like this, and give you an intuition for what's going on. My suggestion is that you carefully execute this yourself, <b>after</b> watching the lecture. Add print statements to understand what's going on, and then come up with your own variations.<br/><br/>If you have time, I'd love it if you submit a PR for changes in the community_contributions folder - instructions in the resources. Also, if you have a Github account, use this to showcase your variations. Not only is this essential practice, but it demonstrates your skills to others, including perhaps future clients or employers...\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Start with imports - ask ChatGPT to explain any package that you don't know\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from anthropic import Anthropic\\n\",\n \"from IPython.display import Markdown, display\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Always remember to do this!\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Print the key prefixes to help with any debugging\\n\",\n \"\\n\",\n \"openai_api_key = os.getenv('OPENAI_API_KEY')\\n\",\n \"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\\n\",\n \"google_api_key = os.getenv('GOOGLE_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"groq_api_key = os.getenv('GROQ_API_KEY')\\n\",\n \"\\n\",\n \"if openai_api_key:\\n\",\n \" print(f\\\"OpenAI API Key exists and begins {openai_api_key[:8]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"OpenAI API Key not set\\\")\\n\",\n \" \\n\",\n \"if anthropic_api_key:\\n\",\n \" print(f\\\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Anthropic API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if google_api_key:\\n\",\n \" print(f\\\"Google API Key exists and begins {google_api_key[:2]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Google API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if deepseek_api_key:\\n\",\n \" print(f\\\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"DeepSeek API Key not set (and this is optional)\\\")\\n\",\n \"\\n\",\n \"if groq_api_key:\\n\",\n \" print(f\\\"Groq API Key exists and begins {groq_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Groq API Key not set (and this is optional)\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"request = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"request += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": request}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"question = response.choices[0].message.content\\n\",\n \"print(question)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"competitors = []\\n\",\n \"answers = []\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": question}]\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Note - update since the videos\\n\",\n \"\\n\",\n \"I've updated the model names to use the latest models below, like GPT 5 and Claude Sonnet 4.5. It's worth noting that these models can be quite slow - like 1-2 minutes - but they do a great job! Feel free to switch them for faster models if you'd prefer, like the ones I use in the video.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# The API we know well\\n\",\n \"# I've updated this with the latest model, but it can take some time because it likes to think!\\n\",\n \"# Replace the model with gpt-4.1-mini if you'd prefer not to wait 1-2 mins\\n\",\n \"\\n\",\n \"model_name = \\\"gpt-5-nano\\\"\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic has a slightly different API, and Max Tokens is required\\n\",\n \"\\n\",\n \"model_name = \\\"claude-sonnet-4-5\\\"\\n\",\n \"\\n\",\n \"claude = Anthropic()\\n\",\n \"response = claude.messages.create(model=model_name, messages=messages, max_tokens=1000)\\n\",\n \"answer = response.content[0].text\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"gemini = OpenAI(api_key=google_api_key, base_url=\\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\")\\n\",\n \"model_name = \\\"gemini-2.5-flash\\\"\\n\",\n \"\\n\",\n \"response = gemini.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"deepseek = OpenAI(api_key=deepseek_api_key, base_url=\\\"https://api.deepseek.com/v1\\\")\\n\",\n \"model_name = \\\"deepseek-chat\\\"\\n\",\n \"\\n\",\n \"response = deepseek.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Updated with the latest Open Source model from OpenAI\\n\",\n \"\\n\",\n \"groq = OpenAI(api_key=groq_api_key, base_url=\\\"https://api.groq.com/openai/v1\\\")\\n\",\n \"model_name = \\\"openai/gpt-oss-120b\\\"\\n\",\n \"\\n\",\n \"response = groq.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## For the next cell, we will use Ollama\\n\",\n \"\\n\",\n \"Ollama runs a local web service that gives an OpenAI compatible endpoint, \\n\",\n \"and runs models locally using high performance C++ code.\\n\",\n \"\\n\",\n \"If you don't have Ollama, install it here by visiting https://ollama.com then pressing Download and following the instructions.\\n\",\n \"\\n\",\n \"After it's installed, you should be able to visit here: http://localhost:11434 and see the message \\\"Ollama is running\\\"\\n\",\n \"\\n\",\n \"You might need to restart Cursor (and maybe reboot). Then open a Terminal (control+\\\\`) and run `ollama serve`\\n\",\n \"\\n\",\n \"Useful Ollama commands (run these in the terminal, or with an exclamation mark in this notebook):\\n\",\n \"\\n\",\n \"`ollama pull <model_name>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_name>` deletes the specified model from your downloads\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/stop.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Super important - ignore me at your peril!</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">The model called <b>llama3.3</b> is FAR too large for home computers - it's not intended for personal computing and will consume all your resources! Stick with the nicely sized <b>llama3.2</b> or <b>llama3.2:1b</b> and if you want larger, try llama3.1 or smaller variants of Qwen, Gemma, Phi or DeepSeek. See the <A href=\\\"https://ollama.com/models\\\">the Ollama models page</a> for a full list of models and sizes.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"!ollama pull llama3.2\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"ollama = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\\n\",\n \"model_name = \\\"llama3.2\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(model=model_name, messages=messages)\\n\",\n \"answer = response.choices[0].message.content\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_name)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# So where are we?\\n\",\n \"\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# It's nice to know how to use \\\"zip\\\"\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Let's bring this together - note the use of \\\"enumerate\\\"\\n\",\n \"\\n\",\n \"together = \\\"\\\"\\n\",\n \"for index, answer in enumerate(answers):\\n\",\n \" together += f\\\"# Response from competitor {index+1}\\\\n\\\\n\\\"\\n\",\n \" together += answer + \\\"\\\\n\\\\n\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(together)\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": []\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge = f\\\"\\\"\\\"You are judging a competition between {len(competitors)} competitors.\\n\",\n \"Each model has been given this question:\\n\",\n \"\\n\",\n \"{question}\\n\",\n \"\\n\",\n \"Your job is to evaluate each response for clarity and strength of argument, and rank them in order of best to worst.\\n\",\n \"Respond with JSON, and only JSON, with the following format:\\n\",\n \"{{\\\"results\\\": [\\\"best competitor number\\\", \\\"second best competitor number\\\", \\\"third best competitor number\\\", ...], \\\"summary\\\": [\\\"summary of best competitor\\\", \\\"summary of second best competitor\\\", \\\"summary of third best competitor\\\", ...]}}\\n\",\n \"\\n\",\n \"Here are the responses from each competitor:\\n\",\n \"\\n\",\n \"{together}\\n\",\n \"\\n\",\n \"Now respond with the JSON with the ranked order of the competitors, and a one sentence summary of your assessment, nothing else. Do not include markdown formatting or code blocks\\\"\\\"\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(judge)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"judge_messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": judge}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Judgement time!\\n\",\n \"\\n\",\n \"openai = OpenAI()\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=\\\"gpt-5-mini\\\",\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"results = response.choices[0].message.content\\n\",\n \"print(results)\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# OK let's turn this into results!\\n\",\n \"\\n\",\n \"results_dict = json.loads(results)\\n\",\n \"ranks = results_dict[\\\"results\\\"]\\n\",\n \"for index, result in enumerate(ranks):\\n\",\n \" competitor = competitors[int(result)-1]\\n\",\n \" print(f\\\"Rank {index+1}: {competitor} {results_dict['summary'][index]}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/exercise.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#ff7800;\\\">Exercise</h2>\\n\",\n \" <span style=\\\"color:#ff7800;\\\">Which pattern(s) did this use? Try updating this to add another Agentic design pattern.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"<table style=\\\"margin: 0; text-align: left; width:100%\\\">\\n\",\n \" <tr>\\n\",\n \" <td style=\\\"width: 150px; height: 150px; vertical-align: middle;\\\">\\n\",\n \" <img src=\\\"../assets/business.png\\\" width=\\\"150\\\" height=\\\"150\\\" style=\\\"display: block;\\\" />\\n\",\n \" </td>\\n\",\n \" <td>\\n\",\n \" <h2 style=\\\"color:#00bfff;\\\">Commercial implications</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">These kinds of patterns - to send a task to multiple models, and evaluate results,\\n\",\n \" are common where you need to improve the quality of your LLM response. This approach can be universally applied\\n\",\n \" to business projects where accuracy is critical.\\n\",\n \" </span>\\n\",\n \" </td>\\n\",\n \" </tr>\\n\",\n \"</table>\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \".venv\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.12.3\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}}}