{
 "cells": [
  {
   "cell_type": "raw",
   "id": "c7a67d03-07ec-4c56-a5d6-8df8773e42b0",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 1\n",
    "title: Chat models\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a1a454a9-f963-417b-8be0-e60317cd328c",
   "metadata": {},
   "source": [
    ":::info\n",
    "\n",
    "Head to [Integrations](/docs/integrations/chat/) for documentation on built-in integrations with chat model providers.\n",
    "\n",
    ":::\n",
    "\n",
    "Chat models are a variation on language models.\n",
    "While chat models use language models under the hood, the interface they use is a bit different.\n",
    "Rather than using a \"text in, text out\" API, they use an interface where \"chat messages\" are the inputs and outputs.\n",
    "\n",
    "## Setup\n",
    "\n",
    "For this example we'll need to install the OpenAI Python package:\n",
    "\n",
    "```bash\n",
    "pip install openai\n",
    "```\n",
    "\n",
    "Accessing the API requires an API key, which you can get by creating an account and heading [here](https://platform.openai.com/account/api-keys). Once we have a key we'll want to set it as an environment variable by running:\n",
    "\n",
    "```bash\n",
    "export OPENAI_API_KEY=\"...\"\n",
    "```\n",
    "If you'd prefer not to set an environment variable you can pass the key in directly via the `openai_api_key` named parameter when initiating the OpenAI LLM class:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e230abb2-bc84-438b-b9ff-dd124acb1375",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "chat = ChatOpenAI(openai_api_key=\"...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "609bbd5c-e5a1-4166-89e1-d6c52054860d",
   "metadata": {},
   "source": [
    "Otherwise you can initialize without any params:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3d9dbf70-2397-4d6b-87ec-3e6d4699f3df",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "chat = ChatOpenAI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ca3a777-8641-42fb-9e02-a7770a633d29",
   "metadata": {},
   "source": [
    "## Messages\n",
    "\n",
    "The chat model interface is based around messages rather than raw text.\n",
    "The types of messages currently supported in LangChain are `AIMessage`, `HumanMessage`, `SystemMessage`, `FunctionMessage` and `ChatMessage` -- `ChatMessage` takes in an arbitrary role parameter. Most of the time, you'll just be dealing with `HumanMessage`, `AIMessage`, and `SystemMessage`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54e5088f-98dd-437e-bac8-99b750946b29",
   "metadata": {},
   "source": [
    "## LCEL\n",
    "\n",
    "Chat models implement the [Runnable interface](/docs/expression_language/interface), the basic building block of the [LangChain Expression Language (LCEL)](/docs/expression_language/). This means they support `invoke`, `ainvoke`, `stream`, `astream`, `batch`, `abatch`, `astream_log` calls.\n",
    "\n",
    "Chat models accept `List[BaseMessage]` as inputs, or objects which can be coerced to messages, including `str` (converted to `HumanMessage`) and `PromptValue`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "64ab84bc-de67-45a9-b12f-17c30da32032",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema.messages import HumanMessage, SystemMessage\n",
    "\n",
    "messages = [\n",
    "    SystemMessage(content=\"You're a helpful assistant\"),\n",
    "    HumanMessage(content=\"What is the purpose of model regularization?\"),\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "bde21756-19ab-4e63-ab50-dfb44b5bd44d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content=\"The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to fit the noise in the training data, leading to poor generalization on unseen data. Regularization techniques introduce additional constraints or penalties to the model's objective function, discouraging it from becoming overly complex and promoting simpler and more generalizable models. Regularization helps to strike a balance between fitting the training data well and avoiding overfitting, leading to better performance on new, unseen data.\")"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat.invoke(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "cbac65af-0003-4b63-8a88-e9bc2fc0a345",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The purpose of model regularization is to prevent overfitting and improve the generalization of a machine learning model. Overfitting occurs when a model is too complex and learns the noise or random variations in the training data, which leads to poor performance on new, unseen data. Regularization techniques introduce additional constraints or penalties to the model's learning process, discouraging it from fitting the noise and reducing the complexity of the model. This helps to improve the model's ability to generalize well and make accurate predictions on unseen data."
     ]
    }
   ],
   "source": [
    "for chunk in chat.stream(messages):\n",
    "    print(chunk.content, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "0661ea53-bf38-44b1-8de9-0d5c6c31c5d2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AIMessage(content=\"The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to learn the noise or random fluctuations in the training data, rather than the underlying patterns or relationships. Regularization techniques add a penalty term to the model's objective function, which discourages the model from becoming too complex and helps it generalize better to new, unseen data. This improves the model's ability to make accurate predictions on new data by reducing the variance and increasing the model's overall performance.\")]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat.batch([messages])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a384fa49-55af-4044-9125-28f4d322766a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to memorize the training data instead of learning general patterns and relationships. This leads to poor performance on new, unseen data.\\n\\nRegularization techniques introduce additional constraints or penalties to the model during training, discouraging it from becoming overly complex. This helps to strike a balance between fitting the training data well and generalizing to new data. Regularization techniques can include adding a penalty term to the loss function, such as L1 or L2 regularization, or using techniques like dropout or early stopping. By regularizing the model, it encourages it to learn the most relevant features and reduce the impact of noise or outliers in the data.')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await chat.ainvoke(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "276ff472-18b0-4234-98e2-6cdcfeb6c3e7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to memorize the training data instead of learning the underlying patterns. Regularization techniques help in reducing the complexity of the model by adding a penalty to the loss function. This penalty encourages the model to have smaller weights or fewer features, making it more generalized and less prone to overfitting. The goal is to find the right balance between fitting the training data well and being able to generalize well to unseen data."
     ]
    }
   ],
   "source": [
    "async for chunk in chat.astream(messages):\n",
    "    print(chunk.content, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "3037dc67-da8a-419a-a65b-44dde2365838",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RunLogPatch({'op': 'replace',\n",
      "  'path': '',\n",
      "  'value': {'final_output': None,\n",
      "            'id': '754c4143-2348-46c4-ad2b-3095913084c6',\n",
      "            'logs': {},\n",
      "            'streamed_output': []}})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='The')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' purpose')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' of')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' regularization')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' is')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' to')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' prevent')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' a')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' machine')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' learning')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' from')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' over')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='fit')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ting')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' training')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' data')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' and')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' improve')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' its')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' general')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ization')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' ability')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='.')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' Over')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='fit')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ting')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' occurs')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' when')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' a')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' becomes')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' too')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' complex')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' and')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' learns')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' to')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' fit')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' noise')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' or')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' random')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' fluctuations')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' in')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' training')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' data')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=',')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' instead')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' of')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' capturing')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' underlying')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' patterns')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' and')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' relationships')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='.')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' Regular')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ization')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' techniques')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' introduce')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' a')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' penalty')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' term')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' to')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=\"'s\")})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' objective')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' function')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=',')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' which')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' discour')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ages')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' from')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' becoming')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' too')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' complex')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='.')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' This')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' helps')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' to')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' control')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' model')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=\"'s\")})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' complexity')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' and')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' reduces')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' the')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' risk')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' of')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' over')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='fit')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='ting')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=',')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' leading')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' to')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' better')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' performance')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' on')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' unseen')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content=' data')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='.')})\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/streamed_output/-',\n",
      "  'value': AIMessageChunk(content='')})\n",
      "RunLogPatch({'op': 'replace',\n",
      "  'path': '/final_output',\n",
      "  'value': {'generations': [[{'generation_info': {'finish_reason': 'stop'},\n",
      "                              'message': AIMessageChunk(content=\"The purpose of model regularization is to prevent a machine learning model from overfitting the training data and improve its generalization ability. Overfitting occurs when a model becomes too complex and learns to fit the noise or random fluctuations in the training data, instead of capturing the underlying patterns and relationships. Regularization techniques introduce a penalty term to the model's objective function, which discourages the model from becoming too complex. This helps to control the model's complexity and reduces the risk of overfitting, leading to better performance on unseen data.\"),\n",
      "                              'text': 'The purpose of model regularization is '\n",
      "                                      'to prevent a machine learning model '\n",
      "                                      'from overfitting the training data and '\n",
      "                                      'improve its generalization ability. '\n",
      "                                      'Overfitting occurs when a model becomes '\n",
      "                                      'too complex and learns to fit the noise '\n",
      "                                      'or random fluctuations in the training '\n",
      "                                      'data, instead of capturing the '\n",
      "                                      'underlying patterns and relationships. '\n",
      "                                      'Regularization techniques introduce a '\n",
      "                                      \"penalty term to the model's objective \"\n",
      "                                      'function, which discourages the model '\n",
      "                                      'from becoming too complex. This helps '\n",
      "                                      \"to control the model's complexity and \"\n",
      "                                      'reduces the risk of overfitting, '\n",
      "                                      'leading to better performance on unseen '\n",
      "                                      'data.'}]],\n",
      "            'llm_output': None,\n",
      "            'run': None}})\n"
     ]
    }
   ],
   "source": [
    "async for chunk in chat.astream_log(messages):\n",
    "    print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4a7d783-4ddf-42e7-b143-8050891663c2",
   "metadata": {},
   "source": [
    "## [LangSmith](/docs/langsmith)\n",
    "\n",
    "All `ChatModel`s come with built-in LangSmith tracing. Just set the following environment variables:\n",
    "```bash\n",
    "export LANGCHAIN_TRACING_V2=\"true\"\n",
    "export LANGCHAIN_API_KEY=<your-api-key>\n",
    "```\n",
    "\n",
    "and any `ChatModel` invocation (whether it's nested in a chain or not) will automatically be traced. A trace will include inputs, outputs, latency, token usage, invocation params, environment params, and more. See an example here: https://smith.langchain.com/public/a54192ae-dd5c-4f7a-88d1-daa1eaba1af7/r.\n",
    "\n",
    "In LangSmith you can then provide feedback for any trace, compile annotated datasets for evals, debug performance in the playground, and more."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b289727-3983-43f7-a8b2-dd5582d49b6a",
   "metadata": {},
   "source": [
    "## [Legacy] `__call__`\n",
    "#### Messages in -> message out\n",
    "\n",
    "For convenience you can also treat chat models as callables. You can get chat completions by passing one or more messages to the chat model. The response will be a message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e3d59f6f-176c-4d63-9b0e-8f3018810ecd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content=\"J'adore la programmation.\")"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.schema import HumanMessage, SystemMessage\n",
    "\n",
    "chat(\n",
    "    [\n",
    "        HumanMessage(\n",
    "            content=\"Translate this sentence from English to French: I love programming.\"\n",
    "        )\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ffa2968e-3a7e-4139-a13f-5364e6525d2a",
   "metadata": {},
   "source": [
    "OpenAI's chat model supports multiple messages as input. See [here](https://platform.openai.com/docs/guides/chat/chat-vs-completions) for more information. Here is an example of sending a system and user message to the chat model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "89227e01-8d59-4aa2-8530-c1b28a5c4beb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content=\"J'adore la programmation.\")"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "messages = [\n",
    "    SystemMessage(\n",
    "        content=\"You are a helpful assistant that translates English to French.\"\n",
    "    ),\n",
    "    HumanMessage(content=\"I love programming.\"),\n",
    "]\n",
    "chat(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b996c69-fd5d-4889-af4a-19dfd2833021",
   "metadata": {},
   "source": [
    "## [Legacy] `generate`\n",
    "#### Batch calls, richer outputs\n",
    "\n",
    "You can go one step further and generate completions for multiple sets of messages using `generate`. This returns an `LLMResult` with an additional `message` parameter. This will include additional information about each generation beyond the returned message (e.g. the finish reason) and additional information about the full API call (e.g. total tokens used)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "9b610194-5ccd-4c41-8125-24aa7d50ed38",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LLMResult(generations=[[ChatGeneration(text=\"J'adore programmer.\", generation_info={'finish_reason': 'stop'}, message=AIMessage(content=\"J'adore programmer.\"))], [ChatGeneration(text=\"J'adore l'intelligence artificielle.\", generation_info={'finish_reason': 'stop'}, message=AIMessage(content=\"J'adore l'intelligence artificielle.\"))]], llm_output={'token_usage': {'prompt_tokens': 53, 'completion_tokens': 18, 'total_tokens': 71}, 'model_name': 'gpt-3.5-turbo'}, run=[RunInfo(run_id=UUID('077917a9-026c-47c4-b308-77b37c3a3bfa')), RunInfo(run_id=UUID('0a70a0bf-c599-4f51-932a-c7d42202c984'))])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch_messages = [\n",
    "    [\n",
    "        SystemMessage(\n",
    "            content=\"You are a helpful assistant that translates English to French.\"\n",
    "        ),\n",
    "        HumanMessage(content=\"I love programming.\"),\n",
    "    ],\n",
    "    [\n",
    "        SystemMessage(\n",
    "            content=\"You are a helpful assistant that translates English to French.\"\n",
    "        ),\n",
    "        HumanMessage(content=\"I love artificial intelligence.\"),\n",
    "    ],\n",
    "]\n",
    "result = chat.generate(batch_messages)\n",
    "result"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3c289a4-9e1b-483c-a7f8-7f430da74b1e",
   "metadata": {},
   "source": [
    "You can recover things like token usage from this LLMResult:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2ecf2c7e-935f-42c8-9c5f-9ca08e214f40",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'token_usage': {'prompt_tokens': 53,\n",
       "  'completion_tokens': 18,\n",
       "  'total_tokens': 71},\n",
       " 'model_name': 'gpt-3.5-turbo'}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.llm_output"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "poetry-venv",
   "language": "python",
   "name": "poetry-venv"
  },
  "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.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
