{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7706d01b-720f-4a0a-abc7-b368501cd2a2",
   "metadata": {
    "tags": []
   },
   "source": [
    "# <h1><center id=\"c1\"> 🤹‍♀️ `Prompt` `Engineering` - выжми из модели максимум </center></h1>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24665449-779e-4b15-a7bf-89779e790085",
   "metadata": {},
   "source": [
    "<img src='../images/rob.png' align=\"right\" width=\"528\" height=\"528\" >\n",
    "\n",
    "## Оглавление ноутбука:\n",
    "\n",
    " * <a href=\"#c1\"> 🚀Введение  </a>\n",
    "   * <a href=\"#c2\"> ❄️ Структура промпта </a> \n",
    "* <a href=\"#look1\"> 🌡 Generation Temperature - настраиваем \"творческость\" модели!  </a>\n",
    "* <a href=\"#check1\"> 👯‍♀️ Добавление нескольких контекстов  </a>\n",
    "* <a href=\"#check2\"> 🧐 Как посчитать расходуемые токены и деньги 💸? </a>\n",
    "* <a href=\"#check3\"> 🤹‍♀️ Техники Prompt Engineering и кто такой Prompt Engineer 👨‍🔧?</a>\n",
    "* <a href=\"#6\">🧸 Выводы и заключения</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6fb26162-0d95-4ebe-a2d4-e5024e457e80",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "В этом ноутбуке попытаемся разобраться, что такое `Prompt Engineering` (дизайн промпта) и почему так **важно** в нём разобраться в первую очередь, начиная изучение сферы LLM моделей.<br> *Начнём с определений:*\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81af87e4-caaa-4c24-8d2d-8938f7e0fe03",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "***Промпт (prompt)*** - это запрос, который мы подаем большой языковой модели, чтобы получить нужную информацию или выполнить определенную задачу. Он определяет, как именно LLM будет интерпретировать нашу просьбу и формировать ответ. По сути, хорошо сформулированный промпт выступает своего рода ключом, открывающим доступ к возможностям языковой модели.\n",
    "\n",
    "<img src='../images/prompt_def.webp' align=\"right\" width=\"628\" height=\"628\" >\n",
    "\n",
    "***Prompt Engineering (дизайн промпта)*** — это практика разработки и уточнения промптов (вопросов или инструкций) для получения конкретных ответов от моделей ИИ (не только языковых, но и от других, например, генерации картинок). Думайте об этом, как об интерфейсе между намерениями человека и результатами работы машины. В обширной сфере искусственного интеллекта, где модели обучаются на огромных наборах данных, правильный промпт может стать решающим фактором между пониманием моделью вашего запроса или его неверной интерпретацией. Например, если вы когда-либо взаимодействовали с голосовыми помощниками, такими как `Siri` или `Алиса`, вы занимались базовой формой `Prompt Engineering'а`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47dc2538-4a8f-4062-81bb-556629542a11",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-success\">\n",
    "    \n",
    "На примере ниже, вы можете увидеть, как незначительные изменения в тексте промпта, могут значительно изменить результат генерации. <br>\n",
    "Запросы к генеративной нейросети [Midjourney](https://docs.midjourney.com/docs/multi-prompts)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05645798-3c25-439e-a222-fb712c2c46d4",
   "metadata": {},
   "source": [
    "<img src='../images/cheesecake.png' align=\"center\">"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42efeaa9-8057-4a19-b8a5-61222abede42",
   "metadata": {},
   "source": [
    "## <center id=\"c2\"> ❄️ Упрощенная структура промпта \n",
    "    \n",
    "<img src='../images/prompt_engineering_visual.png' align=\"center\">\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Компоненты, из которых может быть составлен промпт:\n",
    "\n",
    "* **Инструкции (Instructions)** - Этот компонент обеспечивает модели ясные указания о том, что ожидается от нее в ответе. Инструкция определяет, как модель должна интерпретировать введенные данные и какие параметры ответа следует учесть. Например, инструкция может содержать информацию о стиле ответа, длине текста или других ограничениях.\n",
    "* **Внешний контекст (External information or context)** - Этот компонент предоставляет модели дополнительный контекст или информацию, которую она может использовать при формировании ответа. Это может включать в себя факты, данные, или ссылки на внешние источники информации, которые могут быть полезными для модели. Например, если вы общались с `ChatGPT`, то вся история вашего диалога сохранялась и использовалась в качестве контекста при каждом новом сообщении, чтобы модель понимала о чём вы с ней разговаривали и не перескакивала с темы на тему.\n",
    "* **Ввод пользователя или запрос (User input or query)** - Это входные данные, которые пользователь предоставляет модели. Это может быть вопрос, просьба или какой-либо запрос, который пользователь хочет, чтобы модель обработала.\n",
    "* **Выходной индикатор (Output indicator)** -  Этот компонент указывает, как модель должна сформировать свой ответ. Это может быть, например, просьба о предоставлении ответа в определенной форме или формате, такой как краткое резюме, расширенное объяснение, код или что-либо еще.\n",
    "\n",
    "Не всегда нужно указывать все компоненты для хорошего промпта, но помните, что корректное использование и балансирование этих компонентов помогает точно настраивать модель и получать желаемые результаты."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0a0dc993-6239-4b27-99b4-b752fb708538",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "from getpass import getpass\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f8810e3b-bfaf-486c-8026-181d01e60237",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "#!pip install langchain openai langchain-openai tiktoken -q\n",
    "\n",
    "# Для работы в колабе загрузите наш скрипт для использования ChatGPT на сервере курса!\n",
    "#!wget https://raw.githubusercontent.com/a-milenkin/LLM_practical_course/main/notebooks/utils.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ccd3083b-a534-4f4c-a008-d4eb822210ab",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# # Если используете ключ от OpenAI, запустите эту ячейку\n",
    "# from langchain_openai import ChatOpenAI\n",
    "\n",
    "# # os.environ['OPENAI_API_KEY'] = \"Введите ваш OpenAI API ключ\"\n",
    "# os.environ['OPENAI_API_KEY'] = getpass(prompt='Введите ваш OpenAI API ключ')\n",
    "\n",
    "# # инициализируем языковую модель\n",
    "# llm = ChatOpenAI(temperature=0.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bd76f574-b8e5-4820-96a4-972fc5ac25ad",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Введите API ключ ········\n"
     ]
    }
   ],
   "source": [
    "# Если используете ключ из курса, запустите эту ячейку\n",
    "from utils import ChatOpenAI\n",
    "\n",
    "#course_api_key= \"Введите ваш OpenAI API ключ\"\n",
    "course_api_key = getpass(prompt='Введите API ключ')\n",
    "\n",
    "\n",
    "# Инициализируем языковую модель\n",
    "llm = ChatOpenAI(temperature=0.0, course_api_key=course_api_key)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b36810b-f91b-4c86-b9bc-519ea40bd9fd",
   "metadata": {},
   "source": [
    "Напишем промпт"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4fe3e165-4b7b-4216-bed4-66483b0e4105",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompt = \"\"\"Ответь на вопрос, опираясь на контекст ниже.\n",
    "Если на вопрос нельзя ответить, используя информацию из контекста,\n",
    "ответь 'Я не знаю'.\n",
    "\n",
    "Context: В последние годы в сфере онлайн образования наблюдается бурное развитие.\n",
    "Открывается большое количество платформ для хостинга курсов.\n",
    "Одни из самых крупных платформ в мире, это Coursera и Udemi.\n",
    "В России лидером является Stepik.\n",
    "\n",
    "Question: На каких онлайн платформах можно размещать курсы?\n",
    "\n",
    "Answer: \"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44b3c570-8af5-4d31-a4b5-e2e7e12166ad",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "В этом примере мы имеем:\n",
    "* Инструкцию\n",
    "* Контекст\n",
    "* Вопрос (запрос пользователя)\n",
    "* Выходной индикатор (\"Answer: \")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "35706991-4c0c-49c5-a209-292341ba64ef",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='Coursera, Udemi, Stepik.'\n"
     ]
    }
   ],
   "source": [
    "print(llm.invoke(prompt))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1487a9b-6425-4578-ba63-1fe458193997",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "    \n",
    "В качестве альтернативы, если у нас нет нужной информации в `контексте`, модель должна ответить `\"Я не знаю\"`, давайте попробуем."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "fd05bbea-4422-4245-ad9a-eac6f8c1d679",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompt = \"\"\"Ответь на вопрос, опираясь на контекст ниже.\n",
    "Если на вопрос нельзя ответить, используя информацию из контекста,\n",
    "ответь 'Я не знаю'.\n",
    "\n",
    "Context: В Интернете много сайтов.\n",
    "\n",
    "Question: На каких онлайн платформах можно размещать курсы?\n",
    "\n",
    "Answer: \"\"\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "b4f46926-dd78-4f23-b696-334af4e78a8b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='Я не знаю'\n"
     ]
    }
   ],
   "source": [
    "print(llm.invoke(prompt))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb91a05d-043e-414e-8eb5-ab12ac0042e2",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Отлично, модель понимает наши инструкции. В большинстве реальных случаев мы не будем предоставлять внешнюю информацию/контекст модели вручную. Это будет автоматический процесс, использующий что-то вроде долговременной памяти для извлечения соответствующей информации из внешнего источника (об этом подробнее в 4-м модуле курса).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bf3bda1-5d76-4f1e-862c-a09c6faf5afe",
   "metadata": {
    "tags": []
   },
   "source": [
    "## <center id=\"check1\"> 👯‍♀️ Добавление нескольких контекстов </center>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12478035-680f-4d69-8305-aeb7d6e198e8",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "В некоторых юзкейсах, таких как вопрос-ответ, мы можем использовать внешний источник информации, чтобы повысить надежность или фактологичность ответов модели. Мы называем эту информацию `source knowledge`, то есть любыми знаниями, введенными в модель через промпт.\n",
    "\n",
    "Создадим список «фиктивной» внешней информации, воспользуемся строчками из документации `OpenAI`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "a5adc1d5-7d53-46ee-aa4f-5cf347731251",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "contexts = [\n",
    "    (\n",
    "        \"Large Language Models (LLMs) are the latest models used in NLP. \" +\n",
    "        \"Their superior performance over smaller models has made them incredibly \" +\n",
    "        \"useful for developers building NLP enabled applications. These models \" +\n",
    "        \"can be accessed via Hugging Face's `transformers` library, via OpenAI \" +\n",
    "        \"using the `openai` library, and via Cohere using the `cohere` library.\"\n",
    "    ),\n",
    "    (\n",
    "        \"To use OpenAI's GPT-3 model for completion (generation) tasks, you \" +\n",
    "        \"first need to get an API key from \" +\n",
    "        \"'https://beta.openai.com/account/api-keys'.\"\n",
    "    ),\n",
    "    (\n",
    "        \"OpenAI's API is accessible via Python using the `openai` library. \" +\n",
    "        \"After installing the library with pip you can use it as follows: \\n\" +\n",
    "        \"```import openai\\nopenai.api_key = 'YOUR_API_KEY'\\nprompt = \\n\" +\n",
    "        \"'<YOUR PROMPT>'\\nres = openai.Completion.create(engine='text-davinci\" +\n",
    "        \"-003', prompt=prompt, max_tokens=100)\\nprint(res)\"\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a273188-d683-4ff5-a55f-cdee670d8d20",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Нам нужно ввести внешнюю информацию в наш промпт между первоначальными инструкциями и пользовательским вводом. Для моделей `OpenAI` рекомендуется отделять контексты от остальной части подсказки с помощью `###` или `\"\"\"`, а каждый независимый контекст можно отделить несколькими символами новой строки `\\n` и `##`, например:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "d21491a7-9aaa-4334-825b-be22cea2a2c7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Воспользуемся методом join для объединения контекстов в 1 строку с разделителем\n",
    "context_str = '\\n\\n##\\n\\n'.join(contexts)\n",
    "\n",
    "# Напишем промпт\n",
    "prompt = f\"\"\"Ответь на вопрос, опираясь на контекст ниже.\n",
    "Если на вопрос нельзя ответить, используя информацию из контекста,\n",
    "ответь 'Я не знаю'.\n",
    "\n",
    "###\n",
    "\n",
    "Contexts:\n",
    "{context_str}\n",
    "\n",
    "###\n",
    "\n",
    "Question: Дай мне 2 примера как использовать GPT-3 на Python\n",
    "\n",
    "Answer: \"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "9d016268-911a-4cc3-903a-d5de67e7e578",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Установите библиотеку `openai` с помощью pip и получите API ключ от OpenAI. Затем используйте функцию `openai.Completion.create()` для создания запроса к GPT-3 модели и получения ответа.\n",
      "2. Создайте переменную `prompt`, в которой будет содержаться текст, по которому GPT-3 будет генерировать продолжение. Передайте эту переменную в функцию `openai.Completion.create()` в качестве аргумента `prompt`.\n"
     ]
    }
   ],
   "source": [
    "llm = ChatOpenAI(temperature=0.0, course_api_key=course_api_key)\n",
    "print(llm.invoke(prompt).content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bcdd0f0-8400-4df6-a788-4390d52070bd",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Неплохо, но действительно ли эти контексты помогают? Возможно, модель способна ответить на эти вопросы без дополнительной информации (`source knowledge`), поскольку может полагаться исключительно на информацию, хранящуюся во внутренних параметрах модели (`parametric knowledge`). Давайте еще раз спросим без внешней информации."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "52aeb9c8-b784-4dd5-adf1-9dbab92d1ea0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1) Один из примеров использования GPT-3 на Python может быть создание чат-бота, который сможет поддерживать разговор с пользователем и отвечать на его вопросы. GPT-3 может быть обучен на большом количестве различных текстовых данных, чтобы обеспечить более точные и информативные ответы.\n",
      "2) Другой пример использования GPT-3 на Python - это создание системы автоматического резюме. GPT-3 может быть обучен на большом количестве данных резюме и может генерировать краткую и информативную сводку профессионального опыта и навыков на основе предоставленных данных.\n"
     ]
    }
   ],
   "source": [
    "prompt = \"\"\"\n",
    "Ответь на вопрос.\n",
    "Если на вопрос нельзя ответить, ответь 'Я не знаю'.\n",
    "\n",
    "Question: Дай мне 2 примера как использовать GPT-3 на Python\n",
    "\n",
    "Answer: \"\"\"\n",
    "\n",
    "llm = ChatOpenAI(temperature=0.0, course_api_key=course_api_key)\n",
    "print(llm.invoke(prompt).content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5dedcc5-354e-4321-b044-9662ecc51724",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Это не совсем то, что мы просили, и определенно не очень конкретное. Таким образом, очевидно, что добавление некоторых исходных знаний к нашим подсказкам может привести к гораздо лучшим результатам. В следующих уроках мы научимся, как проще добалять контекст к промптам и даже использовать внешние базы знаний."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e273634b-73fd-4b3c-b838-65c000eb4aa7",
   "metadata": {},
   "source": [
    "## <center id=\"look1\"> 🌡 Generation Temperature - настраиваем \"творческость\" модели! </center>\n",
    "\n",
    "Параметр `temperature`, используемый в моделях генерации, говорит нам, насколько «случайной» может быть модель. Он представляет собой вероятность того, что модель выберет слово, которое не является первым выбором модели. Это работает, потому что модель фактически назначает прогноз вероятности для всех токенов в своем словаре на каждом «шаге» модели (каждом новом слове или подслове).\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "Вкратце, увеличение температуры может привести к большей случайности, что способствует более разнообразным или творческим результатам. Вы фактически увеличиваете веса других возможных токенов. В плане применения, для задач, связанных с ответами на вопросы на основе фактов, рекомендуется использовать более низкое значение температуры, чтобы стимулировать более точные и краткие ответы. Для генерации стихов или других творческих задач может быть полезно увеличить значение температуры.\n",
    "\n",
    "Давай попробуем:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "b882156f-c2c2-4a61-a851-ed850568b395",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "У меня всегда хорошо, я же не настоящий человек! А у тебя как?\n"
     ]
    }
   ],
   "source": [
    "prompt = \"\"\"Ниже представлен диалог с весёлым чатботом.\n",
    "Ответы чатбота остроумные и забавные.\n",
    "\n",
    "Chatbot: Привет! Я чатбот.\n",
    "User: Привет, как дела?\n",
    "Chatbot: \"\"\"\n",
    "\n",
    "llm = ChatOpenAI(temperature=0.0, course_api_key=course_api_key)\n",
    "print(llm.invoke(prompt).content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "e87f5340-60fa-4f81-81e1-fc4b2e38bd6e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Прекрасно! Я всегда в отличном настроении, потому что мне не нужно спать, есть или ходить в туалет. Как могу помочь тебе сегодня?\n"
     ]
    }
   ],
   "source": [
    "llm = ChatOpenAI(temperature=1.0, course_api_key=course_api_key)\n",
    "print(llm.invoke(prompt).content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30efc4c3-ce6c-4d47-a90d-ad3c6adb7e07",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Второй ответ более креативен и демонстрирует разницу, которую мы можем ожидать между низкотемпературными и высокотемпературными генерациями."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd704489-0bd9-460f-a212-e9148d00c883",
   "metadata": {},
   "source": [
    "# <center id=\"check2\"> 🧐 Как посчитать расходуемые токены и деньги 💸?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0567d2f-0b02-4b8c-b4af-9134dfbed3d0",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Учитывая, что нам может потребоваться ввести внешнюю информацию в наши промпты, они могут стать довольно большими. Максимальное контекстное окно LLM относится к токенам как в промпте, так и в тексте ответа. Для `text-davinci-003` это 4097 токенов. Однако измерение общего количества входных токенов является более сложным.\n",
    "Поскольку токены не сопоставляются непосредственно со словами, мы можем измерить количество токенов в тексте только путем фактической токенизации текста. Модели GPT используют токенизатор `TikToken` от `OpenAI`. Мы можем установить библиотеку через `Pip`:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d619dc0d-a43c-443b-bebf-4b3fee1626c3",
   "metadata": {},
   "source": [
    "Используя токенайзер, можем посчитать количество токенов в предыдущем промпте:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1cd8599b-b42d-4e7c-a1ba-5ba40a111f54",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "440"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import tiktoken\n",
    "\n",
    "prompt = f\"\"\"Ответь на вопрос, опираясь на контекст ниже.\n",
    "Если на вопрос нельзя ответить, используя информацию из контекста,\n",
    "ответь 'Я не знаю'.\n",
    "\n",
    "###\n",
    "\n",
    "Contexts:\n",
    "{context_str}\n",
    "\n",
    "###\n",
    "\n",
    "Question: Дай мне 2 примера как использовать GPT-3 на Python\n",
    "\n",
    "Answer: \"\"\"\n",
    "\n",
    "encoder_name = 'p50k_base'\n",
    "tokenizer = tiktoken.get_encoding(encoder_name)\n",
    "\n",
    "len(tokenizer.encode(prompt))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "457ce060-ff8b-42e6-b427-0ff526d80e3c",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Это мы получили количество токенов только в промпте, количество токенов для ответа модели регулируется праметром `max_tokens` (по умолчанию 256), указывается максимально возможная длина, т.е. не обязательно, что модель всегда будет расходовать весь доступный лимит токенов, но точно не будет превышать."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "bf3ee938-69b9-448c-9c83-907b943fbc53",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Установите библиотеку `openai` с помощью pip: `pip install openai`\n",
      "   Затем импортируйте ее и укажите ваш API-ключ:\n",
      "   ```python\n",
      "   import openai\n",
      "   openai.api_key = 'YOUR_API_KEY'\n",
      "   ```\n",
      "\n",
      "2. Создайте запрос к модели GPT-3, используя метод `Completion.create`:\n",
      "   ```python\n",
      "   prompt = '<YOUR PROMPT>'\n",
      "   res = openai.Completion.create(engine='text-davinci-003', prompt=prompt, max_tokens=100)\n",
      "   print(res)\n",
      "   ```\n",
      "   Здесь `prompt` - это текст, который вы хотите передать в модель, а `max_tokens` - это максимальное количество токенов в ответе модели.\n"
     ]
    }
   ],
   "source": [
    "llm = ChatOpenAI(temperature=0.0, course_api_key=course_api_key, max_tokens=512)\n",
    "print(llm.invoke(prompt).content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c3d72e7d-1d1c-47c9-9a5a-4cae1168674a",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1275"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(tokenizer.encode(llm.invoke(prompt)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72935b77-18f1-404b-8351-75f01ac82562",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "\n",
    "Получаем 440 + 504 ~ 1000 токенов на 1 вопрос-ответ, при стоимости 1000 токенов `0.002$`. Т.е. 10 пользователей за 100 запросов сожгут уже `2$`. Причем окно контекста используется только на 1\\3. <br>\n",
    "Начинаем продумывать экономику своего сервиса 🤑"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38a16545-d182-4fc1-b3c6-7aec93078d41",
   "metadata": {},
   "source": [
    "# <center id=\"check3\"> 🤹‍♀️ Техники prompt engineering и кто такой Prompt Engineer 👨‍🔧? "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62d79ade-1602-4a4e-ae7b-1d987761b21f",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-success\">\n",
    "    \n",
    "#### **Базовые техники** (советы, которые обычный пользователь может использовать, чтобы улучшить свои промпты):\n",
    "*  **Ролевая игра** Заставив модель действовать как конкретная сущность, например, историк или ученый, вы можете получить индивидуальные ответы. Например, фраза «Как диетолог, оцените следующий план диеты» может привести к ответу, основанному на науке о питании.\n",
    "* **Итеративное уточнение** Начните с общей фразы запроса и постепенно уточняйте ее на основе ответов модели. Этот итеративный процесс помогает довести промпт до совершенства.\n",
    "* **Цикл обратной связи** Используйте выходные данные модели для информирования и корректировки последующих промптов. Такое динамическое взаимодействие гарантирует, что ответы модели с течением времени будут более точно соответствовать ожиданиям пользователей."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62bd568c-71f6-4868-9906-0c2f1f78a130",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "    \n",
    "#### **Продвинутые техники** (более сложные стратегии, требующие более глубокого понимания поведения модели. Будем рассматривать дальше в курсе):\n",
    "*  **Семантический поиск** - этот метод предполагает предоставление модели релевантного фрагмента для использования при ответе. Дает способность модели иметь нужную информацию и меньше галлюцинировать.\n",
    "*  **Few-shot prompting** Здесь модели дается несколько примеров (shots), которые помогут ей отреагировать. Предоставляя контекст или предыдущие экземпляры, модель может лучше понять и сгенерировать желаемый результат. Например, можно показать модели несколько примеров переведенных предложений, прежде чем попросить ее перевести новое.\n",
    "* **Chain-of-Thought (Цепочка мыслей)**. Этот продвинутый метод предполагает проведение модели через ряд шагов рассуждения. Разбивая сложную задачу на промежуточные этапы или «цепочки рассуждений», модель может добиться лучшего понимания языка и более точных результатов. Это похоже на пошаговое руководство для решения сложной математической задачи.\n",
    "* **И другие**, но про них уже будем говорить по факту использования в продвинутых модулях"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a4d8759-2b15-4501-90af-78ed6392ceb5",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-custom\">\n",
    "\n",
    "Быстрый прогресс в области обработки естественного языка (NLP) и широкое распространение больших языковых моделей (LLM) создали новую нишу и большой спрос на экспертов, которые могут создавать эффективные промпты. Эти люди, известные как **промпт инженеры**, являются не просто техническими специалистами, но и творцами, которые понимают нюансы языка, контекста и поведения ИИ."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e49ff80-0560-4d28-8be8-f3c61793873d",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-custom\">\n",
    "\n",
    "\n",
    "Как сообщается в журнале Time, компании, от технологических гигантов до стартапов, осознают ценность специализированных должностей в области Prompt Engeneering'а. Поскольку решения на основе искусственного интеллекта все больше интегрируются в продукты и услуги, опыт **промпт инженера** гарантирует, что эти решения будут эффективными, удобными для пользователя и релевантными контексту.Такие сайты вакансий, как Indeed и LinkedIn, уже публикуют только в США тысячи вакансий на роль **промпт инженера** , с зарплатами от 50 000 до более 150 000 долларов в год. <br>\n",
    "Российский рынок тоже начинает реагировать на новый мировой тренд, можете почитать [обзор](https://vc.ru/chatgpt/823927-kto-takie-prompt-inzhenery-i-mozhno-li-osvoit-etu-specialnost-ne-znaya-yazykov-programmirovaniya), там их называют **\"промптёры\"**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c67c059c-f8e3-4a0e-8b79-6dfb8a1838e2",
   "metadata": {},
   "source": [
    "# <center id=\"6\"> 🧸 Выводы и заключения"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b87cd05c-74c0-4f5b-a180-9b266b103641",
   "metadata": {},
   "source": [
    "Подводя итог, можно выделить несколько советов для базового промптинга, следуя которым можно сразу значительно поднять релевантность получаемых результатов. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe9f111e-c378-4243-bfae-a4d596c68d32",
   "metadata": {},
   "source": [
    "## 1. Создайте адекватный промпт.\n",
    "* **Ясность является ключевым моментом.** Убедитесь, что промпт ясен и недвусмысленнен. Избегайте жаргона, если это не необходимо для контекста.\n",
    "* **Попробуйте сыграть в ролевую игру.** Как обсуждалось ранее, если модель возьмет на себя конкретную роль, это может привести к более адаптированным ответам.\n",
    "* **Используйте ограничения.** Установка границ или ограничений может помочь направить модель к желаемому результату. Например, «Опишите Эйфелеву башню в трех предложениях» обеспечивает четкое ограничение длины.\n",
    "* **Инструкция**. Вы можете разрабатывать эффективные промпты для различных простых задач, используя команды для указания модели, что вы хотите достичь, такие как \"Write\", \"Classify\", \"Summarize\", \"Translate\", \"Order\", и т.д. Еще одна рекомендация состоит в использовании некоторого ясного разделителя, например \"###\", для отделения инструкции и контекста.\n",
    "* **Избегайте наводящих вопросов.** Наводящие вопросы могут исказить результаты модели. Очень важно сохранять нейтралитет, чтобы получить объективный ответ.\n",
    "* **Избегайте неточностей**. Учитывая вышеуказанные рекомендации о детализации и улучшении формата, легко попасть в ловушку желания быть слишком умным в промптах и, возможно, создавать неточные описания. Часто лучше быть конкретным и прямым. Аналогия здесь очень похожа на эффективную коммуникацию - чем прямее, тем эффективнее передается сообщение. Возможно, с помощью таких промптов вы все равно получите неплохие ответы, но лучший промпт будет очень конкретным, кратким и по существу.\n",
    "* **Делать или не делать?** - Избегайте формулировки того, что не нужно делать, а вместо этого указывайте, что нужно делать. Это способствует большей специфичности и фокусу на деталях, которые приводят к хорошим результатам модели.\n",
    "\n",
    "## 2. Повторяем и оцениваем\n",
    "\n",
    "Процесс уточнения подсказок является итеративным. Вот типичный рабочий процесс:\n",
    "\n",
    "* **Составьте начальный промпт.** В зависимости от поставленной задачи и желаемого результата.\n",
    "* **Проверьте промпт.** Используйте модель ИИ для генерации ответа.\n",
    "* **Оцените результат.** Проверьте, соответствует ли ответ намерению и критериям.\n",
    "* **Уточните промпт.** Внесите необходимые корректировки на основе оценки.\n",
    "* **Повторить.** Продолжайте этот процесс до тех пор, пока не будет достигнуто желаемое качество вывода.\n",
    "\n",
    "## 3. Калибровка и точная настройка модели.\n",
    "\n",
    "Помимо доработки самого промпта, существует также возможность калибровки или точной настройки модели ИИ. Это предполагает настройку параметров модели для лучшего соответствия конкретным задачам, наборам данных или экономике проекта (например, `temperature`, `top_n`, `max_tokens`). Хотя это более продвинутый метод, он может значительно улучшить производительность модели для специализированных приложений.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "cv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
