"        messageLog: [\n",
      "          AIMessageChunk {\n",
      "            \"id\": \"chatcmpl-A7eziUrDmLSSMoiOskhrfbsHqx4Sd\",\n",
      "            \"content\": \"\",\n",
      "            \"additional_kwargs\": {\n",
      "              \"tool_calls\": [\n",
      "                {\n",
      "                  \"index\": 0,\n",
      "                  \"id\": \"call_IQZr1yy2Ug6904VkQg6pWGgR\",\n",
      "                  \"type\": \"function\",\n",
      "                  \"function\": \"[Object]\"\n",
      "                }\n",
      "              ]\n",
      "            },\n",
      "            \"response_metadata\": {\n",
      "              \"prompt\": 0,\n",
      "              \"completion\": 0,\n",
      "              \"finish_reason\": \"tool_calls\",\n",
      "              \"system_fingerprint\": \"fp_483d39d857\"\n",
      "            },\n",
      "            \"tool_calls\": [\n",
      "              {\n",
      "                \"name\": \"magic_function\",\n",
      "                \"args\": {\n",
      "                  \"input\": 3\n",
      "                },\n",
      "                \"id\": \"call_IQZr1yy2Ug6904VkQg6pWGgR\",\n",
      "                \"type\": \"tool_call\"\n",
      "              }\n",
      "            ],\n",
      "            \"tool_call_chunks\": [\n",
      "              {\n",
      "                \"name\": \"magic_function\",\n",
      "                \"args\": \"{\\\"input\\\":3}\",\n",
      "                \"id\": \"call_IQZr1yy2Ug6904VkQg6pWGgR\",\n",
      "                \"index\": 0,\n",
      "                \"type\": \"tool_call_chunk\"\n",
      "              }\n",
      "            ],\n",
      "            \"invalid_tool_calls\": [],\n",
      "            \"usage_metadata\": {\n",
      "              \"input_tokens\": 61,\n",
      "              \"output_tokens\": 14,\n",
      "              \"total_tokens\": 75\n",
      "            }\n",
      "          }\n",
      "        ]\n",
      "      },\n",
      "      observation: \"5\"\n",
      "    }\n",
      "  ]\n",
      "}\n",
      "{ output: \"The value of `magic_function(3)` is 5.\" }\n"
     ]
    }
   ],
   "source": [
    "const langChainStream = await agentExecutor.stream({ input: query });\n",
    "\n",
    "for await (const step of langChainStream) {\n",
    "  console.log(step);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd371818",
   "metadata": {},
   "source": [
    "#### In LangGraph\n",
    "\n",
    "In LangGraph, things are handled natively using the stream method.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2be89a30",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  agent: {\n",
      "    messages: [\n",
      "      AIMessage {\n",
      "        \"id\": \"chatcmpl-A7ezu8hirCENjdjR2GpLjkzXFTEmp\",\n",
      "        \"content\": \"\",\n",
      "        \"additional_kwargs\": {\n",
      "          \"tool_calls\": [\n",
      "            {\n",
      "              \"id\": \"call_KhhNL0m3mlPoJiboFMoX8hzk\",\n",
      "              \"type\": \"function\",\n",
      "              \"function\": \"[Object]\"\n",
      "            }\n",
      "          ]\n",
      "        },\n",
      "        \"response_metadata\": {\n",
      "          \"tokenUsage\": {\n",
      "            \"completionTokens\": 14,\n",
      "            \"promptTokens\": 55,\n",
      "            \"totalTokens\": 69\n",
      "          },\n",
      "          \"finish_reason\": \"tool_calls\",\n",
      "          \"system_fingerprint\": \"fp_483d39d857\"\n",
      "        },\n",
      "        \"tool_calls\": [\n",
      "          {\n",
      "            \"name\": \"magic_function\",\n",
      "            \"args\": {\n",
      "              \"input\": 3\n",
      "            },\n",
      "            \"type\": \"tool_call\",\n",
      "            \"id\": \"call_KhhNL0m3mlPoJiboFMoX8hzk\"\n",
      "          }\n",
      "        ],\n",
      "        \"invalid_tool_calls\": [],\n",
      "        \"usage_metadata\": {\n",
      "          \"input_tokens\": 55,\n",
      "          \"output_tokens\": 14,\n",
      "          \"total_tokens\": 69\n",
      "        }\n",
      "      }\n",
      "    ]\n",
      "  }\n",
      "}\n",
      "{\n",
      "  tools: {\n",
      "    messages: [\n",
      "      ToolMessage {\n",
      "        \"content\": \"5\",\n",
      "        \"name\": \"magic_function\",\n",
      "        \"additional_kwargs\": {},\n",
      "        \"response_metadata\": {},\n",
      "        \"tool_call_id\": \"call_KhhNL0m3mlPoJiboFMoX8hzk\"\n",
      "      }\n",
      "    ]\n",
      "  }\n",
      "}\n",
      "{\n",
      "  agent: {\n",
      "    messages: [\n",
      "      AIMessage {\n",
      "        \"id\": \"chatcmpl-A7ezuTrh8GC550eKa1ZqRZGjpY5zh\",\n",
      "        \"content\": \"The value of `magic_function(3)` is 5.\",\n",
      "        \"additional_kwargs\": {},\n",
      "        \"response_metadata\": {\n",
      "          \"tokenUsage\": {\n",
      "            \"completionTokens\": 14,\n",
      "            \"promptTokens\": 78,\n",
      "            \"totalTokens\": 92\n",
      "          },\n",
      "          \"finish_reason\": \"stop\",\n",
      "          \"system_fingerprint\": \"fp_483d39d857\"\n",
      "        },\n",
      "        \"tool_calls\": [],\n",
      "        \"invalid_tool_calls\": [],\n",
      "        \"usage_metadata\": {\n",
      "          \"input_tokens\": 78,\n",
      "          \"output_tokens\": 14,\n",
      "          \"total_tokens\": 92\n",
      "        }\n",
      "      }\n",
      "    ]\n",
      "  }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "const langGraphStream = await app.stream(\n",
    "  { messages: [{ role: \"user\", content: query }] },\n",
    "  { streamMode: \"updates\" },\n",
    ");\n",
    "\n",
    "for await (const step of langGraphStream) {\n",
    "  console.log(step);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce023792",
   "metadata": {},
   "source": [
    "## `returnIntermediateSteps`\n",
    "\n",
    "Setting this parameter on AgentExecutor allows users to access\n",
    "intermediate_steps, which pairs agent actions (e.g., tool invocations) with\n",
    "their outcomes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "77ce2771",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "  {\n",
      "    action: {\n",
      "      tool: \"magic_function\",\n",
      "      toolInput: { input: 3 },\n",
      "      toolCallId: \"call_mbg1xgLEYEEWClbEaDe7p5tK\",\n",
      "      log: 'Invoking \"magic_function\" with {\"input\":3}\\n',\n",


"      messageLog: [\n",
      "        AIMessageChunk {\n",
      "          \"id\": \"chatcmpl-A7f0NdSRSUJsBP6ENTpiQD4LzpBAH\",\n",
      "          \"content\": \"\",\n",
      "          \"additional_kwargs\": {\n",
      "            \"tool_calls\": [\n",
      "              {\n",
      "                \"index\": 0,\n",
      "                \"id\": \"call_mbg1xgLEYEEWClbEaDe7p5tK\",\n",
      "                \"type\": \"function\",\n",
      "                \"function\": \"[Object]\"\n",
      "              }\n",
      "            ]\n",
      "          },\n",
      "          \"response_metadata\": {\n",
      "            \"prompt\": 0,\n",
      "            \"completion\": 0,\n",
      "            \"finish_reason\": \"tool_calls\",\n",
      "            \"system_fingerprint\": \"fp_54e2f484be\"\n",
      "          },\n",
      "          \"tool_calls\": [\n",
      "            {\n",
      "              \"name\": \"magic_function\",\n",
      "              \"args\": {\n",
      "                \"input\": 3\n",
      "              },\n",
      "              \"id\": \"call_mbg1xgLEYEEWClbEaDe7p5tK\",\n",
      "              \"type\": \"tool_call\"\n",
      "            }\n",
      "          ],\n",
      "          \"tool_call_chunks\": [\n",
      "            {\n",
      "              \"name\": \"magic_function\",\n",
      "              \"args\": \"{\\\"input\\\":3}\",\n",
      "              \"id\": \"call_mbg1xgLEYEEWClbEaDe7p5tK\",\n",
      "              \"index\": 0,\n",
      "              \"type\": \"tool_call_chunk\"\n",
      "            }\n",
      "          ],\n",
      "          \"invalid_tool_calls\": [],\n",
      "          \"usage_metadata\": {\n",
      "            \"input_tokens\": 61,\n",
      "            \"output_tokens\": 14,\n",
      "            \"total_tokens\": 75\n",
      "          }\n",
      "        }\n",
      "      ]\n",
      "    },\n",
      "    observation: \"5\"\n",
      "  }\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "const agentExecutorWithIntermediateSteps = new AgentExecutor({\n",
    "  agent,\n",
    "  tools,\n",
    "  returnIntermediateSteps: true,\n",
    "});\n",
    "\n",
    "const result = await agentExecutorWithIntermediateSteps.invoke({\n",
    "  input: query,\n",
    "});\n",
    "\n",
    "console.log(result.intermediateSteps);\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "050845ae",
   "metadata": {},
   "source": [
    "By default the\n",
    "[react agent executor](https://langchain-ai.github.io/langgraphjs/reference/functions/prebuilt.createReactAgent.html)\n",
    "in LangGraph appends all messages to the central state. Therefore, it is easy to\n",
    "see any intermediate steps by just looking at the full state.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "2f9cdfa8",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "  HumanMessage {\n",
      "    \"id\": \"46a825b2-13a3-4f19-b1aa-7716c53eb247\",\n",
      "    \"content\": \"what is the value of magic_function(3)?\",\n",
      "    \"additional_kwargs\": {},\n",
      "    \"response_metadata\": {}\n",
      "  },\n",
      "  AIMessage {\n",
      "    \"id\": \"chatcmpl-A7f0iUuWktC8gXztWZCjofqyCozY2\",\n",
      "    \"content\": \"\",\n",
      "    \"additional_kwargs\": {\n",
      "      \"tool_calls\": [\n",
      "        {\n",
      "          \"id\": \"call_ndsPDU58wsMeGaqr41cSlLlF\",\n",
      "          \"type\": \"function\",\n",
      "          \"function\": \"[Object]\"\n",
      "        }\n",
      "      ]\n",
      "    },\n",
      "    \"response_metadata\": {\n",
      "      \"tokenUsage\": {\n",
      "        \"completionTokens\": 14,\n",
      "        \"promptTokens\": 55,\n",
      "        \"totalTokens\": 69\n",
      "      },\n",
      "      \"finish_reason\": \"tool_calls\",\n",
      "      \"system_fingerprint\": \"fp_483d39d857\"\n",
      "    },\n",
      "    \"tool_calls\": [\n",
      "      {\n",
      "        \"name\": \"magic_function\",\n",
      "        \"args\": {\n",
      "          \"input\": 3\n",
      "        },\n",
      "        \"type\": \"tool_call\",\n",
      "        \"id\": \"call_ndsPDU58wsMeGaqr41cSlLlF\"\n",
      "      }\n",
      "    ],\n",
      "    \"invalid_tool_calls\": [],\n",
      "    \"usage_metadata\": {\n",
      "      \"input_tokens\": 55,\n",
      "      \"output_tokens\": 14,\n",
      "      \"total_tokens\": 69\n",
      "    }\n",
      "  },\n",
      "  ToolMessage {\n",
      "    \"id\": \"ac6aa309-bbfb-46cd-ba27-cbdbfd848705\",\n",
      "    \"content\": \"5\",\n",
      "    \"name\": \"magic_function\",\n",
      "    \"additional_kwargs\": {},\n",
      "    \"response_metadata\": {},\n",
      "    \"tool_call_id\": \"call_ndsPDU58wsMeGaqr41cSlLlF\"\n",
      "  },\n",
      "  AIMessage {\n",
      "    \"id\": \"chatcmpl-A7f0i7iHyDUV6is6sgwtcXivmFZ1x\",\n",
      "    \"content\": \"The value of `magic_function(3)` is 5.\",\n",
      "    \"additional_kwargs\": {},\n",
      "    \"response_metadata\": {\n",
      "      \"tokenUsage\": {\n",
      "        \"completionTokens\": 14,\n",
      "        \"promptTokens\": 78,\n",
      "        \"totalTokens\": 92\n",
      "      },\n",
      "      \"finish_reason\": \"stop\",\n",
      "      \"system_fingerprint\": \"fp_54e2f484be\"\n",
      "    },\n",
      "    \"tool_calls\": [],\n",
      "    \"invalid_tool_calls\": [],\n",
      "    \"usage_metadata\": {\n",
      "      \"input_tokens\": 78,\n",
      "      \"output_tokens\": 14,\n",
      "      \"total_tokens\": 92\n",
      "    }\n",
      "  }\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "agentOutput = await app.invoke({\n",
    "  messages: [\n",
    "    { role: \"user\", content: query },\n",
    "  ]\n",
    "});\n",
    "\n",
    "console.log(agentOutput.messages);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6e671e6",
   "metadata": {},
   "source": [
    "## `maxIterations`\n",
    "\n",
    "`AgentExecutor` implements a `maxIterations` parameter, whereas this is\n",
    "controlled via `recursionLimit` in LangGraph.\n",
    "\n",
    "Note that in the LangChain `AgentExecutor`, an \"iteration\" includes a full turn of tool\n",
    "invocation and execution. In LangGraph, each step contributes to the recursion\n",
    "limit, so we will need to multiply by two (and add one) to get equivalent\n",
    "results.\n",
    "\n",
    "Here's an example of how you'd set this parameter with the legacy `AgentExecutor`:"
   ]
  },
  {


"data": {
      "text/plain": [
       "{ input: \u001b[32m\"hi!\"\u001b[39m, output: \u001b[32m\"Hello! How can I assist you today?\"\u001b[39m }"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await agentExecutor.invoke({ input: \"hi!\" })"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71493a42",
   "metadata": {},
   "source": [
    "In order to see exactly what is happening under the hood (and to make sure it's not calling a tool) we can take a look at the [LangSmith trace](https://smith.langchain.com/public/b8051e80-14fd-4931-be0f-6416280bc500/r)\n",
    "\n",
    "Let's now try it out on an example where it should be invoking the retriever"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "3fa4780a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  input: \u001b[32m\"how can langsmith help with testing?\"\u001b[39m,\n",
       "  output: \u001b[32m\"LangSmith can assist with testing in several ways, particularly for applications built using large l\"\u001b[39m... 1474 more characters\n",
       "}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await agentExecutor.invoke({ input: \"how can langsmith help with testing?\" })"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2d94242",
   "metadata": {},
   "source": [
    "Let's take a look at the [LangSmith trace](https://smith.langchain.com/public/35bd4f0f-aa2f-4ac2-b9a9-89ce0ca306ca/r) to make sure it's actually calling that.\n",
    "\n",
    "Now let's try one where it needs to call the search tool:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "77c2f769",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  input: \u001b[32m\"whats the weather in sf?\"\u001b[39m,\n",
       "  output: \u001b[32m\"The current weather in San Francisco is as follows:\\n\"\u001b[39m +\n",
       "    \u001b[32m\"\\n\"\u001b[39m +\n",
       "    \u001b[32m\"- **Temperature**: 15.6°C (60.1°F)\\n\"\u001b[39m +\n",
       "    \u001b[32m\"- **Conditio\"\u001b[39m... 303 more characters\n",
       "}"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await agentExecutor.invoke({ input: \"whats the weather in sf?\" })"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c174f838",
   "metadata": {},
   "source": [
    "We can check out the [LangSmith trace](https://smith.langchain.com/public/dfde6f46-0e7b-4dfe-813c-87d7bfb2ade5/r) to make sure it's calling the search tool effectively."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "022cbc8a",
   "metadata": {},
   "source": [
    "## Adding in memory\n",
    "\n",
    "As mentioned earlier, this agent is stateless. This means it does not remember previous interactions. To give it memory we need to pass in previous `chat_history`.\n",
    "\n",
    "**Note**: The input variable needs to be called `chat_history` because of the prompt we are using. If we use a different prompt, we could change the variable name."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "c4073e35",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  input: \u001b[32m\"hi! my name is bob\"\u001b[39m,\n",
       "  chat_history: [],\n",
       "  output: \u001b[32m\"Hello Bob! How can I assist you today?\"\u001b[39m\n",
       "}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// Here we pass in an empty list of messages for chat_history because it is the first message in the chat\n",
    "await agentExecutor.invoke({ input: \"hi! my name is bob\", chat_history: [] })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "550e0c6e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  chat_history: [\n",
       "    { role: \u001b[32m\"user\"\u001b[39m, content: \u001b[32m\"hi! my name is bob\"\u001b[39m },\n",
       "    {\n",
       "      role: \u001b[32m\"assistant\"\u001b[39m,\n",
       "      content: \u001b[32m\"Hello Bob! How can I assist you today?\"\u001b[39m\n",
       "    }\n",
       "  ],\n",
       "  input: \u001b[32m\"what's my name?\"\u001b[39m,\n",
       "  output: \u001b[32m\"Your name is Bob. How can I help you today, Bob?\"\u001b[39m\n",
       "}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await agentExecutor.invoke(\n",
    "  {\n",
    "    chat_history: [\n",
    "      { role: \"user\", content: \"hi! my name is bob\" },\n",
    "      { role: \"assistant\", content: \"Hello Bob! How can I assist you today?\" },\n",
    "    ],\n",
    "    input: \"what's my name?\",\n",
    "  }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07b3bcf2",
   "metadata": {},
   "source": [
    "If we want to keep track of these messages automatically, we can wrap this in a RunnableWithMessageHistory.\n",
    "\n",
    "Because we have multiple inputs, we need to specify two things:\n",
    "\n",
    "- `inputMessagesKey`: The input key to use to add to the conversation history.\n",
    "- `historyMessagesKey`: The key to add the loaded messages into.\n",
    "\n",
    "For more information on how to use this, see [this guide](/docs/how_to/message_history). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "8edd96e6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  input: \u001b[32m\"hi! I'm bob\"\u001b[39m,\n",
       "  chat_history: [\n",
       "    HumanMessage {\n",
       "      \"content\": \"hi! I'm bob\",\n",
       "      \"additional_kwargs\": {},\n",
       "      \"response_metadata\": {}\n",
       "    },\n",
       "    AIMessage {\n",
       "      \"content\": \"Hello Bob! How can I assist you today?\",\n",
       "      \"additional_kwargs\": {},\n",
       "      \"response_metadata\": {},\n",


{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "ea37db49-d389-4291-be73-885d06c1fb7e",
      "metadata": {},
      "source": [
        "# How to do extraction without using function calling\n",
        "\n",
        ":::info Prerequisites\n",
        "\n",
        "This guide assumes familiarity with the following:\n",
        "\n",
        "- [Extraction](/docs/tutorials/extraction)\n",
        "\n",
        ":::\n",
        "\n",
        "LLMs that are able to follow prompt instructions well can be tasked with outputting information in a given format without using function calling.\n",
        "\n",
        "This approach relies on designing good prompts and then parsing the output of the LLMs to make them extract information well, though it lacks some of the guarantees provided by function calling or JSON mode.\n",
        "\n",
        "Here, we'll use Claude which is great at following instructions! See [here for more about Anthropic models](/docs/integrations/chat/anthropic).\n",
        "\n",
        "First, we'll install the integration package:\n",
        "\n",
        "```{=mdx}\n",
        "import IntegrationInstallTooltip from \"@mdx_components/integration_install_tooltip.mdx\";\n",
        "import Npm2Yarn from \"@theme/Npm2Yarn\";\n",
        "\n",
        "<IntegrationInstallTooltip></IntegrationInstallTooltip>\n",
        "\n",
        "<Npm2Yarn>\n",
        "  @langchain/anthropic @langchain/core zod zod-to-json-schema\n",
        "</Npm2Yarn>\n",
        "```"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "d71b32de-a6b4-45ed-83a9-ba1925f9470c",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { ChatAnthropic } from \"@langchain/anthropic\";\n",
        "\n",
        "const model = new ChatAnthropic({\n",
        "  model: \"claude-3-sonnet-20240229\",\n",
        "  temperature: 0,\n",
        "})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3e412374-3beb-4bbf-966b-400c1f66a258",
      "metadata": {},
      "source": [
        ":::{.callout-tip}\n",
        "All the same considerations for extraction quality apply for parsing approach.\n",
        "\n",
        "This tutorial is meant to be simple, but generally should really include reference examples to squeeze out performance!\n",
        ":::"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "abc1a945-0f80-4953-add4-cd572b6f2a51",
      "metadata": {},
      "source": [
        "## Using StructuredOutputParser\n",
        "\n",
        "The following example uses the built-in [`StructuredOutputParser`](/docs/how_to/output_parser_structured/) to parse the output of a chat model. We use the built-in prompt formatting instructions contained in the parser."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "497eb023-c043-443d-ac62-2d4ea85fe1b0",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { z } from \"zod\";\n",
        "import { StructuredOutputParser } from \"langchain/output_parsers\";\n",
        "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
        "\n",
        "let personSchema = z.object({\n",
        "  name: z.optional(z.string()).describe(\"The name of the person\"),\n",
        "  hair_color: z.optional(z.string()).describe(\"The color of the person's hair, if known\"),\n",
        "  height_in_meters: z.optional(z.string()).describe(\"Height measured in meters\")\n",
        "}).describe(\"Information about a person.\");\n",
        "\n",
        "const parser = StructuredOutputParser.fromZodSchema(personSchema);\n",
        "\n",
        "const prompt = ChatPromptTemplate.fromMessages([\n",
        "  [\"system\", \"Answer the user query. Wrap the output in `json` tags\\n{format_instructions}\"],\n",
        "  [\"human\", \"{query}\"],\n",
        "]);\n",
        "\n",
        "const partialedPrompt = await prompt.partial({\n",
        "  format_instructions: parser.getFormatInstructions(),\n",
        "});"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c31aa2c8-05a9-4a12-80c5-ea1250dea0ae",
      "metadata": {},
      "source": [
        "Let's take a look at what information is sent to the model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "20b99ffb-a114-49a9-a7be-154c525f8ada",
      "metadata": {},
      "outputs": [],
      "source": [
        "const query = \"Anna is 23 years old and she is 6 feet tall\";"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "4f3a66ce-de19-4571-9e54-67504ae3fba7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[\n",
            "  SystemMessage {\n",
            "    lc_serializable: true,\n",
            "    lc_kwargs: {\n",
            "      content: \"Answer the user query. Wrap the output in `json` tags\\n\" +\n",
            "        \"You must format your output as a JSON value th\"... 1444 more characters,\n",
            "      additional_kwargs: {}\n",
            "    },\n",
            "    lc_namespace: [ \"langchain_core\", \"messages\" ],\n",
            "    content: \"Answer the user query. Wrap the output in `json` tags\\n\" +\n",
            "      \"You must format your output as a JSON value th\"... 1444 more characters,\n",
            "    name: undefined,\n",
            "    additional_kwargs: {}\n",
            "  },\n",
            "  HumanMessage {\n",
            "    lc_serializable: true,\n",
            "    lc_kwargs: {\n",
            "      content: \"Anna is 23 years old and she is 6 feet tall\",\n",
            "      additional_kwargs: {}\n",
            "    },\n",
            "    lc_namespace: [ \"langchain_core\", \"messages\" ],\n",
            "    content: \"Anna is 23 years old and she is 6 feet tall\",\n",
            "    name: undefined,\n",
            "    additional_kwargs: {}\n",
            "  }\n",
            "]\n"
          ]
        }
      ],
      "source": [
        "const promptValue = await partialedPrompt.invoke({ query });\n",
        "\n",
        "console.log(promptValue.toChatMessages());"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "3a46b5fd-9242-4b8c-a4e2-3f04fc19b3a4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{ name: \u001b[32m\"Anna\"\u001b[39m, hair_color: \u001b[32m\"\"\u001b[39m, height_in_meters: \u001b[32m\"1.83\"\u001b[39m }"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "const chain = partialedPrompt.pipe(model).pipe(parser);\n",
        "\n",
        "await chain.invoke({ query });"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "815b3b87-3bc6-4b56-835e-c6b6703cef5d",
      "metadata": {},
      "source": [
        "## Custom Parsing\n",
        "\n",
        "You can also create a custom prompt and parser with `LangChain` and `LCEL`.\n",
        "\n",
        "You can use a raw function to parse the output from the model.\n",
        "\n",


This guide assumes familiarity with the following concepts:

This is the simplest method for splitting text. This splits based on a given character sequence, which defaults to `"\n\n"`. Chunk length is measured by number of characters.

1. How the text is split: by single character separator.

2. How the chunk size is measured: by number of characters.

To obtain the string content directly, use `.splitText()`.

To create LangChain [Document](https://api.js.langchain.com/classes/langchain_core.documents.Document.html) objects (e.g., for use in downstream tasks), use `.createDocuments()`.

stdout

Document {

pageContent: "Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and th"... 839 more characters,

metadata: { loc: { lines: { from: 1, to: 17 } } }

import { CharacterTextSplitter } from "@langchain/textsplitters";

const rawData = await fs.readFileSync("../../../../examples/state_of_the_union.txt");

const stateOfTheUnion = rawData.toString();

const textSplitter = new CharacterTextSplitter({

const texts = await textSplitter.createDocuments([stateOfTheUnion]);

You can also propagate metadata associated with each document to the output chunks:

Document {

pageContent: "Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and th"... 839 more characters,

metadata: { document: 1, loc: { lines: { from: 1, to: 17 } } }

const metadatas = [{ document: 1 }, { document: 2 }];

const documents = await textSplitter.createDocuments(

To obtain the string content directly, use `.splitText()`:

"Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and th"... 839 more characters

const chunks = await textSplitter.splitText(stateOfTheUnion);

You've now learned a method for splitting text by character.

Next, check out a [more advanced way of splitting by character](/docs/how_to/recursive_text_splitter), or the [full tutorial on retrieval-augmented generation](/docs/tutorials/rag).


```bash
[chain/start] [1:chain:AgentExecutor] Entering Chain run with input: {
  "input": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?"
}
[chain/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent] Entering Chain run with input: {
  "input": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
  "steps": []
}
[chain/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign] Entering Chain run with input: {
  "input": ""
}
[chain/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign > 4:chain:RunnableMap] Entering Chain run with input: {
  "input": ""
}
[chain/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign > 4:chain:RunnableMap > 5:chain:RunnableLambda] Entering Chain run with input: {
  "input": ""
}
[chain/end] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign > 4:chain:RunnableMap > 5:chain:RunnableLambda] [0ms] Exiting Chain run with output: {
  "output": []
}
[chain/end] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign > 4:chain:RunnableMap] [1ms] Exiting Chain run with output: {
  "agent_scratchpad": []
}
[chain/end] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 3:chain:RunnableAssign] [1ms] Exiting Chain run with output: {
  "input": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
  "steps": [],
  "agent_scratchpad": []
}
[chain/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 6:prompt:ChatPromptTemplate] Entering Chain run with input: {
  "input": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
  "steps": [],
  "agent_scratchpad": []
}
[chain/end] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 6:prompt:ChatPromptTemplate] [0ms] Exiting Chain run with output: {
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "prompt_values",
    "ChatPromptValue"
  ],
  "kwargs": {
    "messages": [
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "SystemMessage"
        ],
        "kwargs": {
          "content": "You are a helpful assistant",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      },
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "HumanMessage"
        ],
        "kwargs": {
          "content": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      }
    ]
  }
}
[llm/start] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 7:llm:ChatAnthropic] Entering LLM run with input: {
  "messages": [
    [
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "SystemMessage"
        ],
        "kwargs": {
          "content": "You are a helpful assistant",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      },
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "HumanMessage"
        ],
        "kwargs": {
          "content": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      }
    ]
  ]
}
[llm/start] [1:llm:ChatAnthropic] Entering LLM run with input: {
  "messages": [
    [
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "SystemMessage"
        ],
        "kwargs": {
          "content": "You are a helpful assistant",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      },
      {
        "lc": 1,
        "type": "constructor",
        "id": [
          "langchain_core",
          "messages",
          "HumanMessage"
        ],
        "kwargs": {
          "content": "Who directed the 2023 film Oppenheimer and what is their age? What is their age in days (assume 365 days per year)?",
          "additional_kwargs": {},
          "response_metadata": {}
        }
      }
    ]
  ]
}
[llm/end] [1:chain:AgentExecutor > 2:chain:ToolCallingAgent > 7:llm:ChatAnthropic] [1.98s] Exiting LLM run with output: {
  "generations": [
    [
      {
        "text": "",
        "message": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain_core",
            "messages",
            "AIMessageChunk"
          ],
          "kwargs": {
            "content": [
              {
                "type": "tool_use",
                "id": "toolu_01NUVejujVo2y8WGVtZ49KAN",
                "name": "tavily_search_results_json",
                "input": {
                  "input": "Oppenheimer 2023 film director age"
                }
              }
            ],
            "additional_kwargs": {
              "id": "msg_015MqAHr84dBCAqBgjou41Km",
              "type": "message",
              "role": "assistant",
              "model": "claude-3-sonnet-20240229",
              "stop_sequence": null,
              "usage": {
                "input_tokens": 409,
                "output_tokens": 68
              },
              "stop_reason": "tool_use"
            },
            "tool_call_chunks": [
              {
                "name": "tavily_search_results_json",
                "args": "{\"input\":\"Oppenheimer 2023 film director age\"}",
                "id": "toolu_01NUVejujVo2y8WGVtZ49KAN",
                "index": 0
              }
            ],
            "tool_calls": [
              {
                "name": "tavily_search_results_json",
                "args": {
                  "input": "Oppenheimer 2023 film director age"
                },
                "id": "toolu_01NUVejujVo2y8WGVtZ49KAN"
              }
            ],
            "invalid_tool_calls": [],
            "response_metadata": {}
          }
        }
      }
    ]
  ]
}
[llm/end] [1:llm:ChatAnthropic] [1.98s] Exiting LLM run with output: {
  "generations": [
    [
      {
        "text": "",
        "message": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain_core",
            "messages",
            "AIMessageChunk"
          ],
          "kwargs": {
            "content": [
              {
                "type": "tool_use",
                "id": "toolu_01NUVejujVo2y8WGVtZ49KAN",
                "name": "tavily_search_results_json",
                "input": {
                  "input": "Oppenheimer 2023 film director age"
                }
              }
            ],
            "additional_kwargs": {
              "id": "msg_015MqAHr84dBCAqBgjou41Km",
              "type": "message",
              "role": "assistant",
              "model": "claude-3-sonnet-20240229",
              "stop_sequence": null,
              "usage": {
                "input_tokens": 409,
                "output_tokens": 68
              },
              "stop_reason": "tool_use"
            },
            "tool_call_chunks": [
              {
                "name": "tavily_search_results_json",
                "args": "{\"input\":\"Oppenheimer 2023 film director age\"}",


"execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import { ConsoleCallbackHandler } from \"@langchain/core/tracers/console\";\n",
    "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
    "import { ChatAnthropic } from \"@langchain/anthropic\";\n",
    "\n",
    "const handler = new ConsoleCallbackHandler();\n",
    "\n",
    "const prompt = ChatPromptTemplate.fromTemplate(`What is 1 + {number}?`);\n",
    "const model = new ChatAnthropic({\n",
    "  model: \"claude-3-sonnet-20240229\",\n",
    "  callbacks: [handler],\n",
    "});\n",
    "\n",
    "const chain = prompt.pipe(model);\n",
    "\n",
    "await chain.invoke({ number: \"2\" });"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see that we only see events from the chat model run - none from the prompt or broader chain.\n",
    "\n",
    "## Next steps\n",
    "\n",
    "You've now learned how to pass callbacks into a constructor.\n",
    "\n",
    "Next, check out the other how-to guides in this section, such as how to create your own [custom callback handlers](/docs/how_to/custom_callbacks)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Deno",
   "language": "typescript",
   "name": "deno"
  },
  "language_info": {
   "file_extension": ".ts",
   "mimetype": "text/x.typescript",
   "name": "typescript",
   "nb_converter": "script",
   "pygments_lexer": "typescript",
   "version": "5.3.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}


---
sidebar_position: 2
---

# How to embed text data

:::info
Head to [Integrations](/docs/integrations/text_embedding) for documentation on built-in integrations with text embedding providers.
:::

:::info Prerequisites

This guide assumes familiarity with the following concepts:

- [Embeddings](/docs/concepts/#embedding-models)

:::

Embeddings create a vector representation of a piece of text. This is useful because it means we can think about text in the vector space, and do things like semantic search where we look for pieces of text that are most similar in the vector space.

The base Embeddings class in LangChain exposes two methods: one for embedding documents and one for embedding a query. The former takes as input multiple texts, while the latter takes a single text. The reason for having these as two separate methods is that some embedding providers have different embedding methods for documents (to be searched over) vs queries (the search query itself).

## Get started

Below is an example of how to use the OpenAI embeddings. Embeddings occasionally have different embedding methods for queries versus documents, so the embedding class exposes a `embedQuery` and `embedDocuments` method.

import IntegrationInstallTooltip from "@mdx_components/integration_install_tooltip.mdx";

<IntegrationInstallTooltip></IntegrationInstallTooltip>

```bash npm2yarn
npm install @langchain/openai @langchain/core
```

## Get started

```typescript
import { OpenAIEmbeddings } from "@langchain/openai";

const embeddings = new OpenAIEmbeddings();
```

## Embed queries

```typescript
const res = await embeddings.embedQuery("Hello world");
/*
[
   -0.004845875,   0.004899438,  -0.016358767,  -0.024475135, -0.017341806,
    0.012571548,  -0.019156644,   0.009036391,  -0.010227379, -0.026945334,
    0.022861943,   0.010321903,  -0.023479493, -0.0066544134,  0.007977734,
   0.0026371893,   0.025206111,  -0.012048521,   0.012943339,  0.013094575,
   -0.010580265,  -0.003509951,   0.004070787,   0.008639394, -0.020631202,
  ... 1511 more items
]
*/
```

## Embed documents

```typescript
const documentRes = await embeddings.embedDocuments(["Hello world", "Bye bye"]);
/*
[
  [
    -0.004845875,   0.004899438,  -0.016358767,  -0.024475135, -0.017341806,
      0.012571548,  -0.019156644,   0.009036391,  -0.010227379, -0.026945334,
      0.022861943,   0.010321903,  -0.023479493, -0.0066544134,  0.007977734,
    0.0026371893,   0.025206111,  -0.012048521,   0.012943339,  0.013094575,
    -0.010580265,  -0.003509951,   0.004070787,   0.008639394, -0.020631202,
    ... 1511 more items
  ]
  [
      -0.009446913,  -0.013253193,   0.013174579,  0.0057552797,  -0.038993083,
      0.0077763423,    -0.0260478, -0.0114384955, -0.0022683728,  -0.016509168,
      0.041797023,    0.01787183,    0.00552271, -0.0049789557,   0.018146982,
      -0.01542166,   0.033752076,   0.006112323,   0.023872782,  -0.016535373,
      -0.006623321,   0.016116094, -0.0061090477, -0.0044155475,  -0.016627092,
    ... 1511 more items
  ]
]
*/
```

## Next steps

You've now learned how to use embeddings models with queries and text.

Next, check out how to [avoid excessively recomputing embeddings with caching](/docs/how_to/caching_embeddings), or the [full tutorial on retrieval-augmented generation](/docs/tutorials/rag).


{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 1\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# How to add memory to chatbots\n",
    "\n",
    "A key feature of chatbots is their ability to use content of previous conversation turns as context. This state management can take several forms, including:\n",
    "\n",
    "- Simply stuffing previous messages into a chat model prompt.\n",
    "- The above, but trimming old messages to reduce the amount of distracting information the model has to deal with.\n",
    "- More complex modifications like synthesizing summaries for long running conversations.\n",
    "\n",
    "We'll go into more detail on a few techniques below!\n",
    "\n",
    ":::note\n",
    "\n",
    "This how-to guide previously built a chatbot using [RunnableWithMessageHistory](https://v03.api.js.langchain.com/classes/_langchain_core.runnables.RunnableWithMessageHistory.html). You can access this version of the tutorial in the [v0.2 docs](https://js.langchain.com/v0.2/docs/how_to/chatbots_memory/).\n",
    "\n",
    "The LangGraph implementation offers a number of advantages over `RunnableWithMessageHistory`, including the ability to persist arbitrary components of an application's state (instead of only messages).\n",
    "\n",
    ":::\n",
    "\n",
    "## Setup\n",
    "\n",
    "You'll need to install a few packages, select your chat model, and set its enviroment variable.\n",
    "\n",
    "```{=mdx}\n",
    "import Npm2Yarn from \"@theme/Npm2Yarn\"\n",
    "\n",
    "<Npm2Yarn>\n",
    "  @langchain/core @langchain/langgraph\n",
    "</Npm2Yarn>\n",
    "```\n",
    "\n",
    "Let's set up a chat model that we'll use for the below examples.\n",
    "\n",
    "```{=mdx}\n",
    "import ChatModelTabs from \"@theme/ChatModelTabs\";\n",
    "\n",
    "<ChatModelTabs />\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Message passing\n",
    "\n",
    "The simplest form of memory is simply passing chat history messages into a chain. Here's an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "// @lc-docs-hide-cell\n",
    "\n",
    "import { ChatOpenAI } from \"@langchain/openai\";\n",
    "\n",
    "const llm = new ChatOpenAI({ model: \"gpt-4o\" })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AIMessage {\n",
      "  \"id\": \"chatcmpl-ABSxUXVIBitFRBh9MpasB5jeEHfCA\",\n",
      "  \"content\": \"I said \\\"J'adore la programmation,\\\" which means \\\"I love programming\\\" in French.\",\n",
      "  \"additional_kwargs\": {},\n",
      "  \"response_metadata\": {\n",
      "    \"tokenUsage\": {\n",
      "      \"completionTokens\": 18,\n",
      "      \"promptTokens\": 58,\n",
      "      \"totalTokens\": 76\n",
      "    },\n",
      "    \"finish_reason\": \"stop\",\n",
      "    \"system_fingerprint\": \"fp_e375328146\"\n",
      "  },\n",
      "  \"tool_calls\": [],\n",
      "  \"invalid_tool_calls\": [],\n",
      "  \"usage_metadata\": {\n",
      "    \"input_tokens\": 58,\n",
      "    \"output_tokens\": 18,\n",
      "    \"total_tokens\": 76\n",
      "  }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "import { HumanMessage, AIMessage } from \"@langchain/core/messages\";\n",
    "import {\n",
    "  ChatPromptTemplate,\n",
    "  MessagesPlaceholder,\n",
    "} from \"@langchain/core/prompts\";\n",
    "\n",
    "const prompt = ChatPromptTemplate.fromMessages([\n",
    "  [\n",
    "    \"system\",\n",
    "    \"You are a helpful assistant. Answer all questions to the best of your ability.\",\n",
    "  ],\n",
    "  new MessagesPlaceholder(\"messages\"),\n",
    "]);\n",
    "\n",
    "const chain = prompt.pipe(llm);\n",
    "\n",
    "await chain.invoke({\n",
    "  messages: [\n",
    "    new HumanMessage(\n",
    "      \"Translate this sentence from English to French: I love programming.\"\n",
    "    ),\n",
    "    new AIMessage(\"J'adore la programmation.\"),\n",
    "    new HumanMessage(\"What did you just say?\"),\n",
    "  ],\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that by passing the previous conversation into a chain, it can use it as context to answer questions. This is the basic concept underpinning chatbot memory - the rest of the guide will demonstrate convenient techniques for passing or reformatting messages."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Automatic history management\n",
    "\n",
    "The previous examples pass messages to the chain (and model) explicitly. This is a completely acceptable approach, but it does require external management of new messages. LangChain also provides a way to build applications that have memory using LangGraph's persistence. You can enable persistence in LangGraph applications by providing a `checkpointer` when compiling the graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "import { START, END, MessagesAnnotation, StateGraph, MemorySaver } from \"@langchain/langgraph\";\n",
    "\n",
    "\n",
    "// Define the function that calls the model\n",
    "const callModel = async (state: typeof MessagesAnnotation.State) => {\n",
    "  const systemPrompt = \n",
    "    \"You are a helpful assistant. \" +\n",
    "    \"Answer all questions to the best of your ability.\";\n",
    "  const messages = [{ role: \"system\", content: systemPrompt }, ...state.messages];\n",
    "  const response = await llm.invoke(messages);\n",
    "  return { messages: response };\n",
    "};\n",
    "\n",
    "const workflow = new StateGraph(MessagesAnnotation)\n",
    "// Define the node and edge\n",
    "  .addNode(\"model\", callModel)\n",
    "  .addEdge(START, \"model\")\n",
    "  .addEdge(\"model\", END);\n",
    "\n",
    "// Add simple in-memory checkpointer\n",
    "// highlight-start\n",
    "const memory = new MemorySaver();\n",
    "const app = workflow.compile({ checkpointer: memory });\n",
    "// highlight-end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " We'll pass the latest input to the conversation here and let the LangGraph keep track of the conversation history using the checkpointer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  messages: [\n",
      "    HumanMessage {\n",
      "      \"id\": \"227b82a9-4084-46a5-ac79-ab9a3faa140e\",\n",
      "      \"content\": \"Translate to French: I love programming.\",\n",
      "      \"additional_kwargs\": {},\n",
      "      \"response_metadata\": {}\n",
      "    },\n",
      "    AIMessage {\n",
      "      \"id\": \"chatcmpl-ABSxVrvztgnasTeMSFbpZQmyYqjJZ\",\n",


"We can use this same pattern in other ways too. For example, we could use an additional LLM call to generate a summary of the conversation before calling our app. Let's recreate our chat history:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "const demoEphemeralChatHistory2 = [\n",
    "  { role: \"user\", content: \"Hey there! I'm Nemo.\" },\n",
    "  { role: \"assistant\", content: \"Hello!\" },\n",
    "  { role: \"user\", content: \"How are you today?\" },\n",
    "  { role: \"assistant\", content: \"Fine thanks!\" },\n",
    "];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And now, let's update the model-calling function to distill previous interactions into a summary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "import { START, END, MessagesAnnotation, StateGraph, MemorySaver } from \"@langchain/langgraph\";\n",
    "import { RemoveMessage } from \"@langchain/core/messages\";\n",
    "\n",
    "\n",
    "// Define the function that calls the model\n",
    "const callModel3 = async (state: typeof MessagesAnnotation.State) => {\n",
    "  const systemPrompt = \n",
    "    \"You are a helpful assistant. \" +\n",
    "    \"Answer all questions to the best of your ability. \" +\n",
    "    \"The provided chat history includes a summary of the earlier conversation.\";\n",
    "  const systemMessage = { role: \"system\", content: systemPrompt };\n",
    "  const messageHistory = state.messages.slice(0, -1); // exclude the most recent user input\n",
    "  \n",
    "  // Summarize the messages if the chat history reaches a certain size\n",
    "  if (messageHistory.length >= 4) {\n",
    "    const lastHumanMessage = state.messages[state.messages.length - 1];\n",
    "    // Invoke the model to generate conversation summary\n",
    "    const summaryPrompt = \n",
    "      \"Distill the above chat messages into a single summary message. \" +\n",
    "      \"Include as many specific details as you can.\";\n",
    "    const summaryMessage = await llm.invoke([\n",
    "      ...messageHistory,\n",
    "      { role: \"user\", content: summaryPrompt }\n",
    "    ]);\n",
    "\n",
    "    // Delete messages that we no longer want to show up\n",
    "    const deleteMessages = state.messages.map(m => new RemoveMessage({ id: m.id }));\n",
    "    // Re-add user message\n",
    "    const humanMessage = { role: \"user\", content: lastHumanMessage.content };\n",
    "    // Call the model with summary & response\n",
    "    const response = await llm.invoke([systemMessage, summaryMessage, humanMessage]);\n",
    "    return { messages: [summaryMessage, humanMessage, response, ...deleteMessages] };\n",
    "  } else {\n",
    "    const response = await llm.invoke([systemMessage, ...state.messages]);\n",
    "    return { messages: response };\n",
    "  }\n",
    "};\n",
    "\n",
    "const workflow3 = new StateGraph(MessagesAnnotation)\n",
    "  // Define the node and edge\n",
    "  .addNode(\"model\", callModel3)\n",
    "  .addEdge(START, \"model\")\n",
    "  .addEdge(\"model\", END);\n",
    "\n",
    "// Add simple in-memory checkpointer\n",
    "const app3 = workflow3.compile({ checkpointer: new MemorySaver() });"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see if it remembers the name we gave it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  messages: [\n",
      "    AIMessage {\n",
      "      \"id\": \"chatcmpl-ABSxXjFDj6WRo7VLSneBtlAxUumPE\",\n",
      "      \"content\": \"Nemo greeted the assistant and asked how it was doing, to which the assistant responded that it was fine.\",\n",
      "      \"additional_kwargs\": {},\n",
      "      \"response_metadata\": {\n",
      "        \"tokenUsage\": {\n",
      "          \"completionTokens\": 22,\n",
      "          \"promptTokens\": 60,\n",
      "          \"totalTokens\": 82\n",
      "        },\n",
      "        \"finish_reason\": \"stop\",\n",
      "        \"system_fingerprint\": \"fp_e375328146\"\n",
      "      },\n",
      "      \"tool_calls\": [],\n",
      "      \"invalid_tool_calls\": [],\n",
      "      \"usage_metadata\": {\n",
      "        \"input_tokens\": 60,\n",
      "        \"output_tokens\": 22,\n",
      "        \"total_tokens\": 82\n",
      "      }\n",
      "    },\n",
      "    HumanMessage {\n",
      "      \"id\": \"8b1309b7-c09e-47fb-9ab3-34047f6973e3\",\n",
      "      \"content\": \"What did I say my name was?\",\n",
      "      \"additional_kwargs\": {},\n",
      "      \"response_metadata\": {}\n",
      "    },\n",
      "    AIMessage {\n",
      "      \"id\": \"chatcmpl-ABSxYAQKiBsQ6oVypO4CLFDsi1HRH\",\n",
      "      \"content\": \"You mentioned that your name is Nemo.\",\n",
      "      \"additional_kwargs\": {},\n",
      "      \"response_metadata\": {\n",
      "        \"tokenUsage\": {\n",
      "          \"completionTokens\": 8,\n",
      "          \"promptTokens\": 73,\n",
      "          \"totalTokens\": 81\n",
      "        },\n",
      "        \"finish_reason\": \"stop\",\n",
      "        \"system_fingerprint\": \"fp_52a7f40b0b\"\n",
      "      },\n",
      "      \"tool_calls\": [],\n",
      "      \"invalid_tool_calls\": [],\n",
      "      \"usage_metadata\": {\n",
      "        \"input_tokens\": 73,\n",
      "        \"output_tokens\": 8,\n",
      "        \"total_tokens\": 81\n",
      "      }\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "await app3.invoke(\n",
    "  {\n",
    "    messages: [\n",
    "      ...demoEphemeralChatHistory2,\n",
    "      { role: \"user\", content: \"What did I say my name was?\" }\n",
    "    ]\n",
    "  },\n",
    "  {\n",
    "    configurable: { thread_id: \"4\" }\n",
    "  }\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that invoking the app again will keep accumulating the history until it reaches the specified number of messages (four in our case). At that point we will generate another summary generated from the initial summary plus new messages and so on."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Deno",
   "language": "typescript",
   "name": "deno"
  },
  "language_info": {
   "codemirror_mode": {
    "mode": "typescript",
    "name": "javascript",
    "typescript": true
   },
   "file_extension": ".ts",
   "mimetype": "text/typescript",
   "name": "typescript",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}


# How to write a custom retriever class

:::info Prerequisites

This guide assumes familiarity with the following concepts:

- [Retrievers](/docs/concepts/#retrievers)

:::

To create your own retriever, you need to extend the [`BaseRetriever`](https://api.js.langchain.com/classes/langchain_core.retrievers.BaseRetriever.html) class
and implement a `_getRelevantDocuments` method that takes a `string` as its first parameter (and an optional `runManager` for tracing).
This method should return an array of `Document`s fetched from some source. This process can involve calls to a database, to the web using `fetch`, or any other source.
Note the underscore before `_getRelevantDocuments()`. The base class wraps the non-prefixed version in order to automatically handle tracing of the original call.

Here's an example of a custom retriever that returns static documents:

```ts
import {
  BaseRetriever,
  type BaseRetrieverInput,
} from "@langchain/core/retrievers";
import type { CallbackManagerForRetrieverRun } from "@langchain/core/callbacks/manager";
import { Document } from "@langchain/core/documents";

export interface CustomRetrieverInput extends BaseRetrieverInput {}

export class CustomRetriever extends BaseRetriever {
  lc_namespace = ["langchain", "retrievers"];

  constructor(fields?: CustomRetrieverInput) {
    super(fields);
  }

  async _getRelevantDocuments(
    query: string,
    runManager?: CallbackManagerForRetrieverRun
  ): Promise<Document[]> {
    // Pass `runManager?.getChild()` when invoking internal runnables to enable tracing
    // const additionalDocs = await someOtherRunnable.invoke(params, runManager?.getChild());
    return [
      // ...additionalDocs,
      new Document({
        pageContent: `Some document pertaining to ${query}`,
        metadata: {},
      }),
      new Document({
        pageContent: `Some other document pertaining to ${query}`,
        metadata: {},
      }),
    ];
  }
}
```

Then, you can call `.invoke()` as follows:

```ts
const retriever = new CustomRetriever({});

await retriever.invoke("LangChain docs");
```

```
[
  Document {
    pageContent: 'Some document pertaining to LangChain docs',
    metadata: {}
  },
  Document {
    pageContent: 'Some other document pertaining to LangChain docs',
    metadata: {}
  }
]
```

## Next steps

You've now seen an example of implementing your own custom retriever.

Next, check out the individual sections for deeper dives on specific retrievers, or the [broader tutorial on RAG](/docs/tutorials/rag).


{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# How to return sources\n",
        "\n",
        ":::info Prerequisites\n",
        "\n",
        "This guide assumes familiarity with the following:\n",
        "\n",
        "- [Retrieval-augmented generation](/docs/tutorials/rag/)\n",
        "\n",
        ":::\n",
        "\n",
        "Often in Q&A applications it’s important to show users the sources that were used to generate the answer. The simplest way to do this is for the chain to return the Documents that were retrieved in each generation.\n",
        "\n",
        "We'll be using the [LLM Powered Autonomous Agents](https://lilianweng.github.io/posts/2023-06-23-agent/) blog post by Lilian Weng for retrieval content this notebook."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Setup\n",
        "### Dependencies\n",
        "\n",
        "We’ll use an OpenAI chat model and embeddings and a Memory vector store in this walkthrough, but everything shown here works with any [ChatModel](/docs/concepts/#chat-models) or [LLM](/docs/concepts#llms), [Embeddings](/docs/concepts#embedding-models), and [VectorStore](/docs/concepts#vectorstores) or [Retriever](/docs/concepts#retrievers).\n",
        "\n",
        "We’ll use the following packages:\n",
        "\n",
        "```bash\n",
        "npm install --save langchain @langchain/openai cheerio\n",
        "```\n",
        "\n",
        "We need to set environment variable `OPENAI_API_KEY`:\n",
        "\n",
        "```bash\n",
        "export OPENAI_API_KEY=YOUR_KEY\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### LangSmith\n",
        "\n",
        "Many of the applications you build with LangChain will contain multiple steps with multiple invocations of LLM calls. As these applications get more and more complex, it becomes crucial to be able to inspect what exactly is going on inside your chain or agent. The best way to do this is with [LangSmith](https://smith.langchain.com/).\n",
        "\n",
        "Note that LangSmith is not needed, but it is helpful. If you do want to use LangSmith, after you sign up at the link above, make sure to set your environment variables to start logging traces:\n",
        "\n",
        "\n",
        "```bash\n",
        "export LANGCHAIN_TRACING_V2=true\n",
        "export LANGCHAIN_API_KEY=YOUR_KEY\n",
        "\n",
        "# Reduce tracing latency if you are not in a serverless environment\n",
        "# export LANGCHAIN_CALLBACKS_BACKGROUND=true\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Chain without sources\n",
        "\n",
        "Here is the Q&A app we built over the [LLM Powered Autonomous Agents](https://lilianweng.github.io/posts/2023-06-23-agent/) blog post by Lilian Weng in the [Quickstart](/docs/tutorials/qa_chat_history/)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import \"cheerio\";\n",
        "import { CheerioWebBaseLoader } from \"@langchain/community/document_loaders/web/cheerio\";\n",
        "import { RecursiveCharacterTextSplitter } from \"langchain/text_splitter\";\n",
        "import { MemoryVectorStore } from \"langchain/vectorstores/memory\"\n",
        "import { OpenAIEmbeddings, ChatOpenAI } from \"@langchain/openai\";\n",
        "import { pull } from \"langchain/hub\";\n",
        "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
        "import { formatDocumentsAsString } from \"langchain/util/document\";\n",
        "import { RunnableSequence, RunnablePassthrough } from \"@langchain/core/runnables\";\n",
        "import { StringOutputParser } from \"@langchain/core/output_parsers\";\n",
        "\n",
        "const loader = new CheerioWebBaseLoader(\n",
        "  \"https://lilianweng.github.io/posts/2023-06-23-agent/\"\n",
        ");\n",
        "\n",
        "const docs = await loader.load();\n",
        "\n",
        "const textSplitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });\n",
        "const splits = await textSplitter.splitDocuments(docs);\n",
        "const vectorStore = await MemoryVectorStore.fromDocuments(splits, new OpenAIEmbeddings());\n",
        "\n",
        "// Retrieve and generate using the relevant snippets of the blog.\n",
        "const retriever = vectorStore.asRetriever();\n",
        "const prompt = await pull<ChatPromptTemplate>(\"rlm/rag-prompt\");\n",
        "const llm = new ChatOpenAI({ model: \"gpt-3.5-turbo\", temperature: 0 });\n",
        "\n",
        "const ragChain = RunnableSequence.from([\n",
        "  {\n",
        "    context: retriever.pipe(formatDocumentsAsString),\n",
        "    question: new RunnablePassthrough(),\n",
        "  },\n",
        "  prompt,\n",
        "  llm,\n",
        "  new StringOutputParser()\n",
        "]);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's see what this prompt actually looks like:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\n",
            "Question: {question} \n",
            "Context: {context} \n",
            "Answer:\n"
          ]
        }
      ],
      "source": [
        "console.log(prompt.promptMessages.map((msg) => msg.prompt.template).join(\"\\n\"));"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "\u001b[32m\"Task decomposition is a technique used to break down complex tasks into smaller and simpler steps. T\"\u001b[39m... 254 more characters"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await ragChain.invoke(\"What is task decomposition?\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Adding sources\n",
        "\n",
        "With LCEL, we can easily pass the retrieved documents through the chain and return them in the final response:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{\n",
              "  question: \u001b[32m\"What is Task Decomposition\"\u001b[39m,\n",
              "  context: [\n",
              "    Document {\n",
              "      pageContent: \u001b[32m\"Fig. 1. Overview of a LLM-powered autonomous agent system.\\n\"\u001b[39m +\n",
              "        \u001b[32m\"Component One: Planning#\\n\"\u001b[39m +\n",
              "        \u001b[32m\"A complicated ta\"\u001b[39m... 898 more characters,\n",
              "      metadata: {\n",
              "        source: \u001b[32m\"https://lilianweng.github.io/posts/2023-06-23-agent/\"\u001b[39m,\n",
              "        loc: { lines: \u001b[36m[Object]\u001b[39m }\n",
              "      }\n",
              "    },\n",
              "    Document {\n",


"      pageContent: \u001b[32m'Task decomposition can be done (1) by LLM with simple prompting like \"Steps for XYZ.\\\\n1.\", \"What are'\u001b[39m... 887 more characters,\n",
              "      metadata: {\n",
              "        source: \u001b[32m\"https://lilianweng.github.io/posts/2023-06-23-agent/\"\u001b[39m,\n",
              "        loc: { lines: \u001b[36m[Object]\u001b[39m }\n",
              "      }\n",
              "    },\n",
              "    Document {\n",
              "      pageContent: \u001b[32m\"Agent System Overview\\n\"\u001b[39m +\n",
              "        \u001b[32m\"                \\n\"\u001b[39m +\n",
              "        \u001b[32m\"                    Component One: Planning\\n\"\u001b[39m +\n",
              "        \u001b[32m\"                 \"\u001b[39m... 850 more characters,\n",
              "      metadata: {\n",
              "        source: \u001b[32m\"https://lilianweng.github.io/posts/2023-06-23-agent/\"\u001b[39m,\n",
              "        loc: { lines: \u001b[36m[Object]\u001b[39m }\n",
              "      }\n",
              "    },\n",
              "    Document {\n",
              "      pageContent: \u001b[32m\"Resources:\\n\"\u001b[39m +\n",
              "        \u001b[32m\"1. Internet access for searches and information gathering.\\n\"\u001b[39m +\n",
              "        \u001b[32m\"2. Long Term memory management\"\u001b[39m... 456 more characters,\n",
              "      metadata: {\n",
              "        source: \u001b[32m\"https://lilianweng.github.io/posts/2023-06-23-agent/\"\u001b[39m,\n",
              "        loc: { lines: \u001b[36m[Object]\u001b[39m }\n",
              "      }\n",
              "    }\n",
              "  ],\n",
              "  answer: \u001b[32m\"Task decomposition is a technique used to break down complex tasks into smaller and simpler steps fo\"\u001b[39m... 230 more characters\n",
              "}"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import {\n",
        "  RunnableMap,\n",
        "  RunnablePassthrough,\n",
        "  RunnableSequence\n",
        "} from \"@langchain/core/runnables\";\n",
        "import { formatDocumentsAsString } from \"langchain/util/document\";\n",
        "\n",
        "const ragChainWithSources = RunnableMap.from({\n",
        "  // Return raw documents here for now since we want to return them at\n",
        "  // the end - we'll format in the next step of the chain\n",
        "  context: retriever,\n",
        "  question: new RunnablePassthrough(),\n",
        "}).assign({\n",
        "  answer: RunnableSequence.from([\n",
        "    (input) => {\n",
        "      return {\n",
        "        // Now we format the documents as strings for the prompt\n",
        "        context: formatDocumentsAsString(input.context),\n",
        "        question: input.question\n",
        "      };\n",
        "    },\n",
        "    prompt,\n",
        "    llm,\n",
        "    new StringOutputParser()\n",
        "  ]),\n",
        "})\n",
        "\n",
        "await ragChainWithSources.invoke(\"What is Task Decomposition\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Check out the [LangSmith trace](https://smith.langchain.com/public/c3753531-563c-40d4-a6bf-21bfe8741d10/r) here to see the internals of the chain.\n",
        "\n",
        "## Next steps\n",
        "\n",
        "You've now learned how to return sources from your QA chains.\n",
        "\n",
        "Next, check out some of the other guides around RAG, such as [how to stream responses](/docs/how_to/qa_streaming)."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Deno",
      "language": "typescript",
      "name": "deno"
    },
    "language_info": {
      "file_extension": ".ts",
      "mimetype": "text/x.typescript",
      "name": "typescript",
      "nb_converter": "script",
      "pygments_lexer": "typescript",
      "version": "5.3.3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}


"  documents, new OpenAIEmbeddings(),\n",
    ");\n",
    "\n",
    "const retriever = vectorstore.asRetriever({\n",
    "  k: 1,\n",
    "  searchType: \"similarity\",\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9ba737ac-43a2-4a6f-b855-5bd0305017f1",
   "metadata": {},
   "source": [
    "We next create a pre-built [LangGraph agent](/docs/how_to/migrate_agent/) and provide it with the tool:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c939cf2a-60e9-4afd-8b47-84d76ccb13f5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AGENT: AIMessage {\n",
      "  \"id\": \"chatcmpl-9m9RIN1GQVeXcrVdp0lNBTcZFVHb9\",\n",
      "  \"content\": \"\",\n",
      "  \"additional_kwargs\": {\n",
      "    \"tool_calls\": [\n",
      "      {\n",
      "        \"id\": \"call_n30LPDbegmytrj5GdUxZt9xn\",\n",
      "        \"type\": \"function\",\n",
      "        \"function\": \"[Object]\"\n",
      "      }\n",
      "    ]\n",
      "  },\n",
      "  \"response_metadata\": {\n",
      "    \"tokenUsage\": {\n",
      "      \"completionTokens\": 17,\n",
      "      \"promptTokens\": 52,\n",
      "      \"totalTokens\": 69\n",
      "    },\n",
      "    \"finish_reason\": \"tool_calls\"\n",
      "  },\n",
      "  \"tool_calls\": [\n",
      "    {\n",
      "      \"name\": \"pet_info_retriever\",\n",
      "      \"args\": {\n",
      "        \"input\": \"dogs\"\n",
      "      },\n",
      "      \"type\": \"tool_call\",\n",
      "      \"id\": \"call_n30LPDbegmytrj5GdUxZt9xn\"\n",
      "    }\n",
      "  ],\n",
      "  \"invalid_tool_calls\": [],\n",
      "  \"usage_metadata\": {\n",
      "    \"input_tokens\": 52,\n",
      "    \"output_tokens\": 17,\n",
      "    \"total_tokens\": 69\n",
      "  }\n",
      "}\n",
      "----\n",
      "TOOLS: ToolMessage {\n",
      "  \"content\": \"[{\\\"pageContent\\\":\\\"Dogs are great companions, known for their loyalty and friendliness.\\\",\\\"metadata\\\":{}}]\",\n",
      "  \"name\": \"pet_info_retriever\",\n",
      "  \"additional_kwargs\": {},\n",
      "  \"response_metadata\": {},\n",
      "  \"tool_call_id\": \"call_n30LPDbegmytrj5GdUxZt9xn\"\n",
      "}\n",
      "----\n",
      "AGENT: AIMessage {\n",
      "  \"id\": \"chatcmpl-9m9RJ3TT3ITfv6R0Tb7pcrNOUtnm8\",\n",
      "  \"content\": \"Dogs are known for being great companions, known for their loyalty and friendliness.\",\n",
      "  \"additional_kwargs\": {},\n",
      "  \"response_metadata\": {\n",
      "    \"tokenUsage\": {\n",
      "      \"completionTokens\": 18,\n",
      "      \"promptTokens\": 104,\n",
      "      \"totalTokens\": 122\n",
      "    },\n",
      "    \"finish_reason\": \"stop\"\n",
      "  },\n",
      "  \"tool_calls\": [],\n",
      "  \"invalid_tool_calls\": [],\n",
      "  \"usage_metadata\": {\n",
      "    \"input_tokens\": 104,\n",
      "    \"output_tokens\": 18,\n",
      "    \"total_tokens\": 122\n",
      "  }\n",
      "}\n",
      "----\n"
     ]
    }
   ],
   "source": [
    "import { createReactAgent } from \"@langchain/langgraph/prebuilt\";\n",
    "\n",
    "const tools = [\n",
    "  retriever.asTool({\n",
    "    name: \"pet_info_retriever\",\n",
    "    description: \"Get information about pets.\",\n",
    "    schema: z.string(),\n",
    "  })\n",
    "];\n",
    "\n",
    "const agent = createReactAgent({ llm: llm, tools });\n",
    "\n",
    "const stream = await agent.stream({\"messages\": [[\"human\", \"What are dogs known for?\"]]});\n",
    "\n",
    "for await (const chunk of stream) {\n",
    "  // Log output from the agent or tools node\n",
    "  if (chunk.agent) {\n",
    "    console.log(\"AGENT:\", chunk.agent.messages[0]);\n",
    "  } else if (chunk.tools) {\n",
    "    console.log(\"TOOLS:\", chunk.tools.messages[0]);\n",
    "  }\n",
    "  console.log(\"----\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96f2ac9c-36f4-4b7a-ae33-f517734c86aa",
   "metadata": {},
   "source": [
    "This [LangSmith trace](https://smith.langchain.com/public/5e141617-ae82-44af-8fe0-b64dbd007826/r) shows what's going on under the hood for the above run.\n",
    "\n",
    "Going further, we can even create a tool from a full [RAG chain](/docs/tutorials/rag/):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bea518c9-c711-47c2-b8cc-dbd102f71f09",
   "metadata": {},
   "outputs": [],
   "source": [
    "import { StringOutputParser } from \"@langchain/core/output_parsers\";\n",
    "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
    "import { RunnableSequence } from \"@langchain/core/runnables\";\n",
    "\n",
    "const SYSTEM_TEMPLATE = `\n",
    "You are an assistant for question-answering tasks.\n",
    "Use the below context to answer the question. If\n",
    "you don't know the answer, say you don't know.\n",
    "Use three sentences maximum and keep the answer\n",
    "concise.\n",
    "\n",
    "Answer in the style of {answer_style}.\n",
    "\n",
    "Context: {context}`;\n",
    "\n",
    "const prompt = ChatPromptTemplate.fromMessages([\n",
    "  [\"system\", SYSTEM_TEMPLATE],\n",
    "  [\"human\", \"{question}\"],\n",
    "]);\n",
    "\n",
    "const ragChain = RunnableSequence.from([\n",
    "  {\n",
    "    context: (input, config) => retriever.invoke(input.question, config),\n",
    "    question: (input) => input.question,\n",
    "    answer_style: (input) => input.answer_style,\n",
    "  },\n",
    "  prompt,\n",
    "  llm,\n",
    "  new StringOutputParser(),\n",
    "]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4570615b-8f96-4d97-ae01-1c08b14be584",
   "metadata": {},
   "source": [
    "Below we again invoke the agent. Note that the agent populates the required parameters in its `tool_calls`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "06409913-a2ad-400f-a202-7b8dd2ef483a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AGENT: AIMessage {\n",


{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# How to pass callbacks in at runtime\n",
    "\n",
    ":::info Prerequisites\n",
    "\n",
    "This guide assumes familiarity with the following concepts:\n",
    "\n",
    "- [Callbacks](/docs/concepts/#callbacks)\n",
    "\n",
    ":::\n",
    "\n",
    "In many cases, it is advantageous to pass in handlers instead when running the object. When we pass through [`CallbackHandlers`](https://api.js.langchain.com/interfaces/langchain_core.callbacks_base.CallbackHandlerMethods.html) using the `callbacks` keyword arg when executing an run, those callbacks will be issued by all nested objects involved in the execution. For example, when a handler is passed through to an Agent, it will be used for all callbacks related to the agent and all the objects involved in the agent's execution, in this case, the Tools and LLM.\n",
    "\n",
    "This prevents us from having to manually attach the handlers to each individual nested object. Here's an example using LangChain's built-in [`ConsoleCallbackHandler`](https://api.js.langchain.com/classes/langchain_core.tracers_console.ConsoleCallbackHandler.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32m[chain/start]\u001b[39m [\u001b[90m\u001b[1m1:chain:RunnableSequence\u001b[22m\u001b[39m] Entering Chain run with input: {\n",
      "  \"number\": \"2\"\n",
      "}\n",
      "\u001b[32m[chain/start]\u001b[39m [\u001b[90m1:chain:RunnableSequence > \u001b[1m2:prompt:ChatPromptTemplate\u001b[22m\u001b[39m] Entering Chain run with input: {\n",
      "  \"number\": \"2\"\n",
      "}\n",
      "\u001b[36m[chain/end]\u001b[39m [\u001b[90m1:chain:RunnableSequence > \u001b[1m2:prompt:ChatPromptTemplate\u001b[22m\u001b[39m] [1ms] Exiting Chain run with output: {\n",
      "  \"lc\": 1,\n",
      "  \"type\": \"constructor\",\n",
      "  \"id\": [\n",
      "    \"langchain_core\",\n",
      "    \"prompt_values\",\n",
      "    \"ChatPromptValue\"\n",
      "  ],\n",
      "  \"kwargs\": {\n",
      "    \"messages\": [\n",
      "      {\n",
      "        \"lc\": 1,\n",
      "        \"type\": \"constructor\",\n",
      "        \"id\": [\n",
      "          \"langchain_core\",\n",
      "          \"messages\",\n",
      "          \"HumanMessage\"\n",
      "        ],\n",
      "        \"kwargs\": {\n",
      "          \"content\": \"What is 1 + 2?\",\n",
      "          \"additional_kwargs\": {},\n",
      "          \"response_metadata\": {}\n",
      "        }\n",
      "      }\n",
      "    ]\n",
      "  }\n",
      "}\n",
      "\u001b[32m[llm/start]\u001b[39m [\u001b[90m1:chain:RunnableSequence > \u001b[1m3:llm:ChatAnthropic\u001b[22m\u001b[39m] Entering LLM run with input: {\n",
      "  \"messages\": [\n",
      "    [\n",
      "      {\n",
      "        \"lc\": 1,\n",
      "        \"type\": \"constructor\",\n",
      "        \"id\": [\n",
      "          \"langchain_core\",\n",
      "          \"messages\",\n",
      "          \"HumanMessage\"\n",
      "        ],\n",
      "        \"kwargs\": {\n",
      "          \"content\": \"What is 1 + 2?\",\n",
      "          \"additional_kwargs\": {},\n",
      "          \"response_metadata\": {}\n",
      "        }\n",
      "      }\n",
      "    ]\n",
      "  ]\n",
      "}\n",
      "\u001b[36m[llm/end]\u001b[39m [\u001b[90m1:chain:RunnableSequence > \u001b[1m3:llm:ChatAnthropic\u001b[22m\u001b[39m] [766ms] Exiting LLM run with output: {\n",
      "  \"generations\": [\n",
      "    [\n",
      "      {\n",
      "        \"text\": \"1 + 2 = 3\",\n",
      "        \"message\": {\n",
      "          \"lc\": 1,\n",
      "          \"type\": \"constructor\",\n",
      "          \"id\": [\n",
      "            \"langchain_core\",\n",
      "            \"messages\",\n",
      "            \"AIMessage\"\n",
      "          ],\n",
      "          \"kwargs\": {\n",
      "            \"content\": \"1 + 2 = 3\",\n",
      "            \"tool_calls\": [],\n",
      "            \"invalid_tool_calls\": [],\n",
      "            \"additional_kwargs\": {\n",
      "              \"id\": \"msg_01SGGkFVbUbH4fK7JS7agerD\",\n",
      "              \"type\": \"message\",\n",
      "              \"role\": \"assistant\",\n",
      "              \"model\": \"claude-3-sonnet-20240229\",\n",
      "              \"stop_sequence\": null,\n",
      "              \"usage\": {\n",
      "                \"input_tokens\": 16,\n",
      "                \"output_tokens\": 13\n",
      "              },\n",
      "              \"stop_reason\": \"end_turn\"\n",
      "            },\n",
      "            \"response_metadata\": {\n",
      "              \"id\": \"msg_01SGGkFVbUbH4fK7JS7agerD\",\n",
      "              \"model\": \"claude-3-sonnet-20240229\",\n",
      "              \"stop_sequence\": null,\n",
      "              \"usage\": {\n",
      "                \"input_tokens\": 16,\n",
      "                \"output_tokens\": 13\n",
      "              },\n",
      "              \"stop_reason\": \"end_turn\"\n",
      "            }\n",
      "          }\n",
      "        }\n",
      "      }\n",
      "    ]\n",
      "  ],\n",
      "  \"llmOutput\": {\n",
      "    \"id\": \"msg_01SGGkFVbUbH4fK7JS7agerD\",\n",
      "    \"model\": \"claude-3-sonnet-20240229\",\n",
      "    \"stop_sequence\": null,\n",
      "    \"usage\": {\n",
      "      \"input_tokens\": 16,\n",
      "      \"output_tokens\": 13\n",
      "    },\n",
      "    \"stop_reason\": \"end_turn\"\n",
      "  }\n",
      "}\n",
      "\u001b[36m[chain/end]\u001b[39m [\u001b[90m\u001b[1m1:chain:RunnableSequence\u001b[22m\u001b[39m] [778ms] Exiting Chain run with output: {\n",
      "  \"lc\": 1,\n",
      "  \"type\": \"constructor\",\n",
      "  \"id\": [\n",
      "    \"langchain_core\",\n",
      "    \"messages\",\n",
      "    \"AIMessage\"\n",
      "  ],\n",
      "  \"kwargs\": {\n",
      "    \"content\": \"1 + 2 = 3\",\n",
      "    \"tool_calls\": [],\n",
      "    \"invalid_tool_calls\": [],\n",
      "    \"additional_kwargs\": {\n",
      "      \"id\": \"msg_01SGGkFVbUbH4fK7JS7agerD\",\n",
      "      \"type\": \"message\",\n",
      "      \"role\": \"assistant\",\n",
      "      \"model\": \"claude-3-sonnet-20240229\",\n",
      "      \"stop_sequence\": null,\n",
      "      \"usage\": {\n",
      "        \"input_tokens\": 16,\n",
      "        \"output_tokens\": 13\n",
      "      },\n",


# How to partially format prompt templates

:::info Prerequisites

This guide assumes familiarity with the following concepts:

- [Prompt templates](/docs/concepts/#prompt-templates)

:::

Like partially binding arguments to a function, it can make sense to "partial" a prompt template - e.g. pass in
a subset of the required values, as to create a new prompt template which expects only the remaining subset of values.

LangChain supports this in two ways:

1. Partial formatting with string values.
2. Partial formatting with functions that return string values.

In the examples below, we go over the motivations for both use cases as well as how to do it in LangChain.

## Partial with strings

One common use case for wanting to partial a prompt template is if you get access to some of the variables in a
prompt before others. For example, suppose you have a prompt template that requires two variables, `foo` and `baz`.
If you get the `foo` value early on in your chain, but the `baz` value later, it can be inconvenient to pass both variables all the way through the chain.
Instead, you can partial the prompt template with the `foo` value, and then pass the partialed prompt template along and just use that.
Below is an example of doing this:

```typescript
import { PromptTemplate } from "langchain/prompts";

const prompt = new PromptTemplate({
  template: "{foo}{bar}",
  inputVariables: ["foo", "bar"],
});

const partialPrompt = await prompt.partial({
  foo: "foo",
});

const formattedPrompt = await partialPrompt.format({
  bar: "baz",
});

console.log(formattedPrompt);

// foobaz
```

You can also just initialize the prompt with the partialed variables.

```typescript
const prompt = new PromptTemplate({
  template: "{foo}{bar}",
  inputVariables: ["bar"],
  partialVariables: {
    foo: "foo",
  },
});

const formattedPrompt = await prompt.format({
  bar: "baz",
});

console.log(formattedPrompt);

// foobaz
```

## Partial With Functions

You can also partial with a function. The use case for this is when you have a variable you know that you always want to fetch in a common way. A prime example of this is with date or time. Imagine you have a prompt which you always want to have the current date. You can't hard code it in the prompt, and passing it along with the other input variables can be tedious. In this case, it's very handy to be able to partial the prompt with a function that always returns the current date.

```typescript
const getCurrentDate = () => {
  return new Date().toISOString();
};

const prompt = new PromptTemplate({
  template: "Tell me a {adjective} joke about the day {date}",
  inputVariables: ["adjective", "date"],
});

const partialPrompt = await prompt.partial({
  date: getCurrentDate,
});

const formattedPrompt = await partialPrompt.format({
  adjective: "funny",
});

console.log(formattedPrompt);

// Tell me a funny joke about the day 2023-07-13T00:54:59.287Z
```

You can also just initialize the prompt with the partialed variables:

```typescript
const prompt = new PromptTemplate({
  template: "Tell me a {adjective} joke about the day {date}",
  inputVariables: ["adjective"],
  partialVariables: {
    date: getCurrentDate,
  },
});

const formattedPrompt = await prompt.format({
  adjective: "funny",
});

console.log(formattedPrompt);

// Tell me a funny joke about the day 2023-07-13T00:54:59.287Z
```

## Next steps

You've now learned how to partially apply variables to your prompt templates.

Next, check out the other how-to guides on prompt templates in this section, like [adding few-shot examples to your prompt templates](/docs/how_to/few_shot_examples_chat).


# How to generate multiple embeddings per document

:::info Prerequisites

This guide assumes familiarity with the following concepts:

- [Retrievers](/docs/concepts/#retrievers)
- [Text splitters](/docs/concepts/#text-splitters)
- [Retrieval-augmented generation (RAG)](/docs/tutorials/rag)

:::

Embedding different representations of an original document, then returning the original document when any of the representations result in a search hit, can allow you to
tune and improve your retrieval performance. LangChain has a base [`MultiVectorRetriever`](https://api.js.langchain.com/classes/langchain.retrievers_multi_vector.MultiVectorRetriever.html) designed to do just this!

A lot of the complexity lies in how to create the multiple vectors per document.
This guide covers some of the common ways to create those vectors and use the `MultiVectorRetriever`.

Some methods to create multiple vectors per document include:

- smaller chunks: split a document into smaller chunks, and embed those (e.g. the [`ParentDocumentRetriever`](/docs/how_to/parent_document_retriever))
- summary: create a summary for each document, embed that along with (or instead of) the document
- hypothetical questions: create hypothetical questions that each document would be appropriate to answer, embed those along with (or instead of) the document

Note that this also enables another method of adding embeddings - manually. This is great because you can explicitly add questions or queries that should lead to a document being recovered, giving you more control.

## Smaller chunks

Often times it can be useful to retrieve larger chunks of information, but embed smaller chunks.
This allows for embeddings to capture the semantic meaning as closely as possible, but for as much context as possible to be passed downstream.
NOTE: this is what the ParentDocumentRetriever does. Here we show what is going on under the hood.

import IntegrationInstallTooltip from "@mdx_components/integration_install_tooltip.mdx";

<IntegrationInstallTooltip></IntegrationInstallTooltip>

```bash npm2yarn
npm install @langchain/openai @langchain/community @langchain/core
```

import CodeBlock from "@theme/CodeBlock";
import SmallChunksExample from "@examples/retrievers/multi_vector_small_chunks.ts";

<CodeBlock language="typescript">{SmallChunksExample}</CodeBlock>

## Summary

Oftentimes a summary may be able to distill more accurately what a chunk is about, leading to better retrieval.
Here we show how to create summaries, and then embed those.

import SummaryExample from "@examples/retrievers/multi_vector_summary.ts";

<CodeBlock language="typescript">{SummaryExample}</CodeBlock>

## Hypothetical queries

An LLM can also be used to generate a list of hypothetical questions that could be asked of a particular document.
These questions can then be embedded and used to retrieve the original document:

import HypotheticalExample from "@examples/retrievers/multi_vector_hypothetical.ts";

<CodeBlock language="typescript">{HypotheticalExample}</CodeBlock>

## Next steps

You've now learned a few ways to generate multiple embeddings per document.

Next, check out the individual sections for deeper dives on specific retrievers, the [broader tutorial on RAG](/docs/tutorials/rag), or this section to learn how to
[create your own custom retriever over any data source](/docs/how_to/custom_retriever/).


# How to init any model in one line

import CodeBlock from "@theme/CodeBlock";

Many LLM applications let end users specify what model provider and model they want the application to be powered by.
This requires writing some logic to initialize different ChatModels based on some user configuration.
The `initChatModel()` helper method makes it easy to initialize a number of different model integrations without having to worry about import paths and class names.
Keep in mind this feature is only for chat models.

:::info Prerequisites

This guide assumes familiarity with the following concepts:

- [Chat models](/docs/concepts/#chat-models)

- [LangChain Expression Language (LCEL)](/docs/concepts#langchain-expression-language)

- [Tool calling](/docs/concepts#tools)

:::

:::caution Compatibility
**This feature is only intended to be used in Node environments. Use in non Node environments or with bundlers is not guaranteed to work and not officially supported.**

`initChatModel` requires `langchain>=0.2.11`. See [this guide](/docs/how_to/installation/#installing-integration-packages) for some considerations to take when upgrading.

See the [initChatModel()](https://api.js.langchain.com/functions/langchain.chat_models_universal.initChatModel.html) API reference for a full list of supported integrations.

Make sure you have the integration packages installed for any model providers you want to support. E.g. you should have `@langchain/openai` installed to init an OpenAI model.
:::

## Basic usage

import BasicExample from "@examples/models/chat/configurable/basic.ts";

<CodeBlock language="typescript">{BasicExample}</CodeBlock>

## Inferring model provider

For common and distinct model names `initChatModel()` will attempt to infer the model provider.
See the [API reference](https://api.js.langchain.com/functions/langchain.chat_models_universal.initChatModel.html) for a full list of inference behavior.
E.g. any model that starts with `gpt-3...` or `gpt-4...` will be inferred as using model provider `openai`.

import InferringProviderExample from "@examples/models/chat/configurable/inferring_model_provider.ts";

<CodeBlock language="typescript">{InferringProviderExample}</CodeBlock>

## Creating a configurable model

You can also create a runtime-configurable model by specifying `configurableFields`.
If you don't specify a `model` value, then "model" and "modelProvider" be configurable by default.

import ConfigurableModelExample from "@examples/models/chat/configurable/configurable_model.ts";

<CodeBlock language="typescript">{ConfigurableModelExample}</CodeBlock>

### Configurable model with default values

We can create a configurable model with default model values, specify which parameters are configurable, and add prefixes to configurable params:

import ConfigurableModelWithDefaultsExample from "@examples/models/chat/configurable/configurable_model_with_defaults.ts";

<CodeBlock language="typescript">
  {ConfigurableModelWithDefaultsExample}
</CodeBlock>

### Using a configurable model declaratively

We can call declarative operations like `bindTools`, `withStructuredOutput`, `withConfig`, etc. on a configurable model and chain a configurable model in the same way that we would a regularly instantiated chat model object.

import ConfigurableModelDeclarativelyExample from "@examples/models/chat/configurable/configurable_model_declaratively.ts";

<CodeBlock language="typescript">
  {ConfigurableModelDeclarativelyExample}
</CodeBlock>