diff --git a/learn/generation/langchain/handbook/04-langchain-chat.ipynb b/learn/generation/langchain/handbook/04-langchain-chat.ipynb index a4df9966..51e69817 100644 --- a/learn/generation/langchain/handbook/04-langchain-chat.ipynb +++ b/learn/generation/langchain/handbook/04-langchain-chat.ipynb @@ -1,9 +1,10 @@ { "cells": [ { - "attachments": {}, "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "yvZxs0nFi_LI" + }, "source": [ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/04-langchain-chat.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/04-langchain-chat.ipynb)" ] @@ -16,25 +17,31 @@ "base_uri": "https://localhost:8080/" }, "id": "sdwa2QfAp9pT", - "outputId": "cfc21d75-c308-45c5-bae2-3b16016a53fb" + "outputId": "5a168276-60f7-41f9-9fc2-e1f5d07d6989" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.0.1\u001b[0m\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.0/1.0 MB\u001b[0m \u001b[31m16.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.5/2.5 MB\u001b[0m \u001b[31m38.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m65.3/65.3 kB\u001b[0m \u001b[31m2.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m363.0/363.0 kB\u001b[0m \u001b[31m14.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.2/45.2 kB\u001b[0m \u001b[31m2.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.9/50.9 kB\u001b[0m \u001b[31m2.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h" ] } ], "source": [ - "!pip install -qU langchain openai" + "!pip install -qU \\\n", + " langchain==0.3.25 \\\n", + " langchain-community==0.3.25 \\\n", + " langchain-openai==0.3.22" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "wnXqS4T_q5m4" @@ -51,18 +58,28 @@ "base_uri": "https://localhost:8080/" }, "id": "f3xQHFXErQyv", - "outputId": "4604b640-9fb7-434c-d185-0dd1fc1c5313" + "outputId": "b105e220-4260-4261-ab85-6d9b9fdb61d3" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter your OpenAI API key: ··········\n" + ] + } + ], "source": [ + "import os\n", "from getpass import getpass\n", "\n", - "# enter your api key\n", - "OPENAI_API_KEY = getpass(\"OpenAI API key: \")" + "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") \\\n", + " or getpass(\"Enter your OpenAI API key: \")\n", + "\n", + "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "_zKBICpJsNqp" @@ -73,29 +90,29 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": { "id": "1i7tIsh2rX8Q" }, "outputs": [], "source": [ - "from langchain.chat_models import ChatOpenAI\n", + "from langchain_openai import ChatOpenAI\n", "\n", + "# Initialize the chat model\n", "chat = ChatOpenAI(\n", " openai_api_key=OPENAI_API_KEY,\n", " temperature=0,\n", - " model='gpt-3.5-turbo'\n", + " model='gpt-4.1-mini'\n", ")" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "RRZFsmH_t3K5" }, "source": [ - "Chats with the Chat-GPT model `gpt-3.5-turbo` are typically structured like so:\n", + "Chats with the Chat-GPT model `gpt-4.1-mini` are typically structured like so:\n", "\n", "```\n", "System: You are a helpful assistant.\n", @@ -105,17 +122,15 @@ "Assistant: I'm great thank you. How can I help you?\n", "\n", "User: I'd like to understand string theory.\n", - "\n", - "Assistant: \n", "```\n", "\n", - "The final `\"Assistant:\"` without a response is what would prompt the model to continue the comversation. In the official OpenAI `ChatCompletion` endpoint these would be passed to the model in a format like:\n", + "The final `\"Assistant:\"` without a response is what would prompt the model to continue the conversation. In the official OpenAI `ChatCompletion` endpoint these would be passed to the model in a format like:\n", "\n", "```json\n", "[\n", " {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n", " {\"role\": \"user\", \"content\": \"Hi AI, how are you today?\"},\n", - " {\"role\": \"assistant\", \"content\": \"I'm great thank you. How can I help you?\"}\n", + " {\"role\": \"assistant\", \"content\": \"I'm great thank you. How can I help you?\"},\n", " {\"role\": \"user\", \"content\": \"I'd like to understand string theory.\"}\n", "]\n", "```\n", @@ -125,106 +140,109 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "id": "jqFLoaRqtl8z" - }, - "outputs": [], - "source": [ - "from langchain.schema import (\n", - " SystemMessage,\n", - " HumanMessage,\n", - " AIMessage\n", - ")\n", - "\n", - "messages = [\n", - " SystemMessage(content=\"You are a helpful assistant.\"),\n", - " HumanMessage(content=\"Hi AI, how are you today?\"),\n", - " AIMessage(content=\"I'm great thank you. How can I help you?\"),\n", - " HumanMessage(content=\"I'd like to understand string theory.\")\n", - "]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "O7AJh2ACytwc" - }, - "source": [ - "The format is very similar, we're just swapper the role of `\"user\"` for `HumanMessage`, and the role of `\"assistant\"` for `AIMessage`.\n", - "\n", - "We generate the next response from the AI by passing these messages to the `ChatOpenAI` object." - ] - }, - { - "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "wc52xfziyhPU", - "outputId": "6329e634-a6eb-4ce6-e271-6b3d91381ab5" + "id": "jqFLoaRqtl8z", + "outputId": "a9945991-4be1-4ad1-a97d-a3117049196f" }, "outputs": [ { - "data": { - "text/plain": [ - "AIMessage(content='Sure, I can help you with that. String theory is a theoretical framework in physics that attempts to reconcile quantum mechanics and general relativity. It proposes that the fundamental building blocks of the universe are not particles, but rather tiny, one-dimensional \"strings\" that vibrate at different frequencies. These strings are incredibly small, with a length scale of around 10^-35 meters.\\n\\nThe theory suggests that there are many different possible configurations of these strings, each corresponding to a different particle. For example, an electron might be a string vibrating in one way, while a photon might be a string vibrating in a different way.\\n\\nOne of the key features of string theory is that it requires the existence of extra dimensions beyond the three spatial dimensions we are familiar with. In fact, the theory requires a total of 10 or 11 dimensions, depending on the specific version of the theory.\\n\\nString theory is still a highly speculative area of physics, and there is currently no experimental evidence to support it. However, it is an active area of research, and many physicists believe that it has the potential to provide a unified description of all the fundamental forces of nature.', additional_kwargs={})" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello! I'm just a bunch of code, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?\n" + ] } ], "source": [ - "res = chat(messages)\n", - "res" + "from langchain.prompts.chat import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "\n", + "# Create the message templates\n", + "system_template = \"You are a helpful assistant.\"\n", + "human_template = \"{input}\"\n", + "\n", + "# Create the prompt template\n", + "prompt = ChatPromptTemplate.from_messages([\n", + " (\"system\", system_template),\n", + " (\"human\", human_template)\n", + "])\n", + "\n", + "# Create the chain\n", + "chain = prompt | chat | StrOutputParser()\n", + "\n", + "# Test the chain\n", + "result = chain.invoke({\"input\": \"Hi AI, how are you today?\"})\n", + "print(result)" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "--7J-7Ap3Jd7" + "id": "O7AJh2ACytwc" }, "source": [ - "In response we get another AI message object. We can print it more clearly like so:" + "The format is very similar, we're just swapping the role of `\"user\"` for `HumanMessage`, and the role of `\"assistant\"` for `AIMessage`.\n", + "\n", + "We generate the next response from the AI by passing these messages to the `ChatOpenAI` object." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "OKMcBaPR3AAv", - "outputId": "2de7d416-d8b6-4a1d-c3c0-6fc3239a4a9e" + "outputId": "f7110315-cd4a-4fc9-c25a-a007017312d2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Sure, I can help you with that. String theory is a theoretical framework in physics that attempts to reconcile quantum mechanics and general relativity. It proposes that the fundamental building blocks of the universe are not particles, but rather tiny, one-dimensional \"strings\" that vibrate at different frequencies. These strings are incredibly small, with a length scale of around 10^-35 meters.\n", + "Certainly! String theory is a theoretical framework in physics that attempts to reconcile quantum mechanics and general relativity, aiming to provide a unified description of all fundamental forces and particles.\n", + "\n", + "Here’s a basic overview:\n", + "\n", + "1. **Fundamental Idea**: Instead of viewing the smallest building blocks of the universe as point-like particles (like electrons or quarks), string theory proposes that these are tiny, one-dimensional \"strings\" that can vibrate at different frequencies. Each vibration mode corresponds to a different particle.\n", "\n", - "The theory suggests that there are many different possible configurations of these strings, each corresponding to a different particle. For example, an electron might be a string vibrating in one way, while a photon might be a string vibrating in a different way.\n", + "2. **Dimensions**: While we experience the universe in 3 spatial dimensions plus time, string theory requires additional spatial dimensions—typically 10 or 11 total dimensions—to be mathematically consistent. These extra dimensions are thought to be compactified or curled up at scales too small to detect.\n", "\n", - "One of the key features of string theory is that it requires the existence of extra dimensions beyond the three spatial dimensions we are familiar with. In fact, the theory requires a total of 10 or 11 dimensions, depending on the specific version of the theory.\n", + "3. **Types of Strings**: Strings can be open (with two endpoints) or closed (forming loops). Different types of strings and their vibrations give rise to different particles, including force carriers like photons and gravitons.\n", "\n", - "String theory is still a highly speculative area of physics, and there is currently no experimental evidence to support it. However, it is an active area of research, and many physicists believe that it has the potential to provide a unified description of all the fundamental forces of nature.\n" + "4. **Unification**: One of the main goals of string theory is to unify all fundamental forces—gravity, electromagnetism, the strong nuclear force, and the weak nuclear force—into a single framework.\n", + "\n", + "5. **Supersymmetry**: Many versions of string theory incorporate supersymmetry, a proposed symmetry between bosons (force-carrying particles) and fermions (matter particles). This helps solve certain theoretical problems and predicts partner particles for those we know.\n", + "\n", + "6. **Current Status**: String theory is still a work in progress. It has not yet been experimentally confirmed, partly because the energy scales involved are far beyond current experimental capabilities. However, it remains a leading candidate for a theory of quantum gravity.\n", + "\n", + "If you want, I can explain any of these points in more detail or discuss related topics!\n" ] } ], "source": [ - "print(res.content)" + "# Create initial messages\n", + "prompt = ChatPromptTemplate.from_messages([\n", + " (\"system\", \"You are a helpful assistant.\"),\n", + " (\"human\", \"Hi AI, how are you today?\"),\n", + " (\"ai\", \"I'm great thank you. How can I help you?\"),\n", + " (\"human\", \"I'd like to understand string theory.\")\n", + "])\n", + "\n", + "# Create the chain using LCEL pipe syntax\n", + "chain = prompt | chat | StrOutputParser()\n", + "\n", + "# Get response using LCEL\n", + "res = chain.invoke({})\n", + "print(res)" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "STl7g3PQ3kg8" @@ -235,50 +253,46 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": { "colab": { - "base_uri": "https://localhost:8080/" + "base_uri": "https://localhost:8080/", + "height": 192 }, "id": "ESZ6UrBA4PwZ", - "outputId": "e8155ce2-0fbc-40ae-f46e-a034393c3881" + "outputId": "5d6e5a9e-91f0-403b-88fb-2bcad1dacd0e" }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Physicists believe that string theory has the potential to produce a unified theory because it provides a framework for describing all the fundamental particles and forces of nature in a single, coherent framework. \n", - "\n", - "In the standard model of particle physics, there are four fundamental forces: gravity, electromagnetism, the strong nuclear force, and the weak nuclear force. These forces are described by different mathematical equations and are not easily reconciled with each other. \n", - "\n", - "String theory, on the other hand, proposes that all of these forces arise from the same underlying physical principles. In particular, the theory suggests that the different particles and forces are all manifestations of the same underlying strings vibrating in different ways. \n", - "\n", - "Furthermore, string theory requires the existence of extra dimensions beyond the three spatial dimensions we are familiar with. These extra dimensions could potentially provide a way to unify the different forces of nature by showing how they arise from a single, higher-dimensional framework. \n", - "\n", - "While there is currently no experimental evidence to support string theory, many physicists believe that it is a promising avenue for developing a unified theory of physics.\n" - ] + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Great question! Physicists believe string theory has the potential to produce a \"unified theory\"—often called a \"Theory of Everything\"—because of several key reasons:\\n\\n1. **All Particles as Vibrations of Strings**: In string theory, every fundamental particle is just a different vibrational mode of the same basic object: a string. This means that matter particles (like electrons and quarks) and force-carrying particles (like photons and gravitons) are all manifestations of the same underlying entity. This naturally unifies the description of particles and forces.\\n\\n2. **Inclusion of Gravity**: Unlike the Standard Model of particle physics, which successfully describes three of the four fundamental forces but does not include gravity, string theory inherently includes a particle that behaves like the graviton—the hypothetical quantum particle that mediates gravity. This is a major step toward unifying gravity with quantum mechanics.\\n\\n3. **Mathematical Consistency**: String theory requires a consistent mathematical framework that only works if all forces and particles fit together in a specific way. This constraint means that the theory naturally combines the different forces into a single framework, rather than treating them separately.\\n\\n4. **Supersymmetry and Extra Dimensions**: The incorporation of supersymmetry and extra spatial dimensions allows string theory to resolve many theoretical problems that arise when trying to combine quantum mechanics and gravity. These features help unify the forces by embedding them in a higher-dimensional space where they appear as different aspects of the same fundamental structure.\\n\\n5. **No Free Parameters**: Unlike some other theories, string theory is highly constrained. The properties of particles and forces emerge from the geometry and topology of the extra dimensions and the way strings vibrate, rather than being put in by hand. This suggests a deep underlying unity.\\n\\nIn summary, physicists see string theory as a promising candidate for a unified theory because it provides a single, coherent framework that naturally includes all known particles and forces—including gravity—arising from one fundamental entity: the string. However, it’s important to note that this is still a theoretical proposal and has yet to be experimentally verified.\\n\\nWould you like me to explain any of these points further?'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "# add latest AI response to messages\n", - "messages.append(res)\n", - "\n", - "# now create a new user prompt\n", - "prompt = HumanMessage(\n", - " content=\"Why do physicists believe it can produce a 'unified theory'?\"\n", - ")\n", - "# add to messages\n", - "messages.append(prompt)\n", + "# For the follow-up question, we can extend the existing prompt\n", + "prompt.extend([\n", + " (\"ai\", res), # Previous AI response\n", + " (\"human\", \"Why do physicists believe it can produce a 'unified theory'?\")\n", + "])\n", "\n", - "# send to chat-gpt\n", - "res = chat(messages)\n", + "# Create the chain using LCEL pipe syntax\n", + "chain = prompt | chat | StrOutputParser()\n", "\n", - "print(res.content)" + "# Get response\n", + "result = chain.invoke({})\n", + "result" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "3jfnGuEK5suC" @@ -288,155 +302,135 @@ "\n", "Alongside what we've seen so far there are also three new prompt templates that we can use. Those are the `SystemMessagePromptTemplate`, `AIMessagePromptTemplate`, and `HumanMessagePromptTemplate`.\n", "\n", - "These are simply an extension of [Langchain's prompt templates](https://www.pinecone.io/learn/langchain-prompt-templates/) that modify the returning \"prompt\" to be a `SystemMessage`, `AIMessage`, or `HumanMessage` object respectively.\n", + "These are simply an extension of [Langchain's prompt templates](https://www.pinecone.io/learn/series/langchain/langchain-prompt-templates/) that modify the returning \"prompt\" to be a `SystemMessage`, `AIMessage`, or `HumanMessage` object respectively.\n", + "\n", + "For now, there are not a huge number of use-cases for these objects. However, they can be useful if:\n", + "- You want different types of response; AND\n", + "- The types of response should depend on a set of pre-determined input values; AND\n", + "- You want to save tokens by not explicitly specifying every possible type of input value in the prompts.\n", "\n", - "For now, there are not a huge number of use-cases for these objects. However, if we have something that we'd like to add to our messages, this can be helpful. For example, let's say we'd like our AI responses to always consist of no more than 50 characters.\n", + "This will make more sense with an example. Suppose you want to tailor responses to people from a wide variety of countries. E.g. an LLM powered worldwide translator!\n", "\n", - "Using the current OpenAI `gpt-3.5-turbo-0301` model, we might run into issues if passing this instruction in the first system message only." + "Some of the languages listed have been commented out as this is just an illustrative example, but the idea is that we can have many languages and dynamically alter the `HumanMessage` prompt so that we don't have to list all of them every time." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "metadata": { - "id": "YWPa7sGO4w_O" + "id": "nuZ2f7wci_LK" }, "outputs": [], "source": [ - "chat = ChatOpenAI(\n", - " openai_api_key=OPENAI_API_KEY,\n", - " temperature=0,\n", - " model='gpt-3.5-turbo-0301'\n", - ")\n", - "\n", - "# setup first system message\n", - "messages = [\n", - " SystemMessage(content=(\n", - " 'You are a helpful assistant. You keep responses to no more than '\n", - " '100 characters long (including whitespace), and sign off every '\n", - " 'message with a random name like \"Robot McRobot\" or \"Bot Rob\".'\n", - " )),\n", - " HumanMessage(content=\"Hi AI, how are you? What is quantum physics?\")\n", + "languages = [\n", + " \"English\",\n", + " \"Esperanto\",\n", + " \"Spanish\",\n", + " # \"French\",\n", + " # \"German\",\n", + " # \"Italian\",\n", + " # \"Portuguese\",\n", + " # \"Dutch\",\n", + " # \"Russian\",\n", + " # \"Chinese (Simplified)\",\n", + " # \"Chinese (Traditional)\",\n", + " # \"Japanese\",\n", + " # \"Korean\",\n", + " # \"Arabic\",\n", + " # \"Hindi\",\n", + " # \"Turkish\",\n", + " # \"Swedish\",\n", + " # \"Danish\",\n", + " # \"Norwegian\",\n", + " # \"Finnish\",\n", + " # \"Polish\",\n", + " # \"Czech\",\n", + " # \"Hungarian\",\n", + " # \"Greek\",\n", + " # \"Hebrew\",\n", + " # \"Vietnamese\",\n", + " # \"Thai\"\n", "]" ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "DkAPNshW9P_m" - }, - "source": [ - "Now make our first completion." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "jxhj2N3Z48We", - "outputId": "c2f36c1b-dd4c-4a23-d20c-18faa93e2031" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Length: 154\n", - "I'm doing well, thank you! Quantum physics is the study of the behavior of matter and energy at a very small scale, such as atoms and subatomic particles.\n" - ] - } - ], - "source": [ - "res = chat(messages)\n", - "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" - ] - }, - { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "tpHo2X0E9rCZ" + "id": "Sto1isO-i_LK" }, "source": [ - "Okay, seems like our AI assistant isn't so good at following either of our instructions. What if we add these instructions to the `HumanMessage` via a `HumanMessagePromptTemplate`?" + "First let's see what the prompt looks like with single example." ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "76gOrGGO9l1Z", - "outputId": "01b52ad9-226b-4942-e53d-744e83c88fde" + "id": "m62JxYxqi_LK", + "outputId": "9a865e15-2b5e-4d92-f959-4ab9e6178d20" }, "outputs": [ { "data": { "text/plain": [ - "ChatPromptValue(messages=[HumanMessage(content='Hi AI, how are you? What is quantum physics? Can you keep the response to no more than 100 characters (including whitespace), and sign off with a random name like \"Robot McRobot\" or \"Bot Rob\".', additional_kwargs={})])" + "ChatPromptValue(messages=[HumanMessage(content='Translate this input I hope when you come the weather will be clement. into Esperanto. Do not include any other text in your response.', additional_kwargs={}, response_metadata={})])" ] }, - "execution_count": 12, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from langchain.prompts.chat import HumanMessagePromptTemplate, ChatPromptTemplate\n", + "from langchain.prompts.chat import HumanMessagePromptTemplate\n", "\n", + "# Create the prompt template\n", "human_template = HumanMessagePromptTemplate.from_template(\n", - " '{input} Can you keep the response to no more than 100 characters '+\n", - " '(including whitespace), and sign off with a random name like \"Robot '+\n", - " 'McRobot\" or \"Bot Rob\".'\n", + " \"Translate this input {input} into {language}. Do not include any other text in your response.\"\n", ")\n", - "\n", - "# create the human message\n", "chat_prompt = ChatPromptTemplate.from_messages([human_template])\n", - "# format with some input\n", + "\n", + "# Format with dynamic input\n", "chat_prompt_value = chat_prompt.format_prompt(\n", - " input=\"Hi AI, how are you? What is quantum physics?\"\n", + " input=\"I hope when you come the weather will be clement.\", # Extra points if you get the reference.\n", + " language=\"Esperanto\"\n", ")\n", - "chat_prompt_value" + "\n", + "chat_prompt_value\n" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "C0TFI5NWBg3Q" + "id": "dMpQ6dOxi_LK" }, "source": [ "Note that to use `HumanMessagePromptTemplate` as typical a prompt templates with the `.format_prompt` method, we needed to pass it through a `ChatPromptTemplate` object. This is case for all of the new chat-based prompt templates.\n", "\n", - "Using this we return a `ChatPromptValue` object. This can be formatted into a list or string like so:\n", - "\n" + "Using this we return a `ChatPromptValue` object. This can be formatted into a list or string like so:" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "OOfnW7MKEnRq", - "outputId": "9d3a2730-2675-4afb-d7ac-f95c5f7d8499" + "id": "-LCL-7wAi_LK", + "outputId": "013f2e49-ef0c-44d2-dfa7-4b6238328b4f" }, "outputs": [ { "data": { "text/plain": [ - "[HumanMessage(content='Hi AI, how are you? What is quantum physics? Can you keep the response to no more than 100 characters (including whitespace), and sign off with a random name like \"Robot McRobot\" or \"Bot Rob\".', additional_kwargs={})]" + "[HumanMessage(content='Translate this input I hope when you come the weather will be clement. into Esperanto. Do not include any other text in your response.', additional_kwargs={}, response_metadata={})]" ] }, - "execution_count": 13, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -447,23 +441,26 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 11, "metadata": { "colab": { "base_uri": "https://localhost:8080/", - "height": 70 + "height": 53 }, - "id": "H6ajbWcgD0RF", - "outputId": "81ac5e6a-d8d4-47e5-b97d-56a40d29216b" + "id": "7-wYQKNmi_LK", + "outputId": "7cb380ea-5c9b-42cd-ae1f-aca0a6716555" }, "outputs": [ { "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, "text/plain": [ - "'Human: Hi AI, how are you? What is quantum physics? Can you keep the response to no more than 100 characters (including whitespace), and sign off with a random name like \"Robot McRobot\" or \"Bot Rob\".'" + "'Human: Translate this input I hope when you come the weather will be clement. into Esperanto. Do not include any other text in your response.'" ] }, - "execution_count": 14, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -473,473 +470,604 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "lQG6nkl4Dz42" + "id": "BsCQlnaYi_LK" }, "source": [ - "Let's see if this new approach works." + "Okay, let's see this new approach in action with our list of languages." ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "L4Epd1D2_RP9", - "outputId": "22e8e4d1-5e32-4d33-f0ed-1376dbddfe3e" + "id": "YWPa7sGO4w_O", + "outputId": "216a3d5c-3581-4547-a800-60a8c485f23f" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Length: 99\n", - "I'm good! Quantum physics studies the behavior of matter and energy at a very small scale. -Bot Rob\n" + "\n", + "=== Response in English ===\n", + "I hope when you come the weather will be mild.\n", + "==================================================\n", + "\n", + "=== Response in Esperanto ===\n", + "Mi esperas, ke kiam vi venos, la vetero estos milda.\n", + "==================================================\n", + "\n", + "=== Response in Spanish ===\n", + "Espero que cuando vengas el tiempo sea benigno.\n", + "==================================================\n" ] } ], "source": [ - "messages = [\n", - " SystemMessage(content=(\n", - " 'You are a helpful assistant. You keep responses to no more than '\n", - " '100 characters long (including whitespace), and sign off every '\n", - " 'message with a random name like \"Robot McRobot\" or \"Bot Rob\".'\n", - " )),\n", - " chat_prompt.format_prompt(\n", - " input=\"Hi AI, how are you? What is quantum physics?\"\n", - " ).to_messages()[0]\n", - "]\n", + "from langchain.prompts.chat import SystemMessagePromptTemplate\n", "\n", - "res = chat(messages)\n", + "# Create the prompt template\n", + "human_template = HumanMessagePromptTemplate.from_template(\n", + " \"Translate this input '{input}' into {language}. Do not include any other text in your response.\"\n", + ")\n", + "system_template = SystemMessagePromptTemplate.from_template(\"You are a helpful assistant.\")\n", + "\n", + "# Create the chain using LCEL pipe syntax\n", + "chain = (\n", + " ChatPromptTemplate.from_messages([system_template, human_template])\n", + " | chat\n", + " | StrOutputParser()\n", + ")\n", "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" + "# Loop through each language\n", + "for language in languages:\n", + " print(f\"\\n=== Response in {language} ===\")\n", + "\n", + " # Invoke the chain with our inputs\n", + " result = chain.invoke({\n", + " \"input\": \"I hope when you come the weather will be clement.\",\n", + " \"language\": language\n", + " })\n", + "\n", + " print(result)\n", + " print(\"=\" * 50) # Separator for readability" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "dfLRjgjCFNUY" + "id": "9riszRQri_LK" }, "source": [ - "This time we get pretty close, we're slightly over the character limit (by `8` characters), and we got a sign off with `- Bot Rob`.\n", + "Excellent!\n", "\n", - "We can also use the prompt templates approach for building an initial system message with a few examples for the chatbot to follow — few-shot training via examples. Let's see what that looks like." + "As you can see, it's successfully translated into different languages based on our inputs, *and we didn't have to use unnecessary tokens by inserting the entire language list into the prompt.*" ] }, { - "cell_type": "code", - "execution_count": 20, + "cell_type": "markdown", "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "M19Ji8gGCOwk", - "outputId": "6dc9d239-6700-4bce-c3b2-780e05db5188" + "id": "dfLRjgjCFNUY" }, - "outputs": [ - { - "data": { - "text/plain": [ - "ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant. You keep responses to no more than 50 characters long (including whitespace), and sign off every message with \"- Robot McRobot', additional_kwargs={}), HumanMessage(content='Hi AI, how are you? What is quantum physics?', additional_kwargs={}), AIMessage(content=\"Good! It's physics of small things - Robot McRobot\", additional_kwargs={})])" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "from langchain.prompts.chat import (\n", - " SystemMessagePromptTemplate,\n", - " AIMessagePromptTemplate\n", - ")\n", + "What if the outputs we need are more complicated? For example, what if the input information is technical information that needs to be formatted in a very specific way for the output?\n", "\n", - "system_template = SystemMessagePromptTemplate.from_template(\n", - " 'You are a helpful assistant. You keep responses to no more than '\n", - " '{character_limit} characters long (including whitespace), and sign '\n", - " 'off every message with \"- {sign_off}'\n", - ")\n", - "human_template = HumanMessagePromptTemplate.from_template(\"{input}\")\n", - "ai_template = AIMessagePromptTemplate.from_template(\"{response} - {sign_off}\")\n", + "E.g. Say that we want to:\n", + "1. Input technical information.\n", + "2. Only translate part of the technical information, not all of the text.\n", + "3. Maintain the same input structure in the output structure.\n", "\n", - "# create the list of messages\n", - "chat_prompt = ChatPromptTemplate.from_messages([\n", - " system_template,\n", - " human_template,\n", - " ai_template\n", - "])\n", - "# format with required inputs\n", - "chat_prompt_value = chat_prompt.format_prompt(\n", - " character_limit=\"50\", sign_off=\"Robot McRobot\",\n", - " input=\"Hi AI, how are you? What is quantum physics?\",\n", - " response=\"Good! It's physics of small things\"\n", - ")\n", - "chat_prompt_value" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "it_SZF-xJ0um" - }, - "source": [ - "We extract these as messages and feed them into the chat model alongside our next query, which we'll feed in as usual (without the template)." + "We can use the prompt templates approach for building an initial system message with a few examples for the chatbot to follow — few-shot training via examples. Let's see what that looks like." ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "ut1yrMqVIxg2", - "outputId": "162983d9-bed9-44fc-d53b-0f5a59383fed" + "id": "M19Ji8gGCOwk", + "outputId": "312b7d66-e709-46cd-8271-35f81680c128" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Length: 41\n", - "Atoms, electrons, photons - Robot McRobot\n" + "\n", + "=== Technical Translation in English ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Technical Note: This error occurs when the application cannot connect to the database.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Esperanto ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Technical Note: Ĉi tiu eraro okazas kiam la aplikaĵo ne povas konekti al la datumbazo.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Spanish ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Nota técnica: Este error ocurre cuando la aplicación no puede conectarse a la base de datos.\n", + "================================================================================\n" ] } ], "source": [ - "messages = chat_prompt_value.to_messages()\n", + "# Create few-shot examples for technical content formatting\n", + "system_template = SystemMessagePromptTemplate.from_template(\n", + " \"\"\"You are a technical translator. You must maintain the exact same format and structure in your translations.\n", + " Only translate the explanatory text, keeping all technical terms, numbers, and formatting unchanged.\n", + "\n", + " Example input and output pairs:\n", + "\n", + " Input: \"Error 404: Page not found\"\n", + " Output: \"Error 404: Página no encontrada\"\n", "\n", - "messages.append(\n", - " HumanMessage(content=\"How small?\")\n", + " Input: \"Status: 200 OK\n", + " Response: {{\n", + " 'data': 'success',\n", + " 'message': 'Operation completed'\n", + " }}\"\n", + " Output: \"Status: 200 OK\n", + " Response: {{\n", + " 'data': 'success',\n", + " 'message': 'Operación completada'\n", + " }}\"\n", + " \"\"\"\n", ")\n", "\n", - "res = chat(messages)\n", + "# Example of a technical input\n", + "human_template = HumanMessagePromptTemplate.from_template(\n", + " \"\"\"Translate this technical information to {language}:\n", + "\n", + " Status: 500 Internal Server Error\n", + " Response: {{\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + " }}\n", + "\n", + " Technical Note: This error occurs when the application cannot connect to the database.\n", + " \"\"\"\n", + ")\n", + "\n", + "# Create the chain using LCEL pipe syntax\n", + "chain = (\n", + " ChatPromptTemplate.from_messages([system_template, human_template])\n", + " | chat\n", + " | StrOutputParser()\n", + ")\n", "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" + "# Loop through each language\n", + "for language in languages:\n", + " print(f\"\\n=== Technical Translation in {language} ===\")\n", + "\n", + " # Invoke the chain with our input\n", + " result = chain.invoke({\"language\": language})\n", + "\n", + " print(result)\n", + " print(\"=\" * 80) # Separator for readability" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { "id": "5jZTYOHvKb_B" }, "source": [ - "Perfect, we seem to get a good response there, let's try a couple more." + "Perfect, we seem to get a good response!\n", + "\n", + "Now, it's arguable as to whether all of the above is better than simple f-strings like:" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 14, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "o89AE74SKYwV", - "outputId": "1d930a2a-544d-4d35-83cf-842c7ea4c933" + "id": "gIZz2eewP3k4", + "outputId": "898cadb4-7310-49f6-d5aa-3b16a56afe25" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Length: 54\n", - "Yes, it's a branch of particle physics - Robot McRobot\n" + "\n", + "=== Technical Translation in English ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Technical Note: This error occurs when the application cannot connect to the database.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Esperanto ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Technical Note: Ĉi tiu eraro okazas kiam la aplikaĵo ne povas konekti al la datumbazo.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Spanish ===\n", + "Status: 500 Internal Server Error\n", + "Response: {\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}\n", + "\n", + "Nota técnica: Este error ocurre cuando la aplicación no puede conectarse a la base de datos.\n", + "================================================================================\n" ] } ], "source": [ - "# add last response\n", - "messages.append(res)\n", + "from langchain.schema import SystemMessage, HumanMessage\n", "\n", - "# make new query\n", - "messages.append(\n", - " HumanMessage(content=\"Okay cool, so it is like 'partical physics'?\")\n", - ")\n", + "# Create the system message with examples\n", + "system_message = SystemMessage(content=\"\"\"You are a technical translator. You must maintain the exact same format and structure in your translations.\n", + "Only translate the explanatory text, keeping all technical terms, numbers, and formatting unchanged.\n", "\n", - "res = chat(messages)\n", + "Example input and output pairs:\n", "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "MXYyMAYMLGzV" - }, - "source": [ - "We went a little over here. We could begin using the previous `HumanMessagePromptTemplate` again like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "eljP-T_kLCpI", - "outputId": "55ef7c6c-0cf6-4220-c5c2-35a93fcb85aa" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "ChatPromptValue(messages=[HumanMessage(content=\"Okay cool, so it is like 'partical physics'? Answer in less than 50 characters (including whitespace).\", additional_kwargs={})])" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain import PromptTemplate\n", + "Input: \"Error 404: Page not found\"\n", + "Output: \"Error 404: Página no encontrada\"\n", "\n", - "# this is a faster way of building the prompt via a PromptTemplate\n", - "human_template = HumanMessagePromptTemplate.from_template(\n", - " '{input} Answer in less than {character_limit} characters (including whitespace).'\n", - ")\n", - "# create the human message\n", - "human_prompt = ChatPromptTemplate.from_messages([human_template])\n", - "# format with some input\n", - "human_prompt_value = human_prompt.format_prompt(\n", - " input=\"Okay cool, so it is like 'partical physics'?\",\n", - " character_limit=\"50\"\n", - ")\n", - "human_prompt_value" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "gfgMiRF9PYyn", - "outputId": "af6788c3-6d4d-455d-af7e-909a7bf340f3" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "HumanMessage(content=\"Okay cool, so it is like 'partical physics'?\", additional_kwargs={})" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# drop the last message about partical physics so we can rewrite\n", - "messages.pop(-1)" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Pu-G2U-7PLVw", - "outputId": "3a5ae086-c959-4ded-d0c7-070f9dee6fef" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[SystemMessage(content='You are a helpful assistant. You keep responses to no more than 50 characters long (including whitespace), and sign off every message with \"- Robot McRobot', additional_kwargs={}),\n", - " HumanMessage(content='Hi AI, how are you? What is quantum physics?', additional_kwargs={}),\n", - " AIMessage(content=\"Good! It's physics of small things - Robot McRobot\", additional_kwargs={}),\n", - " HumanMessage(content='How small?', additional_kwargs={}),\n", - " AIMessage(content='Atoms, electrons, photons - Robot McRobot', additional_kwargs={}),\n", - " HumanMessage(content=\"Okay cool, so it is like 'partical physics'? Answer in less than 50 characters (including whitespace).\", additional_kwargs={})]" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages.extend(human_prompt_value.to_messages())\n", - "messages" + "Input: \"Status: 200 OK\n", + "Response: {\n", + " 'data': 'success',\n", + " 'message': 'Operation completed'\n", + "}\"\n", + "Output: \"Status: 200 OK\n", + "Response: {\n", + " 'data': 'success',\n", + " 'message': 'Operación completada'\n", + "}\"\n", + "\"\"\")\n", + "\n", + "# Loop through each language\n", + "for language in languages:\n", + " print(f\"\\n=== Technical Translation in {language} ===\")\n", + "\n", + " # Create the human message using f-string\n", + " human_message = HumanMessage(content=f\"\"\"Translate this technical information to {language}:\n", + "\n", + " Status: 500 Internal Server Error\n", + " Response: {{\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + " }}\n", + "\n", + " Technical Note: This error occurs when the application cannot connect to the database.\n", + " \"\"\")\n", + "\n", + " # Create messages list\n", + " messages = [system_message, human_message]\n", + "\n", + " # Get response\n", + " res = chat.invoke(messages)\n", + "\n", + " print(res.content)\n", + " print(\"=\" * 80) # Separator for readability" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "qSbk6kKxPkrT" + "id": "yiDVIIkhQwWD" }, "source": [ - "Now process:" + "In this example, the above is far simpler. So we wouldn't necessarily recommend using prompt templates over f-strings in all scenarios.\n", + "\n", + "One example where Prompt Templates might prove useful is in interpreting specific template format types. For example, suppose a project uses lots of `jinja` templates. Rather than writing our functions that handle the input values, f-strings and which renders the jinja template, LangChain Prompt Templates do all of this for us:" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 15, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "Y8RW-HMXN2Ux", - "outputId": "e3d90661-9b15-4a48-9081-e4e81a6a3c5e" + "id": "qVWvyfhNQivT", + "outputId": "25969dda-60b6-419e-92f1-2a3f5eca7e3c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Length: 28\n", - "Yes, similar - Robot McRobot\n" + "\n", + "=== Technical Translation in English ===\n", + "Status: 500 Internal Server Error\n", + "Response: {{\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}}\n", + "\n", + "Technical Note: This error occurs when the application cannot connect to the database.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Esperanto ===\n", + "Status: 500 Internal Server Error\n", + "Response: {{\n", + " 'error': 'Database connection malsukcesis',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}}\n", + "\n", + "Teknika Noto: Ĉi tiu eraro okazas kiam la aplikaĵo ne povas konekti al la datumbazo.\n", + "================================================================================\n", + "\n", + "=== Technical Translation in Spanish ===\n", + "Status: 500 Internal Server Error\n", + "Response: {{\n", + " 'error': 'Fallo en la conexión a la Database',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + "}}\n", + "\n", + "Nota Técnica: Este error ocurre cuando la aplicación no puede conectarse a la Database.\n", + "================================================================================\n" ] } ], "source": [ - "res = chat(messages)\n", + "# Create few-shot examples for technical content formatting\n", + "system_template = SystemMessagePromptTemplate.from_template(\n", + " \"\"\"You are a technical translator. You must maintain the exact same format and structure in your translations.\n", + " Only translate the explanatory text, keeping all technical terms, numbers, and formatting unchanged.\n", "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "1mMuvzuYPruD" - }, - "source": [ - "There we go, a good answer again!\n", + " Example input and output pairs:\n", "\n", - "Now, it's arguable as to whether all of the above is better than simple f-strings like:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "gIZz2eewP3k4", - "outputId": "1b71be09-0c94-4ea6-cc37-80fc8627d5d7" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "HumanMessage(content=\"Okay cool, so it is like 'partical physics'? Answer in less than 50 characters (including whitespace).\", additional_kwargs={})" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "_input = \"Okay cool, so it is like 'partical physics'?\"\n", - "character_limit = 50\n", + " Input: \"Error 404: Page not found\"\n", + " Output: \"Error 404: Página no encontrada\"\n", + "\n", + " Input: \"Status: 200 OK\n", + " Response: {% raw %}{{\n", + " 'data': 'success',\n", + " 'message': 'Operation completed'\n", + " }}{% endraw %}\"\n", + " Output: \"Status: 200 OK\n", + " Response: {% raw %}{{\n", + " 'data': 'success',\n", + " 'message': 'Operación completada'\n", + " }}{% endraw %}\"\n", + " \"\"\",\n", + " template_format=\"jinja2\"\n", + ")\n", + "\n", + "# Example of a technical input using Jinja2's control structures and filters\n", + "human_template = HumanMessagePromptTemplate.from_template(\n", + " \"\"\"Translate this technical information to {{ language|upper }}:\n", + "\n", + " Status: 500 Internal Server Error\n", + " Response: {% raw %}{{\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + " }}{% endraw %}\n", + "\n", + " Technical Note: This error occurs when the application cannot connect to the database.\n", + "\n", + " {% if language == 'spanish' %}\n", + " Note: Please use formal Spanish for technical documentation.\n", + " {% elif language == 'french' %}\n", + " Note: Please use formal French for technical documentation.\n", + " {% else %}\n", + " Note: Please maintain a formal tone in the translation.\n", + " {% endif %}\n", "\n", - "human_message = HumanMessage(content=(\n", - " f\"{_input} Answer in less than {character_limit} characters \"\n", - " \"(including whitespace).\"\n", - "))\n", + " {% for term in technical_terms %}\n", + " Keep the term \"{{ term }}\" unchanged in the translation.\n", + " {% endfor %}\n", + " \"\"\",\n", + " template_format=\"jinja2\"\n", + ")\n", + "\n", + "# Create the chain using LCEL pipe syntax\n", + "chain = (\n", + " ChatPromptTemplate.from_messages([system_template, human_template])\n", + " | chat\n", + " | StrOutputParser()\n", + ")\n", "\n", - "human_message" + "# Loop through each language\n", + "for language in languages:\n", + " print(f\"\\n=== Technical Translation in {language} ===\")\n", + "\n", + " # Invoke the chain with our inputs\n", + " result = chain.invoke({\n", + " \"language\": language,\n", + " \"technical_terms\": ['DB_001', 'Internal Server Error', 'Database connection']\n", + " })\n", + "\n", + " print(result)\n", + " print(\"=\" * 80) # Separator for readability" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "yiDVIIkhQwWD" + "id": "kYNYCY0Fi_LL" }, "source": [ - "In this example, the above is far simpler. So we wouldn't necessarily recommend using prompt templates over f-strings in all scenarios. But, if you do find yourself in a scenario where they become more useful — you now know how to use them.\n", - "\n", - "To finish off, let's see how the rest of the completion process can be done using the f-string formatted message `human_message`:" + "Let's see what the prompts look like after LangChain interprets the Jinja2 templates. This demonstrates how LangChain automatically handles the template interpretation for us:" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 16, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, - "id": "qVWvyfhNQivT", - "outputId": "479035cb-4ece-4f13-d8be-3994afa8c351" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[SystemMessage(content='You are a helpful assistant. You keep responses to no more than 50 characters long (including whitespace), and sign off every message with \"- Robot McRobot', additional_kwargs={}),\n", - " HumanMessage(content='Hi AI, how are you? What is quantum physics?', additional_kwargs={}),\n", - " AIMessage(content=\"Good! It's physics of small things - Robot McRobot\", additional_kwargs={}),\n", - " HumanMessage(content='How small?', additional_kwargs={}),\n", - " AIMessage(content='Atoms, electrons, photons - Robot McRobot', additional_kwargs={}),\n", - " HumanMessage(content=\"Okay cool, so it is like 'partical physics'? Answer in less than 50 characters (including whitespace).\", additional_kwargs={})]" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# drop the last message about partical physics so we can rewrite\n", - "messages.pop(-1)\n", - "\n", - "# add f-string formatted message\n", - "messages.append(human_message)\n", - "messages" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "ehrgANBHQVOk", - "outputId": "bd50a793-2c60-44b8-cd85-d2bec0319b52" + "id": "K2P_BmPVi_LL", + "outputId": "def1bc71-40ad-4c82-9c10-92172680b1e6" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Length: 28\n", - "Yes, similar - Robot McRobot\n" + "\n", + "=== Formatted Prompt for Spanish ===\n", + "\n", + "SYSTEM MESSAGE:\n", + "----------------------------------------\n", + "You are a technical translator. You must maintain the exact same format and structure in your translations.\n", + " Only translate the explanatory text, keeping all technical terms, numbers, and formatting unchanged.\n", + " \n", + " Example input and output pairs:\n", + " \n", + " Input: \"Error 404: Page not found\"\n", + " Output: \"Error 404: Página no encontrada\"\n", + " \n", + " Input: \"Status: 200 OK\n", + " Response: {{\n", + " 'data': 'success',\n", + " 'message': 'Operation completed'\n", + " }}\"\n", + " Output: \"Status: 200 OK\n", + " Response: {{\n", + " 'data': 'success',\n", + " 'message': 'Operación completada'\n", + " }}\"\n", + " \n", + "================================================================================\n", + "\n", + "HUMAN MESSAGE:\n", + "----------------------------------------\n", + "Translate this technical information to SPANISH:\n", + " \n", + " Status: 500 Internal Server Error\n", + " Response: {{\n", + " 'error': 'Database connection failed',\n", + " 'code': 'DB_001',\n", + " 'timestamp': '2024-03-20T10:30:00Z'\n", + " }}\n", + " \n", + " Technical Note: This error occurs when the application cannot connect to the database.\n", + " \n", + " \n", + " Note: Please use formal Spanish for technical documentation.\n", + " \n", + " \n", + " \n", + " Keep the term \"DB_001\" unchanged in the translation.\n", + " \n", + " Keep the term \"Internal Server Error\" unchanged in the translation.\n", + " \n", + " Keep the term \"Database connection\" unchanged in the translation.\n", + " \n", + " \n", + "================================================================================\n" ] } ], "source": [ - "res = chat(messages)\n", + "# Get the formatted prompt for Spanish\n", + "print(\"\\n=== Formatted Prompt for Spanish ===\")\n", "\n", - "print(f\"Length: {len(res.content)}\\n{res.content}\")" + "# Format the prompts with our inputs\n", + "formatted_prompt = ChatPromptTemplate.from_messages([\n", + " system_template,\n", + " human_template\n", + "]).format_prompt(\n", + " language='spanish',\n", + " technical_terms=['DB_001', 'Internal Server Error', 'Database connection']\n", + ")\n", + "\n", + "# Print the formatted messages\n", + "for message in formatted_prompt.to_messages():\n", + " print(f\"\\n{message.type.upper()} MESSAGE:\")\n", + " print(\"-\" * 40)\n", + " print(message.content)\n", + " print(\"=\" * 80)" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "9NEKmKmURLCk" + "id": "Bb4DmDPxi_LL" }, "source": [ - "That's it for this example exploring LangChain's new features for chat." + "Let's break down how LangChain automatically interpreted the Jinja2 templates in our prompts:\n", + "\n", + "1. **Language Filter and Variable**:\n", + " - Original: `{{ language|upper }}`\n", + " - Interpreted as: `SPANISH`\n", + " - The `|upper` filter automatically converted the language to uppercase\n", + "\n", + "2. **Conditional Logic**:\n", + " - Original:\n", + " ```jinja2\n", + " {% if language == 'spanish' %}\n", + " Note: Please use formal Spanish for technical documentation.\n", + " {% elif language == 'french' %}\n", + " Note: Please use formal French for technical documentation.\n", + " {% else %}\n", + " Note: Please maintain a formal tone in the translation.\n", + " {% endif %}\n", + " ```\n", + " - Interpreted as: `Note: Please use formal Spanish for technical documentation.`\n", + " - The `if` statement automatically selected the Spanish-specific note\n", + "\n", + "3. **Loop Structure**:\n", + " - Original:\n", + " ```jinja2\n", + " {% for term in technical_terms %}\n", + " Keep the term \"{{ term }}\" unchanged in the translation.\n", + " {% endfor %}\n", + " ```\n", + " - Interpreted as three separate lines, one for each technical term:\n", + " ```\n", + " Keep the term \"DB_001\" unchanged in the translation.\n", + " Keep the term \"Internal Server Error\" unchanged in the translation.\n", + " Keep the term \"Database connection\" unchanged in the translation.\n", + " ```\n", + " - The `for` loop automatically iterated through our list of technical terms\n", + "\n", + "4. **Raw JSON Blocks**:\n", + " - Original: `{% raw %}{{ ... }}{% endraw %}`\n", + " - Interpreted as: `{{ ... }}`\n", + " - The `raw` tags were automatically removed while preserving the JSON structure" ] } ], @@ -948,7 +1076,8 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3", + "display_name": "examples", + "language": "python", "name": "python3" }, "language_info": { @@ -961,7 +1090,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.12.7" } }, "nbformat": 4,