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.
1 line
135 KiB
JSON
1 line
135 KiB
JSON
{"repo": "aithashi/agentic-ai-cource", "files": {"1_foundations/community_contributions/kisali/2_lab2_aws_bedrock_multi_llm.ipynb": {"6ece898767225cd94d9e566abd11417d0655b7f3": {"t": 1785745478.9204776, "n": 13807, "h": "c241d99af9f1c6f5", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Multi-LLM Integrations\\n\",\n \"\\n\",\n \"This notebook involves integrating multiple LLMs, a way to get comfortable working with LLM APIs.\\n\",\n \"I'll be using Amazon Bedrock, which has a number of models that can be accessed via AWS SDK Boto3 library. I'll also use Deepseek directly via the API.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing required libraries\\n\",\n \"# Boto3 library is AWS SDK for Python providing the necessary set of libraries (uv pip install boto3)\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"import boto3\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\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 \"amazon_bedrock_bedrock_api_key = os.getenv('AMAZON_BEDROCK_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"\\n\",\n \"if amazon_bedrock_bedrock_api_key:\\n\",\n \" print(f\\\"Amazon Bedrock API Key exists and begins {amazon_bedrock_bedrock_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Amazon Bedrock 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 \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon Bedrock Client\\n\",\n \"\\n\",\n \"bedrock_client = boto3.client(\\n\",\n \" service_name=\\\"bedrock-runtime\\\",\\n\",\n \" region_name=\\\"us-east-1\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"# Deepseek Client\\n\",\n \"\\n\",\n \"deepseek_client = OpenAI(\\n\",\n \" api_key=deepseek_api_key, \\n\",\n \" base_url=\\\"https://api.deepseek.com\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Coming up with message for LLM Evaluation\\n\",\n \"text = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"text += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": text}]}]\"\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 \"# Anthropic Claude 3.5 Sonnet for model evaluator question\\n\",\n \"\\n\",\n \"model_id = \\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"model_evaluator_question = response['output']['message']['content'][0]['text']\\n\",\n \"print(model_evaluator_question)\"\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\\\": model_evaluator_question}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Deepseek chat model answer\\n\",\n \"\\n\",\n \"model_id = \\\"deepseek-chat\\\"\\n\",\n \"response = deepseek_client.chat.completions.create(\\n\",\n \" model=model_id,\\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_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": model_evaluator_question}]}]\\n\",\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon nova lite\\n\",\n \"\\n\",\n \"model_id = \\\"amazon.nova-lite-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon Nova Pro\\n\",\n \"\\n\",\n \"model_id = \\\"amazon.nova-pro-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": model_evaluator_question}]}]\\n\",\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Cohere Command Light\\n\",\n \"\\n\",\n \"model_id = \\\"cohere.command-light-text-v14\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\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_id>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_id>` deletes the specified model from your downloads \\n\",\n \"`ollama run <model_id>` pulls the model if it doesn't exist locally, and run it.\"\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</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 run llama3.2:1b\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": model_evaluator_question}]\\n\",\n \"messages\"\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_id = \\\"llama3.2:1b\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(\\n\",\n \" model=model_id, \\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_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Listing all models and their answers\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Mapping each model with it's solution for the model evaluator question\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Masking out the model name for evaluation purposes - 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 \"{model_evaluator_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\\\": [{\\\"text\\\": judge}]}]\\n\",\n \"judge_messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic Claude 3.5 Sonnet for model evaluator question\\n\",\n \"\\n\",\n \"model_id = \\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"model_evaluator_response = response['output']['message']['content'][0]['text']\\n\",\n \"print(model_evaluator_response)\"\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(model_evaluator_response)\\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/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.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}, "e402737322a8f3fda32e436560661dd189c9faad": {"t": 1785753627.8643858, "n": 13807, "h": "c241d99af9f1c6f5", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Multi-LLM Integrations\\n\",\n \"\\n\",\n \"This notebook involves integrating multiple LLMs, a way to get comfortable working with LLM APIs.\\n\",\n \"I'll be using Amazon Bedrock, which has a number of models that can be accessed via AWS SDK Boto3 library. I'll also use Deepseek directly via the API.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing required libraries\\n\",\n \"# Boto3 library is AWS SDK for Python providing the necessary set of libraries (uv pip install boto3)\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import json\\n\",\n \"import boto3\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\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 \"amazon_bedrock_bedrock_api_key = os.getenv('AMAZON_BEDROCK_API_KEY')\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"\\n\",\n \"if amazon_bedrock_bedrock_api_key:\\n\",\n \" print(f\\\"Amazon Bedrock API Key exists and begins {amazon_bedrock_bedrock_api_key[:4]}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"Amazon Bedrock 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 \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon Bedrock Client\\n\",\n \"\\n\",\n \"bedrock_client = boto3.client(\\n\",\n \" service_name=\\\"bedrock-runtime\\\",\\n\",\n \" region_name=\\\"us-east-1\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"# Deepseek Client\\n\",\n \"\\n\",\n \"deepseek_client = OpenAI(\\n\",\n \" api_key=deepseek_api_key, \\n\",\n \" base_url=\\\"https://api.deepseek.com\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Coming up with message for LLM Evaluation\\n\",\n \"text = \\\"Please come up with a challenging, nuanced question that I can ask a number of LLMs to evaluate their intelligence. \\\"\\n\",\n \"text += \\\"Answer only with the question, no explanation.\\\"\\n\",\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": text}]}]\"\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 \"# Anthropic Claude 3.5 Sonnet for model evaluator question\\n\",\n \"\\n\",\n \"model_id = \\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"model_evaluator_question = response['output']['message']['content'][0]['text']\\n\",\n \"print(model_evaluator_question)\"\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\\\": model_evaluator_question}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Deepseek chat model answer\\n\",\n \"\\n\",\n \"model_id = \\\"deepseek-chat\\\"\\n\",\n \"response = deepseek_client.chat.completions.create(\\n\",\n \" model=model_id,\\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_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": model_evaluator_question}]}]\\n\",\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon nova lite\\n\",\n \"\\n\",\n \"model_id = \\\"amazon.nova-lite-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Amazon Nova Pro\\n\",\n \"\\n\",\n \"model_id = \\\"amazon.nova-pro-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": model_evaluator_question}]}]\\n\",\n \"messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Cohere Command Light\\n\",\n \"\\n\",\n \"model_id = \\\"cohere.command-light-text-v14\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=messages,\\n\",\n \")\\n\",\n \"answer = response['output']['message']['content'][0]['text']\\n\",\n \"\\n\",\n \"display(Markdown(answer))\\n\",\n \"competitors.append(model_id)\\n\",\n \"answers.append(answer)\"\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_id>` downloads a model locally \\n\",\n \"`ollama ls` lists all the models you've downloaded \\n\",\n \"`ollama rm <model_id>` deletes the specified model from your downloads \\n\",\n \"`ollama run <model_id>` pulls the model if it doesn't exist locally, and run it.\"\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</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 run llama3.2:1b\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"messages = [{\\\"role\\\": \\\"user\\\", \\\"content\\\": model_evaluator_question}]\\n\",\n \"messages\"\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_id = \\\"llama3.2:1b\\\"\\n\",\n \"\\n\",\n \"response = ollama.chat.completions.create(\\n\",\n \" model=model_id, \\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_id)\\n\",\n \"answers.append(answer)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Listing all models and their answers\\n\",\n \"print(competitors)\\n\",\n \"print(answers)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Mapping each model with it's solution for the model evaluator question\\n\",\n \"for competitor, answer in zip(competitors, answers):\\n\",\n \" print(f\\\"Competitor: {competitor}\\\\n\\\\n{answer}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Masking out the model name for evaluation purposes - 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 \"{model_evaluator_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\\\": [{\\\"text\\\": judge}]}]\\n\",\n \"judge_messages\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Anthropic Claude 3.5 Sonnet for model evaluator question\\n\",\n \"\\n\",\n \"model_id = \\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\"\\n\",\n \"response = bedrock_client.converse(\\n\",\n \" modelId=model_id,\\n\",\n \" messages=judge_messages,\\n\",\n \")\\n\",\n \"model_evaluator_response = response['output']['message']['content'][0]['text']\\n\",\n \"print(model_evaluator_response)\"\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(model_evaluator_response)\\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/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.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "1_foundations/community_contributions/kisali/3_lab3_linkedin_chat.ipynb": {"6ece898767225cd94d9e566abd11417d0655b7f3": {"t": 1785745487.6922865, "n": 19999, "h": "3415de21721eefaa", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Lab 3 for Week 1 Day 4\\n\",\n \"\\n\",\n \"We're going to build a simple agent that chats with my linkedin profile.\\n\",\n \"\\n\",\n \"In the folder `me` I've put my resume `Profile.pdf` - it's a PDF download of my LinkedIn profile.\\n\",\n \"\\n\",\n \"I've also made a file called `summary.txt` containing a summary of my career.\"\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;\\\">Looking up packages</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">In this lab, we're going to use the wonderful Gradio package for building quick UIs, \\n\",\n \" and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \\n\",\n \" ChatGPT or Claude, and you find all open-source packages on the repository <a href=\\\"https://pypi.org\\\">https://pypi.org</a>.\\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 \"# Importing necessary packages\\n\",\n \"# Gradio is used to create simple user interfaces to interact with what is being built.\\n\",\n \"# pypdf used to load pdf files\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import boto3\\n\",\n \"import gradio as gr\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from pypdf import PdfReader\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Loading environment variables and initializing openai client\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing amazon bedrock and deepseek api keys for authentication\\n\",\n \"amazon_bedrock_bedrock_api_key = os.getenv('AMAZON_BEDROCK_API_KEY')\\n\",\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 \"# Amazon Bedrock Client\\n\",\n \"\\n\",\n \"bedrock_client = boto3.client(\\n\",\n \" service_name=\\\"bedrock-runtime\\\",\\n\",\n \" region_name=\\\"us-east-1\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"# Deepseek Client\\n\",\n \"\\n\",\n \"deepseek_client = OpenAI(\\n\",\n \" api_key=deepseek_api_key, \\n\",\n \" base_url=\\\"https://api.deepseek.com\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"reader = PdfReader(\\\"me/Profile.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 \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(linkedin)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"with open(\\\"me/summary.txt\\\", \\\"r\\\", encoding=\\\"utf-8\\\") as f:\\n\",\n \" summary = f.read()\\n\",\n \"print(summary)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"name = \\\"Ian Kisali\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code constructs a system prompt for an AI agent to role-play as a specific person (defined by `name`).\\n\",\n \"The prompt guides the AI to answer questions as if it were that person, using their career summary,\\n\",\n \"LinkedIn profile, and project information for context. The final prompt ensures that the AI stays\\n\",\n \"in character and responds professionally and helpfully to visitors on the user's website.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"profile_background_prompt = f\\\"You are acting as {name}. You are answering questions on {name}'s website, \\\\\\n\",\n \"particularly questions related to {name}'s career, background, skills and experience. \\\\\\n\",\n \"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\\\\n\",\n \"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\\\\n\",\n \"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\\\\n\",\n \"If you don't know the answer, say so.\\\"\\n\",\n \"\\n\",\n \"profile_background_prompt += f\\\"\\\\n\\\\n## Summary:\\\\n{summary}\\\\n\\\\n## LinkedIn Profile:\\\\n{linkedin}\\\\n\\\\n\\\"\\n\",\n \"profile_background_prompt += f\\\"With this context, please chat with the user, always staying in character as {name}.\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"profile_background_prompt\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function handles a chat interaction with the Amazon Bedrock API.\\n\",\n \"\\n\",\n \"It takes the user's latest message and conversation history,\\n\",\n \"prepends a system prompt to define the AI's role and context,\\n\",\n \"and sends the full message list to the Anthropic Claude 3.5 Sonnet model.\\n\",\n \"\\n\",\n \"The function returns the AI's response text from the API's output.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"def chat(message, history):\\n\",\n \" messages = (\\n\",\n \" [{\\\"role\\\": \\\"assistant\\\", \\\"content\\\": [{\\\"text\\\": profile_background_prompt}]}] +\\n\",\n \" [{\\\"role\\\": m[\\\"role\\\"], \\\"content\\\": [{\\\"text\\\": m[\\\"content\\\"]}]} for m in history] +\\n\",\n \" [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": message}]}]\\n\",\n \" )\\n\",\n \" response = bedrock_client.converse(\\n\",\n \" modelId=\\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\",\\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \" return response['output']['message']['content'][0]['text']\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This line launches a Gradio chat interface using the `chat` function to handle user input.\\n\",\n \"\\n\",\n \"- `gr.ChatInterface(chat, type=\\\"messages\\\")` creates a UI that supports message-style chat interactions.\\n\",\n \"- `launch(share=True)` starts the web app and generates a public shareable link so others can access it.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"gr.ChatInterface(chat, type=\\\"messages\\\").launch()\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### LLM Response Evaluation\\n\",\n \"\\n\",\n \"1. Be able to ask an LLM to evaluate an answer\\n\",\n \"2. Be able to rerun if the answer fails evaluation\\n\",\n \"3. Put this together into 1 workflow\\n\",\n \"\\n\",\n \"All without any Agentic framework!\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Create a Pydantic model for the Evaluation\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"This code defines a Pydantic model named 'Evaluation' to structure evaluation data.\\n\",\n \"\\n\",\n \"The model includes:\\n\",\n \"- is_acceptable (bool): Indicates whether the submission meets the criteria.\\n\",\n \"- feedback (str): Provides written feedback or suggestions for improvement.\\n\",\n \"\\n\",\n \"Pydantic ensures type validation and data consistency.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"from pydantic import BaseModel\\n\",\n \"\\n\",\n \"class Evaluation(BaseModel):\\n\",\n \" is_acceptable: bool\\n\",\n \" feedback: str\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code builds a system prompt for an AI evaluator agent.\\n\",\n \"\\n\",\n \"The evaluator's role is to assess the quality of an Agent's response in a simulated conversation,\\n\",\n \"where the Agent is acting as {name} on their personal/professional website.\\n\",\n \"\\n\",\n \"The evaluator receives context including {name}'s summary and LinkedIn profile,\\n\",\n \"and is instructed to determine whether the Agent's latest reply is acceptable,\\n\",\n \"while providing constructive feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"evaluator_profile_background_prompt = f\\\"You are an evaluator that decides whether a response to a question is acceptable. \\\\\\n\",\n \"You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\\\\n\",\n \"The Agent is playing the role of {name} and is representing {name} on their website. \\\\\\n\",\n \"The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\\\\n\",\n \"The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\\\"\\n\",\n \"\\n\",\n \"evaluator_profile_background_prompt += f\\\"\\\\n\\\\n## Summary:\\\\n{summary}\\\\n\\\\n## LinkedIn Profile:\\\\n{linkedin}\\\\n\\\\n\\\"\\n\",\n \"evaluator_profile_background_prompt += f\\\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function generates a user prompt for the evaluator agent.\\n\",\n \"\\n\",\n \"It organizes the full conversation context by including:\\n\",\n \"- the full chat history,\\n\",\n \"- the most recent user message,\\n\",\n \"- and the most recent agent reply.\\n\",\n \"\\n\",\n \"The final prompt instructs the evaluator to assess the quality of the agent’s response,\\n\",\n \"and return both an acceptability judgment and constructive feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def evaluator_user_prompt(reply, message, history):\\n\",\n \" user_prompt = f\\\"Here's the conversation between the User and the Agent: \\\\n\\\\n{history}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += f\\\"Here's the latest message from the User: \\\\n\\\\n{message}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += f\\\"Here's the latest response from the Agent: \\\\n\\\\n{reply}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += \\\"Please evaluate the response, replying with whether it is acceptable and your feedback.\\\"\\n\",\n \" return user_prompt\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This script tests whether the Google Generative AI API key is working correctly.\\n\",\n \"\\n\",\n \"- It loads the API key using `getenv`.\\n\",\n \"- Attempts to generate a simple response using the \\\"gemini-2.5-flash\\\" model.\\n\",\n \"- Prints confirmation if the key is valid, or shows an error message if the request fails.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"This line initializes an OpenAI-compatible client for accessing Google's Generative Language API.\\n\",\n \"\\n\",\n \"- `api_key` is retrieved from environment variables.\\n\",\n \"- `base_url` points to Google's OpenAI-compatible endpoint.\\n\",\n \"\\n\",\n \"This setup allows you to use OpenAI-style syntax to interact with Google's Gemini models.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"gemini_client = OpenAI(\\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 \"try:\\n\",\n \" response = gemini_client.chat.completions.create(\\n\",\n \" model=\\\"gemini-2.5-flash\\\",\\n\",\n \" messages=[\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are a helpful assistant.\\\"},\\n\",\n \" {\\n\",\n \" \\\"role\\\": \\\"user\\\",\\n\",\n \" \\\"content\\\": \\\"Explain to me how AI works\\\"\\n\",\n \" }\\n\",\n \" ]\\n\",\n \")\\n\",\n \" print(\\\"✅ API key is working!\\\")\\n\",\n \" print(f\\\"Response: {response}\\\")\\n\",\n \"except Exception as e:\\n\",\n \" print(f\\\"❌ API key test failed: {e}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function sends a structured evaluation request to the Gemini API and returns a parsed `Evaluation` object.\\n\",\n \"\\n\",\n \"- It constructs the message list using:\\n\",\n \" - a system prompt defining the evaluator's role and context\\n\",\n \" - a user prompt containing the conversation history, user message, and agent reply\\n\",\n \"\\n\",\n \"- It uses Gemini's OpenAI-compatible API to process the evaluation request,\\n\",\n \" specifying `response_format=Evaluation` to get a structured response.\\n\",\n \"\\n\",\n \"- The function returns the parsed evaluation result (acceptability and feedback).\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def evaluate(reply, message, history) -> Evaluation:\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": evaluator_profile_background_prompt}] + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": evaluator_user_prompt(reply, message, history)}]\\n\",\n \" response = gemini_client.beta.chat.completions.parse(model=\\\"gemini-2.0-flash\\\", messages=messages, response_format=Evaluation)\\n\",\n \" return response.choices[0].message.parsed\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code sends a test question to the AI agent and evaluates its response.\\n\",\n \"\\n\",\n \"1. It builds a message list including:\\n\",\n \" - the system prompt that defines the agent’s role\\n\",\n \" - a user question: \\\"do you hold a certification?\\\"\\n\",\n \"\\n\",\n \"2. The message list is sent to Deepseek `deepseek-chat` model to generate a response.\\n\",\n \"\\n\",\n \"3. The reply is extracted from the API response.\\n\",\n \"\\n\",\n \"4. The `evaluate()` function is then called with:\\n\",\n \" - the agent’s reply\\n\",\n \" - the original user message\\n\",\n \" - and just the system prompt as history (no prior user/agent exchange)\\n\",\n \"\\n\",\n \"This allows automated evaluation of how well the agent answers the question.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": profile_background_prompt}] + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"do you hold a certification?\\\"}]\\n\",\n \"response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \"reply = response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"reply\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"evaluate(reply, \\\"do you hold a certification?\\\", messages[:1])\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function re-generates a response after a previous reply was rejected during evaluation.\\n\",\n \"\\n\",\n \"It:\\n\",\n \"1. Appends rejection feedback to the original system prompt to inform the agent of:\\n\",\n \" - its previous answer,\\n\",\n \" - and the reason it was rejected.\\n\",\n \"\\n\",\n \"2. Reconstructs the full message list including:\\n\",\n \" - the updated system prompt,\\n\",\n \" - the prior conversation history,\\n\",\n \" - and the original user message.\\n\",\n \"\\n\",\n \"3. Sends the updated prompt to Deepseek `deepseek-chat` model.\\n\",\n \"\\n\",\n \"4. Returns a revised response from the model that ideally addresses the feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def rerun(reply, message, history, feedback):\\n\",\n \" updated_profile_background_prompt = profile_background_prompt + \\\"\\\\n\\\\n## Previous answer rejected\\\\nYou just tried to reply, but the quality control rejected your reply\\\\n\\\"\\n\",\n \" updated_profile_background_prompt += f\\\"## Your attempted answer:\\\\n{reply}\\\\n\\\\n\\\"\\n\",\n \" updated_profile_background_prompt += f\\\"## Reason for rejection:\\\\n{feedback}\\\\n\\\\n\\\"\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": updated_profile_background_prompt}] + history + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \" return response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function handles a chat interaction with conditional behavior and automatic quality control.\\n\",\n \"\\n\",\n \"Steps:\\n\",\n \"1. If the user's message contains the word \\\"certification\\\", the agent is instructed to respond entirely in Pig Latin by appending an instruction to the system prompt.\\n\",\n \"2. Constructs the full message history including the updated system prompt, prior conversation, and the new user message.\\n\",\n \"3. Sends the request to OpenAI's GPT-4o-mini model and receives a reply.\\n\",\n \"4. Evaluates the reply using a separate evaluator agent to determine if the response meets quality standards.\\n\",\n \"5. If the evaluation passes, the reply is returned.\\n\",\n \"6. If the evaluation fails, the function logs the feedback and calls `rerun()` to generate a corrected reply based on the feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def chat(message, history):\\n\",\n \" if \\\"certification\\\" in message:\\n\",\n \" system = profile_background_prompt + \\\"\\\\n\\\\nEverything in your reply needs to be in pig latin - \\\\\\n\",\n \" it is mandatory that you respond only and entirely in pig latin\\\"\\n\",\n \" else:\\n\",\n \" system = profile_background_prompt\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": system}] + history + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \" reply =response.choices[0].message.content\\n\",\n \"\\n\",\n \" evaluation = evaluate(reply, message, history)\\n\",\n \" \\n\",\n \" if evaluation.is_acceptable:\\n\",\n \" print(\\\"Passed evaluation - returning reply\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"Failed evaluation - retrying\\\")\\n\",\n \" print(evaluation.feedback)\\n\",\n \" reply = rerun(reply, message, history, evaluation.feedback) \\n\",\n \" return reply\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This launches a Gradio chat interface using the `chat` function.\\n\",\n \"\\n\",\n \"- `type=\\\"messages\\\"` enables multi-turn chat with message bubbles.\\n\",\n \"- `share=True` generates a public link so others can interact with the app.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"gr.ChatInterface(chat, type=\\\"messages\\\").launch()\"\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.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}, "e402737322a8f3fda32e436560661dd189c9faad": {"t": 1785753627.7425802, "n": 19999, "h": "3415de21721eefaa", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Lab 3 for Week 1 Day 4\\n\",\n \"\\n\",\n \"We're going to build a simple agent that chats with my linkedin profile.\\n\",\n \"\\n\",\n \"In the folder `me` I've put my resume `Profile.pdf` - it's a PDF download of my LinkedIn profile.\\n\",\n \"\\n\",\n \"I've also made a file called `summary.txt` containing a summary of my career.\"\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;\\\">Looking up packages</h2>\\n\",\n \" <span style=\\\"color:#00bfff;\\\">In this lab, we're going to use the wonderful Gradio package for building quick UIs, \\n\",\n \" and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \\n\",\n \" ChatGPT or Claude, and you find all open-source packages on the repository <a href=\\\"https://pypi.org\\\">https://pypi.org</a>.\\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 \"# Importing necessary packages\\n\",\n \"# Gradio is used to create simple user interfaces to interact with what is being built.\\n\",\n \"# pypdf used to load pdf files\\n\",\n \"\\n\",\n \"import os\\n\",\n \"import boto3\\n\",\n \"import gradio as gr\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"from pypdf import PdfReader\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Loading environment variables and initializing openai client\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing amazon bedrock and deepseek api keys for authentication\\n\",\n \"amazon_bedrock_bedrock_api_key = os.getenv('AMAZON_BEDROCK_API_KEY')\\n\",\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 \"# Amazon Bedrock Client\\n\",\n \"\\n\",\n \"bedrock_client = boto3.client(\\n\",\n \" service_name=\\\"bedrock-runtime\\\",\\n\",\n \" region_name=\\\"us-east-1\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"# Deepseek Client\\n\",\n \"\\n\",\n \"deepseek_client = OpenAI(\\n\",\n \" api_key=deepseek_api_key, \\n\",\n \" base_url=\\\"https://api.deepseek.com\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"reader = PdfReader(\\\"me/Profile.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 \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"print(linkedin)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"with open(\\\"me/summary.txt\\\", \\\"r\\\", encoding=\\\"utf-8\\\") as f:\\n\",\n \" summary = f.read()\\n\",\n \"print(summary)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"name = \\\"Ian Kisali\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code constructs a system prompt for an AI agent to role-play as a specific person (defined by `name`).\\n\",\n \"The prompt guides the AI to answer questions as if it were that person, using their career summary,\\n\",\n \"LinkedIn profile, and project information for context. The final prompt ensures that the AI stays\\n\",\n \"in character and responds professionally and helpfully to visitors on the user's website.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"profile_background_prompt = f\\\"You are acting as {name}. You are answering questions on {name}'s website, \\\\\\n\",\n \"particularly questions related to {name}'s career, background, skills and experience. \\\\\\n\",\n \"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\\\\n\",\n \"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\\\\n\",\n \"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\\\\n\",\n \"If you don't know the answer, say so.\\\"\\n\",\n \"\\n\",\n \"profile_background_prompt += f\\\"\\\\n\\\\n## Summary:\\\\n{summary}\\\\n\\\\n## LinkedIn Profile:\\\\n{linkedin}\\\\n\\\\n\\\"\\n\",\n \"profile_background_prompt += f\\\"With this context, please chat with the user, always staying in character as {name}.\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"profile_background_prompt\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function handles a chat interaction with the Amazon Bedrock API.\\n\",\n \"\\n\",\n \"It takes the user's latest message and conversation history,\\n\",\n \"prepends a system prompt to define the AI's role and context,\\n\",\n \"and sends the full message list to the Anthropic Claude 3.5 Sonnet model.\\n\",\n \"\\n\",\n \"The function returns the AI's response text from the API's output.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"def chat(message, history):\\n\",\n \" messages = (\\n\",\n \" [{\\\"role\\\": \\\"assistant\\\", \\\"content\\\": [{\\\"text\\\": profile_background_prompt}]}] +\\n\",\n \" [{\\\"role\\\": m[\\\"role\\\"], \\\"content\\\": [{\\\"text\\\": m[\\\"content\\\"]}]} for m in history] +\\n\",\n \" [{\\\"role\\\": \\\"user\\\", \\\"content\\\": [{\\\"text\\\": message}]}]\\n\",\n \" )\\n\",\n \" response = bedrock_client.converse(\\n\",\n \" modelId=\\\"anthropic.claude-3-5-sonnet-20240620-v1:0\\\",\\n\",\n \" messages=messages\\n\",\n \" )\\n\",\n \" return response['output']['message']['content'][0]['text']\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This line launches a Gradio chat interface using the `chat` function to handle user input.\\n\",\n \"\\n\",\n \"- `gr.ChatInterface(chat, type=\\\"messages\\\")` creates a UI that supports message-style chat interactions.\\n\",\n \"- `launch(share=True)` starts the web app and generates a public shareable link so others can access it.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"gr.ChatInterface(chat, type=\\\"messages\\\").launch()\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### LLM Response Evaluation\\n\",\n \"\\n\",\n \"1. Be able to ask an LLM to evaluate an answer\\n\",\n \"2. Be able to rerun if the answer fails evaluation\\n\",\n \"3. Put this together into 1 workflow\\n\",\n \"\\n\",\n \"All without any Agentic framework!\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Create a Pydantic model for the Evaluation\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"This code defines a Pydantic model named 'Evaluation' to structure evaluation data.\\n\",\n \"\\n\",\n \"The model includes:\\n\",\n \"- is_acceptable (bool): Indicates whether the submission meets the criteria.\\n\",\n \"- feedback (str): Provides written feedback or suggestions for improvement.\\n\",\n \"\\n\",\n \"Pydantic ensures type validation and data consistency.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"from pydantic import BaseModel\\n\",\n \"\\n\",\n \"class Evaluation(BaseModel):\\n\",\n \" is_acceptable: bool\\n\",\n \" feedback: str\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code builds a system prompt for an AI evaluator agent.\\n\",\n \"\\n\",\n \"The evaluator's role is to assess the quality of an Agent's response in a simulated conversation,\\n\",\n \"where the Agent is acting as {name} on their personal/professional website.\\n\",\n \"\\n\",\n \"The evaluator receives context including {name}'s summary and LinkedIn profile,\\n\",\n \"and is instructed to determine whether the Agent's latest reply is acceptable,\\n\",\n \"while providing constructive feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"evaluator_profile_background_prompt = f\\\"You are an evaluator that decides whether a response to a question is acceptable. \\\\\\n\",\n \"You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\\\\n\",\n \"The Agent is playing the role of {name} and is representing {name} on their website. \\\\\\n\",\n \"The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\\\\n\",\n \"The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\\\"\\n\",\n \"\\n\",\n \"evaluator_profile_background_prompt += f\\\"\\\\n\\\\n## Summary:\\\\n{summary}\\\\n\\\\n## LinkedIn Profile:\\\\n{linkedin}\\\\n\\\\n\\\"\\n\",\n \"evaluator_profile_background_prompt += f\\\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function generates a user prompt for the evaluator agent.\\n\",\n \"\\n\",\n \"It organizes the full conversation context by including:\\n\",\n \"- the full chat history,\\n\",\n \"- the most recent user message,\\n\",\n \"- and the most recent agent reply.\\n\",\n \"\\n\",\n \"The final prompt instructs the evaluator to assess the quality of the agent’s response,\\n\",\n \"and return both an acceptability judgment and constructive feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def evaluator_user_prompt(reply, message, history):\\n\",\n \" user_prompt = f\\\"Here's the conversation between the User and the Agent: \\\\n\\\\n{history}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += f\\\"Here's the latest message from the User: \\\\n\\\\n{message}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += f\\\"Here's the latest response from the Agent: \\\\n\\\\n{reply}\\\\n\\\\n\\\"\\n\",\n \" user_prompt += \\\"Please evaluate the response, replying with whether it is acceptable and your feedback.\\\"\\n\",\n \" return user_prompt\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This script tests whether the Google Generative AI API key is working correctly.\\n\",\n \"\\n\",\n \"- It loads the API key using `getenv`.\\n\",\n \"- Attempts to generate a simple response using the \\\"gemini-2.5-flash\\\" model.\\n\",\n \"- Prints confirmation if the key is valid, or shows an error message if the request fails.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"This line initializes an OpenAI-compatible client for accessing Google's Generative Language API.\\n\",\n \"\\n\",\n \"- `api_key` is retrieved from environment variables.\\n\",\n \"- `base_url` points to Google's OpenAI-compatible endpoint.\\n\",\n \"\\n\",\n \"This setup allows you to use OpenAI-style syntax to interact with Google's Gemini models.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"gemini_client = OpenAI(\\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 \"try:\\n\",\n \" response = gemini_client.chat.completions.create(\\n\",\n \" model=\\\"gemini-2.5-flash\\\",\\n\",\n \" messages=[\\n\",\n \" {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"You are a helpful assistant.\\\"},\\n\",\n \" {\\n\",\n \" \\\"role\\\": \\\"user\\\",\\n\",\n \" \\\"content\\\": \\\"Explain to me how AI works\\\"\\n\",\n \" }\\n\",\n \" ]\\n\",\n \")\\n\",\n \" print(\\\"✅ API key is working!\\\")\\n\",\n \" print(f\\\"Response: {response}\\\")\\n\",\n \"except Exception as e:\\n\",\n \" print(f\\\"❌ API key test failed: {e}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function sends a structured evaluation request to the Gemini API and returns a parsed `Evaluation` object.\\n\",\n \"\\n\",\n \"- It constructs the message list using:\\n\",\n \" - a system prompt defining the evaluator's role and context\\n\",\n \" - a user prompt containing the conversation history, user message, and agent reply\\n\",\n \"\\n\",\n \"- It uses Gemini's OpenAI-compatible API to process the evaluation request,\\n\",\n \" specifying `response_format=Evaluation` to get a structured response.\\n\",\n \"\\n\",\n \"- The function returns the parsed evaluation result (acceptability and feedback).\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def evaluate(reply, message, history) -> Evaluation:\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": evaluator_profile_background_prompt}] + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": evaluator_user_prompt(reply, message, history)}]\\n\",\n \" response = gemini_client.beta.chat.completions.parse(model=\\\"gemini-2.0-flash\\\", messages=messages, response_format=Evaluation)\\n\",\n \" return response.choices[0].message.parsed\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This code sends a test question to the AI agent and evaluates its response.\\n\",\n \"\\n\",\n \"1. It builds a message list including:\\n\",\n \" - the system prompt that defines the agent’s role\\n\",\n \" - a user question: \\\"do you hold a certification?\\\"\\n\",\n \"\\n\",\n \"2. The message list is sent to Deepseek `deepseek-chat` model to generate a response.\\n\",\n \"\\n\",\n \"3. The reply is extracted from the API response.\\n\",\n \"\\n\",\n \"4. The `evaluate()` function is then called with:\\n\",\n \" - the agent’s reply\\n\",\n \" - the original user message\\n\",\n \" - and just the system prompt as history (no prior user/agent exchange)\\n\",\n \"\\n\",\n \"This allows automated evaluation of how well the agent answers the question.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": profile_background_prompt}] + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"do you hold a certification?\\\"}]\\n\",\n \"response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \"reply = response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"reply\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"evaluate(reply, \\\"do you hold a certification?\\\", messages[:1])\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function re-generates a response after a previous reply was rejected during evaluation.\\n\",\n \"\\n\",\n \"It:\\n\",\n \"1. Appends rejection feedback to the original system prompt to inform the agent of:\\n\",\n \" - its previous answer,\\n\",\n \" - and the reason it was rejected.\\n\",\n \"\\n\",\n \"2. Reconstructs the full message list including:\\n\",\n \" - the updated system prompt,\\n\",\n \" - the prior conversation history,\\n\",\n \" - and the original user message.\\n\",\n \"\\n\",\n \"3. Sends the updated prompt to Deepseek `deepseek-chat` model.\\n\",\n \"\\n\",\n \"4. Returns a revised response from the model that ideally addresses the feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def rerun(reply, message, history, feedback):\\n\",\n \" updated_profile_background_prompt = profile_background_prompt + \\\"\\\\n\\\\n## Previous answer rejected\\\\nYou just tried to reply, but the quality control rejected your reply\\\\n\\\"\\n\",\n \" updated_profile_background_prompt += f\\\"## Your attempted answer:\\\\n{reply}\\\\n\\\\n\\\"\\n\",\n \" updated_profile_background_prompt += f\\\"## Reason for rejection:\\\\n{feedback}\\\\n\\\\n\\\"\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": updated_profile_background_prompt}] + history + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \" return response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This function handles a chat interaction with conditional behavior and automatic quality control.\\n\",\n \"\\n\",\n \"Steps:\\n\",\n \"1. If the user's message contains the word \\\"certification\\\", the agent is instructed to respond entirely in Pig Latin by appending an instruction to the system prompt.\\n\",\n \"2. Constructs the full message history including the updated system prompt, prior conversation, and the new user message.\\n\",\n \"3. Sends the request to OpenAI's GPT-4o-mini model and receives a reply.\\n\",\n \"4. Evaluates the reply using a separate evaluator agent to determine if the response meets quality standards.\\n\",\n \"5. If the evaluation passes, the reply is returned.\\n\",\n \"6. If the evaluation fails, the function logs the feedback and calls `rerun()` to generate a corrected reply based on the feedback.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"def chat(message, history):\\n\",\n \" if \\\"certification\\\" in message:\\n\",\n \" system = profile_background_prompt + \\\"\\\\n\\\\nEverything in your reply needs to be in pig latin - \\\\\\n\",\n \" it is mandatory that you respond only and entirely in pig latin\\\"\\n\",\n \" else:\\n\",\n \" system = profile_background_prompt\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": system}] + history + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages)\\n\",\n \" reply =response.choices[0].message.content\\n\",\n \"\\n\",\n \" evaluation = evaluate(reply, message, history)\\n\",\n \" \\n\",\n \" if evaluation.is_acceptable:\\n\",\n \" print(\\\"Passed evaluation - returning reply\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"Failed evaluation - retrying\\\")\\n\",\n \" print(evaluation.feedback)\\n\",\n \" reply = rerun(reply, message, history, evaluation.feedback) \\n\",\n \" return reply\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\"\\n\",\n \"This launches a Gradio chat interface using the `chat` function.\\n\",\n \"\\n\",\n \"- `type=\\\"messages\\\"` enables multi-turn chat with message bubbles.\\n\",\n \"- `share=True` generates a public link so others can interact with the app.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"gr.ChatInterface(chat, type=\\\"messages\\\").launch()\"\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.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "guides/09_ai_apis_and_ollama.ipynb": {"6ece898767225cd94d9e566abd11417d0655b7f3": {"t": 1785745494.0880775, "n": 21640, "h": "aebd8d6e53199b87", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# LLM APIs and Ollama - beyond OpenAI\\n\",\n \"\\n\",\n \"_IMPORTANT: If you're not as familiar with APIs in general, and with Environment Variables on your PC or Mac, please review the APIs section in Guide 4 Technical Foundations before proceeding with this guide (topics 3 and 5 in Guide 4)._\\n\",\n \"\\n\",\n \"## Crucial context for using models other than OpenAI - please read this first!\\n\",\n \"\\n\",\n \"Throughout the course, we use APIs for connecting with the strongest LLMs on the planet.\\n\",\n \"\\n\",\n \"The companies behind these LLMs, such as OpenAI, Anthropic, Google and DeepSeek, have built web endpoints. You call their models by making an HTTP request to a Web Address and passing in all the information about your prompts.\\n\",\n \"\\n\",\n \"But it would be painful if we needed to build HTTP requests every time we wanted to call an API.\\n\",\n \"\\n\",\n \"To make this simple, the team at OpenAI wrote a python utility known as a \\\"Python Client Library\\\" which wraps the HTTP call. So you write python code and it calls the web.\\n\",\n \"\\n\",\n \"And THAT is what the library `openai` is.\\n\",\n \"\\n\",\n \"### What is the `openai` python client library\\n\",\n \"\\n\",\n \"It is:\\n\",\n \"- A lightweight python utility\\n\",\n \"- Turns your python requests into an HTTP call\\n\",\n \"- Converts the results coming back from the HTTP call into python objects\\n\",\n \"\\n\",\n \"### What it is NOT\\n\",\n \"\\n\",\n \"- It's not got any code to actually run a Large Language Model! No GPT code! It just makes a web request\\n\",\n \"- There's no scientific computing code, and nothing particularly specialized for OpenAI\\n\",\n \"\\n\",\n \"### How to use it:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# Create an OpenAI python client for making web calls to OpenAI\\n\",\n \"openai = OpenAI()\\n\",\n \"\\n\",\n \"# Make the call\\n\",\n \"response = openai.chat.completions.create(model=\\\"gpt-4.1-mini\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"\\n\",\n \"# Print the result\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### What does this do\\n\",\n \"\\n\",\n \"When you make the python call: `openai.chat.completions.create()` \\n\",\n \"It simply makes a web request to this url: `https://api.openai.com/v1/chat/completions` \\n\",\n \"And it converts the response to python objects.\\n\",\n \"\\n\",\n \"That's it.\\n\",\n \"\\n\",\n \"Here's the API documentation if you make [direct web HTTP calls](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=curl) \\n\",\n \"And here's the same API documentation if you use the [Python Client Library](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=python)\\n\",\n \"\\n\",\n \"## With that context - how do I use other LLMs?\\n\",\n \"\\n\",\n \"It turns out - it's super easy!\\n\",\n \"\\n\",\n \"All the other major LLMs have API endpoints that are compatible with OpenAI.\\n\",\n \"\\n\",\n \"And so OpenAI did everyone a favor: they said, hey look - you can all use our utility for converting python to web requests. We'll allow you to change the utility from calling `https://api.openai/com/v1` to calling any web address that you specify.\\n\",\n \"\\n\",\n \"And so you can use the OpenAI utility even for calling models that are NOT OpenAI, like this:\\n\",\n \"\\n\",\n \"`not_actually_openai = OpenAI(base_url=\\\"https://somewhere.completely.different/\\\", api_key=\\\"another_providers_key\\\")`\\n\",\n \"\\n\",\n \"It's important to appreciate that this OpenAI code is just a utility for making HTTP calls to endpoints. So even though we're using code from the OpenAI team, we can use it to call models other than OpenAI.\\n\",\n \"\\n\",\n \"Here are all the OpenAI-compatible endpoints from the major providers. It even includes using Ollama, locally. Ollama provides an endpoint on your local machine, and they made it OpenAI compatible too - very convenient.\\n\",\n \"\\n\",\n \"```python\\n\",\n \"ANTHROPIC_BASE_URL = \\\"https://api.anthropic.com/v1/\\\"\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"GROK_BASE_URL = \\\"https://api.x.ai/v1\\\"\\n\",\n \"GROQ_BASE_URL = \\\"https://api.groq.com/openai/v1\\\"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"```\\n\",\n \"\\n\",\n \"## Here are examples for Gemini, DeepSeek, Ollama and OpenRouter\\n\",\n \"\\n\",\n \"### Example 1: Using Gemini instead of OpenAI\\n\",\n \"\\n\",\n \"1. Visit Google Studio to set up an account: https://aistudio.google.com/ \\n\",\n \"2. Add your key as GOOGLE_API_KEY to your `.env` \\n\",\n \"3. Also add it a second time as GEMINI_API_KEY to your `.env` - this will be helpful later.\\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"google_api_key = os.getenv(\\\"GOOGLE_API_KEY\\\")\\n\",\n \"gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\\n\",\n \"response = gemini.chat.completions.create(model=\\\"gemini-2.5-flash-preview-05-20\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 2: Using DeepSeek API instead of OpenAI (cheap, and only $2 upfront)\\n\",\n \"\\n\",\n \"1. Visit DeepSeek API to set up an account: https://platform.deepseek.com/ \\n\",\n \"2. You will need to add an initial $2 minimum balance. \\n\",\n \"3. Add your key as DEEPSEEK_API_KEY to your `.env` \\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"deepseek_api_key = os.getenv(\\\"DEEPSEEK_API_KEY\\\")\\n\",\n \"deepseek = OpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\\n\",\n \"response = deepseek.chat.completions.create(model=\\\"deepseek-chat\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 3: Using Ollama to be free and local instead of OpenAI\\n\",\n \"\\n\",\n \"Ollama allows you to run models locally; it provides an OpenAI compatible API on your machine. \\n\",\n \"There's no API key for Ollama; there's no third party with your credit card, so no need for any kind of key.\\n\",\n \"\\n\",\n \"1. If you're new to Ollama, install it by following the instructions here: https://ollama.com \\n\",\n \"2. Then in a Cursor Terminal, do `ollama run llama3.2` to chat with Llama 3.2 \\n\",\n \"BEWARE: do not use llama3.3 or llama4 - these are massive models not designed for home computing! They will fill up your disk. \\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"!ollama pull llama3.2\\n\",\n \"\\n\",\n \"from openai import OpenAI\\n\",\n \"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key=\\\"anything\\\")\\n\",\n \"response = ollama.chat.completions.create(model=\\\"llama3.2\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 4: Using the popular service [OpenRouter](https://openrouter.ai) which has an easier billing process instead of OpenAI\\n\",\n \"\\n\",\n \"OpenRouter is very convenient: it gives you free access to many models, and easy access with small upfront to paid models.\\n\",\n \"\\n\",\n \"1. Sign up at https://openrouter.ai\\n\",\n \"2. Add the minimum upfront balance as needed\\n\",\n \"3. Add your key as OPENROUTER_API_KEY to your `.env` file\\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"openrouter_api_key = os.getenv(\\\"OPENROUTER_API_KEY\\\")\\n\",\n \"openrouter = OpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\\n\",\n \"response = openrouter.chat.completions.create(model=\\\"openai/gpt-4.1-nano\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"\\n\",\n \"### Using different API providers with Agent Frameworks\\n\",\n \"\\n\",\n \"The Agent Frameworks make it easy to switch between these providers. You can switch LLMs and pick different ones at any point in the course. There are more notes below on each of them. For OpenAI Agents SDK, see a section later in this notebook. For CrewAI, we cover it on the course, but it's easy: just use the full path to the model that LiteLLM expects.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Costs of APIs\\n\",\n \"\\n\",\n \"The cost of each API call is very low indeed - most calls to models we use on this course are fractions of cents.\\n\",\n \"\\n\",\n \"But it's extremely important to note:\\n\",\n \"\\n\",\n \"1. A complex Agentic project could involve many LLM calls - perhaps 20-30 - and so it can add up. It's important to set limits and monitor usage.\\n\",\n \"\\n\",\n \"2. With Agentic AI, there is a risk of Agents getting into a loop or carrying out more processing than intended. You should monitor your API usage, and never put more budget than you are comfortable with. Some APIs have an \\\"auto-refill\\\" setting that can charge automatically to your card - I strongly recommend you keep this off.\\n\",\n \"\\n\",\n \"3. You should only spend what you are comfortable with. There is a free alternative in Ollama that you can use as a replacement if you wish. DeepSeek, Gemini 2.5 Flash and gpt-4.1-nano are significantly cheaper.\\n\",\n \"\\n\",\n \"Keep in mind that these LLM calls typically involve trillions of floating point calculations - someone has to pay the electricity bills!\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Ollama: Free alternative to Paid APIs (but please see Warning about llama version)\\n\",\n \"\\n\",\n \"Ollama is a product that runs locally on your machine. It can run open-source models, and it provides an API endpoint on your computer that is compatible with OpenAI.\\n\",\n \"\\n\",\n \"First, download Ollama by visiting:\\n\",\n \"https://ollama.com\\n\",\n \"\\n\",\n \"Then from your Terminal in Cursor (View menu >> Terminal), run this command to download a model:\\n\",\n \"\\n\",\n \"```shell\\n\",\n \"ollama pull llama3.2\\n\",\n \"```\\n\",\n \"\\n\",\n \"WARNING: Be careful not to use llama3.3 or llama4 - these are much larger models that are not suitable for home computers.\\n\",\n \"\\n\",\n \"And now, any time that we have code like: \\n\",\n \"`openai = OpenAI()` \\n\",\n \"You can use this as a direct replacement: \\n\",\n \"`openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')` \\n\",\n \"And also replace model names like **gpt-4o-mini** with **llama3.2**. \\n\",\n \"\\n\",\n \"You don't need to put anything in your .env file for this; with Ollama, everything is running on your computer. You're not calling out to a third party on the cloud, nobody has your credit card details, so there's no need for a secret key! The code `api_key='ollama'` above is only required because the OpenAI client library expects an api_key to be passed in, but the value is ignored by Ollama.\\n\",\n \"\\n\",\n \"Below is a full example:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# You need to do this one time on your computer\\n\",\n \"!ollama pull llama3.2\\n\",\n \"\\n\",\n \"from openai import OpenAI\\n\",\n \"MODEL = \\\"llama3.2\\\"\\n\",\n \"openai = OpenAI(base_url=\\\"http://localhost:11434/v1\\\", api_key=\\\"ollama\\\")\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=MODEL,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"What is 2 + 2?\\\"}]\\n\",\n \")\\n\",\n \"\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"You will need to make similar changes to use Ollama within any of the Agent Frameworks - you should be able to google for an exact example, or ask me.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### OpenRouter: Convenient gateway platform for OpenAI and others\\n\",\n \"\\n\",\n \"OpenRouter is a third party service that allows you to connect to a wide range of LLMs, including OpenAI.\\n\",\n \"\\n\",\n \"It's known for having a simpler billing process that may be easier for some countries outside the US.\\n\",\n \"\\n\",\n \"First, check out their website: \\n\",\n \"https://openrouter.ai/\\n\",\n \"\\n\",\n \"Then, take a peak at their quickstart: \\n\",\n \"https://openrouter.ai/docs/quickstart\\n\",\n \"\\n\",\n \"And add your key to your .env file: \\n\",\n \"```shell\\n\",\n \"OPENROUTER_API_KEY=sk-or....\\n\",\n \"```\\n\",\n \"\\n\",\n \"And now, any time you have code like this: \\n\",\n \"```python\\n\",\n \"MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \"openai = OpenAI()\\n\",\n \"```\\n\",\n \"\\n\",\n \"You can replace it with code like this:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"MODEL = \\\"openai/gpt-4o-mini\\\"\\n\",\n \"openrouter_api_key = os.getenv(\\\"OPENROUTER_API_KEY\\\")\\n\",\n \"openai = OpenAI(base_url=\\\"https://openrouter.ai/api/v1\\\", api_key=openrouter_api_key)\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=MODEL,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"What is 2 + 2?\\\"}]\\n\",\n \")\\n\",\n \"\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"You will need to make similar changes to use OpenRouter within any of the Agent Frameworks - you should be able to google for an exact example, or ask me.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## OpenAI Agents SDK - specific instructions\\n\",\n \"\\n\",\n \"With OpenAI Agents SDK (weeks 2 and 6), it's particularly easy to use any model provided by OpenAI themselves. Simply pass in the model name:\\n\",\n \"\\n\",\n \"`agent = Agent(name=\\\"Jokester\\\", instructions=\\\"You are a joke teller\\\", model=\\\"gpt-4o-mini\\\")`\\n\",\n \"\\n\",\n \"You can also substitute in any other provider with an OpenAI compatible API. You do it in 3 steps like this:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"deepseek_client = AsyncOpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\\n\",\n \"deepseek_model = OpenAIChatCompletionsModel(model=\\\"deepseek-chat\\\", openai_client=deepseek_client)\\n\",\n \"```\\n\",\n \"\\n\",\n \"And then you simply provide this model when you create an Agent.\\n\",\n \"\\n\",\n \"`agent = Agent(name=\\\"Jokester\\\", instructions=\\\"You are a joke teller\\\", model=deepseek_model)`\\n\",\n \"\\n\",\n \"And you can use a similar approach for any other OpenAI compatible API, with the same 3 steps:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# extra imports\\n\",\n \"from agents import OpenAIChatCompletionsModel\\n\",\n \"from openai import AsyncOpenAI\\n\",\n \"\\n\",\n \"# Step 1: specify the base URL endpoints where the provider offers an OpenAI compatible API\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"GROK_BASE_URL = \\\"https://api.x.ai/v1\\\"\\n\",\n \"GROQ_BASE_URL = \\\"https://api.groq.com/openai/v1\\\"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"\\n\",\n \"# Step 2: Create an AsyncOpenAI object for that endpoint\\n\",\n \"gemini_client = AsyncOpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\\n\",\n \"grok_client = AsyncOpenAI(base_url=GROK_BASE_URL, api_key=grok_api_key)\\n\",\n \"groq_client = AsyncOpenAI(base_url=GROQ_BASE_URL, api_key=groq_api_key)\\n\",\n \"openrouter_client = AsyncOpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\\n\",\n \"ollama_client = AsyncOpenAI(base_url=OLLAMA_BASE_URL, api_key=\\\"ollama\\\")\\n\",\n \"\\n\",\n \"# Step 3: Create a model object to provide when creating an Agent\\n\",\n \"gemini_model = OpenAIChatCompletionsModel(model=\\\"gemini-2.5-flash\\\", openai_client=gemini_client)\\n\",\n \"grok_3_model = OpenAIChatCompletionsModel(model=\\\"grok-3-mini-beta\\\", openai_client=openrouter_client)\\n\",\n \"llama3_3_model = OpenAIChatCompletionsModel(model=\\\"llama-3.3-70b-versatile\\\", openai_client=groq_client)\\n\",\n \"grok_3_via_openrouter_model = OpenAIChatCompletionsModel(model=\\\"x-ai/grok-3-mini-beta\\\", openai_client=openrouter_client)\\n\",\n \"llama_3_2_local_model = OpenAIChatCompletionsModel(model=\\\"llama3.2\\\", openai_client=ollama_client)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### To use Azure with OpenAI Agents SDK\\n\",\n \"\\n\",\n \"See instructions here: \\n\",\n \"https://techcommunity.microsoft.com/blog/azure-ai-services-blog/use-azure-openai-and-apim-with-the-openai-agents-sdk/4392537\\n\",\n \"\\n\",\n \"Such as this:\\n\",\n \"```python\\n\",\n \"from openai import AsyncAzureOpenAI\\n\",\n \"from agents import set_default_openai_client\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \" \\n\",\n \"# Load environment variables\\n\",\n \"load_dotenv()\\n\",\n \" \\n\",\n \"# Create OpenAI client using Azure OpenAI\\n\",\n \"openai_client = AsyncAzureOpenAI(\\n\",\n \" api_key=os.getenv(\\\"AZURE_OPENAI_API_KEY\\\"),\\n\",\n \" api_version=os.getenv(\\\"AZURE_OPENAI_API_VERSION\\\"),\\n\",\n \" azure_endpoint=os.getenv(\\\"AZURE_OPENAI_ENDPOINT\\\"),\\n\",\n \" azure_deployment=os.getenv(\\\"AZURE_OPENAI_DEPLOYMENT\\\")\\n\",\n \")\\n\",\n \" \\n\",\n \"# Set the default OpenAI client for the Agents SDK\\n\",\n \"set_default_openai_client(openai_client)\\n\",\n \"```\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## CrewAI setup\\n\",\n \"\\n\",\n \"Here's Crew's docs for LLM connections with the model names to use for all models. As student Sadan S. pointed out (thank you!), it's worth knowing that for Google you need to use the environment variable `GEMINI_API_KEY` instead of `GOOGLE_API_KEY`:\\n\",\n \"\\n\",\n \"https://docs.crewai.com/concepts/llms\\n\",\n \"\\n\",\n \"And here's their tutorial with some more info:\\n\",\n \"\\n\",\n \"https://docs.crewai.com/how-to/llm-connections\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## LangGraph setup\\n\",\n \"\\n\",\n \"To use LangGraph with Ollama (and follow similar for other models): \\n\",\n \"https://python.langchain.com/docs/integrations/chat/ollama/#installation\\n\",\n \"\\n\",\n \"First add the package: \\n\",\n \"`uv add langchain-ollama`\\n\",\n \"\\n\",\n \"Then in the lab, make this replacement: \\n\",\n \"```python\\n\",\n \"from langchain_ollama import ChatOllama\\n\",\n \"# llm = ChatOpenAI(model=\\\"gpt-4o-mini\\\")\\n\",\n \"llm = ChatOllama(model=\\\"gemma3:4b\\\")\\n\",\n \"```\\n\",\n \"\\n\",\n \"And obviously run `!ollama pull gemma3:4b` (or whichever model) beforehand.\\n\",\n \"\\n\",\n \"Many thanks to Miroslav P. for adding this, and to Arvin F. for the question!\\n\",\n \"\\n\",\n \"## LangGraph with other models\\n\",\n \"\\n\",\n \"Just follow the same recipe as above, but use any of the models from here: \\n\",\n \"https://python.langchain.com/docs/integrations/chat/\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## AutoGen with other models\\n\",\n \"\\n\",\n \"Here's another contribution from Miroslav P. (thank you!) for using Ollama + local models with AutoGen, and Miroslav has a great example showing gemma3 performing well.\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# model_client = OpenAIChatCompletionClient(model=\\\"gpt-4o-mini\\\")\\n\",\n \" \\n\",\n \"from autogen_ext.models.ollama import OllamaChatCompletionClient\\n\",\n \" \\n\",\n \"model_client = OllamaChatCompletionClient(\\n\",\n \" model=\\\"gemma3:4b\\\",\\n\",\n \" model_info={\\n\",\n \" \\\"vision\\\": True,\\n\",\n \" \\\"function_calling\\\": False,\\n\",\n \" \\\"json_output\\\": True,\\n\",\n \" \\\"family\\\": \\\"unknown\\\",\\n\",\n \" },\\n\",\n \")\\n\",\n \"```\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Worth keeping in mind\\n\",\n \"\\n\",\n \"1. If you wish to use Ollama to run models locally, you may find that smaller models struggle with the more advanced projects. You'll need to experiment with different model sizes and capabilities, and plenty of patience may be needed to find something that works well. I expect several of our projects are too challenging for llama3.2. As an alternative, consider the free models on openrouter.ai, or the very cheap models that are almost free - like DeepSeek.\\n\",\n \"\\n\",\n \"2. Chat models often do better than Reasoning models because Reasoning models can \\\"over-think\\\" some assignments. It's important to experiment. Bigger isn't always better...\\n\",\n \"\\n\",\n \"3. It's confusing, but there are 2 different providers that sound similar! \\n\",\n \"- Grok is the LLM from Elon Musk's X\\n\",\n \"- Groq is a platform for fast inference of open source models\\n\",\n \"\\n\",\n \"A student pointed out to me that \\\"Groq\\\" came first!\\n\"\n ]\n }\n ],\n \"metadata\": {\n \"language_info\": {\n \"name\": \"python\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}, "e402737322a8f3fda32e436560661dd189c9faad": {"t": 1785753630.6232376, "n": 21640, "h": "aebd8d6e53199b87", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# LLM APIs and Ollama - beyond OpenAI\\n\",\n \"\\n\",\n \"_IMPORTANT: If you're not as familiar with APIs in general, and with Environment Variables on your PC or Mac, please review the APIs section in Guide 4 Technical Foundations before proceeding with this guide (topics 3 and 5 in Guide 4)._\\n\",\n \"\\n\",\n \"## Crucial context for using models other than OpenAI - please read this first!\\n\",\n \"\\n\",\n \"Throughout the course, we use APIs for connecting with the strongest LLMs on the planet.\\n\",\n \"\\n\",\n \"The companies behind these LLMs, such as OpenAI, Anthropic, Google and DeepSeek, have built web endpoints. You call their models by making an HTTP request to a Web Address and passing in all the information about your prompts.\\n\",\n \"\\n\",\n \"But it would be painful if we needed to build HTTP requests every time we wanted to call an API.\\n\",\n \"\\n\",\n \"To make this simple, the team at OpenAI wrote a python utility known as a \\\"Python Client Library\\\" which wraps the HTTP call. So you write python code and it calls the web.\\n\",\n \"\\n\",\n \"And THAT is what the library `openai` is.\\n\",\n \"\\n\",\n \"### What is the `openai` python client library\\n\",\n \"\\n\",\n \"It is:\\n\",\n \"- A lightweight python utility\\n\",\n \"- Turns your python requests into an HTTP call\\n\",\n \"- Converts the results coming back from the HTTP call into python objects\\n\",\n \"\\n\",\n \"### What it is NOT\\n\",\n \"\\n\",\n \"- It's not got any code to actually run a Large Language Model! No GPT code! It just makes a web request\\n\",\n \"- There's no scientific computing code, and nothing particularly specialized for OpenAI\\n\",\n \"\\n\",\n \"### How to use it:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# Create an OpenAI python client for making web calls to OpenAI\\n\",\n \"openai = OpenAI()\\n\",\n \"\\n\",\n \"# Make the call\\n\",\n \"response = openai.chat.completions.create(model=\\\"gpt-4.1-mini\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"\\n\",\n \"# Print the result\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### What does this do\\n\",\n \"\\n\",\n \"When you make the python call: `openai.chat.completions.create()` \\n\",\n \"It simply makes a web request to this url: `https://api.openai.com/v1/chat/completions` \\n\",\n \"And it converts the response to python objects.\\n\",\n \"\\n\",\n \"That's it.\\n\",\n \"\\n\",\n \"Here's the API documentation if you make [direct web HTTP calls](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=curl) \\n\",\n \"And here's the same API documentation if you use the [Python Client Library](https://platform.openai.com/docs/guides/text?api-mode=chat&lang=python)\\n\",\n \"\\n\",\n \"## With that context - how do I use other LLMs?\\n\",\n \"\\n\",\n \"It turns out - it's super easy!\\n\",\n \"\\n\",\n \"All the other major LLMs have API endpoints that are compatible with OpenAI.\\n\",\n \"\\n\",\n \"And so OpenAI did everyone a favor: they said, hey look - you can all use our utility for converting python to web requests. We'll allow you to change the utility from calling `https://api.openai/com/v1` to calling any web address that you specify.\\n\",\n \"\\n\",\n \"And so you can use the OpenAI utility even for calling models that are NOT OpenAI, like this:\\n\",\n \"\\n\",\n \"`not_actually_openai = OpenAI(base_url=\\\"https://somewhere.completely.different/\\\", api_key=\\\"another_providers_key\\\")`\\n\",\n \"\\n\",\n \"It's important to appreciate that this OpenAI code is just a utility for making HTTP calls to endpoints. So even though we're using code from the OpenAI team, we can use it to call models other than OpenAI.\\n\",\n \"\\n\",\n \"Here are all the OpenAI-compatible endpoints from the major providers. It even includes using Ollama, locally. Ollama provides an endpoint on your local machine, and they made it OpenAI compatible too - very convenient.\\n\",\n \"\\n\",\n \"```python\\n\",\n \"ANTHROPIC_BASE_URL = \\\"https://api.anthropic.com/v1/\\\"\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"GROK_BASE_URL = \\\"https://api.x.ai/v1\\\"\\n\",\n \"GROQ_BASE_URL = \\\"https://api.groq.com/openai/v1\\\"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"```\\n\",\n \"\\n\",\n \"## Here are examples for Gemini, DeepSeek, Ollama and OpenRouter\\n\",\n \"\\n\",\n \"### Example 1: Using Gemini instead of OpenAI\\n\",\n \"\\n\",\n \"1. Visit Google Studio to set up an account: https://aistudio.google.com/ \\n\",\n \"2. Add your key as GOOGLE_API_KEY to your `.env` \\n\",\n \"3. Also add it a second time as GEMINI_API_KEY to your `.env` - this will be helpful later.\\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"google_api_key = os.getenv(\\\"GOOGLE_API_KEY\\\")\\n\",\n \"gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\\n\",\n \"response = gemini.chat.completions.create(model=\\\"gemini-2.5-flash-preview-05-20\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 2: Using DeepSeek API instead of OpenAI (cheap, and only $2 upfront)\\n\",\n \"\\n\",\n \"1. Visit DeepSeek API to set up an account: https://platform.deepseek.com/ \\n\",\n \"2. You will need to add an initial $2 minimum balance. \\n\",\n \"3. Add your key as DEEPSEEK_API_KEY to your `.env` \\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"deepseek_api_key = os.getenv(\\\"DEEPSEEK_API_KEY\\\")\\n\",\n \"deepseek = OpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\\n\",\n \"response = deepseek.chat.completions.create(model=\\\"deepseek-chat\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 3: Using Ollama to be free and local instead of OpenAI\\n\",\n \"\\n\",\n \"Ollama allows you to run models locally; it provides an OpenAI compatible API on your machine. \\n\",\n \"There's no API key for Ollama; there's no third party with your credit card, so no need for any kind of key.\\n\",\n \"\\n\",\n \"1. If you're new to Ollama, install it by following the instructions here: https://ollama.com \\n\",\n \"2. Then in a Cursor Terminal, do `ollama run llama3.2` to chat with Llama 3.2 \\n\",\n \"BEWARE: do not use llama3.3 or llama4 - these are massive models not designed for home computing! They will fill up your disk. \\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"!ollama pull llama3.2\\n\",\n \"\\n\",\n \"from openai import OpenAI\\n\",\n \"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key=\\\"anything\\\")\\n\",\n \"response = ollama.chat.completions.create(model=\\\"llama3.2\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Example 4: Using the popular service [OpenRouter](https://openrouter.ai) which has an easier billing process instead of OpenAI\\n\",\n \"\\n\",\n \"OpenRouter is very convenient: it gives you free access to many models, and easy access with small upfront to paid models.\\n\",\n \"\\n\",\n \"1. Sign up at https://openrouter.ai\\n\",\n \"2. Add the minimum upfront balance as needed\\n\",\n \"3. Add your key as OPENROUTER_API_KEY to your `.env` file\\n\",\n \"\\n\",\n \"Then:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"import os\\n\",\n \"from openai import OpenAI\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"load_dotenv(override=True)\\n\",\n \"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"openrouter_api_key = os.getenv(\\\"OPENROUTER_API_KEY\\\")\\n\",\n \"openrouter = OpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\\n\",\n \"response = openrouter.chat.completions.create(model=\\\"openai/gpt-4.1-nano\\\", messages=[{\\\"role\\\":\\\"user\\\", \\\"content\\\": \\\"what is 2+2?\\\"}])\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"\\n\",\n \"### Using different API providers with Agent Frameworks\\n\",\n \"\\n\",\n \"The Agent Frameworks make it easy to switch between these providers. You can switch LLMs and pick different ones at any point in the course. There are more notes below on each of them. For OpenAI Agents SDK, see a section later in this notebook. For CrewAI, we cover it on the course, but it's easy: just use the full path to the model that LiteLLM expects.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Costs of APIs\\n\",\n \"\\n\",\n \"The cost of each API call is very low indeed - most calls to models we use on this course are fractions of cents.\\n\",\n \"\\n\",\n \"But it's extremely important to note:\\n\",\n \"\\n\",\n \"1. A complex Agentic project could involve many LLM calls - perhaps 20-30 - and so it can add up. It's important to set limits and monitor usage.\\n\",\n \"\\n\",\n \"2. With Agentic AI, there is a risk of Agents getting into a loop or carrying out more processing than intended. You should monitor your API usage, and never put more budget than you are comfortable with. Some APIs have an \\\"auto-refill\\\" setting that can charge automatically to your card - I strongly recommend you keep this off.\\n\",\n \"\\n\",\n \"3. You should only spend what you are comfortable with. There is a free alternative in Ollama that you can use as a replacement if you wish. DeepSeek, Gemini 2.5 Flash and gpt-4.1-nano are significantly cheaper.\\n\",\n \"\\n\",\n \"Keep in mind that these LLM calls typically involve trillions of floating point calculations - someone has to pay the electricity bills!\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### Ollama: Free alternative to Paid APIs (but please see Warning about llama version)\\n\",\n \"\\n\",\n \"Ollama is a product that runs locally on your machine. It can run open-source models, and it provides an API endpoint on your computer that is compatible with OpenAI.\\n\",\n \"\\n\",\n \"First, download Ollama by visiting:\\n\",\n \"https://ollama.com\\n\",\n \"\\n\",\n \"Then from your Terminal in Cursor (View menu >> Terminal), run this command to download a model:\\n\",\n \"\\n\",\n \"```shell\\n\",\n \"ollama pull llama3.2\\n\",\n \"```\\n\",\n \"\\n\",\n \"WARNING: Be careful not to use llama3.3 or llama4 - these are much larger models that are not suitable for home computers.\\n\",\n \"\\n\",\n \"And now, any time that we have code like: \\n\",\n \"`openai = OpenAI()` \\n\",\n \"You can use this as a direct replacement: \\n\",\n \"`openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')` \\n\",\n \"And also replace model names like **gpt-4o-mini** with **llama3.2**. \\n\",\n \"\\n\",\n \"You don't need to put anything in your .env file for this; with Ollama, everything is running on your computer. You're not calling out to a third party on the cloud, nobody has your credit card details, so there's no need for a secret key! The code `api_key='ollama'` above is only required because the OpenAI client library expects an api_key to be passed in, but the value is ignored by Ollama.\\n\",\n \"\\n\",\n \"Below is a full example:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# You need to do this one time on your computer\\n\",\n \"!ollama pull llama3.2\\n\",\n \"\\n\",\n \"from openai import OpenAI\\n\",\n \"MODEL = \\\"llama3.2\\\"\\n\",\n \"openai = OpenAI(base_url=\\\"http://localhost:11434/v1\\\", api_key=\\\"ollama\\\")\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=MODEL,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"What is 2 + 2?\\\"}]\\n\",\n \")\\n\",\n \"\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"You will need to make similar changes to use Ollama within any of the Agent Frameworks - you should be able to google for an exact example, or ask me.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"### OpenRouter: Convenient gateway platform for OpenAI and others\\n\",\n \"\\n\",\n \"OpenRouter is a third party service that allows you to connect to a wide range of LLMs, including OpenAI.\\n\",\n \"\\n\",\n \"It's known for having a simpler billing process that may be easier for some countries outside the US.\\n\",\n \"\\n\",\n \"First, check out their website: \\n\",\n \"https://openrouter.ai/\\n\",\n \"\\n\",\n \"Then, take a peak at their quickstart: \\n\",\n \"https://openrouter.ai/docs/quickstart\\n\",\n \"\\n\",\n \"And add your key to your .env file: \\n\",\n \"```shell\\n\",\n \"OPENROUTER_API_KEY=sk-or....\\n\",\n \"```\\n\",\n \"\\n\",\n \"And now, any time you have code like this: \\n\",\n \"```python\\n\",\n \"MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \"openai = OpenAI()\\n\",\n \"```\\n\",\n \"\\n\",\n \"You can replace it with code like this:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"MODEL = \\\"openai/gpt-4o-mini\\\"\\n\",\n \"openrouter_api_key = os.getenv(\\\"OPENROUTER_API_KEY\\\")\\n\",\n \"openai = OpenAI(base_url=\\\"https://openrouter.ai/api/v1\\\", api_key=openrouter_api_key)\\n\",\n \"\\n\",\n \"response = openai.chat.completions.create(\\n\",\n \" model=MODEL,\\n\",\n \" messages=[{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"What is 2 + 2?\\\"}]\\n\",\n \")\\n\",\n \"\\n\",\n \"print(response.choices[0].message.content)\\n\",\n \"```\\n\",\n \"\\n\",\n \"You will need to make similar changes to use OpenRouter within any of the Agent Frameworks - you should be able to google for an exact example, or ask me.\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## OpenAI Agents SDK - specific instructions\\n\",\n \"\\n\",\n \"With OpenAI Agents SDK (weeks 2 and 6), it's particularly easy to use any model provided by OpenAI themselves. Simply pass in the model name:\\n\",\n \"\\n\",\n \"`agent = Agent(name=\\\"Jokester\\\", instructions=\\\"You are a joke teller\\\", model=\\\"gpt-4o-mini\\\")`\\n\",\n \"\\n\",\n \"You can also substitute in any other provider with an OpenAI compatible API. You do it in 3 steps like this:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"DEEPSEEK_BASE_URL = \\\"https://api.deepseek.com/v1\\\"\\n\",\n \"deepseek_client = AsyncOpenAI(base_url=DEEPSEEK_BASE_URL, api_key=deepseek_api_key)\\n\",\n \"deepseek_model = OpenAIChatCompletionsModel(model=\\\"deepseek-chat\\\", openai_client=deepseek_client)\\n\",\n \"```\\n\",\n \"\\n\",\n \"And then you simply provide this model when you create an Agent.\\n\",\n \"\\n\",\n \"`agent = Agent(name=\\\"Jokester\\\", instructions=\\\"You are a joke teller\\\", model=deepseek_model)`\\n\",\n \"\\n\",\n \"And you can use a similar approach for any other OpenAI compatible API, with the same 3 steps:\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# extra imports\\n\",\n \"from agents import OpenAIChatCompletionsModel\\n\",\n \"from openai import AsyncOpenAI\\n\",\n \"\\n\",\n \"# Step 1: specify the base URL endpoints where the provider offers an OpenAI compatible API\\n\",\n \"GEMINI_BASE_URL = \\\"https://generativelanguage.googleapis.com/v1beta/openai/\\\"\\n\",\n \"GROK_BASE_URL = \\\"https://api.x.ai/v1\\\"\\n\",\n \"GROQ_BASE_URL = \\\"https://api.groq.com/openai/v1\\\"\\n\",\n \"OPENROUTER_BASE_URL = \\\"https://openrouter.ai/api/v1\\\"\\n\",\n \"OLLAMA_BASE_URL = \\\"http://localhost:11434/v1\\\"\\n\",\n \"\\n\",\n \"# Step 2: Create an AsyncOpenAI object for that endpoint\\n\",\n \"gemini_client = AsyncOpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)\\n\",\n \"grok_client = AsyncOpenAI(base_url=GROK_BASE_URL, api_key=grok_api_key)\\n\",\n \"groq_client = AsyncOpenAI(base_url=GROQ_BASE_URL, api_key=groq_api_key)\\n\",\n \"openrouter_client = AsyncOpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\\n\",\n \"ollama_client = AsyncOpenAI(base_url=OLLAMA_BASE_URL, api_key=\\\"ollama\\\")\\n\",\n \"\\n\",\n \"# Step 3: Create a model object to provide when creating an Agent\\n\",\n \"gemini_model = OpenAIChatCompletionsModel(model=\\\"gemini-2.5-flash\\\", openai_client=gemini_client)\\n\",\n \"grok_3_model = OpenAIChatCompletionsModel(model=\\\"grok-3-mini-beta\\\", openai_client=openrouter_client)\\n\",\n \"llama3_3_model = OpenAIChatCompletionsModel(model=\\\"llama-3.3-70b-versatile\\\", openai_client=groq_client)\\n\",\n \"grok_3_via_openrouter_model = OpenAIChatCompletionsModel(model=\\\"x-ai/grok-3-mini-beta\\\", openai_client=openrouter_client)\\n\",\n \"llama_3_2_local_model = OpenAIChatCompletionsModel(model=\\\"llama3.2\\\", openai_client=ollama_client)\\n\",\n \"```\\n\",\n \"\\n\",\n \"### To use Azure with OpenAI Agents SDK\\n\",\n \"\\n\",\n \"See instructions here: \\n\",\n \"https://techcommunity.microsoft.com/blog/azure-ai-services-blog/use-azure-openai-and-apim-with-the-openai-agents-sdk/4392537\\n\",\n \"\\n\",\n \"Such as this:\\n\",\n \"```python\\n\",\n \"from openai import AsyncAzureOpenAI\\n\",\n \"from agents import set_default_openai_client\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \" \\n\",\n \"# Load environment variables\\n\",\n \"load_dotenv()\\n\",\n \" \\n\",\n \"# Create OpenAI client using Azure OpenAI\\n\",\n \"openai_client = AsyncAzureOpenAI(\\n\",\n \" api_key=os.getenv(\\\"AZURE_OPENAI_API_KEY\\\"),\\n\",\n \" api_version=os.getenv(\\\"AZURE_OPENAI_API_VERSION\\\"),\\n\",\n \" azure_endpoint=os.getenv(\\\"AZURE_OPENAI_ENDPOINT\\\"),\\n\",\n \" azure_deployment=os.getenv(\\\"AZURE_OPENAI_DEPLOYMENT\\\")\\n\",\n \")\\n\",\n \" \\n\",\n \"# Set the default OpenAI client for the Agents SDK\\n\",\n \"set_default_openai_client(openai_client)\\n\",\n \"```\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## CrewAI setup\\n\",\n \"\\n\",\n \"Here's Crew's docs for LLM connections with the model names to use for all models. As student Sadan S. pointed out (thank you!), it's worth knowing that for Google you need to use the environment variable `GEMINI_API_KEY` instead of `GOOGLE_API_KEY`:\\n\",\n \"\\n\",\n \"https://docs.crewai.com/concepts/llms\\n\",\n \"\\n\",\n \"And here's their tutorial with some more info:\\n\",\n \"\\n\",\n \"https://docs.crewai.com/how-to/llm-connections\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## LangGraph setup\\n\",\n \"\\n\",\n \"To use LangGraph with Ollama (and follow similar for other models): \\n\",\n \"https://python.langchain.com/docs/integrations/chat/ollama/#installation\\n\",\n \"\\n\",\n \"First add the package: \\n\",\n \"`uv add langchain-ollama`\\n\",\n \"\\n\",\n \"Then in the lab, make this replacement: \\n\",\n \"```python\\n\",\n \"from langchain_ollama import ChatOllama\\n\",\n \"# llm = ChatOpenAI(model=\\\"gpt-4o-mini\\\")\\n\",\n \"llm = ChatOllama(model=\\\"gemma3:4b\\\")\\n\",\n \"```\\n\",\n \"\\n\",\n \"And obviously run `!ollama pull gemma3:4b` (or whichever model) beforehand.\\n\",\n \"\\n\",\n \"Many thanks to Miroslav P. for adding this, and to Arvin F. for the question!\\n\",\n \"\\n\",\n \"## LangGraph with other models\\n\",\n \"\\n\",\n \"Just follow the same recipe as above, but use any of the models from here: \\n\",\n \"https://python.langchain.com/docs/integrations/chat/\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## AutoGen with other models\\n\",\n \"\\n\",\n \"Here's another contribution from Miroslav P. (thank you!) for using Ollama + local models with AutoGen, and Miroslav has a great example showing gemma3 performing well.\\n\",\n \"\\n\",\n \"```python\\n\",\n \"# model_client = OpenAIChatCompletionClient(model=\\\"gpt-4o-mini\\\")\\n\",\n \" \\n\",\n \"from autogen_ext.models.ollama import OllamaChatCompletionClient\\n\",\n \" \\n\",\n \"model_client = OllamaChatCompletionClient(\\n\",\n \" model=\\\"gemma3:4b\\\",\\n\",\n \" model_info={\\n\",\n \" \\\"vision\\\": True,\\n\",\n \" \\\"function_calling\\\": False,\\n\",\n \" \\\"json_output\\\": True,\\n\",\n \" \\\"family\\\": \\\"unknown\\\",\\n\",\n \" },\\n\",\n \")\\n\",\n \"```\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## Worth keeping in mind\\n\",\n \"\\n\",\n \"1. If you wish to use Ollama to run models locally, you may find that smaller models struggle with the more advanced projects. You'll need to experiment with different model sizes and capabilities, and plenty of patience may be needed to find something that works well. I expect several of our projects are too challenging for llama3.2. As an alternative, consider the free models on openrouter.ai, or the very cheap models that are almost free - like DeepSeek.\\n\",\n \"\\n\",\n \"2. Chat models often do better than Reasoning models because Reasoning models can \\\"over-think\\\" some assignments. It's important to experiment. Bigger isn't always better...\\n\",\n \"\\n\",\n \"3. It's confusing, but there are 2 different providers that sound similar! \\n\",\n \"- Grok is the LLM from Elon Musk's X\\n\",\n \"- Groq is a platform for fast inference of open source models\\n\",\n \"\\n\",\n \"A student pointed out to me that \\\"Groq\\\" came first!\\n\"\n ]\n }\n ],\n \"metadata\": {\n \"language_info\": {\n \"name\": \"python\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}, "1_foundations/community_contributions/kisali/4_lab4_linkedin_chat_using_tools.ipynb": {"6ece898767225cd94d9e566abd11417d0655b7f3": {"t": 1786068256.087929, "n": 11933, "h": "42644b2e541e5029", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"## AI Project Using Tools\\n\",\n \"\\n\",\n \"This is a chatbot that uses AI tools to make decisions, enhancing it's autonomy feature. It uses pushover SMS integration to send a notification whenever an answer to a question is unknown and recording user details.\\n\",\n \"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Importing the required libraries\\n\",\n \"\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"from openai import OpenAI\\n\",\n \"import json\\n\",\n \"import os\\n\",\n \"import requests\\n\",\n \"from pypdf import PdfReader\\n\",\n \"import gradio as gr\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Loading environment variables\\n\",\n \"load_dotenv(override=True)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Set up Pushover credentials and API endpoint\\n\",\n \"\\n\",\n \"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"pushover_user = os.getenv(\\\"PUSHOVER_USER\\\")\\n\",\n \"pushover_token = os.getenv(\\\"PUSHOVER_TOKEN\\\")\\n\",\n \"pushover_url = \\\"https://api.pushover.net/1/messages.json\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Setting up Deepseek Client\\n\",\n \"\\n\",\n \"deepseek_client = OpenAI(\\n\",\n \" api_key=deepseek_api_key, \\n\",\n \" base_url=\\\"https://api.deepseek.com\\\"\\n\",\n \")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Function to send a push notification via pushover and test sending a push notification\\n\",\n \"def push(message):\\n\",\n \" print(f\\\"Push: {message}\\\")\\n\",\n \" payload = {\\\"user\\\": pushover_user, \\\"token\\\": pushover_token, \\\"message\\\": message}\\n\",\n \" requests.post(pushover_url, data=payload)\\n\",\n \"push(\\\"Hey! This is a test notification\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\" Record user details an send a push notification\\n\",\n \"- email: email address that will be provided by the user\\n\",\n \"- name: name provided by user, default respond with Name not provided\\n\",\n \"- notes: information provided by user, default respond with not provided\\n\",\n \"\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"def record_user_details(email, name=\\\"Name not provided\\\", notes=\\\"not provided\\\"):\\n\",\n \" push(f\\\"Recording interest from {name} with email {email} and notes {notes}\\\")\\n\",\n \" return {\\\"recorded\\\": \\\"ok\\\"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\" Function to record an unknown question and send a push notification\\n\",\n \"- question: question that is out of context\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"def record_unknown_question(question):\\n\",\n \" push(f\\\"Recording {question} asked that I couldn't answer\\\")\\n\",\n \" return {\\\"recorded\\\": \\\"ok\\\"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\" First tool called record_user_details with a JSON schema\\n\",\n \"This tool get the email address of user(mandatory), name(optional) and notes(optional) if the user wants to get in touch\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"record_user_details_json = {\\n\",\n \" \\\"name\\\": \\\"record_user_details\\\",\\n\",\n \" \\\"description\\\": \\\"Use this tool to record that a user is interested in being in touch and provided an email address\\\",\\n\",\n \" \\\"parameters\\\": {\\n\",\n \" \\\"type\\\": \\\"object\\\",\\n\",\n \" \\\"properties\\\": {\\n\",\n \" \\\"email\\\": {\\n\",\n \" \\\"type\\\": \\\"string\\\",\\n\",\n \" \\\"description\\\": \\\"The email address of this user\\\"\\n\",\n \" },\\n\",\n \" \\\"name\\\": {\\n\",\n \" \\\"type\\\": \\\"string\\\",\\n\",\n \" \\\"description\\\": \\\"The user's name, if they provided it\\\"\\n\",\n \" }\\n\",\n \" ,\\n\",\n \" \\\"notes\\\": {\\n\",\n \" \\\"type\\\": \\\"string\\\",\\n\",\n \" \\\"description\\\": \\\"Any additional information about the conversation that's worth recording to give context\\\"\\n\",\n \" }\\n\",\n \" },\\n\",\n \" \\\"required\\\": [\\\"email\\\"],\\n\",\n \" \\\"additionalProperties\\\": False\\n\",\n \" }\\n\",\n \"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"\\\"\\\"\\\" Second tool called record_unknown_question with a JSON schema\\n\",\n \"This tool will record the question that is unknown and couldn't be answered. The question field is mandatory.\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"record_unknown_question_json = {\\n\",\n \" \\\"name\\\": \\\"record_unknown_question\\\",\\n\",\n \" \\\"description\\\": \\\"Always use this tool to record any question that couldn't be answered as you didn't know the answer\\\",\\n\",\n \" \\\"parameters\\\": {\\n\",\n \" \\\"type\\\": \\\"object\\\",\\n\",\n \" \\\"properties\\\": {\\n\",\n \" \\\"question\\\": {\\n\",\n \" \\\"type\\\": \\\"string\\\",\\n\",\n \" \\\"description\\\": \\\"The question that couldn't be answered\\\"\\n\",\n \" },\\n\",\n \" },\\n\",\n \" \\\"required\\\": [\\\"question\\\"],\\n\",\n \" \\\"additionalProperties\\\": False\\n\",\n \" }\\n\",\n \"}\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# This is a list of the two tools confurd and can be called by an LLM\\n\",\n \"tools = [{\\\"type\\\": \\\"function\\\", \\\"function\\\": record_user_details_json},\\n\",\n \" {\\\"type\\\": \\\"function\\\", \\\"function\\\": record_unknown_question_json}]\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"tools\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# This function can take a list of tool calls, and run them using if logic.\\n\",\n \"\\n\",\n \"def handle_tool_calls(tool_calls):\\n\",\n \" results = []\\n\",\n \" for tool_call in tool_calls:\\n\",\n \" tool_name = tool_call.function.name\\n\",\n \" arguments = json.loads(tool_call.function.arguments)\\n\",\n \" print(f\\\"Tool called: {tool_name}\\\", flush=True)\\n\",\n \"\\n\",\n \" if tool_name == \\\"record_user_details\\\":\\n\",\n \" result = record_user_details(**arguments)\\n\",\n \" elif tool_name == \\\"record_unknown_question\\\":\\n\",\n \" result = record_unknown_question(**arguments)\\n\",\n \"\\n\",\n \" results.append({\\\"role\\\": \\\"tool\\\",\\\"content\\\": json.dumps(result),\\\"tool_call_id\\\": tool_call.id})\\n\",\n \" return results\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Test the record_unknown_question tool directly\\n\",\n \"globals()[\\\"record_unknown_question\\\"](\\\"this is a really hard question\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Handle tool calls dynamically using globals() (preferred version)\\n\",\n \"\\n\",\n \"def handle_tool_calls(tool_calls):\\n\",\n \" results = []\\n\",\n \" for tool_call in tool_calls:\\n\",\n \" tool_name = tool_call.function.name\\n\",\n \" arguments = json.loads(tool_call.function.arguments)\\n\",\n \" print(f\\\"Tool called: {tool_name}\\\", flush=True)\\n\",\n \" tool = globals().get(tool_name)\\n\",\n \" result = tool(**arguments) if tool else {}\\n\",\n \" results.append({\\\"role\\\": \\\"tool\\\",\\\"content\\\": json.dumps(result),\\\"tool_call_id\\\": tool_call.id})\\n\",\n \" return results\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Load LinkedIn PDF and summary.txt for user context\\n\",\n \"reader = PdfReader(\\\"me/Profile.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 \"with open(\\\"me/summary.txt\\\", \\\"r\\\", encoding=\\\"utf-8\\\") as f:\\n\",\n \" summary = f.read()\\n\",\n \"\\n\",\n \"name = \\\"Ian Kisali\\\"\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Build the system prompt for the LLM, including user info and context\\n\",\n \"system_prompt = f\\\"You are acting as {name}. You are answering questions on {name}'s website, \\\\\\n\",\n \"particularly questions related to {name}'s career, background, skills and experience. \\\\\\n\",\n \"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\\\\n\",\n \"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\\\\n\",\n \"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\\\\n\",\n \"If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career. \\\\\\n\",\n \"If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool. \\\"\\n\",\n \"\\n\",\n \"system_prompt += f\\\"\\\\n\\\\n## Summary:\\\\n{summary}\\\\n\\\\n## LinkedIn Profile:\\\\n{linkedin}\\\\n\\\\n\\\"\\n\",\n \"system_prompt += f\\\"With this context, please chat with the user, always staying in character as {name}.\\\"\\n\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Main chat function: interacts with LLM, handles tool calls, manages history\\n\",\n \"def chat(message, history):\\n\",\n \" messages = [{\\\"role\\\": \\\"system\\\", \\\"content\\\": system_prompt}] + history + [{\\\"role\\\": \\\"user\\\", \\\"content\\\": message}]\\n\",\n \" done = False\\n\",\n \" while not done:\\n\",\n \"\\n\",\n \" # This is the call to the LLM - see that we pass in the tools json\\n\",\n \"\\n\",\n \" response = deepseek_client.chat.completions.create(model=\\\"deepseek-chat\\\", messages=messages, tools=tools)\\n\",\n \"\\n\",\n \" finish_reason = response.choices[0].finish_reason\\n\",\n \" \\n\",\n \" # If the LLM wants to call a tool, we do that!\\n\",\n \" \\n\",\n \" if finish_reason==\\\"tool_calls\\\":\\n\",\n \" message = response.choices[0].message\\n\",\n \" tool_calls = message.tool_calls\\n\",\n \" results = handle_tool_calls(tool_calls)\\n\",\n \" messages.append(message)\\n\",\n \" messages.extend(results)\\n\",\n \" else:\\n\",\n \" done = True\\n\",\n \" return response.choices[0].message.content\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Launch Gradio chat interface with the chat function\\n\",\n \"gr.ChatInterface(chat, 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.1\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"}}}} |